diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
| commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
| tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Tools/DumpRenderTree | |
| download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz | |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Tools/DumpRenderTree')
408 files changed, 70902 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp new file mode 100644 index 000000000..b367d5c46 --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityController.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityUIElement.h" +#include <JavaScriptCore/JSRetainPtr.h> + +// Static Value Getters + +static JSValueRef getFocusedElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->focusedElement()); +} + +static JSValueRef getRootElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->rootElement()); +} + +// Object Creation + +void AccessibilityController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> accessibilityControllerStr(Adopt, JSStringCreateWithUTF8CString("accessibilityController")); + + JSClassRef classRef = getJSClass(); + JSValueRef accessibilityControllerObject = JSObjectMake(context, classRef, this); + JSClassRelease(classRef); + + JSObjectSetProperty(context, windowObject, accessibilityControllerStr.get(), accessibilityControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); +} + +static JSValueRef logFocusEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + controller->setLogFocusEvents(true); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef logValueChangeEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + controller->setLogValueChangeEvents(true); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef logScrollingStartEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + controller->setLogScrollingStartEvents(true); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef logAccessibilityEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + controller->setLogAccessibilityEvents(true); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef getElementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int x = 0; + int y = 0; + if (argumentCount == 2) { + x = JSValueToNumber(context, arguments[0], exception); + y = JSValueToNumber(context, arguments[1], exception); + } + + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->elementAtPoint(x, y)); +} + +static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeBoolean(context, false); + + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + JSObjectRef callback = JSValueToObject(context, arguments[0], exception); + bool succeeded = controller->addNotificationListener(callback); + return JSValueMakeBoolean(context, succeeded); +} + +static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); + controller->removeNotificationListener(); + return JSValueMakeUndefined(context); +} + +JSClassRef AccessibilityController::getJSClass() +{ + static JSStaticFunction staticFunctions[] = { + { "logFocusEvents", logFocusEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "logValueChangeEvents", logValueChangeEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "logScrollingStartEvents", logScrollingStartEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "logAccessibilityEvents", logAccessibilityEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "elementAtPoint", getElementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSStaticValue staticValues[] = { + { "focusedElement", getFocusedElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "rootElement", getRootElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0, 0 } + }; + + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "AccessibilityController", 0, staticValues, staticFunctions, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return JSClassCreate(&classDefinition); +} + +void AccessibilityController::resetToConsistentState() +{ + setLogFocusEvents(false); + setLogValueChangeEvents(false); + setLogScrollingStartEvents(false); + setLogAccessibilityEvents(false); +} diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h new file mode 100644 index 000000000..1d52353cd --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityController.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 <JavaScriptCore/JSObjectRef.h> +#include <string> +#include <wtf/HashMap.h> +#include <wtf/Platform.h> +#if PLATFORM(WIN) +#include <windows.h> +#endif + +class AccessibilityController { +public: + AccessibilityController(); + ~AccessibilityController(); + + void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception); + + // Controller Methods - platform-independent implementations + AccessibilityUIElement rootElement(); + AccessibilityUIElement focusedElement(); + AccessibilityUIElement elementAtPoint(int x, int y); + + void setLogFocusEvents(bool); + void setLogValueChangeEvents(bool); + void setLogScrollingStartEvents(bool); + void setLogAccessibilityEvents(bool); + + void resetToConsistentState(); + + // Global notification listener, captures notifications on any object. + bool addNotificationListener(JSObjectRef functionCallback); + void removeNotificationListener(); + +#if PLATFORM(WIN) + // Helper methods so this class can add the listeners on behalf of AccessibilityUIElement. + void winAddNotificationListener(PlatformUIElement, JSObjectRef functionCallback); + void winNotificationReceived(PlatformUIElement, const std::string& eventName); +#endif + +private: + static JSClassRef getJSClass(); + +#if PLATFORM(WIN) + HWINEVENTHOOK m_focusEventHook; + HWINEVENTHOOK m_valueChangeEventHook; + HWINEVENTHOOK m_scrollingStartEventHook; + + HWINEVENTHOOK m_allEventsHook; + HWINEVENTHOOK m_notificationsEventHook; + HashMap<PlatformUIElement, JSObjectRef> m_notificationListeners; +#endif + +#if PLATFORM(MAC) + RetainPtr<NotificationHandler> m_globalNotificationHandler; +#endif +}; + +#endif // AccessibilityController_h diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.cpp b/Tools/DumpRenderTree/AccessibilityTextMarker.cpp new file mode 100644 index 000000000..12504978b --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityTextMarker.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityTextMarker.h" + +#include "AccessibilityUIElement.h" +#include <JavaScriptCore/JSRetainPtr.h> + +// MARK: AccessibilityTextMarker + +// Callback methods + +AccessibilityTextMarker* toTextMarker(JSObjectRef object) +{ + return static_cast<AccessibilityTextMarker*>(JSObjectGetPrivate(object)); +} + +static JSValueRef isMarkerEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeBoolean(context, false); + + JSObjectRef otherMarker = JSValueToObject(context, arguments[0], exception); + return JSValueMakeBoolean(context, toTextMarker(thisObject)->isEqual(toTextMarker(otherMarker))); +} + +// Destruction + +static void markerFinalize(JSObjectRef thisObject) +{ + delete toTextMarker(thisObject); +} + +// Object Creation + +JSObjectRef AccessibilityTextMarker::makeJSAccessibilityTextMarker(JSContextRef context, const AccessibilityTextMarker& element) +{ + return JSObjectMake(context, AccessibilityTextMarker::getJSClass(), new AccessibilityTextMarker(element)); +} + +JSClassRef AccessibilityTextMarker::getJSClass() +{ + static JSStaticValue staticValues[] = { + { 0, 0, 0, 0 } + }; + + static JSStaticFunction staticFunctions[] = { + { "isEqual", isMarkerEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "AccessibilityTextMarker", 0, staticValues, staticFunctions, + 0, markerFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + static JSClassRef accessibilityTextMarkerClass = JSClassCreate(&classDefinition); + return accessibilityTextMarkerClass; +} + +// MARK: AccessibilityTextMarkerRange + +// Callback methods + +AccessibilityTextMarkerRange* toTextMarkerRange(JSObjectRef object) +{ + return static_cast<AccessibilityTextMarkerRange*>(JSObjectGetPrivate(object)); +} + +static JSValueRef isMarkerRangeEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeBoolean(context, false); + + JSObjectRef otherMarker = JSValueToObject(context, arguments[0], exception); + return JSValueMakeBoolean(context, toTextMarkerRange(thisObject)->isEqual(toTextMarkerRange(otherMarker))); +} + +// Destruction + +static void markerRangeFinalize(JSObjectRef thisObject) +{ + delete toTextMarkerRange(thisObject); +} + +// Object Creation + +JSObjectRef AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(JSContextRef context, const AccessibilityTextMarkerRange& element) +{ + return JSObjectMake(context, AccessibilityTextMarkerRange::getJSClass(), new AccessibilityTextMarkerRange(element)); +} + +JSClassRef AccessibilityTextMarkerRange::getJSClass() +{ + static JSStaticValue staticValues[] = { + { 0, 0, 0, 0 } + }; + + static JSStaticFunction staticFunctions[] = { + { "isEqual", isMarkerRangeEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "AccessibilityTextMarkerRange", 0, staticValues, staticFunctions, + 0, markerRangeFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + static JSClassRef accessibilityTextMarkerRangeClass = JSClassCreate(&classDefinition); + return accessibilityTextMarkerRangeClass; +} diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.h b/Tools/DumpRenderTree/AccessibilityTextMarker.h new file mode 100644 index 000000000..aeb078d78 --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityTextMarker.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 AccessibilityTextMarker_h +#define AccessibilityTextMarker_h + +#include <JavaScriptCore/JSObjectRef.h> + +#if PLATFORM(MAC) +#define SUPPORTS_AX_TEXTMARKERS 1 +#else +#define SUPPORTS_AX_TEXTMARKERS 0 +#endif + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +typedef CFTypeRef PlatformTextMarker; +typedef CFTypeRef PlatformTextMarkerRange; +#else +typedef void* PlatformTextMarker; +typedef void* PlatformTextMarkerRange; +#endif + +class AccessibilityUIElement; + +class AccessibilityTextMarker { +public: + AccessibilityTextMarker(PlatformTextMarker); + AccessibilityTextMarker(const AccessibilityTextMarker&); + ~AccessibilityTextMarker(); + + PlatformTextMarker platformTextMarker() const; + + static JSObjectRef makeJSAccessibilityTextMarker(JSContextRef, const AccessibilityTextMarker&); + bool isEqual(AccessibilityTextMarker*); + +private: + static JSClassRef getJSClass(); +#if PLATFORM(MAC) + RetainPtr<PlatformTextMarker> m_textMarker; +#else + PlatformTextMarker m_textMarker; +#endif +}; + +class AccessibilityTextMarkerRange { +public: + AccessibilityTextMarkerRange(PlatformTextMarkerRange); + AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&); + ~AccessibilityTextMarkerRange(); + + PlatformTextMarkerRange platformTextMarkerRange() const; + + static JSObjectRef makeJSAccessibilityTextMarkerRange(JSContextRef, const AccessibilityTextMarkerRange&); + bool isEqual(AccessibilityTextMarkerRange*); + +private: + static JSClassRef getJSClass(); +#if PLATFORM(MAC) + RetainPtr<PlatformTextMarkerRange> m_textMarkerRange; +#else + PlatformTextMarkerRange m_textMarkerRange; +#endif +}; + +AccessibilityTextMarker* toTextMarker(JSObjectRef object); +AccessibilityTextMarkerRange* toTextMarkerRange(JSObjectRef object); + +#if !SUPPORTS_AX_TEXTMARKERS +inline AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker) { } +inline AccessibilityTextMarker::AccessibilityTextMarker(const AccessibilityTextMarker&) { } +inline AccessibilityTextMarker::~AccessibilityTextMarker() { } +inline bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker*) { return false; } +inline PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const { return m_textMarker; } + +inline AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange) { } +inline AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&) { } +inline AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange() { } +inline bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange*) { return false; } +inline PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const { return m_textMarkerRange; } +#endif + +#endif // AccessibilityUIElement_h diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/AccessibilityUIElement.cpp new file mode 100644 index 000000000..67fc4d73c --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityUIElement.cpp @@ -0,0 +1,1122 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 <JavaScriptCore/JSRetainPtr.h> + +// Static Functions + +static inline AccessibilityUIElement* toAXElement(JSObjectRef object) +{ + // FIXME: We should ASSERT that it is the right class here. + return static_cast<AccessibilityUIElement*>(JSObjectGetPrivate(object)); +} + +static JSValueRef allAttributesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributes(Adopt, toAXElement(thisObject)->allAttributes()); + return JSValueMakeString(context, attributes.get()); +} + +static JSValueRef attributesOfLinkedUIElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> linkedUIDescription(Adopt, toAXElement(thisObject)->attributesOfLinkedUIElements()); + return JSValueMakeString(context, linkedUIDescription.get()); +} + +static JSValueRef attributesOfDocumentLinksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> linkedUIDescription(Adopt, toAXElement(thisObject)->attributesOfDocumentLinks()); + return JSValueMakeString(context, linkedUIDescription.get()); +} + +static JSValueRef attributesOfChildrenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> childrenDescription(Adopt, toAXElement(thisObject)->attributesOfChildren()); + return JSValueMakeString(context, childrenDescription.get()); +} + +static JSValueRef parameterizedAttributeNamesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> parameterizedAttributeNames(Adopt, toAXElement(thisObject)->parameterizedAttributeNames()); + return JSValueMakeString(context, parameterizedAttributeNames.get()); +} + +static JSValueRef attributesOfColumnHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfColumnHeaders(Adopt, toAXElement(thisObject)->attributesOfColumnHeaders()); + return JSValueMakeString(context, attributesOfColumnHeaders.get()); +} + +static JSValueRef attributesOfRowHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfRowHeaders(Adopt, toAXElement(thisObject)->attributesOfRowHeaders()); + return JSValueMakeString(context, attributesOfRowHeaders.get()); +} + +static JSValueRef attributesOfColumnsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfColumns(Adopt, toAXElement(thisObject)->attributesOfColumns()); + return JSValueMakeString(context, attributesOfColumns.get()); +} + +static JSValueRef attributesOfRowsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfRows(Adopt, toAXElement(thisObject)->attributesOfRows()); + return JSValueMakeString(context, attributesOfRows.get()); +} + +static JSValueRef attributesOfVisibleCellsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfVisibleCells(Adopt, toAXElement(thisObject)->attributesOfVisibleCells()); + return JSValueMakeString(context, attributesOfVisibleCells.get()); +} + +static JSValueRef attributesOfHeaderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attributesOfHeader(Adopt, toAXElement(thisObject)->attributesOfHeader()); + return JSValueMakeString(context, attributesOfHeader.get()); +} + +static JSValueRef indexInTableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->indexInTable()); +} + +static JSValueRef rowIndexRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> rowIndexRange(Adopt, toAXElement(thisObject)->rowIndexRange()); + return JSValueMakeString(context, rowIndexRange.get()); +} + +static JSValueRef columnIndexRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> columnIndexRange(Adopt, toAXElement(thisObject)->columnIndexRange()); + return JSValueMakeString(context, columnIndexRange.get()); +} + +static JSValueRef lineForIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return JSValueMakeNumber(context, toAXElement(thisObject)->lineForIndex(indexNumber)); +} + +static JSValueRef rangeForLineCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + JSRetainPtr<JSStringRef> rangeLine(Adopt, toAXElement(thisObject)->rangeForLine(indexNumber)); + return JSValueMakeString(context, rangeLine.get()); +} + +static JSValueRef boundsForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned location = UINT_MAX, length = 0; + if (argumentCount == 2) { + location = JSValueToNumber(context, arguments[0], exception); + length = JSValueToNumber(context, arguments[1], exception); + } + + JSRetainPtr<JSStringRef> boundsDescription(Adopt, toAXElement(thisObject)->boundsForRange(location, length)); + return JSValueMakeString(context, boundsDescription.get()); +} + +static JSValueRef stringForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned location = UINT_MAX, length = 0; + if (argumentCount == 2) { + location = JSValueToNumber(context, arguments[0], exception); + length = JSValueToNumber(context, arguments[1], exception); + } + + JSRetainPtr<JSStringRef> stringDescription(Adopt, toAXElement(thisObject)->stringForRange(location, length)); + return JSValueMakeString(context, stringDescription.get()); +} + +static JSValueRef attributedStringForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned location = UINT_MAX, length = 0; + if (argumentCount == 2) { + location = JSValueToNumber(context, arguments[0], exception); + length = JSValueToNumber(context, arguments[1], exception); + } + + JSRetainPtr<JSStringRef> stringDescription(Adopt, toAXElement(thisObject)->attributedStringForRange(location, length)); + return JSValueMakeString(context, stringDescription.get()); +} + +static JSValueRef attributedStringRangeIsMisspelledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned location = UINT_MAX, length = 0; + if (argumentCount == 2) { + location = JSValueToNumber(context, arguments[0], exception); + length = JSValueToNumber(context, arguments[1], exception); + } + + return JSValueMakeBoolean(context, toAXElement(thisObject)->attributedStringRangeIsMisspelled(location, length)); +} + +static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityUIElement* startElement = 0; + bool isDirectionNext = true; + JSStringRef searchKey = 0; + JSStringRef searchText = 0; + if (argumentCount == 4) { + JSObjectRef startElementObject = JSValueToObject(context, arguments[0], exception); + if (startElementObject) + startElement = toAXElement(startElementObject); + isDirectionNext = JSValueToBoolean(context, arguments[1]); + if (JSValueIsString(context, arguments[2])) + searchKey = JSValueToStringCopy(context, arguments[2], exception); + if (JSValueIsString(context, arguments[3])) + searchText = JSValueToStringCopy(context, arguments[3], exception); + } + + JSObjectRef resultObject = AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(startElement, isDirectionNext, searchKey, searchText)); + if (searchKey) + JSStringRelease(searchKey); + if (searchText) + JSStringRelease(searchText); + + return resultObject; +} + +static JSValueRef indexOfChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return 0; + + JSObjectRef otherElement = JSValueToObject(context, arguments[0], exception); + AccessibilityUIElement* childElement = toAXElement(otherElement); + return JSValueMakeNumber(context, (double)toAXElement(thisObject)->indexOfChild(childElement)); +} + +static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->getChildAtIndex(indexNumber)); +} + +static JSValueRef selectedChildAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->selectedChildAtIndex(indexNumber)); +} + +static JSValueRef linkedUIElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->linkedUIElementAtIndex(indexNumber)); +} + +static JSValueRef disclosedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = 0; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedRowAtIndex(indexNumber)); +} + +static JSValueRef ariaOwnsElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = 0; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaOwnsElementAtIndex(indexNumber)); +} + +static JSValueRef ariaFlowToElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = 0; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaFlowToElementAtIndex(indexNumber)); +} + +static JSValueRef selectedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = 0; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->selectedRowAtIndex(indexNumber)); +} + +static JSValueRef isEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSObjectRef otherElement = 0; + if (argumentCount == 1) + otherElement = JSValueToObject(context, arguments[0], exception); + else + return JSValueMakeBoolean(context, false); + + return JSValueMakeBoolean(context, toAXElement(thisObject)->isEqual(toAXElement(otherElement))); +} + +static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSObjectRef element = 0; + if (argumentCount == 1) + element = JSValueToObject(context, arguments[0], exception); + + toAXElement(thisObject)->setSelectedChild(toAXElement(element)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int x = 0; + int y = 0; + if (argumentCount == 2) { + x = JSValueToNumber(context, arguments[0], exception); + y = JSValueToNumber(context, arguments[1], exception); + } + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->elementAtPoint(x, y)); +} + +static JSValueRef isAttributeSupportedCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef attribute = 0; + if (argumentCount == 1) + attribute = JSValueToStringCopy(context, arguments[0], exception); + JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSupported(attribute)); + if (attribute) + JSStringRelease(attribute); + return result; +} + +static JSValueRef isAttributeSettableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef attribute = 0; + if (argumentCount == 1) + attribute = JSValueToStringCopy(context, arguments[0], exception); + JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSettable(attribute)); + if (attribute) + JSStringRelease(attribute); + return result; +} + + +static JSValueRef isActionSupportedCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef action = 0; + if (argumentCount == 1) + action = JSValueToStringCopy(context, arguments[0], exception); + JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isActionSupported(action)); + if (action) + JSStringRelease(action); + return result; +} + +static JSValueRef boolAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef attribute = 0; + if (argumentCount == 1) + attribute = JSValueToStringCopy(context, arguments[0], exception); + bool val = toAXElement(thisObject)->boolAttributeValue(attribute); + JSValueRef result = JSValueMakeBoolean(context, val); + if (attribute) + JSStringRelease(attribute); + return result; +} + +static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef attribute = 0; + if (argumentCount == 1) + attribute = JSValueToStringCopy(context, arguments[0], exception); + JSRetainPtr<JSStringRef> stringAttributeValue(Adopt, toAXElement(thisObject)->stringAttributeValue(attribute)); + JSValueRef result = JSValueMakeString(context, stringAttributeValue.get()); + if (attribute) + JSStringRelease(attribute); + return result; +} + +static JSValueRef uiElementAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> attribute; + if (argumentCount == 1) + attribute.adopt(JSValueToStringCopy(context, arguments[0], exception)); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementAttributeValue(attribute.get())); +} + +static JSValueRef numberAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSStringRef attribute = 0; + if (argumentCount == 1) + attribute = JSValueToStringCopy(context, arguments[0], exception); + double val = toAXElement(thisObject)->numberAttributeValue(attribute); + JSValueRef result = JSValueMakeNumber(context, val); + if (attribute) + JSStringRelease(attribute); + return result; +} + +static JSValueRef cellForColumnAndRowCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned column = 0, row = 0; + if (argumentCount == 2) { + column = JSValueToNumber(context, arguments[0], exception); + row = JSValueToNumber(context, arguments[1], exception); + } + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->cellForColumnAndRow(column, row)); +} + +static JSValueRef titleUIElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->titleUIElement()); +} + +static JSValueRef parentElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->parentElement()); +} + +static JSValueRef disclosedByRowCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedByRow()); +} + +static JSValueRef setSelectedTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + unsigned location = UINT_MAX, length = 0; + if (argumentCount == 2) { + location = JSValueToNumber(context, arguments[0], exception); + length = JSValueToNumber(context, arguments[1], exception); + } + + toAXElement(thisObject)->setSelectedTextRange(location, length); + return JSValueMakeUndefined(context); +} + +static JSValueRef incrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->increment(); + return JSValueMakeUndefined(context); +} + +static JSValueRef decrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->decrement(); + return JSValueMakeUndefined(context); +} + +static JSValueRef showMenuCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->showMenu(); + return JSValueMakeUndefined(context); +} + +static JSValueRef pressCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->press(); + return JSValueMakeUndefined(context); +} + +static JSValueRef takeFocusCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->takeFocus(); + return JSValueMakeUndefined(context); +} + +static JSValueRef takeSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->takeSelection(); + return JSValueMakeUndefined(context); +} + +static JSValueRef addSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->addSelection(); + return JSValueMakeUndefined(context); +} + +static JSValueRef removeSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->removeSelection(); + return JSValueMakeUndefined(context); +} + +static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityUIElement* uiElement = 0; + if (argumentCount == 1) + uiElement = toAXElement(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForElement(uiElement)); +} + +static JSValueRef attributedStringForTextMarkerRangeContainsAttributeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarkerRange* markerRange = 0; + JSStringRef attribute = 0; + if (argumentCount == 2) { + attribute = JSValueToStringCopy(context, arguments[0], exception); + markerRange = toTextMarkerRange(JSValueToObject(context, arguments[1], exception)); + } + + JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->attributedStringForTextMarkerRangeContainsAttribute(attribute, markerRange)); + if (attribute) + JSStringRelease(attribute); + + return result; +} + +static JSValueRef textMarkerRangeLengthCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarkerRange* range = 0; + if (argumentCount == 1) + range = toTextMarkerRange(JSValueToObject(context, arguments[0], exception)); + + return JSValueMakeNumber(context, (int)toAXElement(thisObject)->textMarkerRangeLength(range)); +} + +static JSValueRef nextTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarker* marker = 0; + if (argumentCount == 1) + marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextTextMarker(marker)); +} + +static JSValueRef previousTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarker* marker = 0; + if (argumentCount == 1) + marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousTextMarker(marker)); +} + +static JSValueRef stringForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarkerRange* markerRange = 0; + if (argumentCount == 1) + markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception)); + + JSRetainPtr<JSStringRef> markerRangeString(Adopt, toAXElement(thisObject)->stringForTextMarkerRange(markerRange)); + return JSValueMakeString(context, markerRangeString.get()); +} + +static JSValueRef textMarkerForPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int x = 0; + int y = 0; + if (argumentCount == 2) { + x = JSValueToNumber(context, arguments[0], exception); + y = JSValueToNumber(context, arguments[1], exception); + } + + return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->textMarkerForPoint(x, y)); +} + +static JSValueRef textMarkerRangeForMarkersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarker* startMarker = 0; + AccessibilityTextMarker* endMarker = 0; + if (argumentCount == 2) { + startMarker = toTextMarker(JSValueToObject(context, arguments[0], exception)); + endMarker = toTextMarker(JSValueToObject(context, arguments[1], exception)); + } + + return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForMarkers(startMarker, endMarker)); +} + +static JSValueRef startTextMarkerForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarkerRange* markerRange = 0; + if (argumentCount == 1) + markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->startTextMarkerForTextMarkerRange(markerRange)); +} + +static JSValueRef endTextMarkerForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarkerRange* markerRange = 0; + if (argumentCount == 1) + markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarkerForTextMarkerRange(markerRange)); +} + +static JSValueRef accessibilityElementForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + AccessibilityTextMarker* marker = 0; + if (argumentCount == 1) + marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->accessibilityElementForTextMarker(marker)); +} + +// Static Value Getters + +static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> dropEffects(Adopt, toAXElement(thisObject)->ariaDropEffects()); + return JSValueMakeString(context, dropEffects.get()); +} + +static JSValueRef getARIAIsGrabbedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->ariaIsGrabbed()); +} + +static JSValueRef getIsValidCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + AccessibilityUIElement* uiElement = toAXElement(thisObject); + if (!uiElement->platformUIElement()) + return JSValueMakeBoolean(context, false); + + // There might be other platform logic that one could check here... + + return JSValueMakeBoolean(context, true); +} + +static JSValueRef getRoleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> role(Adopt, toAXElement(thisObject)->role()); + return JSValueMakeString(context, role.get()); +} + +static JSValueRef getSubroleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> role(Adopt, toAXElement(thisObject)->subrole()); + return JSValueMakeString(context, role.get()); +} + +static JSValueRef getRoleDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> roleDesc(Adopt, toAXElement(thisObject)->roleDescription()); + return JSValueMakeString(context, roleDesc.get()); +} + +static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> title(Adopt, toAXElement(thisObject)->title()); + return JSValueMakeString(context, title.get()); +} + +static JSValueRef getDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> description(Adopt, toAXElement(thisObject)->description()); + return JSValueMakeString(context, description.get()); +} + +static JSValueRef getStringValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> stringValue(Adopt, toAXElement(thisObject)->stringValue()); + return JSValueMakeString(context, stringValue.get()); +} + +static JSValueRef getLanguageCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->language()); + return JSValueMakeString(context, language.get()); +} + +static JSValueRef getHelpTextCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->helpText()); + return JSValueMakeString(context, language.get()); +} + +static JSValueRef getOrientationCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> orientation(Adopt, toAXElement(thisObject)->orientation()); + return JSValueMakeString(context, orientation.get()); +} + +static JSValueRef getChildrenCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->childrenCount()); +} + +static JSValueRef rowCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->rowCount()); +} + +static JSValueRef columnCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->columnCount()); +} + +static JSValueRef getXCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->x()); +} + +static JSValueRef getYCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->y()); +} + +static JSValueRef getWidthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->width()); +} + +static JSValueRef getHeightCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->height()); +} + +static JSValueRef getClickPointXCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->clickPointX()); +} + +static JSValueRef getClickPointYCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->clickPointY()); +} + +static JSValueRef getIntValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->intValue()); +} + +static JSValueRef getMinValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->minValue()); +} + +static JSValueRef getMaxValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->maxValue()); +} + +static JSValueRef getInsertionPointLineNumberCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->insertionPointLineNumber()); +} + +static JSValueRef getSelectedTextRangeCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> selectedTextRange(Adopt, toAXElement(thisObject)->selectedTextRange()); + return JSValueMakeString(context, selectedTextRange.get()); +} + +static JSValueRef getIsEnabledCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isEnabled()); +} + +static JSValueRef getIsRequiredCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isRequired()); +} + +static JSValueRef getIsFocusedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocused()); +} + +static JSValueRef getIsFocusableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocusable()); +} + +static JSValueRef getIsSelectedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelected()); +} + +static JSValueRef getIsSelectableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelectable()); +} + +static JSValueRef getIsMultiSelectableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isMultiSelectable()); +} + +static JSValueRef getIsSelectedOptionActiveCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelectedOptionActive()); +} + +static JSValueRef getIsExpandedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isExpanded()); +} + +static JSValueRef getIsCheckedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isChecked()); +} + +static JSValueRef getIsVisibleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isVisible()); +} + +static JSValueRef getIsOffScreenCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isOffScreen()); +} + +static JSValueRef getIsCollapsedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isCollapsed()); +} + +static JSValueRef isIgnoredCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->isIgnored()); +} + +static JSValueRef speakCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + JSRetainPtr<JSStringRef> speakString(Adopt, toAXElement(thisObject)->speak()); + return JSValueMakeString(context, speakString.get()); +} + +static JSValueRef selectedChildrenCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->selectedChildrenCount()); +} + +static JSValueRef horizontalScrollbarCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->horizontalScrollbar()); +} + +static JSValueRef verticalScrollbarCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->verticalScrollbar()); +} + +static JSValueRef getHasPopupCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeBoolean(context, toAXElement(thisObject)->hasPopup()); +} + +static JSValueRef hierarchicalLevelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +{ + return JSValueMakeNumber(context, toAXElement(thisObject)->hierarchicalLevel()); +} + +static JSValueRef getValueDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> valueDescription(Adopt, toAXElement(thisObject)->valueDescription()); + return JSValueMakeString(context, valueDescription.get()); +} + +static JSValueRef getAccessibilityValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> accessibilityValue(Adopt, toAXElement(thisObject)->accessibilityValue()); + return JSValueMakeString(context, accessibilityValue.get()); +} + +static JSValueRef getDocumentEncodingCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> documentEncoding(Adopt, toAXElement(thisObject)->documentEncoding()); + return JSValueMakeString(context, documentEncoding.get()); +} + +static JSValueRef getDocumentURICallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> documentURI(Adopt, toAXElement(thisObject)->documentURI()); + return JSValueMakeString(context, documentURI.get()); +} + +static JSValueRef getURLCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> url(Adopt, toAXElement(thisObject)->url()); + return JSValueMakeString(context, url.get()); +} + +static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeBoolean(context, false); + + JSObjectRef callback = JSValueToObject(context, arguments[0], exception); + bool succeeded = toAXElement(thisObject)->addNotificationListener(callback); + return JSValueMakeBoolean(context, succeeded); +} + +static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + toAXElement(thisObject)->removeNotificationListener(); + return JSValueMakeUndefined(context); +} + +// Implementation + +// Unsupported methods on various platforms. +#if !PLATFORM(MAC) +JSStringRef AccessibilityUIElement::speak() { return 0; } +JSStringRef AccessibilityUIElement::rangeForLine(int line) { return 0; } +void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { } +unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; } +AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned) const { return 0; } +AccessibilityUIElement AccessibilityUIElement::horizontalScrollbar() const { return 0; } +AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const { return 0; } +AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; } +#endif + +#if !PLATFORM(WIN) +bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) +{ + return platformUIElement() == otherElement->platformUIElement(); +} +#endif + +#if !SUPPORTS_AX_TEXTMARKERS + +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*) +{ + return 0; +} + +int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*) +{ + return 0; +} + +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker*, AccessibilityTextMarker*) +{ + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) +{ + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker*) +{ + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y) +{ + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker*) +{ + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker*) +{ + return 0; +} + +JSStringRef AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange*) +{ + return 0; +} + +bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*) +{ + return false; +} + +#endif + +// Destruction + +static void finalize(JSObjectRef thisObject) +{ + delete toAXElement(thisObject); +} + +// Object Creation + +JSObjectRef AccessibilityUIElement::makeJSAccessibilityUIElement(JSContextRef context, const AccessibilityUIElement& element) +{ + return JSObjectMake(context, AccessibilityUIElement::getJSClass(), new AccessibilityUIElement(element)); +} + +JSClassRef AccessibilityUIElement::getJSClass() +{ + static JSStaticValue staticValues[] = { + { "accessibilityValue", getAccessibilityValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "role", getRoleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "subrole", getSubroleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "roleDescription", getRoleDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "helpText", getHelpTextCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "stringValue", getStringValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "x", getXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "y", getYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "width", getWidthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "height", getHeightCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clickPointX", getClickPointXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clickPointY", getClickPointYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "intValue", getIntValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "minValue", getMinValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "maxValue", getMaxValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "childrenCount", getChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "rowCount", rowCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "columnCount", columnCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "insertionPointLineNumber", getInsertionPointLineNumberCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedTextRange", getSelectedTextRangeCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isEnabled", getIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isRequired", getIsRequiredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isFocused", getIsFocusedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isFocusable", getIsFocusableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isSelected", getIsSelectedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isSelectable", getIsSelectableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isMultiSelectable", getIsMultiSelectableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isSelectedOptionActive", getIsSelectedOptionActiveCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isExpanded", getIsExpandedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isChecked", getIsCheckedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isVisible", getIsVisibleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isOffScreen", getIsOffScreenCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isCollapsed", getIsCollapsedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hasPopup", getHasPopupCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "valueDescription", getValueDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hierarchicalLevel", hierarchicalLevelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "documentEncoding", getDocumentEncodingCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "documentURI", getDocumentURICallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "url", getURLCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isValid", getIsValidCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "orientation", getOrientationCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "ariaIsGrabbed", getARIAIsGrabbedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "ariaDropEffects", getARIADropEffectsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isIgnored", isIgnoredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "speak", speakCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedChildrenCount", selectedChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "horizontalScrollbar", horizontalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "verticalScrollbar", verticalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0, 0 } + }; + + static JSStaticFunction staticFunctions[] = { + { "allAttributes", allAttributesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfLinkedUIElements", attributesOfLinkedUIElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfDocumentLinks", attributesOfDocumentLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfChildren", attributesOfChildrenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "parameterizedAttributeNames", parameterizedAttributeNamesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "lineForIndex", lineForIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "rangeForLine", rangeForLineCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "boundsForRange", boundsForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributedStringForRange", attributedStringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributedStringRangeIsMisspelled", attributedStringRangeIsMisspelledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "uiElementForSearchPredicate", uiElementForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "indexOfChild", indexOfChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "elementAtPoint", elementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfColumnHeaders", attributesOfColumnHeadersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfRowHeaders", attributesOfRowHeadersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfColumns", attributesOfColumnsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfRows", attributesOfRowsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfVisibleCells", attributesOfVisibleCellsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributesOfHeader", attributesOfHeaderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "indexInTable", indexInTableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "rowIndexRange", rowIndexRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "columnIndexRange", columnIndexRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "cellForColumnAndRow", cellForColumnAndRowCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "titleUIElement", titleUIElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSelectedTextRange", setSelectedTextRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "stringAttributeValue", stringAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "uiElementAttributeValue", uiElementAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "numberAttributeValue", numberAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "boolAttributeValue", boolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isAttributeSupported", isAttributeSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isAttributeSettable", isAttributeSettableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isActionSupported", isActionSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "parentElement", parentElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "disclosedByRow", disclosedByRowCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "increment", incrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "decrement", decrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "showMenu", showMenuCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "press", pressCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "takeFocus", takeFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeSelection", removeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textMarkerRangeForElement", textMarkerRangeForElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "attributedStringForTextMarkerRangeContainsAttribute", attributedStringForTextMarkerRangeContainsAttributeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textMarkerRangeForMarkers", textMarkerRangeForMarkersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "startTextMarkerForTextMarkerRange", startTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "endTextMarkerForTextMarkerRange", endTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "accessibilityElementForTextMarker", accessibilityElementForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textMarkerRangeLength", textMarkerRangeLengthCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textMarkerForPoint", textMarkerForPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedChildAtIndex", selectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "AccessibilityUIElement", 0, staticValues, staticFunctions, + 0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + static JSClassRef accessibilityUIElementClass = JSClassCreate(&classDefinition); + return accessibilityUIElementClass; +} diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.h b/Tools/DumpRenderTree/AccessibilityUIElement.h new file mode 100644 index 000000000..38d35cf58 --- /dev/null +++ b/Tools/DumpRenderTree/AccessibilityUIElement.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityTextMarker.h" +#include <JavaScriptCore/JSObjectRef.h> +#include <wtf/Platform.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#ifdef __OBJC__ +typedef id PlatformUIElement; +#else +typedef struct objc_object* PlatformUIElement; +#endif +#elif PLATFORM(WIN) +#undef _WINSOCKAPI_ +#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h + +#include <WebCore/COMPtr.h> +#include <oleacc.h> + +typedef COMPtr<IAccessible> PlatformUIElement; +#elif PLATFORM(GTK) +#include <atk/atk.h> +typedef AtkObject* PlatformUIElement; +#else +typedef void* PlatformUIElement; +#endif + +#if PLATFORM(MAC) +#ifdef __OBJC__ +typedef id NotificationHandler; +#else +typedef struct objc_object* NotificationHandler; +#endif +#endif + +class AccessibilityUIElement { +public: + AccessibilityUIElement(PlatformUIElement); + AccessibilityUIElement(const AccessibilityUIElement&); + ~AccessibilityUIElement(); + + PlatformUIElement platformUIElement() { return m_element; } + + static JSObjectRef makeJSAccessibilityUIElement(JSContextRef, const AccessibilityUIElement&); + + bool isEqual(AccessibilityUIElement* otherElement); + + void getLinkedUIElements(Vector<AccessibilityUIElement>&); + void getDocumentLinks(Vector<AccessibilityUIElement>&); + void getChildren(Vector<AccessibilityUIElement>&); + void getChildrenWithRange(Vector<AccessibilityUIElement>&, unsigned location, unsigned length); + + AccessibilityUIElement elementAtPoint(int x, int y); + AccessibilityUIElement getChildAtIndex(unsigned); + unsigned indexOfChild(AccessibilityUIElement*); + int childrenCount(); + AccessibilityUIElement titleUIElement(); + AccessibilityUIElement parentElement(); + + void takeFocus(); + void takeSelection(); + void addSelection(); + void removeSelection(); + + // Methods - platform-independent implementations + JSStringRef allAttributes(); + JSStringRef attributesOfLinkedUIElements(); + AccessibilityUIElement linkedUIElementAtIndex(unsigned); + + JSStringRef attributesOfDocumentLinks(); + JSStringRef attributesOfChildren(); + JSStringRef parameterizedAttributeNames(); + void increment(); + void decrement(); + void showMenu(); + void press(); + + // Attributes - platform-independent implementations + JSStringRef stringAttributeValue(JSStringRef attribute); + double numberAttributeValue(JSStringRef attribute); + AccessibilityUIElement uiElementAttributeValue(JSStringRef attribute) const; + bool boolAttributeValue(JSStringRef attribute); + bool isAttributeSupported(JSStringRef attribute); + bool isAttributeSettable(JSStringRef attribute); + bool isActionSupported(JSStringRef action); + JSStringRef role(); + JSStringRef subrole(); + JSStringRef roleDescription(); + JSStringRef title(); + JSStringRef description(); + JSStringRef language(); + JSStringRef stringValue(); + JSStringRef accessibilityValue() const; + JSStringRef helpText() const; + JSStringRef orientation() const; + double x(); + double y(); + double width(); + double height(); + double intValue() const; + double minValue(); + double maxValue(); + JSStringRef valueDescription(); + int insertionPointLineNumber(); + JSStringRef selectedTextRange(); + bool isEnabled(); + bool isRequired() const; + + bool isFocused() const; + bool isFocusable() const; + bool isSelected() const; + bool isSelectable() const; + bool isMultiSelectable() const; + bool isSelectedOptionActive() const; + void setSelectedChild(AccessibilityUIElement*) const; + unsigned selectedChildrenCount() const; + AccessibilityUIElement selectedChildAtIndex(unsigned) const; + + bool isExpanded() const; + bool isChecked() const; + bool isVisible() const; + bool isOffScreen() const; + bool isCollapsed() const; + bool isIgnored() const; + bool hasPopup() const; + int hierarchicalLevel() const; + double clickPointX(); + double clickPointY(); + JSStringRef documentEncoding(); + JSStringRef documentURI(); + JSStringRef url(); + + // CSS3-speech properties. + JSStringRef speak(); + + // Table-specific attributes + JSStringRef attributesOfColumnHeaders(); + JSStringRef attributesOfRowHeaders(); + JSStringRef attributesOfColumns(); + JSStringRef attributesOfRows(); + JSStringRef attributesOfVisibleCells(); + JSStringRef attributesOfHeader(); + int indexInTable(); + JSStringRef rowIndexRange(); + JSStringRef columnIndexRange(); + int rowCount(); + int columnCount(); + + // Tree/Outline specific attributes + AccessibilityUIElement selectedRowAtIndex(unsigned); + AccessibilityUIElement disclosedByRow(); + AccessibilityUIElement disclosedRowAtIndex(unsigned); + + // ARIA specific + AccessibilityUIElement ariaOwnsElementAtIndex(unsigned); + AccessibilityUIElement ariaFlowToElementAtIndex(unsigned); + + // ARIA Drag and Drop + bool ariaIsGrabbed() const; + // A space concatentated string of all the drop effects. + JSStringRef ariaDropEffects() const; + + // Parameterized attributes + int lineForIndex(int); + JSStringRef rangeForLine(int); + JSStringRef boundsForRange(unsigned location, unsigned length); + void setSelectedTextRange(unsigned location, unsigned length); + JSStringRef stringForRange(unsigned location, unsigned length); + JSStringRef attributedStringForRange(unsigned location, unsigned length); + bool attributedStringRangeIsMisspelled(unsigned location, unsigned length); + AccessibilityUIElement uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText); + + // Table-specific + AccessibilityUIElement cellForColumnAndRow(unsigned column, unsigned row); + + // Scrollarea-specific + AccessibilityUIElement horizontalScrollbar() const; + AccessibilityUIElement verticalScrollbar() const; + + // Text markers. + AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement*); + AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker); + AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); + AccessibilityTextMarker endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); + AccessibilityTextMarker textMarkerForPoint(int x, int y); + AccessibilityTextMarker previousTextMarker(AccessibilityTextMarker*); + AccessibilityTextMarker nextTextMarker(AccessibilityTextMarker*); + AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*); + JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*); + int textMarkerRangeLength(AccessibilityTextMarkerRange*); + bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*); + + // Notifications + // Function callback should take one argument, the name of the notification. + bool addNotificationListener(JSObjectRef functionCallback); + // Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion. + void removeNotificationListener(); + +private: + static JSClassRef getJSClass(); + PlatformUIElement m_element; + + // A retained, platform specific object used to help manage notifications for this object. +#if PLATFORM(MAC) + NotificationHandler m_notificationHandler; +#endif +}; + +#endif // AccessibilityUIElement_h diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp new file mode 100644 index 000000000..562225395 --- /dev/null +++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010, Robert Eisele <robert@xarg.org> 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 "CyclicRedundancyCheck.h" + +#include <wtf/Vector.h> + +static void makeCrcTable(unsigned crcTable[256]) +{ + for (unsigned i = 0; i < 256; i++) { + unsigned c = i; + for (int k = 0; k < 8; k++) { + if (c & 1) + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + else + c = c >> 1; + } + crcTable[i] = c; + } +} + +unsigned computeCrc(const Vector<unsigned char>& buffer) +{ + static unsigned crcTable[256]; + static bool crcTableComputed = false; + if (!crcTableComputed) { + makeCrcTable(crcTable); + crcTableComputed = true; + } + + unsigned crc = 0xffffffffU; + for (size_t i = 0; i < buffer.size(); ++i) + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffU); + return crc ^ 0xffffffffU; +} + diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.h b/Tools/DumpRenderTree/CyclicRedundancyCheck.h new file mode 100644 index 000000000..ef1d78e86 --- /dev/null +++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 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 CyclicRedundancyCheck_h +#define CyclicRedundancyCheck_h + +#include <wtf/Vector.h> + +unsigned computeCrc(const Vector<unsigned char>&); + +#endif diff --git a/Tools/DumpRenderTree/DumpRenderTree.gypi b/Tools/DumpRenderTree/DumpRenderTree.gypi new file mode 100644 index 000000000..47442bf2a --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTree.gypi @@ -0,0 +1,97 @@ +{ + 'variables': { + 'drt_files': [ + 'chromium/AccessibilityController.cpp', + 'chromium/AccessibilityController.h', + 'chromium/AccessibilityUIElement.cpp', + 'chromium/AccessibilityUIElement.h', + 'chromium/CppBoundClass.cpp', + 'chromium/CppBoundClass.h', + 'chromium/CppVariant.cpp', + 'chromium/CppVariant.h', + 'chromium/DRTDevToolsAgent.cpp', + 'chromium/DRTDevToolsAgent.h', + 'chromium/DRTDevToolsClient.cpp', + 'chromium/DRTDevToolsClient.h', + 'chromium/DumpRenderTree.cpp', + 'chromium/EventSender.cpp', + 'chromium/EventSender.h', + 'chromium/GamepadController.cpp', + 'chromium/GamepadController.h', + 'chromium/LayoutTestController.cpp', + 'chromium/LayoutTestController.h', + 'chromium/MockSpellCheck.cpp', + 'chromium/MockSpellCheck.h', + 'chromium/NotificationPresenter.h', + 'chromium/NotificationPresenter.cpp', + 'chromium/PlainTextController.cpp', + 'chromium/PlainTextController.h', + 'chromium/Task.h', + 'chromium/Task.cpp', + 'chromium/TestEventPrinter.h', + 'chromium/TestEventPrinter.cpp', + 'chromium/TestNavigationController.cpp', + 'chromium/TestNavigationController.h', + 'chromium/TestShell.cpp', + 'chromium/TestShell.h', + 'chromium/TestShellLinux.cpp', + 'chromium/TestShellGtk.cpp', + 'chromium/TestShellMac.mm', + 'chromium/TestShellWin.cpp', + 'chromium/TestWebPlugin.cpp', + 'chromium/TestWebPlugin.h', + 'chromium/TextInputController.cpp', + 'chromium/TextInputController.h', + 'chromium/WebPermissions.cpp', + 'chromium/WebPermissions.h', + 'chromium/WebPreferences.cpp', + 'chromium/WebPreferences.h', + 'chromium/WebViewHost.cpp', + 'chromium/WebViewHost.h', + ], + 'test_plugin_files': [ + 'TestNetscapePlugIn/PluginObject.cpp', + 'TestNetscapePlugIn/PluginObject.h', + 'TestNetscapePlugIn/PluginObjectMac.mm', + 'TestNetscapePlugIn/PluginTest.cpp', + 'TestNetscapePlugIn/PluginTest.h', + 'TestNetscapePlugIn/TestObject.cpp', + 'TestNetscapePlugIn/TestObject.h', + 'TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp', + 'TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp', + 'TestNetscapePlugIn/Tests/FormValue.cpp', + 'TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp', + 'TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp', + 'TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp', + 'TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp', + 'TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp', + 'TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp', + 'TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp', + 'TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp', + 'TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp', + 'TestNetscapePlugIn/Tests/PrivateBrowsing.cpp', + 'TestNetscapePlugIn/main.cpp', + ], + 'conditions': [ + ['(OS=="linux" and toolkit_uses_gtk!=1) or OS=="android"', { + 'drt_files': [ + 'chromium/TestShellStub.cpp', + ], + }], + ['OS=="win"', { + 'drt_files': [ + 'chromium/WebThemeControlDRTWin.cpp', + 'chromium/WebThemeControlDRTWin.h', + 'chromium/WebThemeEngineDRTWin.cpp', + 'chromium/WebThemeEngineDRTWin.h', + ], + }], + ['OS=="mac"', { + 'drt_files': [ + 'chromium/WebThemeEngineDRTMac.mm', + 'chromium/WebThemeEngineDRTMac.h', + ], + }], + ], + } +} diff --git a/Tools/DumpRenderTree/DumpRenderTree.h b/Tools/DumpRenderTree/DumpRenderTree.h new file mode 100644 index 000000000..c1e83b5c9 --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTree.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTree_h +#define DumpRenderTree_h + +// FIXME: Remove this when all platforms are using config.h +#ifndef Config_H +#include <wtf/Platform.h> +#endif + +#if PLATFORM(MAC) +#include "DumpRenderTreeMac.h" +#elif PLATFORM(WIN) +#include "DumpRenderTreeWin.h" +#elif PLATFORM(GTK) +#include "DumpRenderTreeGtk.h" +#elif PLATFORM(WX) +#include "DumpRenderTreeWx.h" +#elif PLATFORM(EFL) +#include "DumpRenderTreeEfl.h" +#endif + +#include <string> +#include <wtf/RefPtr.h> + +#if !OS(OPENBSD) +std::wstring urlSuitableForTestResult(const std::wstring& url); +#endif + +class LayoutTestController; + +extern volatile bool done; + +// FIXME: This is a bad abstraction. We should insted pass this to other controller objects which need access to it. +extern RefPtr<LayoutTestController> gLayoutTestController; + +void dump(); +void displayWebView(); + +#endif // DumpRenderTree_h diff --git a/Tools/DumpRenderTree/DumpRenderTree.sln b/Tools/DumpRenderTree/DumpRenderTree.sln new file mode 100644 index 000000000..5a9a70a7b --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTree.sln @@ -0,0 +1,100 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpRenderTree", "win\DumpRenderTree.vcproj", "{6567DFD4-D6DE-4CD5-825D-17E353D160E1}" + ProjectSection(ProjectDependencies) = postProject + {C0737398-3565-439E-A2B8-AB2BE4D5430C} = {C0737398-3565-439E-A2B8-AB2BE4D5430C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestNetscapePlugin", "TestNetscapePlugin\win\TestNetscapePlugin.vcproj", "{C0737398-3565-439E-A2B8-AB2BE4D5430C}" + ProjectSection(ProjectDependencies) = postProject + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017} = {DD7949B6-F2B4-47C2-9C42-E21E84CB1017} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiff", "win\ImageDiff.vcproj", "{59CC0547-70AC-499C-9B19-EC01C6F61137}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpRenderTreeLauncher", "win\DumpRenderTreeLauncher.vcproj", "{2974EA02-840B-4995-8719-8920A61006F1}" + ProjectSection(ProjectDependencies) = postProject + {6567DFD4-D6DE-4CD5-825D-17E353D160E1} = {6567DFD4-D6DE-4CD5-825D-17E353D160E1} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiffLauncher", "win\ImageDiffLauncher.vcproj", "{DD7949B6-F2B4-47C2-9C42-E21E84CB1017}" + ProjectSection(ProjectDependencies) = postProject + {59CC0547-70AC-499C-9B19-EC01C6F61137} = {59CC0547-70AC-499C-9B19-EC01C6F61137} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_All|Win32 = Debug_All|Win32 + Debug_Cairo_CFLite|Win32 = Debug_Cairo_CFLite|Win32 + Debug|Win32 = Debug|Win32 + Production|Win32 = Production|Win32 + Release_Cairo_CFLite|Win32 = Release_Cairo_CFLite|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_All|Win32.ActiveCfg = Debug_All|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_All|Win32.Build.0 = Debug_All|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug|Win32.ActiveCfg = Debug|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug|Win32.Build.0 = Debug|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Production|Win32.ActiveCfg = Production|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Production|Win32.Build.0 = Production|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release|Win32.ActiveCfg = Release|Win32 + {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release|Win32.Build.0 = Release|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_All|Win32.ActiveCfg = Debug_All|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_All|Win32.Build.0 = Debug_All|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug|Win32.Build.0 = Debug|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Production|Win32.ActiveCfg = Production|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Production|Win32.Build.0 = Production|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.ActiveCfg = Release|Win32 + {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.Build.0 = Release|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_All|Win32.ActiveCfg = Debug_All|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_All|Win32.Build.0 = Debug_All|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug|Win32.ActiveCfg = Debug|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug|Win32.Build.0 = Debug|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Production|Win32.ActiveCfg = Production|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Production|Win32.Build.0 = Production|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.ActiveCfg = Release|Win32 + {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.Build.0 = Release|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug_All|Win32.ActiveCfg = Debug_All|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug_All|Win32.Build.0 = Debug_All|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug|Win32.ActiveCfg = Debug|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Debug|Win32.Build.0 = Debug|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Production|Win32.ActiveCfg = Production|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Production|Win32.Build.0 = Production|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Release|Win32.ActiveCfg = Release|Win32 + {2974EA02-840B-4995-8719-8920A61006F1}.Release|Win32.Build.0 = Release|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_All|Win32.ActiveCfg = Debug_All|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_All|Win32.Build.0 = Debug_All|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug|Win32.ActiveCfg = Debug|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug|Win32.Build.0 = Debug|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Production|Win32.ActiveCfg = Production|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Production|Win32.Build.0 = Production|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release|Win32.ActiveCfg = Release|Win32 + {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj new file mode 100644 index 000000000..2032302d1 --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj @@ -0,0 +1,1153 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + A84F608D08B1370600E9745F /* All */ = { + isa = PBXAggregateTarget; + buildConfigurationList = A84F609208B1371400E9745F /* Build configuration list for PBXAggregateTarget "All" */; + buildPhases = ( + ); + dependencies = ( + A84F609108B1370E00E9745F /* PBXTargetDependency */, + A84F608F08B1370E00E9745F /* PBXTargetDependency */, + 141BF238096A451E00E0753C /* PBXTargetDependency */, + 5DC82A701023C93D00FD1D3B /* PBXTargetDependency */, + ); + name = All; + productName = All; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 0F37A4A711E6628700275F54 /* PluginObjectMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */; }; + 0F37A4AA11E6629100275F54 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A752A108AF5D1F00138E45 /* QuartzCore.framework */; }; + 141BF435096A455900E0753C /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9335435F03D75502008635CE /* WebKit.framework */; }; + 141BF436096A455900E0753C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; }; + 141BF438096A455900E0753C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A817090308B164D300CCB9FB /* JavaScriptCore.framework */; }; + 141BF439096A455900E0753C /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; }; + 141BF453096A45EB00E0753C /* PluginObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 141BF447096A45C800E0753C /* PluginObject.h */; }; + 14770FE20A22ADF7009342EE /* GCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 14770FE00A22ADF7009342EE /* GCController.h */; }; + 1A14C8A51406DE0400B254F7 /* SupportsCarbonEventModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */; }; + 1A1E4298141141C400388758 /* PrivateBrowsing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */; }; + 1A215A8111F2609C008AD0F5 /* PluginTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */; }; + 1A215A8211F2609C008AD0F5 /* PluginTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A215A8011F2609C008AD0F5 /* PluginTest.h */; }; + 1A215BE711F27658008AD0F5 /* DocumentOpenInDestroyStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */; }; + 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */; }; + 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A31EB3713466AC100017372 /* ConvertPoint.cpp */; }; + 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */; }; + 1A5CC1F5137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */; }; + 1A66C35114576A920099A115 /* ContentsScaleFactor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */; }; + 1A8F02E80BB9B4EC008CFA34 /* TestObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A8F024C0BB9B056008CFA34 /* TestObject.h */; }; + 1AC6C8490D07638600CD3161 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C77F0D07589B00CD3161 /* main.cpp */; }; + 1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */; }; + 1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7810D07589B00CD3161 /* TestObject.cpp */; }; + 1AC77DCF120605B6005C19EF /* NPRuntimeRemoveProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */; }; + 1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */; }; + 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */; }; + 1AD9D2FE12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */; }; + 1AFF66BC137DEFD200791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */; }; + 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23BCB88F0EA57623003C6289 /* OpenGL.framework */; }; + 29CFBA10122736E600BC30C0 /* AccessibilityTextMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */; }; + 29CFBA11122736E600BC30C0 /* AccessibilityTextMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */; }; + 29CFBA2E12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */; }; + 3A5626CB131CA02A002BE6D9 /* StorageTrackerDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */; }; + 3A5626CC131CA036002BE6D9 /* StorageTrackerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */; }; + 417DAA1D137B3E24007C57FB /* WebCoreTestSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */; }; + 440590711268453800CFD48D /* WebArchiveDumpSupportMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */; }; + 4437730E125CBC3600AAE02C /* WebArchiveDumpSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */; }; + 4437730F125CBC4D00AAE02C /* WebArchiveDumpSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */; }; + 4AD6A11413C8124000EA9737 /* FormValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AD6A11313C8124000EA9737 /* FormValue.cpp */; }; + 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; }; + 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185F69E10714A57007AA393 /* HistoryDelegate.h */; }; + 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */; }; + 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */; }; + 5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */ = {isa = PBXBuildFile; fileRef = AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */; }; + 5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */; }; + 5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */; }; + 5DB9AC9A0F722C3600684641 /* WebKitWeightWatcher300.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */; }; + 5DB9AC9B0F722C3600684641 /* WebKitWeightWatcher400.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */; }; + 5DB9AC9C0F722C3600684641 /* WebKitWeightWatcher500.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */; }; + 5DB9AC9D0F722C3600684641 /* WebKitWeightWatcher600.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */; }; + 5DB9AC9E0F722C3600684641 /* WebKitWeightWatcher700.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */; }; + 5DB9AC9F0F722C3600684641 /* WebKitWeightWatcher800.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */; }; + 5DB9ACA00F722C3600684641 /* WebKitWeightWatcher900.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */; }; + 5DE8AE4413A2C15900D6A37D /* libWebCoreTestSupport.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */; }; + 80045AED147718E7008290A8 /* AccessibilityNotificationHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */; }; + 80045AEE147718E7008290A8 /* AccessibilityNotificationHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */; }; + 8465E2C70FFA8DF2003B8342 /* PixelDumpSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */; }; + 933BF5AB0F93FA5C000F0441 /* PlainTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = 933BF5A90F93FA5C000F0441 /* PlainTextController.h */; }; + 933BF5AC0F93FA5C000F0441 /* PlainTextController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */; }; + 9340994C08540CAE007F3BC8 /* DumpRenderTreePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */; }; + 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9335435F03D75502008635CE /* WebKit.framework */; }; + A817090008B163EF00CCB9FB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; }; + A817090408B164D300CCB9FB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A817090308B164D300CCB9FB /* JavaScriptCore.framework */; }; + A84F608A08B136DA00E9745F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; }; + A8B91ADA0CF3B32F008F91FF /* DumpRenderTreePasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */; }; + A8B91ADC0CF3B32F008F91FF /* DumpRenderTreeWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */; }; + A8B91AE00CF3B372008F91FF /* DumpRenderTreeWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */; }; + A8B91AE20CF3B372008F91FF /* DumpRenderTreePasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */; }; + A8B91BFD0CF522B4008F91FF /* CheckedMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */; }; + A8B91BFF0CF522B4008F91FF /* CheckedMalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */; }; + A8D79CEA0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */; }; + A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */; }; + AE8259F308D22463000507AB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; }; + AE8259F408D22463000507AB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; }; + B5A752A208AF5D1F00138E45 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A752A108AF5D1F00138E45 /* QuartzCore.framework */; }; + BC0131DA0C9772010087317D /* LayoutTestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0131D80C9772010087317D /* LayoutTestController.cpp */; }; + BC0131DB0C9772010087317D /* LayoutTestController.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0131D90C9772010087317D /* LayoutTestController.h */; }; + BC0E24E00E2D9451001B6BC2 /* AccessibilityUIElement.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */; }; + BC0E24E10E2D9451001B6BC2 /* AccessibilityUIElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */; }; + BC0E26150E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */; }; + BC47412A0D038A4C0072B006 /* JavaScriptThreading.h in Headers */ = {isa = PBXBuildFile; fileRef = BC4741290D038A4C0072B006 /* JavaScriptThreading.h */; }; + BC4741410D038A570072B006 /* JavaScriptThreadingPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */; }; + BC9D90240C97472E0099A4A3 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */; }; + BC9D90250C97472E0099A4A3 /* WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9D90220C97472E0099A4A3 /* WorkQueue.h */; }; + BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */; }; + BCA18B230C9B014B00114369 /* GCControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B210C9B014B00114369 /* GCControllerMac.mm */; }; + BCA18B240C9B014B00114369 /* LayoutTestControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */; }; + BCA18B260C9B015C00114369 /* WorkQueueItemMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */; }; + BCA18B310C9B01B400114369 /* ObjCController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B2F0C9B01B400114369 /* ObjCController.h */; }; + BCA18B320C9B01B400114369 /* ObjCController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B300C9B01B400114369 /* ObjCController.m */; }; + BCA18B380C9B021900114369 /* AppleScriptController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B360C9B021900114369 /* AppleScriptController.h */; }; + BCA18B390C9B021900114369 /* AppleScriptController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B370C9B021900114369 /* AppleScriptController.m */; }; + BCA18B3C0C9B024900114369 /* TextInputController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B3A0C9B024900114369 /* TextInputController.h */; }; + BCA18B490C9B02C400114369 /* TextInputController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B480C9B02C400114369 /* TextInputController.m */; }; + BCA18B610C9B08C200114369 /* EditingDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B570C9B08C200114369 /* EditingDelegate.h */; }; + BCA18B620C9B08C200114369 /* EditingDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B580C9B08C200114369 /* EditingDelegate.mm */; }; + BCA18B630C9B08C200114369 /* FrameLoadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */; }; + BCA18B640C9B08C200114369 /* FrameLoadDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */; }; + BCA18B650C9B08C200114369 /* PolicyDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */; }; + BCA18B660C9B08C200114369 /* PolicyDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */; }; + BCA18B670C9B08C200114369 /* ResourceLoadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */; }; + BCA18B680C9B08C200114369 /* ResourceLoadDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */; }; + BCA18B690C9B08C200114369 /* UIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5F0C9B08C200114369 /* UIDelegate.h */; }; + BCA18B6A0C9B08C200114369 /* UIDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B600C9B08C200114369 /* UIDelegate.mm */; }; + BCA18B6F0C9B08DB00114369 /* EventSendingController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B6B0C9B08DB00114369 /* EventSendingController.h */; }; + BCA18B700C9B08DB00114369 /* EventSendingController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */; }; + BCA18B710C9B08DB00114369 /* NavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B6D0C9B08DB00114369 /* NavigationController.h */; }; + BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B6E0C9B08DB00114369 /* NavigationController.m */; }; + BCA18B7A0C9B08F100114369 /* DumpRenderTreeDraggingInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */; }; + BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */; }; + BCA18B7D0C9B08F100114369 /* ObjCPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B760C9B08F100114369 /* ObjCPlugin.h */; }; + BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B770C9B08F100114369 /* ObjCPlugin.m */; }; + BCA18B7F0C9B08F100114369 /* ObjCPluginFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */; }; + BCA18B800C9B08F100114369 /* ObjCPluginFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */; }; + BCA18C0B0C9B59EF00114369 /* DumpRenderTreeMac.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */; }; + BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations"; }; }; + BCB284C70CFA83C4007E533E /* PixelDumpSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */; }; + BCB284CD0CFA83C8007E533E /* PixelDumpSupportCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */; }; + BCB284D00CFA83CC007E533E /* PixelDumpSupportCG.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */; }; + BCB284D60CFA83D1007E533E /* PixelDumpSupportMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */; }; + BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */; }; + BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; }; + BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; }; + BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; }; + C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */; }; + C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */; }; + C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */; }; + C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */; }; + E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */; }; + E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 141BF237096A451E00E0753C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 141BF21E096A441D00E0753C; + remoteInfo = TestNetscapePlugIn; + }; + 5DC82A6F1023C93D00FD1D3B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5DC82A661023C8DE00FD1D3B; + remoteInfo = "DumpRenderTree Perl Support"; + }; + A84F608E08B1370E00E9745F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B5A7525A08AF4A4A00138E45; + remoteInfo = ImageDiff; + }; + A84F609008B1370E00E9745F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9340994A08540CAE007F3BC8; + remoteInfo = DumpRenderTree; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5DB9ACAA0F722C4400684641 /* Copy Font Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = DumpRenderTree.resources; + dstSubfolderSpec = 7; + files = ( + 5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */, + 5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */, + 5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */, + 5DB9AC9A0F722C3600684641 /* WebKitWeightWatcher300.ttf in Copy Font Files */, + 5DB9AC9B0F722C3600684641 /* WebKitWeightWatcher400.ttf in Copy Font Files */, + 5DB9AC9C0F722C3600684641 /* WebKitWeightWatcher500.ttf in Copy Font Files */, + 5DB9AC9D0F722C3600684641 /* WebKitWeightWatcher600.ttf in Copy Font Files */, + 5DB9AC9E0F722C3600684641 /* WebKitWeightWatcher700.ttf in Copy Font Files */, + 5DB9AC9F0F722C3600684641 /* WebKitWeightWatcher800.ttf in Copy Font Files */, + 5DB9ACA00F722C3600684641 /* WebKitWeightWatcher900.ttf in Copy Font Files */, + ); + name = "Copy Font Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PluginObjectMac.mm; sourceTree = "<group>"; }; + 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestNetscapePlugIn.plugin; sourceTree = BUILT_PRODUCTS_DIR; }; + 141BF447096A45C800E0753C /* PluginObject.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PluginObject.h; sourceTree = "<group>"; }; + 141BF448096A45C800E0753C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; name = Info.plist; path = mac/Info.plist; sourceTree = "<group>"; }; + 14770FE00A22ADF7009342EE /* GCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCController.h; sourceTree = "<group>"; }; + 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SupportsCarbonEventModel.cpp; sourceTree = "<group>"; }; + 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrivateBrowsing.cpp; sourceTree = "<group>"; }; + 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentOpenInDestroyStream.cpp; sourceTree = "<group>"; }; + 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginTest.cpp; sourceTree = "<group>"; }; + 1A215A8011F2609C008AD0F5 /* PluginTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginTest.h; sourceTree = "<group>"; }; + 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeObjectFromDestroyedPlugin.cpp; sourceTree = "<group>"; }; + 1A31EB3713466AC100017372 /* ConvertPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertPoint.cpp; sourceTree = "<group>"; }; + 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLWithJavaScriptURLDestroyingPlugin.cpp; sourceTree = "<group>"; }; + 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLWithJavaScriptURL.cpp; sourceTree = "<group>"; }; + 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentsScaleFactor.cpp; sourceTree = "<group>"; }; + 1A8F024C0BB9B056008CFA34 /* TestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestObject.h; sourceTree = "<group>"; }; + 1AC6C77F0D07589B00CD3161 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; }; + 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginObject.cpp; sourceTree = "<group>"; }; + 1AC6C7810D07589B00CD3161 /* TestObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestObject.cpp; sourceTree = "<group>"; }; + 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeRemoveProperty.cpp; sourceTree = "<group>"; }; + 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPDeallocateCalledBeforeNPShutdown.cpp; sourceTree = "<group>"; }; + 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetUserAgentWithNullNPPFromNPPNew.cpp; sourceTree = "<group>"; }; + 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginScriptableNPObjectInvokeDefault.cpp; sourceTree = "<group>"; }; + 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLNotifyWithURLThatFailsToLoad.cpp; sourceTree = "<group>"; }; + 23BCB88F0EA57623003C6289 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; }; + 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityTextMarker.h; sourceTree = "<group>"; }; + 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityTextMarker.cpp; sourceTree = "<group>"; }; + 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityTextMarkerMac.mm; path = mac/AccessibilityTextMarkerMac.mm; sourceTree = "<group>"; }; + 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreePrefix.h; sourceTree = "<group>"; }; + 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher100.ttf; path = fonts/WebKitWeightWatcher100.ttf; sourceTree = "<group>"; }; + 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher200.ttf; path = fonts/WebKitWeightWatcher200.ttf; sourceTree = "<group>"; }; + 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher300.ttf; path = fonts/WebKitWeightWatcher300.ttf; sourceTree = "<group>"; }; + 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher400.ttf; path = fonts/WebKitWeightWatcher400.ttf; sourceTree = "<group>"; }; + 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher500.ttf; path = fonts/WebKitWeightWatcher500.ttf; sourceTree = "<group>"; }; + 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher600.ttf; path = fonts/WebKitWeightWatcher600.ttf; sourceTree = "<group>"; }; + 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher700.ttf; path = fonts/WebKitWeightWatcher700.ttf; sourceTree = "<group>"; }; + 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher800.ttf; path = fonts/WebKitWeightWatcher800.ttf; sourceTree = "<group>"; }; + 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher900.ttf; path = fonts/WebKitWeightWatcher900.ttf; sourceTree = "<group>"; }; + 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageTrackerDelegate.h; sourceTree = "<group>"; }; + 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StorageTrackerDelegate.mm; sourceTree = "<group>"; }; + 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebCoreTestSupport.h; path = WebCoreTestSupport/WebCoreTestSupport.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WebArchiveDumpSupportMac.mm; path = mac/WebArchiveDumpSupportMac.mm; sourceTree = "<group>"; }; + 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebArchiveDumpSupport.h; path = cf/WebArchiveDumpSupport.h; sourceTree = "<group>"; }; + 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebArchiveDumpSupport.cpp; path = cf/WebArchiveDumpSupport.cpp; sourceTree = "<group>"; }; + 4AD6A11313C8124000EA9737 /* FormValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormValue.cpp; sourceTree = "<group>"; }; + 5185F69E10714A57007AA393 /* HistoryDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryDelegate.h; path = mac/HistoryDelegate.h; sourceTree = "<group>"; }; + 5185F69F10714A57007AA393 /* HistoryDelegate.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = HistoryDelegate.mm; path = mac/HistoryDelegate.mm; sourceTree = "<group>"; }; + 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CyclicRedundancyCheck.cpp; sourceTree = "<group>"; }; + 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CyclicRedundancyCheck.h; sourceTree = "<group>"; }; + 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessibilityNotificationHandler.h; path = mac/AccessibilityNotificationHandler.h; sourceTree = "<group>"; }; + 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityNotificationHandler.mm; path = mac/AccessibilityNotificationHandler.mm; sourceTree = "<group>"; }; + 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PixelDumpSupport.cpp; sourceTree = "<group>"; }; + 9335435F03D75502008635CE /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 933BF5A90F93FA5C000F0441 /* PlainTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlainTextController.h; path = mac/PlainTextController.h; sourceTree = "<group>"; }; + 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlainTextController.mm; path = mac/PlainTextController.mm; sourceTree = "<group>"; }; + 9340995408540CAF007F3BC8 /* DumpRenderTree */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpRenderTree; sourceTree = BUILT_PRODUCTS_DIR; }; + A803FF7409CAAD08009B2A37 /* DumpRenderTree.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = DumpRenderTree.h; sourceTree = "<group>"; }; + A817090308B164D300CCB9FB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A84F608908B136DA00E9745F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; }; + A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DumpRenderTreePasteboard.m; path = mac/DumpRenderTreePasteboard.m; sourceTree = "<group>"; }; + A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTreeWindow.mm; path = mac/DumpRenderTreeWindow.mm; sourceTree = "<group>"; }; + A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeWindow.h; path = mac/DumpRenderTreeWindow.h; sourceTree = "<group>"; }; + A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreePasteboard.h; path = mac/DumpRenderTreePasteboard.h; sourceTree = "<group>"; }; + A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckedMalloc.cpp; path = mac/CheckedMalloc.cpp; sourceTree = "<group>"; }; + A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CheckedMalloc.h; path = mac/CheckedMalloc.h; sourceTree = "<group>"; }; + A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreeFileDraggingSource.h; sourceTree = "<group>"; }; + A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DumpRenderTreeFileDraggingSource.m; sourceTree = "<group>"; }; + AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = "AHEM____.TTF"; path = "qt/fonts/AHEM____.TTF"; sourceTree = "<group>"; }; + AE8257EF08D22389000507AB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; + B5A7526708AF4A4A00138E45 /* ImageDiff */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ImageDiff; sourceTree = BUILT_PRODUCTS_DIR; }; + B5A752A108AF5D1F00138E45 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; }; + BC0131D80C9772010087317D /* LayoutTestController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutTestController.cpp; sourceTree = "<group>"; }; + BC0131D90C9772010087317D /* LayoutTestController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LayoutTestController.h; sourceTree = "<group>"; }; + BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityUIElement.h; sourceTree = "<group>"; }; + BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityUIElement.cpp; sourceTree = "<group>"; }; + BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityUIElementMac.mm; path = mac/AccessibilityUIElementMac.mm; sourceTree = "<group>"; }; + BC4741290D038A4C0072B006 /* JavaScriptThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptThreading.h; sourceTree = "<group>"; }; + BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaScriptThreadingPthreads.cpp; path = pthreads/JavaScriptThreadingPthreads.cpp; sourceTree = "<group>"; }; + BC646A4B136905DE00B35DED /* CompilerVersion.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CompilerVersion.xcconfig; path = mac/Configurations/CompilerVersion.xcconfig; sourceTree = "<group>"; }; + BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; }; + BC9D90220C97472E0099A4A3 /* WorkQueue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WorkQueue.h; sourceTree = "<group>"; }; + BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WorkQueueItem.h; sourceTree = "<group>"; }; + BCA18B210C9B014B00114369 /* GCControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = GCControllerMac.mm; path = mac/GCControllerMac.mm; sourceTree = "<group>"; }; + BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = LayoutTestControllerMac.mm; path = mac/LayoutTestControllerMac.mm; sourceTree = "<group>"; }; + BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = WorkQueueItemMac.mm; path = mac/WorkQueueItemMac.mm; sourceTree = "<group>"; }; + BCA18B2F0C9B01B400114369 /* ObjCController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCController.h; path = mac/ObjCController.h; sourceTree = "<group>"; }; + BCA18B300C9B01B400114369 /* ObjCController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCController.m; path = mac/ObjCController.m; sourceTree = "<group>"; }; + BCA18B360C9B021900114369 /* AppleScriptController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AppleScriptController.h; path = mac/AppleScriptController.h; sourceTree = "<group>"; }; + BCA18B370C9B021900114369 /* AppleScriptController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = AppleScriptController.m; path = mac/AppleScriptController.m; sourceTree = "<group>"; }; + BCA18B3A0C9B024900114369 /* TextInputController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextInputController.h; path = mac/TextInputController.h; sourceTree = "<group>"; }; + BCA18B480C9B02C400114369 /* TextInputController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = TextInputController.m; path = mac/TextInputController.m; sourceTree = "<group>"; }; + BCA18B570C9B08C200114369 /* EditingDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = EditingDelegate.h; path = mac/EditingDelegate.h; sourceTree = "<group>"; }; + BCA18B580C9B08C200114369 /* EditingDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = EditingDelegate.mm; path = mac/EditingDelegate.mm; sourceTree = "<group>"; }; + BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = FrameLoadDelegate.h; path = mac/FrameLoadDelegate.h; sourceTree = "<group>"; }; + BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = FrameLoadDelegate.mm; path = mac/FrameLoadDelegate.mm; sourceTree = "<group>"; }; + BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PolicyDelegate.h; path = mac/PolicyDelegate.h; sourceTree = "<group>"; }; + BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = PolicyDelegate.mm; path = mac/PolicyDelegate.mm; sourceTree = "<group>"; }; + BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ResourceLoadDelegate.h; path = mac/ResourceLoadDelegate.h; sourceTree = "<group>"; }; + BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = ResourceLoadDelegate.mm; path = mac/ResourceLoadDelegate.mm; sourceTree = "<group>"; }; + BCA18B5F0C9B08C200114369 /* UIDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = UIDelegate.h; path = mac/UIDelegate.h; sourceTree = "<group>"; }; + BCA18B600C9B08C200114369 /* UIDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = UIDelegate.mm; path = mac/UIDelegate.mm; sourceTree = "<group>"; }; + BCA18B6B0C9B08DB00114369 /* EventSendingController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = EventSendingController.h; path = mac/EventSendingController.h; sourceTree = "<group>"; }; + BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = EventSendingController.mm; path = mac/EventSendingController.mm; sourceTree = "<group>"; }; + BCA18B6D0C9B08DB00114369 /* NavigationController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = NavigationController.h; path = mac/NavigationController.h; sourceTree = "<group>"; }; + BCA18B6E0C9B08DB00114369 /* NavigationController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = NavigationController.m; path = mac/NavigationController.m; sourceTree = "<group>"; }; + BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeDraggingInfo.h; path = mac/DumpRenderTreeDraggingInfo.h; sourceTree = "<group>"; }; + BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTreeDraggingInfo.mm; path = mac/DumpRenderTreeDraggingInfo.mm; sourceTree = "<group>"; }; + BCA18B760C9B08F100114369 /* ObjCPlugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCPlugin.h; path = mac/ObjCPlugin.h; sourceTree = "<group>"; }; + BCA18B770C9B08F100114369 /* ObjCPlugin.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCPlugin.m; path = mac/ObjCPlugin.m; sourceTree = "<group>"; }; + BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCPluginFunction.h; path = mac/ObjCPluginFunction.h; sourceTree = "<group>"; }; + BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCPluginFunction.m; path = mac/ObjCPluginFunction.m; sourceTree = "<group>"; }; + BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeMac.h; path = mac/DumpRenderTreeMac.h; sourceTree = "<group>"; }; + BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTree.mm; path = mac/DumpRenderTree.mm; sourceTree = "<group>"; }; + BCB281EE0CFA713D007E533E /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = mac/Configurations/Base.xcconfig; sourceTree = "<group>"; }; + BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DumpRenderTree.xcconfig; path = mac/Configurations/DumpRenderTree.xcconfig; sourceTree = "<group>"; }; + BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DebugRelease.xcconfig; path = mac/Configurations/DebugRelease.xcconfig; sourceTree = "<group>"; }; + BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = ImageDiff.xcconfig; path = mac/Configurations/ImageDiff.xcconfig; sourceTree = "<group>"; }; + BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = TestNetscapePlugIn.xcconfig; path = mac/Configurations/TestNetscapePlugIn.xcconfig; sourceTree = "<group>"; }; + BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PixelDumpSupportCG.cpp; path = cg/PixelDumpSupportCG.cpp; sourceTree = "<group>"; }; + BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PixelDumpSupportCG.h; path = cg/PixelDumpSupportCG.h; sourceTree = "<group>"; }; + BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PixelDumpSupport.h; sourceTree = "<group>"; }; + BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = PixelDumpSupportMac.mm; path = mac/PixelDumpSupportMac.mm; sourceTree = "<group>"; }; + BCB284B20CFA82CB007E533E /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; }; + BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ImageDiffCG.cpp; path = cg/ImageDiffCG.cpp; sourceTree = "<group>"; }; + BCD08A580E10496B00A7D0C1 /* AccessibilityController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityController.h; sourceTree = "<group>"; }; + BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityController.cpp; sourceTree = "<group>"; }; + BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityControllerMac.mm; path = mac/AccessibilityControllerMac.mm; sourceTree = "<group>"; }; + BCF6C64F0C98E9C000AC063E /* GCController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GCController.cpp; sourceTree = "<group>"; }; + C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPPSetWindowCalledDuringDestruction.cpp; sourceTree = "<group>"; }; + C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PassDifferentNPPStruct.cpp; sourceTree = "<group>"; }; + C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EvaluateJSAfterRemovingPluginElement.cpp; sourceTree = "<group>"; }; + C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullNPPGetValuePointer.cpp; sourceTree = "<group>"; }; + E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockGeolocationProvider.h; path = mac/MockGeolocationProvider.h; sourceTree = "<group>"; }; + E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MockGeolocationProvider.mm; path = mac/MockGeolocationProvider.mm; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 141BF21D096A441D00E0753C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 141BF439096A455900E0753C /* Carbon.framework in Frameworks */, + 141BF436096A455900E0753C /* Cocoa.framework in Frameworks */, + 141BF438096A455900E0753C /* JavaScriptCore.framework in Frameworks */, + 141BF435096A455900E0753C /* WebKit.framework in Frameworks */, + 0F37A4AA11E6629100275F54 /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9340994F08540CAE007F3BC8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5DE8AE4413A2C15900D6A37D /* libWebCoreTestSupport.dylib in Frameworks */, + AE8259F308D22463000507AB /* Carbon.framework in Frameworks */, + A84F608A08B136DA00E9745F /* Cocoa.framework in Frameworks */, + A817090408B164D300CCB9FB /* JavaScriptCore.framework in Frameworks */, + 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */, + 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5A7525F08AF4A4A00138E45 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AE8259F408D22463000507AB /* Carbon.framework in Frameworks */, + A817090008B163EF00CCB9FB /* Cocoa.framework in Frameworks */, + B5A752A208AF5D1F00138E45 /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* DumpRenderTree */ = { + isa = PBXGroup; + children = ( + 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */, + 1422A2750AF6F4BD00E1A883 /* Delegates */, + 1422A2690AF6F45200E1A883 /* Controllers */, + BCB284870CFA81ED007E533E /* PixelDump */, + A803FF7409CAAD08009B2A37 /* DumpRenderTree.h */, + BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */, + A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */, + A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */, + BC4741290D038A4C0072B006 /* JavaScriptThreading.h */, + BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */, + BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */, + BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */, + BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */, + A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */, + A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */, + 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */, + 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */, + 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */, + BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */, + BC9D90220C97472E0099A4A3 /* WorkQueue.h */, + BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */, + A8B91AD20CF3B305008F91FF /* AppKit Overrides */, + A8B91AC40CF3B170008F91FF /* ObjCPlugin */, + 141BF1F5096A439800E0753C /* TestNetscapePlugIn */, + 9345229B0BD12B2C0086EDA0 /* Resources */, + 417DA9181373674D007C57FB /* WebCoreTestSupport */, + A803FF6409CAACC1009B2A37 /* Frameworks */, + 9340995508540CAF007F3BC8 /* Products */, + BCB281ED0CFA711D007E533E /* Configurations */, + ); + name = DumpRenderTree; + sourceTree = "<group>"; + }; + 141BF1F5096A439800E0753C /* TestNetscapePlugIn */ = { + isa = PBXGroup; + children = ( + 1A215A6E11F25FF1008AD0F5 /* Tests */, + 141BF448096A45C800E0753C /* Info.plist */, + 1AC6C77F0D07589B00CD3161 /* main.cpp */, + 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */, + 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */, + 141BF447096A45C800E0753C /* PluginObject.h */, + 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */, + 1A215A8011F2609C008AD0F5 /* PluginTest.h */, + 1AC6C7810D07589B00CD3161 /* TestObject.cpp */, + 1A8F024C0BB9B056008CFA34 /* TestObject.h */, + ); + path = TestNetscapePlugIn; + sourceTree = "<group>"; + }; + 1422A2690AF6F45200E1A883 /* Controllers */ = { + isa = PBXGroup; + children = ( + 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */, + 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */, + BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */, + BCD08A580E10496B00A7D0C1 /* AccessibilityController.h */, + BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */, + 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */, + 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */, + 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */, + BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */, + BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */, + BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */, + BCA18B360C9B021900114369 /* AppleScriptController.h */, + BCA18B370C9B021900114369 /* AppleScriptController.m */, + BCA18B6B0C9B08DB00114369 /* EventSendingController.h */, + BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */, + BCF6C64F0C98E9C000AC063E /* GCController.cpp */, + 14770FE00A22ADF7009342EE /* GCController.h */, + BCA18B210C9B014B00114369 /* GCControllerMac.mm */, + BC0131D80C9772010087317D /* LayoutTestController.cpp */, + BC0131D90C9772010087317D /* LayoutTestController.h */, + BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */, + E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */, + E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */, + BCA18B6D0C9B08DB00114369 /* NavigationController.h */, + BCA18B6E0C9B08DB00114369 /* NavigationController.m */, + BCA18B2F0C9B01B400114369 /* ObjCController.h */, + BCA18B300C9B01B400114369 /* ObjCController.m */, + 933BF5A90F93FA5C000F0441 /* PlainTextController.h */, + 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */, + BCA18B3A0C9B024900114369 /* TextInputController.h */, + BCA18B480C9B02C400114369 /* TextInputController.m */, + ); + name = Controllers; + sourceTree = "<group>"; + usesTabs = 0; + }; + 1422A2750AF6F4BD00E1A883 /* Delegates */ = { + isa = PBXGroup; + children = ( + BCA18B570C9B08C200114369 /* EditingDelegate.h */, + BCA18B580C9B08C200114369 /* EditingDelegate.mm */, + BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */, + BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */, + 5185F69E10714A57007AA393 /* HistoryDelegate.h */, + 5185F69F10714A57007AA393 /* HistoryDelegate.mm */, + BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */, + BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */, + BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */, + BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */, + BCA18B5F0C9B08C200114369 /* UIDelegate.h */, + BCA18B600C9B08C200114369 /* UIDelegate.mm */, + 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */, + 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */, + ); + name = Delegates; + sourceTree = "<group>"; + }; + 1A215A6E11F25FF1008AD0F5 /* Tests */ = { + isa = PBXGroup; + children = ( + 1A31EB3613466AC100017372 /* mac */, + 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */, + C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */, + 4AD6A11313C8124000EA9737 /* FormValue.cpp */, + 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */, + 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */, + 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */, + 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */, + 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */, + C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */, + 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */, + 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */, + C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */, + C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */, + 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */, + 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */, + ); + path = Tests; + sourceTree = "<group>"; + }; + 1A31EB3613466AC100017372 /* mac */ = { + isa = PBXGroup; + children = ( + 1A31EB3713466AC100017372 /* ConvertPoint.cpp */, + 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */, + 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */, + ); + path = mac; + sourceTree = "<group>"; + }; + 417DA9181373674D007C57FB /* WebCoreTestSupport */ = { + isa = PBXGroup; + children = ( + 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */, + ); + name = WebCoreTestSupport; + sourceTree = "<group>"; + }; + 9340995508540CAF007F3BC8 /* Products */ = { + isa = PBXGroup; + children = ( + 9340995408540CAF007F3BC8 /* DumpRenderTree */, + B5A7526708AF4A4A00138E45 /* ImageDiff */, + 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */, + ); + name = Products; + sourceTree = "<group>"; + }; + 9345229B0BD12B2C0086EDA0 /* Resources */ = { + isa = PBXGroup; + children = ( + AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */, + 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */, + 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */, + 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */, + 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */, + 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */, + 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */, + 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */, + 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */, + 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */, + ); + name = Resources; + sourceTree = "<group>"; + }; + A803FF6409CAACC1009B2A37 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */, + BCB284B20CFA82CB007E533E /* ApplicationServices.framework */, + AE8257EF08D22389000507AB /* Carbon.framework */, + A84F608908B136DA00E9745F /* Cocoa.framework */, + A817090308B164D300CCB9FB /* JavaScriptCore.framework */, + 23BCB88F0EA57623003C6289 /* OpenGL.framework */, + B5A752A108AF5D1F00138E45 /* QuartzCore.framework */, + 9335435F03D75502008635CE /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + A8B91AC40CF3B170008F91FF /* ObjCPlugin */ = { + isa = PBXGroup; + children = ( + BCA18B760C9B08F100114369 /* ObjCPlugin.h */, + BCA18B770C9B08F100114369 /* ObjCPlugin.m */, + BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */, + BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */, + BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */, + ); + name = ObjCPlugin; + sourceTree = "<group>"; + }; + A8B91AD20CF3B305008F91FF /* AppKit Overrides */ = { + isa = PBXGroup; + children = ( + A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */, + A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */, + A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */, + A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */, + ); + name = "AppKit Overrides"; + sourceTree = "<group>"; + }; + BCB281ED0CFA711D007E533E /* Configurations */ = { + isa = PBXGroup; + children = ( + BCB281EE0CFA713D007E533E /* Base.xcconfig */, + BC646A4B136905DE00B35DED /* CompilerVersion.xcconfig */, + BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */, + BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */, + BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */, + BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */, + ); + name = Configurations; + sourceTree = "<group>"; + }; + BCB284870CFA81ED007E533E /* PixelDump */ = { + isa = PBXGroup; + children = ( + 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */, + 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */, + BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */, + 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */, + BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */, + BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */, + BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */, + BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */, + ); + name = PixelDump; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 141BF44E096A45DD00E0753C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 141BF453096A45EB00E0753C /* PluginObject.h in Headers */, + 1A8F02E80BB9B4EC008CFA34 /* TestObject.h in Headers */, + 1A215A8211F2609C008AD0F5 /* PluginTest.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9340994B08540CAE007F3BC8 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BC0E24E00E2D9451001B6BC2 /* AccessibilityUIElement.h in Headers */, + BCA18B380C9B021900114369 /* AppleScriptController.h in Headers */, + A8B91BFF0CF522B4008F91FF /* CheckedMalloc.h in Headers */, + 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */, + BCA18B7A0C9B08F100114369 /* DumpRenderTreeDraggingInfo.h in Headers */, + A8D79CEA0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h in Headers */, + BCA18C0B0C9B59EF00114369 /* DumpRenderTreeMac.h in Headers */, + A8B91AE20CF3B372008F91FF /* DumpRenderTreePasteboard.h in Headers */, + 9340994C08540CAE007F3BC8 /* DumpRenderTreePrefix.h in Headers */, + A8B91AE00CF3B372008F91FF /* DumpRenderTreeWindow.h in Headers */, + BCA18B610C9B08C200114369 /* EditingDelegate.h in Headers */, + BCA18B6F0C9B08DB00114369 /* EventSendingController.h in Headers */, + BCA18B630C9B08C200114369 /* FrameLoadDelegate.h in Headers */, + 14770FE20A22ADF7009342EE /* GCController.h in Headers */, + BC47412A0D038A4C0072B006 /* JavaScriptThreading.h in Headers */, + BC0131DB0C9772010087317D /* LayoutTestController.h in Headers */, + BCA18B710C9B08DB00114369 /* NavigationController.h in Headers */, + BCA18B310C9B01B400114369 /* ObjCController.h in Headers */, + BCA18B7D0C9B08F100114369 /* ObjCPlugin.h in Headers */, + BCA18B7F0C9B08F100114369 /* ObjCPluginFunction.h in Headers */, + BCB284C70CFA83C4007E533E /* PixelDumpSupport.h in Headers */, + BCB284D00CFA83CC007E533E /* PixelDumpSupportCG.h in Headers */, + 933BF5AB0F93FA5C000F0441 /* PlainTextController.h in Headers */, + BCA18B650C9B08C200114369 /* PolicyDelegate.h in Headers */, + BCA18B670C9B08C200114369 /* ResourceLoadDelegate.h in Headers */, + BCA18B3C0C9B024900114369 /* TextInputController.h in Headers */, + BCA18B690C9B08C200114369 /* UIDelegate.h in Headers */, + 4437730F125CBC4D00AAE02C /* WebArchiveDumpSupport.h in Headers */, + BC9D90250C97472E0099A4A3 /* WorkQueue.h in Headers */, + BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */, + 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */, + E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */, + 29CFBA10122736E600BC30C0 /* AccessibilityTextMarker.h in Headers */, + 3A5626CC131CA036002BE6D9 /* StorageTrackerDelegate.h in Headers */, + 417DAA1D137B3E24007C57FB /* WebCoreTestSupport.h in Headers */, + 80045AED147718E7008290A8 /* AccessibilityNotificationHandler.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5A7525B08AF4A4A00138E45 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXLegacyTarget section */ + 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION)"; + buildConfigurationList = 5DC82A6E1023C92A00FD1D3B /* Build configuration list for PBXLegacyTarget "DumpRenderTree Perl Support" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = "$(SRCROOT)/mac/PerlSupport"; + dependencies = ( + ); + name = "DumpRenderTree Perl Support"; + passBuildSettingsInEnvironment = 1; + productName = "DumpRenderTree Perl Support"; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXNativeTarget section */ + 141BF21E096A441D00E0753C /* TestNetscapePlugIn */ = { + isa = PBXNativeTarget; + buildConfigurationList = 141BF221096A441E00E0753C /* Build configuration list for PBXNativeTarget "TestNetscapePlugIn" */; + buildPhases = ( + 141BF21B096A441D00E0753C /* Resources */, + 141BF44E096A45DD00E0753C /* Headers */, + 141BF21C096A441D00E0753C /* Sources */, + 141BF21D096A441D00E0753C /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TestNetscapePlugIn; + productName = TestNetscapePlugIn.plugin; + productReference = 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */; + productType = "com.apple.product-type.bundle"; + }; + 9340994A08540CAE007F3BC8 /* DumpRenderTree */ = { + isa = PBXNativeTarget; + buildConfigurationList = 149C29BF08902C6D008A9EFC /* Build configuration list for PBXNativeTarget "DumpRenderTree" */; + buildPhases = ( + 9340994B08540CAE007F3BC8 /* Headers */, + 9340994D08540CAE007F3BC8 /* Sources */, + 9340994F08540CAE007F3BC8 /* Frameworks */, + 5DB9ACAA0F722C4400684641 /* Copy Font Files */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DumpRenderTree; + productInstallPath = "$(HOME)/bin"; + productName = DumpRenderTree; + productReference = 9340995408540CAF007F3BC8 /* DumpRenderTree */; + productType = "com.apple.product-type.tool"; + }; + B5A7525A08AF4A4A00138E45 /* ImageDiff */ = { + isa = PBXNativeTarget; + buildConfigurationList = B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */; + buildPhases = ( + B5A7525B08AF4A4A00138E45 /* Headers */, + B5A7525D08AF4A4A00138E45 /* Sources */, + B5A7525F08AF4A4A00138E45 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ImageDiff; + productInstallPath = "$(HOME)/bin"; + productName = DumpRenderTree; + productReference = B5A7526708AF4A4A00138E45 /* ImageDiff */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 149C29C308902C6D008A9EFC /* Build configuration list for PBXProject "DumpRenderTree" */; + compatibilityVersion = "Xcode 2.4"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* DumpRenderTree */; + productRefGroup = 9340995508540CAF007F3BC8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + A84F608D08B1370600E9745F /* All */, + 9340994A08540CAE007F3BC8 /* DumpRenderTree */, + B5A7525A08AF4A4A00138E45 /* ImageDiff */, + 141BF21E096A441D00E0753C /* TestNetscapePlugIn */, + 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 141BF21B096A441D00E0753C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 141BF21C096A441D00E0753C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1AC6C8490D07638600CD3161 /* main.cpp in Sources */, + 1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */, + 1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */, + 0F37A4A711E6628700275F54 /* PluginObjectMac.mm in Sources */, + 1A215A8111F2609C008AD0F5 /* PluginTest.cpp in Sources */, + 1A215BE711F27658008AD0F5 /* DocumentOpenInDestroyStream.cpp in Sources */, + 1AD9D2FE12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp in Sources */, + 1AC77DCF120605B6005C19EF /* NPRuntimeRemoveProperty.cpp in Sources */, + 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */, + C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */, + C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */, + C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */, + 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */, + 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */, + 1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */, + 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */, + C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */, + 1A5CC1F5137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp in Sources */, + 1AFF66BC137DEFD200791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp in Sources */, + 4AD6A11413C8124000EA9737 /* FormValue.cpp in Sources */, + 1A14C8A51406DE0400B254F7 /* SupportsCarbonEventModel.cpp in Sources */, + 1A1E4298141141C400388758 /* PrivateBrowsing.cpp in Sources */, + 1A66C35114576A920099A115 /* ContentsScaleFactor.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9340994D08540CAE007F3BC8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */, + BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */, + BC0E24E10E2D9451001B6BC2 /* AccessibilityUIElement.cpp in Sources */, + BC0E26150E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm in Sources */, + BCA18B390C9B021900114369 /* AppleScriptController.m in Sources */, + A8B91BFD0CF522B4008F91FF /* CheckedMalloc.cpp in Sources */, + 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */, + BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */, + BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */, + A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */, + A8B91ADA0CF3B32F008F91FF /* DumpRenderTreePasteboard.m in Sources */, + A8B91ADC0CF3B32F008F91FF /* DumpRenderTreeWindow.mm in Sources */, + BCA18B620C9B08C200114369 /* EditingDelegate.mm in Sources */, + BCA18B700C9B08DB00114369 /* EventSendingController.mm in Sources */, + BCA18B640C9B08C200114369 /* FrameLoadDelegate.mm in Sources */, + BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */, + BCA18B230C9B014B00114369 /* GCControllerMac.mm in Sources */, + BC4741410D038A570072B006 /* JavaScriptThreadingPthreads.cpp in Sources */, + BC0131DA0C9772010087317D /* LayoutTestController.cpp in Sources */, + BCA18B240C9B014B00114369 /* LayoutTestControllerMac.mm in Sources */, + BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */, + BCA18B320C9B01B400114369 /* ObjCController.m in Sources */, + BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */, + BCA18B800C9B08F100114369 /* ObjCPluginFunction.m in Sources */, + 8465E2C70FFA8DF2003B8342 /* PixelDumpSupport.cpp in Sources */, + BCB284CD0CFA83C8007E533E /* PixelDumpSupportCG.cpp in Sources */, + BCB284D60CFA83D1007E533E /* PixelDumpSupportMac.mm in Sources */, + 933BF5AC0F93FA5C000F0441 /* PlainTextController.mm in Sources */, + BCA18B660C9B08C200114369 /* PolicyDelegate.mm in Sources */, + BCA18B680C9B08C200114369 /* ResourceLoadDelegate.mm in Sources */, + BCA18B490C9B02C400114369 /* TextInputController.m in Sources */, + BCA18B6A0C9B08C200114369 /* UIDelegate.mm in Sources */, + 4437730E125CBC3600AAE02C /* WebArchiveDumpSupport.cpp in Sources */, + 440590711268453800CFD48D /* WebArchiveDumpSupportMac.mm in Sources */, + BC9D90240C97472E0099A4A3 /* WorkQueue.cpp in Sources */, + BCA18B260C9B015C00114369 /* WorkQueueItemMac.mm in Sources */, + 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */, + E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */, + 29CFBA11122736E600BC30C0 /* AccessibilityTextMarker.cpp in Sources */, + 29CFBA2E12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm in Sources */, + 3A5626CB131CA02A002BE6D9 /* StorageTrackerDelegate.mm in Sources */, + 80045AEE147718E7008290A8 /* AccessibilityNotificationHandler.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5A7525D08AF4A4A00138E45 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 141BF238096A451E00E0753C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 141BF21E096A441D00E0753C /* TestNetscapePlugIn */; + targetProxy = 141BF237096A451E00E0753C /* PBXContainerItemProxy */; + }; + 5DC82A701023C93D00FD1D3B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */; + targetProxy = 5DC82A6F1023C93D00FD1D3B /* PBXContainerItemProxy */; + }; + A84F608F08B1370E00E9745F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B5A7525A08AF4A4A00138E45 /* ImageDiff */; + targetProxy = A84F608E08B1370E00E9745F /* PBXContainerItemProxy */; + }; + A84F609108B1370E00E9745F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9340994A08540CAE007F3BC8 /* DumpRenderTree */; + targetProxy = A84F609008B1370E00E9745F /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 141BF222096A441E00E0753C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist; + }; + name = Debug; + }; + 141BF223096A441E00E0753C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist; + }; + name = Release; + }; + 149C29C008902C6D008A9EFC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 149C29C108902C6D008A9EFC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 149C29C408902C6D008A9EFC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */; + buildSettings = { + GCC_OPTIMIZATION_LEVEL = 0; + }; + name = Debug; + }; + 149C29C508902C6D008A9EFC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 5DC82A671023C8DE00FD1D3B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "DumpRenderTree Perl Support"; + }; + name = Debug; + }; + 5DC82A681023C8DE00FD1D3B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "DumpRenderTree Perl Support"; + }; + name = Release; + }; + 5DC82A691023C8DE00FD1D3B /* Production */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "DumpRenderTree Perl Support"; + }; + name = Production; + }; + 90CBC3500F748B1300A712B7 /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB281EE0CFA713D007E533E /* Base.xcconfig */; + buildSettings = { + WEBKIT_FRAMEWORK_RESOURCES_PATH = WebKit.framework/Versions/A/Resources; + }; + name = Production; + }; + 90CBC3510F748B1300A712B7 /* Production */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)"; + PRODUCT_NAME = All; + }; + name = Production; + }; + 90CBC3520F748B1300A712B7 /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */; + buildSettings = { + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)"; + SKIP_INSTALL = NO; + }; + name = Production; + }; + 90CBC3530F748B1300A712B7 /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */; + buildSettings = { + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)"; + SKIP_INSTALL = NO; + }; + name = Production; + }; + 90CBC3540F748B1300A712B7 /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)"; + SKIP_INSTALL = NO; + }; + name = Production; + }; + A84F609308B1371400E9745F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = All; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Debug; + }; + A84F609408B1371400E9745F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = All; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Release; + }; + B5A7526508AF4A4A00138E45 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + B5A7526608AF4A4A00138E45 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */; + buildSettings = { + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 141BF221096A441E00E0753C /* Build configuration list for PBXNativeTarget "TestNetscapePlugIn" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 141BF222096A441E00E0753C /* Debug */, + 141BF223096A441E00E0753C /* Release */, + 90CBC3540F748B1300A712B7 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; + 149C29BF08902C6D008A9EFC /* Build configuration list for PBXNativeTarget "DumpRenderTree" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 149C29C008902C6D008A9EFC /* Debug */, + 149C29C108902C6D008A9EFC /* Release */, + 90CBC3520F748B1300A712B7 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; + 149C29C308902C6D008A9EFC /* Build configuration list for PBXProject "DumpRenderTree" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 149C29C408902C6D008A9EFC /* Debug */, + 149C29C508902C6D008A9EFC /* Release */, + 90CBC3500F748B1300A712B7 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; + 5DC82A6E1023C92A00FD1D3B /* Build configuration list for PBXLegacyTarget "DumpRenderTree Perl Support" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5DC82A671023C8DE00FD1D3B /* Debug */, + 5DC82A681023C8DE00FD1D3B /* Release */, + 5DC82A691023C8DE00FD1D3B /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; + A84F609208B1371400E9745F /* Build configuration list for PBXAggregateTarget "All" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A84F609308B1371400E9745F /* Debug */, + A84F609408B1371400E9745F /* Release */, + 90CBC3510F748B1300A712B7 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; + B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B5A7526508AF4A4A00138E45 /* Debug */, + B5A7526608AF4A4A00138E45 /* Release */, + 90CBC3530F748B1300A712B7 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h new file mode 100644 index 000000000..e2f45d67c --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h @@ -0,0 +1,39 @@ +// Copyright (c) 2009, 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 <Cocoa/Cocoa.h> + +// An implementation of NSDraggingSource for use with DumpRenderTreeDraggingInfo when dragging files +// Used by -[EventSendingController beginDragWithFiles:] + +@interface DumpRenderTreeFileDraggingSource : NSObject { +} + +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag; + +@end diff --git a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m new file mode 100644 index 000000000..449d9185e --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m @@ -0,0 +1,38 @@ +// Copyright (c) 2009, 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 "DumpRenderTreeFileDraggingSource.h" + +@implementation DumpRenderTreeFileDraggingSource + +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag +{ + return NSDragOperationCopy; +} + +@end diff --git a/Tools/DumpRenderTree/DumpRenderTreePrefix.h b/Tools/DumpRenderTree/DumpRenderTreePrefix.h new file mode 100644 index 000000000..1344754a6 --- /dev/null +++ b/Tools/DumpRenderTree/DumpRenderTreePrefix.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifdef __OBJC__ + +#import <Foundation/Foundation.h> + +#endif + +// If we don't define these, they get defined in windef.h. +// We want to use std::min and std::max +#define max max +#define min min diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h new file mode 100755 index 000000000..4c5dcb983 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h @@ -0,0 +1 @@ +#include <JavaScriptCore/JSExportMacros.h>
\ No newline at end of file diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h new file mode 100644 index 000000000..f2258d298 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h @@ -0,0 +1 @@ +#include <JavaScriptCore/ASCIICType.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h new file mode 100644 index 000000000..e83483e4d --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Alignment.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h new file mode 100644 index 000000000..214441049 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Assertions.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h new file mode 100644 index 000000000..37b18926f --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Atomics.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h new file mode 100644 index 000000000..340d8c989 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Compiler.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h new file mode 100644 index 000000000..a31a23d25 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h @@ -0,0 +1 @@ +#include <JavaScriptCore/CurrentTime.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h new file mode 100644 index 000000000..1280da80d --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h @@ -0,0 +1 @@ +#include <JavaScriptCore/DynamicAnnotations.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h new file mode 100755 index 000000000..50be070ba --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h @@ -0,0 +1 @@ +#include <JavaScriptCore/ExportMacros.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h new file mode 100644 index 000000000..421c04026 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h @@ -0,0 +1 @@ +#include <JavaScriptCore/FastAllocBase.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h new file mode 100644 index 000000000..1701231ee --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h @@ -0,0 +1 @@ +#include <JavaScriptCore/FastMalloc.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h new file mode 100644 index 000000000..9f262e2ea --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h @@ -0,0 +1 @@ +#include <JavaScriptCore/HashMap.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h new file mode 100644 index 000000000..cfe2d80f8 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h @@ -0,0 +1 @@ +#include <JavaScriptCore/HashSet.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h new file mode 100644 index 000000000..412fa9856 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h @@ -0,0 +1 @@ +#include <JavaScriptCore/HashTraits.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h new file mode 100644 index 000000000..75b0acd59 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Locker.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h new file mode 100644 index 000000000..ff75971f8 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h @@ -0,0 +1 @@ +#include <JavaScriptCore/MainThread.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h new file mode 100644 index 000000000..29557867a --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h @@ -0,0 +1 @@ +#include <JavaScriptCore/MathExtras.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h new file mode 100644 index 000000000..f8484d288 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Noncopyable.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h new file mode 100644 index 000000000..595817ddb --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/OwnArrayPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h new file mode 100644 index 000000000..9211d3859 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/OwnPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h new file mode 100644 index 000000000..6064e88dc --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h @@ -0,0 +1 @@ +#include <JavaScriptCore/PassOwnPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h new file mode 100644 index 000000000..6064e88dc --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/PassOwnPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h new file mode 100644 index 000000000..aafd1a236 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/PassRefPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h new file mode 100644 index 000000000..3b229552a --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Platform.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h new file mode 100644 index 000000000..628a63b6e --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h @@ -0,0 +1 @@ +#include <JavaScriptCore/RefCounted.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h new file mode 100644 index 000000000..0ff621398 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/RefPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h new file mode 100644 index 000000000..65fc27bc9 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h @@ -0,0 +1 @@ +#include <JavaScriptCore/RetainPtr.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h new file mode 100644 index 000000000..3222ec1f1 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h @@ -0,0 +1 @@ +#include <JavaScriptCore/StdLibExtras.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h new file mode 100644 index 000000000..063d500ec --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h @@ -0,0 +1 @@ +#include <JavaScriptCore/StringExtras.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h new file mode 100644 index 000000000..3367eb2d2 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h @@ -0,0 +1 @@ +#include <JavaScriptCore/TemporaryChange.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h new file mode 100644 index 000000000..48a54cc77 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h @@ -0,0 +1 @@ +#include <JavaScriptCore/ThreadSafeRefCounted.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h new file mode 100644 index 000000000..17359e5d2 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Threading.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h new file mode 100644 index 000000000..a7ee1170f --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h @@ -0,0 +1 @@ +#include <JavaScriptCore/ThreadingPrimitives.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h new file mode 100644 index 000000000..c6d15fd05 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Vector.h> diff --git a/Tools/DumpRenderTree/GCController.cpp b/Tools/DumpRenderTree/GCController.cpp new file mode 100644 index 000000000..06a04fbca --- /dev/null +++ b/Tools/DumpRenderTree/GCController.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h" + +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> + +GCController::GCController() +{ +} + +GCController::~GCController() +{ +} + +// Static Functions + +static JSValueRef collectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject)); + controller->collect(); + return JSValueMakeUndefined(context); +} + +static JSValueRef collectOnAlternateThreadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + bool waitUntilDone = false; + if (argumentCount > 0) + waitUntilDone = JSValueToBoolean(context, arguments[0]); + + GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject)); + controller->collectOnAlternateThread(waitUntilDone); + + return JSValueMakeUndefined(context); +} + +static JSValueRef getJSObjectCountCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject)); + size_t jsObjectCount = controller->getJSObjectCount(); + + return JSValueMakeNumber(context, jsObjectCount); +} + +// Object Creation + +void GCController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> gcControllerStr(Adopt, JSStringCreateWithUTF8CString("GCController")); + + JSClassRef classRef = getJSClass(); + JSValueRef gcControllerObject = JSObjectMake(context, classRef, this); + JSClassRelease(classRef); + + JSObjectSetProperty(context, windowObject, gcControllerStr.get(), gcControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); +} + +JSClassRef GCController::getJSClass() +{ + static JSStaticFunction staticFunctions[] = { + { "collect", collectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "collectOnAlternateThread", collectOnAlternateThreadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "getJSObjectCount", getJSObjectCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "GCController", 0, 0, staticFunctions, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return JSClassCreate(&classDefinition); +} diff --git a/Tools/DumpRenderTree/GCController.h b/Tools/DumpRenderTree/GCController.h new file mode 100644 index 000000000..afc1de087 --- /dev/null +++ b/Tools/DumpRenderTree/GCController.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 GCController_h +#define GCController_h + +#include <JavaScriptCore/JSObjectRef.h> + +class GCController { +public: + GCController(); + ~GCController(); + + void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception); + + // Controller Methods - platfrom independant implementations + void collect() const; + void collectOnAlternateThread(bool waitUntilDone) const; + size_t getJSObjectCount() const; + +private: + static JSClassRef getJSClass(); +}; + +#endif // GCController_h diff --git a/Tools/DumpRenderTree/JavaScriptThreading.h b/Tools/DumpRenderTree/JavaScriptThreading.h new file mode 100644 index 000000000..43795a1a2 --- /dev/null +++ b/Tools/DumpRenderTree/JavaScriptThreading.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 JavaScriptThreading_h +#define JavaScriptThreading_h + +/* These functions start/stop threads used to abuse the JavaScript interpreter + and assure that our JS implementation remains threadsafe */ + +void startJavaScriptThreads(); +void stopJavaScriptThreads(); + +#endif // JavaScriptThreading_h diff --git a/Tools/DumpRenderTree/LayoutTestController.cpp b/Tools/DumpRenderTree/LayoutTestController.cpp new file mode 100644 index 000000000..6c13d9309 --- /dev/null +++ b/Tools/DumpRenderTree/LayoutTestController.cpp @@ -0,0 +1,2607 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2010 Joone Hur <joone@kldp.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueue.h" +#include "WorkQueueItem.h" +#include <cstring> +#include <JavaScriptCore/JSContextRef.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <locale.h> +#include <stdio.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/RefPtr.h> + +LayoutTestController::LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash) + : m_disallowIncreaseForApplicationCacheQuota(false) + , m_dumpApplicationCacheDelegateCallbacks(false) + , m_dumpAsAudio(false) + , m_dumpAsPDF(false) + , m_dumpAsText(false) + , m_dumpBackForwardList(false) + , m_dumpChildFrameScrollPositions(false) + , m_dumpChildFramesAsText(false) + , m_dumpDOMAsWebArchive(false) + , m_dumpDatabaseCallbacks(false) + , m_dumpEditingCallbacks(false) + , m_dumpFrameLoadCallbacks(false) + , m_dumpProgressFinishedCallback(false) + , m_dumpUserGestureInFrameLoadCallbacks(false) + , m_dumpHistoryDelegateCallbacks(false) + , m_dumpResourceLoadCallbacks(false) + , m_dumpResourceResponseMIMETypes(false) + , m_dumpSelectionRect(false) + , m_dumpSourceAsWebArchive(false) + , m_dumpStatusCallbacks(false) + , m_dumpTitleChanges(false) + , m_dumpIconChanges(false) + , m_dumpVisitedLinksCallback(false) + , m_dumpWillCacheResponse(false) + , m_generatePixelResults(true) + , m_callCloseOnWebViews(true) + , m_canOpenWindows(false) + , m_closeRemainingWindowsWhenComplete(true) + , m_newWindowsCopyBackForwardList(false) + , m_stopProvisionalFrameLoads(false) + , m_testOnscreen(false) + , m_testRepaint(false) + , m_testRepaintSweepHorizontally(false) + , m_waitToDump(false) + , m_willSendRequestReturnsNull(false) + , m_willSendRequestReturnsNullOnRedirect(false) + , m_windowIsKey(true) + , m_alwaysAcceptCookies(false) + , m_globalFlag(false) + , m_isGeolocationPermissionSet(false) + , m_geolocationPermission(false) + , m_handlesAuthenticationChallenges(false) + , m_isPrinting(false) + , m_deferMainResourceDataLoad(true) + , m_shouldPaintBrokenImage(true) + , m_shouldStayOnPageAfterHandlingBeforeUnload(false) + , m_areDesktopNotificationPermissionRequestsIgnored(false) + , m_testPathOrURL(testPathOrURL) + , m_expectedPixelHash(expectedPixelHash) +{ +} + +PassRefPtr<LayoutTestController> LayoutTestController::create(const std::string& testPathOrURL, const std::string& expectedPixelHash) +{ + return adoptRef(new LayoutTestController(testPathOrURL, expectedPixelHash)); +} + +// Static Functions + +static JSValueRef disallowIncreaseForApplicationCacheQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDisallowIncreaseForApplicationCacheQuota(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpApplicationCacheDelegateCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpApplicationCacheDelegateCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpAsPDFCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpAsPDF(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpAsText(true); + + // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode. + controller->setGeneratePixelResults(argumentCount > 0 ? JSValueToBoolean(context, arguments[0]) : false); + + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpBackForwardList(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpChildFramesAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpChildFramesAsText(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpChildFrameScrollPositionsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpChildFrameScrollPositions(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpConfigurationForViewportCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + + double deviceDPI = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + double deviceWidth = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + double deviceHeight = JSValueToNumber(context, arguments[2], exception); + ASSERT(!*exception); + double availableWidth = JSValueToNumber(context, arguments[3], exception); + ASSERT(!*exception); + double availableHeight = JSValueToNumber(context, arguments[4], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->dumpConfigurationForViewport(static_cast<int>(deviceDPI), static_cast<int>(deviceWidth), static_cast<int>(deviceHeight), static_cast<int>(availableWidth), static_cast<int>(availableHeight)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpDatabaseCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpDatabaseCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpDOMAsWebArchiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpDOMAsWebArchive(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpEditingCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpEditingCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpFrameLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpFrameLoadCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpProgressFinishedCallbackCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpProgressFinishedCallback(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpUserGestureInFrameLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpUserGestureInFrameLoadCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpResourceLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpResourceLoadCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpResourceResponseMIMETypesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpResourceResponseMIMETypes(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpSelectionRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpSelectionRect(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpSourceAsWebArchiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpSourceAsWebArchive(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpStatusCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpStatusCallbacks(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpTitleChangesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpTitleChanges(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpIconChangesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpIconChanges(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef dumpWillCacheResponseCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpWillCacheResponse(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef pathToLocalResourceCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> localPath(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> convertedPath(Adopt, controller->pathToLocalResource(context, localPath.get())); + if (!convertedPath) + return JSValueMakeUndefined(context); + + return JSValueMakeString(context, convertedPath.get()); +} + +static JSValueRef removeAllVisitedLinksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDumpVisitedLinksCallback(true); + controller->removeAllVisitedLinks(); + return JSValueMakeUndefined(context); +} + +static JSValueRef repaintSweepHorizontallyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setTestRepaintSweepHorizontally(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef setCallCloseOnWebViewsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setCallCloseOnWebViews(JSValueToBoolean(context, arguments[0])); + return JSValueMakeUndefined(context); +} + +static JSValueRef setCanOpenWindowsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setCanOpenWindows(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef setCloseRemainingWindowsWhenCompleteCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setCloseRemainingWindowsWhenComplete(JSValueToBoolean(context, arguments[0])); + return JSValueMakeUndefined(context); +} + +static JSValueRef setEncodedAudioDataCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> encodedAudioData(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(encodedAudioData.get()); + OwnArrayPtr<char> encodedAudioDataBuffer = adoptArrayPtr(new char[maxLength + 1]); + JSStringGetUTF8CString(encodedAudioData.get(), encodedAudioDataBuffer.get(), maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setEncodedAudioData(encodedAudioDataBuffer.get()); + controller->setDumpAsAudio(true); + + return JSValueMakeUndefined(context); +} + +static JSValueRef testOnscreenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setTestOnscreen(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef testRepaintCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setTestRepaint(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef addDisallowedURLCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addDisallowedURL(url.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef addURLToRedirectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> origin(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> destination(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(origin.get()); + OwnArrayPtr<char> originBuffer = adoptArrayPtr(new char[maxLength + 1]); + JSStringGetUTF8CString(origin.get(), originBuffer.get(), maxLength + 1); + + maxLength = JSStringGetMaximumUTF8CStringSize(destination.get()); + OwnArrayPtr<char> destinationBuffer = adoptArrayPtr(new char[maxLength + 1]); + JSStringGetUTF8CString(destination.get(), destinationBuffer.get(), maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addURLToRedirect(originBuffer.get(), destinationBuffer.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef callShouldCloseOnWebViewCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + return JSValueMakeBoolean(context, controller->callShouldCloseOnWebView()); +} + +static JSValueRef clearAllApplicationCachesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->clearAllApplicationCaches(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef clearApplicationCacheForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->clearApplicationCacheForOrigin(originURL.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef applicationCacheDiskUsageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + return JSValueMakeNumber(context, controller->applicationCacheDiskUsageForOrigin(originURL.get())); +} + +static JSValueRef originsWithApplicationCacheCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return controller->originsWithApplicationCache(context); +} + +static JSValueRef clearAllDatabasesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->clearAllDatabases(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef syncLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + controller->syncLocalStorage(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef observeStorageTrackerNotificationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + unsigned numNotifications = JSValueToNumber(context, arguments[0], exception); + + ASSERT(!*exception); + + controller->observeStorageTrackerNotifications(numNotifications); + + return JSValueMakeUndefined(context); +} + +static JSValueRef deleteAllLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->deleteAllLocalStorage(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef deleteLocalStorageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + controller->deleteLocalStorageForOrigin(url.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef localStorageDiskUsageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + return JSValueMakeNumber(context, controller->localStorageDiskUsageForOrigin(originURL.get())); +} + +static JSValueRef originsWithLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return controller->originsWithLocalStorage(context); +} + +static JSValueRef clearBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->clearBackForwardList(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef clearPersistentUserStyleSheetCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->clearPersistentUserStyleSheet(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef decodeHostNameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> decodedHostName(Adopt, controller->copyDecodedHostName(name.get())); + return JSValueMakeString(context, decodedHostName.get()); +} + +static JSValueRef disableImageLoadingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation, needs windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->disableImageLoading(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef dispatchPendingLoadRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation, needs windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->dispatchPendingLoadRequests(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef displayCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->display(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef displayInvalidatedRegionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + // LayoutTestController::display() only renders the invalidated region so + // we can just use that. + controller->display(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef encodeHostNameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> encodedHostName(Adopt, controller->copyEncodedHostName(name.get())); + return JSValueMakeString(context, encodedHostName.get()); +} + +static JSValueRef execCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac & Windows implementations. + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + // Ignoring the second parameter (userInterface), as this command emulates a manual action. + + JSRetainPtr<JSStringRef> value; + if (argumentCount >= 3) { + value.adopt(JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + } else + value.adopt(JSStringCreateWithUTF8CString("")); + + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->execCommand(name.get(), value.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef findStringCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac implementation. + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> target(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSObjectRef options = JSValueToObject(context, arguments[1], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->findString(context, target.get(), options)); +} + +static JSValueRef counterValueForElementByIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + if (*exception) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> counterValue(controller->counterValueForElementById(elementId.get())); + if (!counterValue.get()) + return JSValueMakeUndefined(context); + return JSValueMakeString(context, counterValue.get()); +} + +static JSValueRef goBackCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->goBack(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef grantDesktopNotificationPermissionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + controller->grantDesktopNotificationPermission(JSValueToStringCopy(context, arguments[0], NULL)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef isCommandEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac implementation. + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + return JSValueMakeBoolean(context, controller->isCommandEnabled(name.get())); +} + +static JSValueRef overridePreferenceCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> key(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> value(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->overridePreference(key.get(), value.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef keepWebHistoryCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->keepWebHistory(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef computedStyleIncludingVisitedInfoCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeUndefined(context); + + // Has mac implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return controller->computedStyleIncludingVisitedInfo(context, arguments[0]); +} + +static JSValueRef nodesFromRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 8) + return JSValueMakeUndefined(context); + + int x = JSValueToNumber(context, arguments[1], NULL); + int y = JSValueToNumber(context, arguments[2], NULL); + int top = static_cast<unsigned>(JSValueToNumber(context, arguments[3], NULL)); + int right = static_cast<unsigned>(JSValueToNumber(context, arguments[4], NULL)); + int bottom = static_cast<unsigned>(JSValueToNumber(context, arguments[5], NULL)); + int left = static_cast<unsigned>(JSValueToNumber(context, arguments[6], NULL)); + bool ignoreClipping = JSValueToBoolean(context, arguments[7]); + + // Has mac implementation. + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return controller->nodesFromRect(context, arguments[0], x, y, top, right, bottom, left, ignoreClipping); +} + +static JSValueRef layerTreeAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeString(context, controller->layerTreeAsText().get()); +} + +static JSValueRef notifyDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->notifyDone(); + return JSValueMakeUndefined(context); +} + +static bool parsePageParameters(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, float& pageWidthInPixels, float& pageHeightInPixels) +{ + pageWidthInPixels = LayoutTestController::maxViewWidth; + pageHeightInPixels = LayoutTestController::maxViewHeight; + switch (argumentCount) { + case 2: + pageWidthInPixels = static_cast<float>(JSValueToNumber(context, arguments[0], exception)); + if (*exception) + return false; + pageHeightInPixels = static_cast<float>(JSValueToNumber(context, arguments[1], exception)); + if (*exception) + return false; + case 0: // Fall through. + break; + default: + return false; + } + return true; +} + +// Caller needs to delete[] propertyName. +static bool parsePagePropertyParameters(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, char*& propertyName, int& pageNumber) +{ + pageNumber = 0; + switch (argumentCount) { + case 2: + pageNumber = static_cast<float>(JSValueToNumber(context, arguments[1], exception)); + if (*exception) + return false; + // Fall through. + case 1: { + JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + if (*exception) + return false; + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(propertyNameString.get()); + propertyName = new char[maxLength + 1]; + JSStringGetUTF8CString(propertyNameString.get(), propertyName, maxLength + 1); + return true; + } + case 0: + default: + return false; + } +} + +static bool parsePageNumber(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, int& pageNumber) +{ + pageNumber = 0; + switch (argumentCount) { + case 1: + pageNumber = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (*exception) + return false; + // Fall through. + case 0: + return true; + default: + return false; + } +} + +static bool parsePageNumberSizeMarings(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, int& pageNumber, int& width, int& height, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) +{ + pageNumber = 0; + width = height = 0; + marginTop = marginRight = marginBottom = marginLeft = 0; + + switch (argumentCount) { + case 7: + marginLeft = static_cast<int>(JSValueToNumber(context, arguments[6], exception)); + if (*exception) + return false; + // Fall through. + case 6: + marginBottom = static_cast<int>(JSValueToNumber(context, arguments[5], exception)); + if (*exception) + return false; + // Fall through. + case 5: + marginRight = static_cast<int>(JSValueToNumber(context, arguments[4], exception)); + if (*exception) + return false; + // Fall through. + case 4: + marginTop = static_cast<int>(JSValueToNumber(context, arguments[3], exception)); + if (*exception) + return false; + // Fall through. + case 3: + height = static_cast<int>(JSValueToNumber(context, arguments[2], exception)); + if (*exception) + return false; + // Fall through. + case 2: + width = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + if (*exception) + return false; + // Fall through. + case 1: + pageNumber = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (*exception) + return false; + // Fall through. + return true; + default: + return false; + } +} + +static JSValueRef pageNumberForElementByIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + float pageWidthInPixels = 0; + float pageHeightInPixels = 0; + if (!parsePageParameters(context, argumentCount - 1, arguments + 1, exception, pageWidthInPixels, pageHeightInPixels)) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + if (*exception) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + int pageNumber = controller->pageNumberForElementById(elementId.get(), pageWidthInPixels, pageHeightInPixels); + return JSValueMakeNumber(context, pageNumber); +} + +static JSValueRef numberOfPagesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + float pageWidthInPixels = 0; + float pageHeightInPixels = 0; + if (!parsePageParameters(context, argumentCount, arguments, exception, pageWidthInPixels, pageHeightInPixels)) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->numberOfPages(pageWidthInPixels, pageHeightInPixels)); +} + +static JSValueRef numberOfPendingGeolocationPermissionRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->numberOfPendingGeolocationPermissionRequests()); +} + +static JSValueRef pagePropertyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + char* propertyName = 0; + int pageNumber = 0; + if (!parsePagePropertyParameters(context, argumentCount, arguments, exception, propertyName, pageNumber)) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSValueRef value = JSValueMakeString(context, controller->pageProperty(propertyName, pageNumber).get()); + + delete[] propertyName; + return value; +} + +static JSValueRef isPageBoxVisibleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int pageNumber = 0; + if (!parsePageNumber(context, argumentCount, arguments, exception, pageNumber)) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->isPageBoxVisible(pageNumber)); +} + +static JSValueRef pageSizeAndMarginsInPixelsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int pageNumber = 0; + int width = 0, height = 0; + int marginTop = 0, marginRight = 0, marginBottom = 0, marginLeft = 0; + if (!parsePageNumberSizeMarings(context, argumentCount, arguments, exception, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft)) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeString(context, controller->pageSizeAndMarginsInPixels(pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft).get()); +} + +static JSValueRef queueBackNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + double howFarBackDouble = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueBackNavigation(static_cast<int>(howFarBackDouble)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef queueForwardNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + double howFarForwardDouble = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueForwardNavigation(static_cast<int>(howFarForwardDouble)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef queueLoadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> target; + if (argumentCount >= 2) { + target.adopt(JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + } else + target.adopt(JSStringCreateWithUTF8CString("")); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueLoad(url.get(), target.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef queueLoadHTMLStringCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac & Windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> content(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> baseURL; + if (argumentCount >= 2) { + baseURL.adopt(JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + } else + baseURL.adopt(JSStringCreateWithUTF8CString("")); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + if (argumentCount >= 3) { + JSRetainPtr<JSStringRef> unreachableURL; + unreachableURL.adopt(JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + controller->queueLoadAlternateHTMLString(content.get(), baseURL.get(), unreachableURL.get()); + return JSValueMakeUndefined(context); + } + + controller->queueLoadHTMLString(content.get(), baseURL.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef queueReloadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueReload(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef queueLoadingScriptCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueLoadingScript(script.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef queueNonLoadingScriptCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + // May be able to be made platform independant by using shared WorkQueue + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->queueNonLoadingScript(script.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAcceptsEditingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAcceptsEditing(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAlwaysAcceptCookiesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAlwaysAcceptCookies(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAppCacheMaximumSizeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + double size = JSValueToNumber(context, arguments[0], NULL); + if (!isnan(size)) + controller->setAppCacheMaximumSize(static_cast<unsigned long long>(size)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setApplicationCacheOriginQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + double size = JSValueToNumber(context, arguments[0], NULL); + if (!isnan(size)) + controller->setApplicationCacheOriginQuota(static_cast<unsigned long long>(size)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAuthenticationPasswordCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> password(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(password.get()); + char* passwordBuffer = new char[maxLength + 1]; + JSStringGetUTF8CString(password.get(), passwordBuffer, maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAuthenticationPassword(passwordBuffer); + delete[] passwordBuffer; + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAuthenticationUsernameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> username(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(username.get()); + char* usernameBuffer = new char[maxLength + 1]; + JSStringGetUTF8CString(username.get(), usernameBuffer, maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAuthenticationUsername(usernameBuffer); + delete[] usernameBuffer; + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAuthorAndUserStylesEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAuthorAndUserStylesEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAutofilledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2 || !arguments[0]) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAutofilled(context, arguments[0], JSValueToBoolean(context, arguments[1])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setCacheModelCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac implementation. + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + int cacheModel = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setCacheModel(cacheModel); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setCustomPolicyDelegateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + bool permissive = false; + if (argumentCount >= 2) + permissive = JSValueToBoolean(context, arguments[1]); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setCustomPolicyDelegate(JSValueToBoolean(context, arguments[0]), permissive); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setDatabaseQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + double quota = JSValueToNumber(context, arguments[0], NULL); + if (!isnan(quota)) + controller->setDatabaseQuota(static_cast<unsigned long long>(quota)); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setDeferMainResourceDataLoadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac and Windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDeferMainResourceDataLoad(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setDefersLoadingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setDefersLoading(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setDomainRelaxationForbiddenForURLSchemeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac and Windows implementation + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + bool forbidden = JSValueToBoolean(context, arguments[0]); + JSRetainPtr<JSStringRef> scheme(Adopt, JSValueToStringCopy(context, arguments[1], 0)); + controller->setDomainRelaxationForbiddenForURLScheme(forbidden, scheme.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setMockDeviceOrientationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 6) + return JSValueMakeUndefined(context); + + bool canProvideAlpha = JSValueToBoolean(context, arguments[0]); + double alpha = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + bool canProvideBeta = JSValueToBoolean(context, arguments[2]); + double beta = JSValueToNumber(context, arguments[3], exception); + ASSERT(!*exception); + bool canProvideGamma = JSValueToBoolean(context, arguments[4]); + double gamma = JSValueToNumber(context, arguments[5], exception); + ASSERT(!*exception); + + LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setMockGeolocationPositionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setMockGeolocationPosition(JSValueToNumber(context, arguments[0], NULL), // latitude + JSValueToNumber(context, arguments[1], NULL), // longitude + JSValueToNumber(context, arguments[2], NULL)); // accuracy + + return JSValueMakeUndefined(context); +} + +static JSValueRef setMockGeolocationErrorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + int code = JSValueToNumber(context, arguments[0], NULL); + JSRetainPtr<JSStringRef> message(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setMockGeolocationError(code, message.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef addMockSpeechInputResultCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> result(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + double confidence = JSValueToNumber(context, arguments[1], exception); + + JSRetainPtr<JSStringRef> language(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addMockSpeechInputResult(result.get(), confidence, language.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setNewWindowsCopyBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setNewWindowsCopyBackForwardList(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setGeolocationPermissionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setGeolocationPermission(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setHandlesAuthenticationChallengesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setHandlesAuthenticationChallenges(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPOSIXLocaleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> locale(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + controller->setPOSIXLocale(locale.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setIconDatabaseEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setIconDatabaseEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setJavaScriptProfilingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setJavaScriptProfilingEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setMainFrameIsFirstResponderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setMainFrameIsFirstResponder(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPersistentUserStyleSheetLocationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> path(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setPersistentUserStyleSheetLocation(path.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPrivateBrowsingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setPrivateBrowsingEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setJavaScriptCanAccessClipboardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setJavaScriptCanAccessClipboard(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setXSSAuditorEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setXSSAuditorEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setSpatialNavigationEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation. + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setSpatialNavigationEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPrintingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setIsPrinting(true); + return JSValueMakeUndefined(context); +} + + +static JSValueRef setFrameFlatteningEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setFrameFlatteningEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAllowUniversalAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAllowUniversalAccessFromFileURLs(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setAllowFileAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAllowFileAccessFromFileURLs(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setTabKeyCyclesThroughElements(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setUseDashboardCompatibilityModeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setUseDashboardCompatibilityMode(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setUserStyleSheetEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setUserStyleSheetEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setUserStyleSheetLocationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> path(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setUserStyleSheetLocation(path.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setValueForUserCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> value(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setValueForUser(context, arguments[0], value.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setViewModeMediaFeatureCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> mode(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setViewModeMediaFeature(mode.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setWillSendRequestClearHeaderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> header(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(header.get()); + OwnArrayPtr<char> headerBuffer = adoptArrayPtr(new char[maxLength + 1]); + JSStringGetUTF8CString(header.get(), headerBuffer.get(), maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWillSendRequestClearHeader(headerBuffer.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setWillSendRequestReturnsNullCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has cross-platform implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWillSendRequestReturnsNull(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setWillSendRequestReturnsNullOnRedirectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has cross-platform implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWillSendRequestReturnsNullOnRedirect(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setWindowIsKeyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWindowIsKey(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef waitUntilDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWaitToDump(true); + + return JSValueMakeUndefined(context); +} + +static JSValueRef windowCountCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac implementation + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + int windows = controller->windowCount(); + return JSValueMakeNumber(context, windows); +} + +static JSValueRef setPopupBlockingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setPopupBlockingEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPluginsEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setPluginsEnabled(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setPageVisibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> visibility(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(visibility.get()); + char* visibilityBuffer = new char[maxLength + 1]; + JSStringGetUTF8CString(visibility.get(), visibilityBuffer, maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setPageVisibility(visibilityBuffer); + delete[] visibilityBuffer; + + return JSValueMakeUndefined(context); +} + +static JSValueRef resetPageVisibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->resetPageVisibility(); + return JSValueMakeUndefined(context); +} + +static JSValueRef setSmartInsertDeleteEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setSmartInsertDeleteEnabled(JSValueToBoolean(context, arguments[0])); + return JSValueMakeUndefined(context); +} + +static JSValueRef setSelectTrailingWhitespaceEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setSelectTrailingWhitespaceEnabled(JSValueToBoolean(context, arguments[0])); + return JSValueMakeUndefined(context); +} + +static JSValueRef setStopProvisionalFrameLoadsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setStopProvisionalFrameLoads(true); + return JSValueMakeUndefined(context); +} + +static JSValueRef setAsynchronousSpellCheckingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAsynchronousSpellCheckingEnabled(JSValueToBoolean(context, arguments[0])); + return JSValueMakeUndefined(context); +} + +static JSValueRef showWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->showWebInspector(); + return JSValueMakeUndefined(context); +} + +static JSValueRef closeWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->closeWebInspector(); + return JSValueMakeUndefined(context); +} + +static JSValueRef evaluateInWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + double callId = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + controller->evaluateInWebInspector(static_cast<long>(callId), script.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef evaluateScriptInIsolatedWorldCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + double worldID = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + controller->evaluateScriptInIsolatedWorld(static_cast<unsigned>(worldID), JSContextGetGlobalObject(context), script.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef elementDoesAutoCompleteForElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + bool autoCompletes = controller->elementDoesAutoCompleteForElementWithId(elementId.get()); + + return JSValueMakeBoolean(context, autoCompletes); +} + +static JSValueRef pauseAnimationAtTimeOnElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> animationName(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + double time = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->pauseAnimationAtTimeOnElementWithId(animationName.get(), time, elementId.get())); +} + +static JSValueRef pauseTransitionAtTimeOnElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> propertyName(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + double time = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->pauseTransitionAtTimeOnElementWithId(propertyName.get(), time, elementId.get())); +} + +static JSValueRef sampleSVGAnimationForElementAtTimeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> animationId(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + double time = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->sampleSVGAnimationForElementAtTime(animationId.get(), time, elementId.get())); +} + +static JSValueRef numberOfActiveAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 0) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->numberOfActiveAnimations()); +} + +static JSValueRef suspendAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->suspendAnimations(); + return JSValueMakeUndefined(context); +} + +static JSValueRef resumeAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->resumeAnimations(); + return JSValueMakeUndefined(context); +} + +static JSValueRef waitForPolicyDelegateCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->waitForPolicyDelegate(); + return JSValueMakeUndefined(context); +} + +static JSValueRef addOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 4) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains); + return JSValueMakeUndefined(context); +} + +static JSValueRef removeOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 4) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->removeOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains); + return JSValueMakeUndefined(context); +} + +static JSValueRef setScrollbarPolicyCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> orientation(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> policy(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setScrollbarPolicy(orientation.get(), policy.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef addUserScriptCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> source(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + bool runAtStart = JSValueToBoolean(context, arguments[1]); + bool allFrames = JSValueToBoolean(context, arguments[2]); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addUserScript(source.get(), runAtStart, allFrames); + return JSValueMakeUndefined(context); +} + +static JSValueRef addUserStyleSheetCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> source(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + bool allFrames = JSValueToBoolean(context, arguments[1]); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addUserStyleSheet(source.get(), allFrames); + return JSValueMakeUndefined(context); +} + +static JSValueRef setShouldPaintBrokenImageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setShouldPaintBrokenImage(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef apiTestNewWindowDataLoadBaseURLCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> utf8Data(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> baseURL(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->apiTestNewWindowDataLoadBaseURL(utf8Data.get(), baseURL.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef apiTestGoToCurrentBackForwardItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->apiTestGoToCurrentBackForwardItem(); + return JSValueMakeUndefined(context); +} + +static JSValueRef setWebViewEditableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has Mac implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setWebViewEditable(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + + +static JSValueRef abortModalCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->abortModal(); + return JSValueMakeUndefined(context); +} + +static JSValueRef hasSpellingMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + int from = JSValueToNumber(context, arguments[0], 0); + int length = JSValueToNumber(context, arguments[1], 0); + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + bool ok = controller->hasSpellingMarker(from, length); + + return JSValueMakeBoolean(context, ok); +} + +static JSValueRef hasGrammarMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + int from = JSValueToNumber(context, arguments[0], 0); + int length = JSValueToNumber(context, arguments[1], 0); + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + bool ok = controller->hasGrammarMarker(from, length); + + return JSValueMakeBoolean(context, ok); +} + +static JSValueRef markerTextForListItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + if (argumentCount < 1) + return JSValueMakeUndefined(context); + return JSValueMakeString(context, controller->markerTextForListItem(context, arguments[0]).get()); +} + +static JSValueRef authenticateSessionCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // authenticateSession(url, username, password) + if (argumentCount != 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> username(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> password(Adopt, JSValueToStringCopy(context, arguments[2], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->authenticateSession(url.get(), username.get(), password.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef setEditingBehaviorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // The editing behavior string. + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> editingBehavior(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(editingBehavior.get()); + char* behaviorBuffer = new char[maxLength + 1]; + JSStringGetUTF8CString(editingBehavior.get(), behaviorBuffer, maxLength); + + if (strcmp(behaviorBuffer, "mac") && strcmp(behaviorBuffer, "win") && strcmp(behaviorBuffer, "unix")) { + JSRetainPtr<JSStringRef> invalidArgument(JSStringCreateWithUTF8CString("Passed invalid editing behavior. Must be 'mac', 'win', or 'unix'.")); + *exception = JSValueMakeString(context, invalidArgument.get()); + return JSValueMakeUndefined(context); + } + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setEditingBehavior(behaviorBuffer); + + delete [] behaviorBuffer; + + return JSValueMakeUndefined(context); +} + +static JSValueRef setSerializeHTTPLoadsCallback(JSContextRef context, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + bool serialize = true; + if (argumentCount == 1) + serialize = JSValueToBoolean(context, arguments[0]); + + LayoutTestController::setSerializeHTTPLoads(serialize); + return JSValueMakeUndefined(context); +} + +static JSValueRef allowRoundingHacksCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + controller->allowRoundingHacks(); + return JSValueMakeUndefined(context); +} + +static JSValueRef setShouldStayOnPageAfterHandlingBeforeUnloadCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + + if (argumentCount == 1) + controller->setShouldStayOnPageAfterHandlingBeforeUnload(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + +static JSValueRef addChromeInputFieldCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->addChromeInputField(); + // the first argument is a callback that is called once the input field has been added + if (argumentCount == 1) + JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0); + return JSValueMakeUndefined(context); +} + +static JSValueRef removeChromeInputFieldCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->removeChromeInputField(); + // the first argument is a callback that is called once the input field has been added + if (argumentCount == 1) + JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0); + return JSValueMakeUndefined(context); +} + +static JSValueRef focusWebViewCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->focusWebView(); + // the first argument is a callback that is called once the input field has been added + if (argumentCount == 1) + JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0); + return JSValueMakeUndefined(context); +} + +static JSValueRef setBackingScaleFactorCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + double backingScaleFactor = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setBackingScaleFactor(backingScaleFactor); + + // The second argument is a callback that is called once the backing scale factor has been set. + JSObjectCallAsFunction(context, JSValueToObject(context, arguments[1], 0), thisObject, 0, 0, 0); + return JSValueMakeUndefined(context); +} + +// Static Values + +static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->globalFlag()); +} + +static JSValueRef getWebHistoryItemCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->webHistoryItemCount()); +} + +static JSValueRef getWorkerThreadCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->workerThreadCount()); +} + +#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN) +static JSValueRef getPlatformNameCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> platformName(controller->platformName()); + if (!platformName.get()) + return JSValueMakeUndefined(context); + return JSValueMakeString(context, platformName.get()); +} +#endif + +static bool setGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setGlobalFlag(JSValueToBoolean(context, value)); + return true; +} + +static JSValueRef ignoreDesktopNotificationPermissionRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->ignoreDesktopNotificationPermissionRequests(); + return JSValueMakeUndefined(context); +} + +static JSValueRef simulateDesktopNotificationClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + JSRetainPtr<JSStringRef> title(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + controller->simulateDesktopNotificationClick(title.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef setMinimumTimerIntervalCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + double minimum = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setMinimumTimerInterval(minimum); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setTextDirectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount == 1) { + JSRetainPtr<JSStringRef> direction(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setTextDirection(direction.get()); + } + + return JSValueMakeUndefined(context); +} + +static void layoutTestControllerObjectFinalize(JSObjectRef object) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(object)); + controller->deref(); +} + +// Object Creation + +void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> layoutTestContollerStr(Adopt, JSStringCreateWithUTF8CString("layoutTestController")); + ref(); + + JSClassRef classRef = getJSClass(); + JSValueRef layoutTestContollerObject = JSObjectMake(context, classRef, this); + JSClassRelease(classRef); + + JSObjectSetProperty(context, windowObject, layoutTestContollerStr.get(), layoutTestContollerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); +} + +JSClassRef LayoutTestController::getJSClass() +{ + static JSStaticValue* staticValues = LayoutTestController::staticValues(); + static JSStaticFunction* staticFunctions = LayoutTestController::staticFunctions(); + static JSClassDefinition classDefinition = { + 0, kJSClassAttributeNone, "LayoutTestController", 0, staticValues, staticFunctions, + 0, layoutTestControllerObjectFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return JSClassCreate(&classDefinition); +} + +JSStaticValue* LayoutTestController::staticValues() +{ + static JSStaticValue staticValues[] = { + { "globalFlag", getGlobalFlagCallback, setGlobalFlagCallback, kJSPropertyAttributeNone }, + { "webHistoryItemCount", getWebHistoryItemCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "workerThreadCount", getWorkerThreadCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, +#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN) + { "platformName", getPlatformNameCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, +#endif + { 0, 0, 0, 0 } + }; + return staticValues; +} + +JSStaticFunction* LayoutTestController::staticFunctions() +{ + static JSStaticFunction staticFunctions[] = { + { "abortModal", abortModalCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addDisallowedURL", addDisallowedURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addURLToRedirect", addURLToRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addUserScript", addUserScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addUserStyleSheet", addUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "apiTestNewWindowDataLoadBaseURL", apiTestNewWindowDataLoadBaseURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "apiTestGoToCurrentBackForwardItem", apiTestGoToCurrentBackForwardItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "applicationCacheDiskUsageForOrigin", applicationCacheDiskUsageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "callShouldCloseOnWebView", callShouldCloseOnWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clearAllApplicationCaches", clearAllApplicationCachesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clearAllDatabases", clearAllDatabasesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clearApplicationCacheForOrigin", clearApplicationCacheForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clearBackForwardList", clearBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "clearPersistentUserStyleSheet", clearPersistentUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "closeWebInspector", closeWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "computedStyleIncludingVisitedInfo", computedStyleIncludingVisitedInfoCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "nodesFromRect", nodesFromRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "decodeHostName", decodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "disableImageLoading", disableImageLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "disallowIncreaseForApplicationCacheQuota", disallowIncreaseForApplicationCacheQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dispatchPendingLoadRequests", dispatchPendingLoadRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "display", displayCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "displayInvalidatedRegion", displayInvalidatedRegionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpApplicationCacheDelegateCallbacks", dumpApplicationCacheDelegateCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpAsText", dumpAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpBackForwardList", dumpBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpChildFrameScrollPositions", dumpChildFrameScrollPositionsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpChildFramesAsText", dumpChildFramesAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpConfigurationForViewport", dumpConfigurationForViewportCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpDOMAsWebArchive", dumpDOMAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpDatabaseCallbacks", dumpDatabaseCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpEditingCallbacks", dumpEditingCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpFrameLoadCallbacks", dumpFrameLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpProgressFinishedCallback", dumpProgressFinishedCallbackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpUserGestureInFrameLoadCallbacks", dumpUserGestureInFrameLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpResourceLoadCallbacks", dumpResourceLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpResourceResponseMIMETypes", dumpResourceResponseMIMETypesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpSelectionRect", dumpSelectionRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpSourceAsWebArchive", dumpSourceAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpStatusCallbacks", dumpStatusCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpTitleChanges", dumpTitleChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpIconChanges", dumpIconChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dumpWillCacheResponse", dumpWillCacheResponseCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "elementDoesAutoCompleteForElementWithId", elementDoesAutoCompleteForElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "encodeHostName", encodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "evaluateInWebInspector", evaluateInWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "evaluateScriptInIsolatedWorld", evaluateScriptInIsolatedWorldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "execCommand", execCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "findString", findStringCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "counterValueForElementById", counterValueForElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "originsWithApplicationCache", originsWithApplicationCacheCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "goBack", goBackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "grantDesktopNotificationPermission", grantDesktopNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hasSpellingMarker", hasSpellingMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hasGrammarMarker", hasGrammarMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "ignoreDesktopNotificationPermissionRequests", ignoreDesktopNotificationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "isPageBoxVisible", isPageBoxVisibleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "layerTreeAsText", layerTreeAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "numberOfPages", numberOfPagesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "numberOfPendingGeolocationPermissionRequests", numberOfPendingGeolocationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "markerTextForListItem", markerTextForListItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "numberOfActiveAnimations", numberOfActiveAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "suspendAnimations", suspendAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "resumeAnimations", resumeAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "overridePreference", overridePreferenceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pageNumberForElementById", pageNumberForElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pageSizeAndMarginsInPixels", pageSizeAndMarginsInPixelsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pageProperty", pagePropertyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pathToLocalResource", pathToLocalResourceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pauseAnimationAtTimeOnElementWithId", pauseAnimationAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "pauseTransitionAtTimeOnElementWithId", pauseTransitionAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "sampleSVGAnimationForElementAtTime", sampleSVGAnimationForElementAtTimeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "printToPDF", dumpAsPDFCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueBackNavigation", queueBackNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueForwardNavigation", queueForwardNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueLoad", queueLoadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueLoadHTMLString", queueLoadHTMLStringCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueLoadingScript", queueLoadingScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueNonLoadingScript", queueNonLoadingScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "queueReload", queueReloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeAllVisitedLinks", removeAllVisitedLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeOriginAccessWhitelistEntry", removeOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "resetPageVisibility", resetPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAllowFileAccessFromFileURLs", setAllowFileAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setApplicationCacheOriginQuota", setApplicationCacheOriginQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setEncodedAudioData", setEncodedAudioDataCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAuthenticationUsername", setAuthenticationUsernameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAuthorAndUserStylesEnabled", setAuthorAndUserStylesEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAutofilled", setAutofilledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setCacheModel", setCacheModelCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setCallCloseOnWebViews", setCallCloseOnWebViewsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setCanOpenWindows", setCanOpenWindowsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setCloseRemainingWindowsWhenComplete", setCloseRemainingWindowsWhenCompleteCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setCustomPolicyDelegate", setCustomPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setDatabaseQuota", setDatabaseQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setDeferMainResourceDataLoad", setDeferMainResourceDataLoadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setDefersLoading", setDefersLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setDomainRelaxationForbiddenForURLScheme", setDomainRelaxationForbiddenForURLSchemeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setEditingBehavior", setEditingBehaviorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setFrameFlatteningEnabled", setFrameFlatteningEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setGeolocationPermission", setGeolocationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setHandlesAuthenticationChallenges", setHandlesAuthenticationChallengesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setIconDatabaseEnabled", setIconDatabaseEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setJavaScriptProfilingEnabled", setJavaScriptProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMainFrameIsFirstResponder", setMainFrameIsFirstResponderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMinimumTimerInterval", setMinimumTimerIntervalCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMockDeviceOrientation", setMockDeviceOrientationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMockGeolocationError", setMockGeolocationErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addMockSpeechInputResult", addMockSpeechInputResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPageVisibility", setPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPersistentUserStyleSheetLocation", setPersistentUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPopupBlockingEnabled", setPopupBlockingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPluginsEnabled", setPluginsEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPrinting", setPrintingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setPrivateBrowsingEnabled", setPrivateBrowsingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSelectTrailingWhitespaceEnabled", setSelectTrailingWhitespaceEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSerializeHTTPLoads", setSerializeHTTPLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSmartInsertDeleteEnabled", setSmartInsertDeleteEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setSpatialNavigationEnabled", setSpatialNavigationEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setStopProvisionalFrameLoads", setStopProvisionalFrameLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setTabKeyCyclesThroughElements", setTabKeyCyclesThroughElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setValueForUser", setValueForUserCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setViewModeMediaFeature", setViewModeMediaFeatureCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setWebViewEditable", setWebViewEditableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setWillSendRequestClearHeader", setWillSendRequestClearHeaderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setWillSendRequestReturnsNull", setWillSendRequestReturnsNullCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setWillSendRequestReturnsNullOnRedirect", setWillSendRequestReturnsNullOnRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setWindowIsKey", setWindowIsKeyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setJavaScriptCanAccessClipboard", setJavaScriptCanAccessClipboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAsynchronousSpellCheckingEnabled", setAsynchronousSpellCheckingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "showWebInspector", showWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "simulateDesktopNotificationClick", simulateDesktopNotificationClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "testOnscreen", testOnscreenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "waitForPolicyDelegate", waitForPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "windowCount", windowCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addOriginAccessWhitelistEntry", addOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setScrollbarPolicy", setScrollbarPolicyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "authenticateSession", authenticateSessionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "deleteAllLocalStorage", deleteAllLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "syncLocalStorage", syncLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "observeStorageTrackerNotifications", observeStorageTrackerNotificationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "deleteLocalStorageForOrigin", deleteLocalStorageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "localStorageDiskUsageForOrigin", localStorageDiskUsageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "originsWithLocalStorage", originsWithLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setShouldPaintBrokenImage", setShouldPaintBrokenImageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setTextDirection", setTextDirectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "allowRoundingHacks", allowRoundingHacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setShouldStayOnPageAfterHandlingBeforeUnload", setShouldStayOnPageAfterHandlingBeforeUnloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addChromeInputField", addChromeInputFieldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "removeChromeInputField", removeChromeInputFieldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "focusWebView", focusWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setBackingScaleFactor", setBackingScaleFactorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + return staticFunctions; +} + +void LayoutTestController::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL) +{ + WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL)); +} + +void LayoutTestController::queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL) +{ + WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, unreachableURL)); +} + +void LayoutTestController::queueBackNavigation(int howFarBack) +{ + WorkQueue::shared()->queue(new BackItem(howFarBack)); +} + +void LayoutTestController::queueForwardNavigation(int howFarForward) +{ + WorkQueue::shared()->queue(new ForwardItem(howFarForward)); +} + +void LayoutTestController::queueLoadingScript(JSStringRef script) +{ + WorkQueue::shared()->queue(new LoadingScriptItem(script)); +} + +void LayoutTestController::queueNonLoadingScript(JSStringRef script) +{ + WorkQueue::shared()->queue(new NonLoadingScriptItem(script)); +} + +void LayoutTestController::queueReload() +{ + WorkQueue::shared()->queue(new ReloadItem); +} + +void LayoutTestController::grantDesktopNotificationPermission(JSStringRef origin) +{ + m_desktopNotificationAllowedOrigins.push_back(JSStringRetain(origin)); +} + +bool LayoutTestController::checkDesktopNotificationPermission(JSStringRef origin) +{ + std::vector<JSStringRef>::iterator i; + for (i = m_desktopNotificationAllowedOrigins.begin(); + i != m_desktopNotificationAllowedOrigins.end(); + ++i) { + if (JSStringIsEqual(*i, origin)) + return true; + } + return false; +} + +void LayoutTestController::ignoreDesktopNotificationPermissionRequests() +{ + m_areDesktopNotificationPermissionRequestsIgnored = false; +} + +void LayoutTestController::waitToDumpWatchdogTimerFired() +{ + const char* message = "FAIL: Timed out waiting for notifyDone to be called\n"; + fprintf(stderr, "%s", message); + fprintf(stdout, "%s", message); + notifyDone(); +} + +void LayoutTestController::setGeolocationPermissionCommon(bool allow) +{ + m_isGeolocationPermissionSet = true; + m_geolocationPermission = allow; +} + +void LayoutTestController::setPOSIXLocale(JSStringRef locale) +{ + char localeBuf[32]; + JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf)); + setlocale(LC_ALL, localeBuf); +} + +void LayoutTestController::addURLToRedirect(std::string origin, std::string destination) +{ + m_URLsToRedirect[origin] = destination; +} + +const std::string& LayoutTestController::redirectionDestinationForURL(std::string origin) +{ + return m_URLsToRedirect[origin]; +} + +void LayoutTestController::setShouldPaintBrokenImage(bool shouldPaintBrokenImage) +{ + m_shouldPaintBrokenImage = shouldPaintBrokenImage; +} + +const unsigned LayoutTestController::maxViewWidth = 800; +const unsigned LayoutTestController::maxViewHeight = 600; diff --git a/Tools/DumpRenderTree/LayoutTestController.h b/Tools/DumpRenderTree/LayoutTestController.h new file mode 100644 index 000000000..9f4db4983 --- /dev/null +++ b/Tools/DumpRenderTree/LayoutTestController.h @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 LayoutTestController_h +#define LayoutTestController_h + +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <map> +#include <set> +#include <string> +#include <vector> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +class LayoutTestController : public RefCounted<LayoutTestController> { +public: + static PassRefPtr<LayoutTestController> create(const std::string& testPathOrURL, const std::string& expectedPixelHash); + ~LayoutTestController(); + + void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception); + + void addDisallowedURL(JSStringRef url); + void addURLToRedirect(std::string origin, std::string destination); + const std::string& redirectionDestinationForURL(std::string); + void clearAllApplicationCaches(); + void clearAllDatabases(); + void clearApplicationCacheForOrigin(JSStringRef name); + void clearBackForwardList(); + void clearPersistentUserStyleSheet(); + bool callShouldCloseOnWebView(); + JSStringRef copyDecodedHostName(JSStringRef name); + JSStringRef copyEncodedHostName(JSStringRef name); + JSRetainPtr<JSStringRef> counterValueForElementById(JSStringRef id); + void disableImageLoading(); + void dispatchPendingLoadRequests(); + void display(); + void displayInvalidatedRegion(); + void execCommand(JSStringRef name, JSStringRef value); + bool findString(JSContextRef, JSStringRef, JSObjectRef optionsArray); + void goBack(); + JSValueRef originsWithApplicationCache(JSContextRef); + long long applicationCacheDiskUsageForOrigin(JSStringRef name); + bool isCommandEnabled(JSStringRef name); + void keepWebHistory(); + JSValueRef computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef); + JSValueRef nodesFromRect(JSContextRef, JSValueRef, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping); + void notifyDone(); + int numberOfPages(float pageWidthInPixels, float pageHeightInPixels); + int numberOfPendingGeolocationPermissionRequests(); + void overridePreference(JSStringRef key, JSStringRef value); + int pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels); + JSRetainPtr<JSStringRef> pageProperty(const char* propertyName, int pageNumber) const; + JSRetainPtr<JSStringRef> pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const; + bool isPageBoxVisible(int pageNumber) const; + JSStringRef pathToLocalResource(JSContextRef, JSStringRef url); + void queueBackNavigation(int howFarBackward); + void queueForwardNavigation(int howFarForward); + void queueLoad(JSStringRef url, JSStringRef target); + void queueLoadHTMLString(JSStringRef content, JSStringRef baseURL); + void queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL); + void queueLoadingScript(JSStringRef script); + void queueNonLoadingScript(JSStringRef script); + void queueReload(); + void removeAllVisitedLinks(); + void setAcceptsEditing(bool acceptsEditing); + void setAllowUniversalAccessFromFileURLs(bool); + void setAllowFileAccessFromFileURLs(bool); + void setAppCacheMaximumSize(unsigned long long quota); + void setApplicationCacheOriginQuota(unsigned long long quota); + void setAuthorAndUserStylesEnabled(bool); + void setAutofilled(JSContextRef, JSValueRef nodeObject, bool autofilled); + void setCacheModel(int); + void setCustomPolicyDelegate(bool setDelegate, bool permissive); + void setDatabaseQuota(unsigned long long quota); + void setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme); + void setDefersLoading(bool); + void setIconDatabaseEnabled(bool iconDatabaseEnabled); + void setJavaScriptProfilingEnabled(bool profilingEnabled); + void setJavaScriptCanAccessClipboard(bool flag); + void setMainFrameIsFirstResponder(bool flag); + void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma); + void setMockGeolocationError(int code, JSStringRef message); + void setMockGeolocationPosition(double latitude, double longitude, double accuracy); + void addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language); + void setPersistentUserStyleSheetLocation(JSStringRef path); + void setPluginsEnabled(bool flag); + void setPopupBlockingEnabled(bool flag); + void setPrivateBrowsingEnabled(bool flag); + void setSelectTrailingWhitespaceEnabled(bool flag); + void setSmartInsertDeleteEnabled(bool flag); + void setTabKeyCyclesThroughElements(bool cycles); + void setUseDashboardCompatibilityMode(bool flag); + void setUserStyleSheetEnabled(bool flag); + void setUserStyleSheetLocation(JSStringRef path); + void setValueForUser(JSContextRef, JSValueRef nodeObject, JSStringRef value); + void setViewModeMediaFeature(JSStringRef mode); + void setXSSAuditorEnabled(bool flag); + void setFrameFlatteningEnabled(bool enable); + void setSpatialNavigationEnabled(bool enable); + void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy); + void setEditingBehavior(const char* editingBehavior); + void startSpeechInput(JSContextRef inputElement); + + void setPageVisibility(const char* visibility) { } + void resetPageVisibility() { } + + void waitForPolicyDelegate(); + size_t webHistoryItemCount(); + unsigned workerThreadCount() const; + int windowCount(); + +#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN) + JSRetainPtr<JSStringRef> platformName() const; +#endif + + void grantDesktopNotificationPermission(JSStringRef origin); + bool checkDesktopNotificationPermission(JSStringRef origin); + void ignoreDesktopNotificationPermissionRequests(); + bool areDesktopNotificationPermissionRequestsIgnored() const { return m_areDesktopNotificationPermissionRequestsIgnored; } + void simulateDesktopNotificationClick(JSStringRef title); + + bool elementDoesAutoCompleteForElementWithId(JSStringRef id); + + bool dumpAsAudio() const { return m_dumpAsAudio; } + void setDumpAsAudio(bool dumpAsAudio) { m_dumpAsAudio = dumpAsAudio; } + + bool dumpAsPDF() const { return m_dumpAsPDF; } + void setDumpAsPDF(bool dumpAsPDF) { m_dumpAsPDF = dumpAsPDF; } + + bool dumpAsText() const { return m_dumpAsText; } + void setDumpAsText(bool dumpAsText) { m_dumpAsText = dumpAsText; } + + bool generatePixelResults() const { return m_generatePixelResults; } + void setGeneratePixelResults(bool generatePixelResults) { m_generatePixelResults = generatePixelResults; } + + bool disallowIncreaseForApplicationCacheQuota() const { return m_disallowIncreaseForApplicationCacheQuota; } + void setDisallowIncreaseForApplicationCacheQuota(bool disallowIncrease) { m_disallowIncreaseForApplicationCacheQuota = disallowIncrease; } + + bool dumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; } + void setDumpApplicationCacheDelegateCallbacks(bool dumpCallbacks) { m_dumpApplicationCacheDelegateCallbacks = dumpCallbacks; } + + bool dumpBackForwardList() const { return m_dumpBackForwardList; } + void setDumpBackForwardList(bool dumpBackForwardList) { m_dumpBackForwardList = dumpBackForwardList; } + + bool dumpChildFrameScrollPositions() const { return m_dumpChildFrameScrollPositions; } + void setDumpChildFrameScrollPositions(bool dumpChildFrameScrollPositions) { m_dumpChildFrameScrollPositions = dumpChildFrameScrollPositions; } + + bool dumpChildFramesAsText() const { return m_dumpChildFramesAsText; } + void setDumpChildFramesAsText(bool dumpChildFramesAsText) { m_dumpChildFramesAsText = dumpChildFramesAsText; } + + bool dumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; } + void setDumpDatabaseCallbacks(bool dumpDatabaseCallbacks) { m_dumpDatabaseCallbacks = dumpDatabaseCallbacks; } + + bool dumpDOMAsWebArchive() const { return m_dumpDOMAsWebArchive; } + void setDumpDOMAsWebArchive(bool dumpDOMAsWebArchive) { m_dumpDOMAsWebArchive = dumpDOMAsWebArchive; } + + bool dumpEditingCallbacks() const { return m_dumpEditingCallbacks; } + void setDumpEditingCallbacks(bool dumpEditingCallbacks) { m_dumpEditingCallbacks = dumpEditingCallbacks; } + + bool dumpFrameLoadCallbacks() const { return m_dumpFrameLoadCallbacks; } + void setDumpFrameLoadCallbacks(bool dumpFrameLoadCallbacks) { m_dumpFrameLoadCallbacks = dumpFrameLoadCallbacks; } + + bool dumpProgressFinishedCallback() const { return m_dumpProgressFinishedCallback; } + void setDumpProgressFinishedCallback(bool dumpProgressFinishedCallback) { m_dumpProgressFinishedCallback = dumpProgressFinishedCallback; } + + bool dumpUserGestureInFrameLoadCallbacks() const { return m_dumpUserGestureInFrameLoadCallbacks; } + void setDumpUserGestureInFrameLoadCallbacks(bool dumpUserGestureInFrameLoadCallbacks) { m_dumpUserGestureInFrameLoadCallbacks = dumpUserGestureInFrameLoadCallbacks; } + + bool dumpHistoryDelegateCallbacks() const { return m_dumpHistoryDelegateCallbacks; } + void setDumpHistoryDelegateCallbacks(bool dumpHistoryDelegateCallbacks) { m_dumpHistoryDelegateCallbacks = dumpHistoryDelegateCallbacks; } + + bool dumpResourceLoadCallbacks() const { return m_dumpResourceLoadCallbacks; } + void setDumpResourceLoadCallbacks(bool dumpResourceLoadCallbacks) { m_dumpResourceLoadCallbacks = dumpResourceLoadCallbacks; } + + bool dumpResourceResponseMIMETypes() const { return m_dumpResourceResponseMIMETypes; } + void setDumpResourceResponseMIMETypes(bool dumpResourceResponseMIMETypes) { m_dumpResourceResponseMIMETypes = dumpResourceResponseMIMETypes; } + + bool dumpSelectionRect() const { return m_dumpSelectionRect; } + void setDumpSelectionRect(bool dumpSelectionRect) { m_dumpSelectionRect = dumpSelectionRect; } + + bool dumpSourceAsWebArchive() const { return m_dumpSourceAsWebArchive; } + void setDumpSourceAsWebArchive(bool dumpSourceAsWebArchive) { m_dumpSourceAsWebArchive = dumpSourceAsWebArchive; } + + bool dumpStatusCallbacks() const { return m_dumpStatusCallbacks; } + void setDumpStatusCallbacks(bool dumpStatusCallbacks) { m_dumpStatusCallbacks = dumpStatusCallbacks; } + + bool dumpTitleChanges() const { return m_dumpTitleChanges; } + void setDumpTitleChanges(bool dumpTitleChanges) { m_dumpTitleChanges = dumpTitleChanges; } + + bool dumpIconChanges() const { return m_dumpIconChanges; } + void setDumpIconChanges(bool dumpIconChanges) { m_dumpIconChanges = dumpIconChanges; } + + bool dumpVisitedLinksCallback() const { return m_dumpVisitedLinksCallback; } + void setDumpVisitedLinksCallback(bool dumpVisitedLinksCallback) { m_dumpVisitedLinksCallback = dumpVisitedLinksCallback; } + + bool dumpWillCacheResponse() const { return m_dumpWillCacheResponse; } + void setDumpWillCacheResponse(bool dumpWillCacheResponse) { m_dumpWillCacheResponse = dumpWillCacheResponse; } + + bool callCloseOnWebViews() const { return m_callCloseOnWebViews; } + void setCallCloseOnWebViews(bool callCloseOnWebViews) { m_callCloseOnWebViews = callCloseOnWebViews; } + + bool canOpenWindows() const { return m_canOpenWindows; } + void setCanOpenWindows(bool canOpenWindows) { m_canOpenWindows = canOpenWindows; } + + bool closeRemainingWindowsWhenComplete() const { return m_closeRemainingWindowsWhenComplete; } + void setCloseRemainingWindowsWhenComplete(bool closeRemainingWindowsWhenComplete) { m_closeRemainingWindowsWhenComplete = closeRemainingWindowsWhenComplete; } + + bool newWindowsCopyBackForwardList() const { return m_newWindowsCopyBackForwardList; } + void setNewWindowsCopyBackForwardList(bool newWindowsCopyBackForwardList) { m_newWindowsCopyBackForwardList = newWindowsCopyBackForwardList; } + + bool stopProvisionalFrameLoads() const { return m_stopProvisionalFrameLoads; } + void setStopProvisionalFrameLoads(bool stopProvisionalFrameLoads) { m_stopProvisionalFrameLoads = stopProvisionalFrameLoads; } + + bool testOnscreen() const { return m_testOnscreen; } + void setTestOnscreen(bool testOnscreen) { m_testOnscreen = testOnscreen; } + + bool testRepaint() const { return m_testRepaint; } + void setTestRepaint(bool testRepaint) { m_testRepaint = testRepaint; } + + bool testRepaintSweepHorizontally() const { return m_testRepaintSweepHorizontally; } + void setTestRepaintSweepHorizontally(bool testRepaintSweepHorizontally) { m_testRepaintSweepHorizontally = testRepaintSweepHorizontally; } + + bool waitToDump() const { return m_waitToDump; } + void setWaitToDump(bool waitToDump); + void waitToDumpWatchdogTimerFired(); + + const std::set<std::string>& willSendRequestClearHeaders() const { return m_willSendRequestClearHeaders; } + void setWillSendRequestClearHeader(std::string header) { m_willSendRequestClearHeaders.insert(header); } + + bool willSendRequestReturnsNull() const { return m_willSendRequestReturnsNull; } + void setWillSendRequestReturnsNull(bool returnsNull) { m_willSendRequestReturnsNull = returnsNull; } + + bool willSendRequestReturnsNullOnRedirect() const { return m_willSendRequestReturnsNullOnRedirect; } + void setWillSendRequestReturnsNullOnRedirect(bool returnsNull) { m_willSendRequestReturnsNullOnRedirect = returnsNull; } + + bool windowIsKey() const { return m_windowIsKey; } + void setWindowIsKey(bool windowIsKey); + + bool alwaysAcceptCookies() const { return m_alwaysAcceptCookies; } + void setAlwaysAcceptCookies(bool alwaysAcceptCookies); + + bool handlesAuthenticationChallenges() const { return m_handlesAuthenticationChallenges; } + void setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges) { m_handlesAuthenticationChallenges = handlesAuthenticationChallenges; } + + bool isPrinting() const { return m_isPrinting; } + void setIsPrinting(bool isPrinting) { m_isPrinting = isPrinting; } + + const std::string& authenticationUsername() const { return m_authenticationUsername; } + void setAuthenticationUsername(std::string username) { m_authenticationUsername = username; } + + const std::string& authenticationPassword() const { return m_authenticationPassword; } + void setAuthenticationPassword(std::string password) { m_authenticationPassword = password; } + + bool globalFlag() const { return m_globalFlag; } + void setGlobalFlag(bool globalFlag) { m_globalFlag = globalFlag; } + + bool deferMainResourceDataLoad() const { return m_deferMainResourceDataLoad; } + void setDeferMainResourceDataLoad(bool flag) { m_deferMainResourceDataLoad = flag; } + + const std::string& testPathOrURL() const { return m_testPathOrURL; } + const std::string& expectedPixelHash() const { return m_expectedPixelHash; } + + const std::string& encodedAudioData() const { return m_encodedAudioData; } + void setEncodedAudioData(const std::string& encodedAudioData) { m_encodedAudioData = encodedAudioData; } + + bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId); + bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId); + bool sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId); + unsigned numberOfActiveAnimations() const; + void suspendAnimations() const; + void resumeAnimations() const; + + void addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains); + void removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains); + + void addUserScript(JSStringRef source, bool runAtStart, bool allFrames); + void addUserStyleSheet(JSStringRef source, bool allFrames); + + void setGeolocationPermission(bool allow); + bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; } + bool geolocationPermission() const { return m_geolocationPermission; } + + void setDeveloperExtrasEnabled(bool); + void setAsynchronousSpellCheckingEnabled(bool); + void showWebInspector(); + void closeWebInspector(); + void evaluateInWebInspector(long callId, JSStringRef script); + void evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script); + void allowRoundingHacks(); + + bool shouldStayOnPageAfterHandlingBeforeUnload() const { return m_shouldStayOnPageAfterHandlingBeforeUnload; } + void setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPageAfterHandlingBeforeUnload) { m_shouldStayOnPageAfterHandlingBeforeUnload = shouldStayOnPageAfterHandlingBeforeUnload; } + + void addChromeInputField(); + void removeChromeInputField(); + void focusWebView(); + + void setBackingScaleFactor(double); + + void setPOSIXLocale(JSStringRef locale); + + void setWebViewEditable(bool); + + void abortModal(); + + bool hasSpellingMarker(int from, int length); + bool hasGrammarMarker(int from, int length); + + void dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight); + + static void setSerializeHTTPLoads(bool serialize); + + // The following API test functions should probably be moved to platform-specific + // unit tests outside of DRT once they exist. + void apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL); + void apiTestGoToCurrentBackForwardItem(); + + // Simulate a request an embedding application could make, populating per-session credential storage. + void authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password); + + JSRetainPtr<JSStringRef> layerTreeAsText() const; + + JSRetainPtr<JSStringRef> markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const; + + JSValueRef originsWithLocalStorage(JSContextRef); + void deleteAllLocalStorage(); + void deleteLocalStorageForOrigin(JSStringRef originIdentifier); + long long localStorageDiskUsageForOrigin(JSStringRef originIdentifier); + void observeStorageTrackerNotifications(unsigned number); + void syncLocalStorage(); + + void setShouldPaintBrokenImage(bool); + bool shouldPaintBrokenImage() const { return m_shouldPaintBrokenImage; } + + static const unsigned maxViewWidth; + static const unsigned maxViewHeight; + + void setMinimumTimerInterval(double); + + void setTextDirection(JSStringRef); + +private: + LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash); + + void setGeolocationPermissionCommon(bool allow); + + bool m_disallowIncreaseForApplicationCacheQuota; + bool m_dumpApplicationCacheDelegateCallbacks; + bool m_dumpAsAudio; + bool m_dumpAsPDF; + bool m_dumpAsText; + bool m_dumpBackForwardList; + bool m_dumpChildFrameScrollPositions; + bool m_dumpChildFramesAsText; + bool m_dumpDOMAsWebArchive; + bool m_dumpDatabaseCallbacks; + bool m_dumpEditingCallbacks; + bool m_dumpFrameLoadCallbacks; + bool m_dumpProgressFinishedCallback; + bool m_dumpUserGestureInFrameLoadCallbacks; + bool m_dumpHistoryDelegateCallbacks; + bool m_dumpResourceLoadCallbacks; + bool m_dumpResourceResponseMIMETypes; + bool m_dumpSelectionRect; + bool m_dumpSourceAsWebArchive; + bool m_dumpStatusCallbacks; + bool m_dumpTitleChanges; + bool m_dumpIconChanges; + bool m_dumpVisitedLinksCallback; + bool m_dumpWillCacheResponse; + bool m_generatePixelResults; + bool m_callCloseOnWebViews; + bool m_canOpenWindows; + bool m_closeRemainingWindowsWhenComplete; + bool m_newWindowsCopyBackForwardList; + bool m_stopProvisionalFrameLoads; + bool m_testOnscreen; + bool m_testRepaint; + bool m_testRepaintSweepHorizontally; + bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called. + bool m_willSendRequestReturnsNull; + bool m_willSendRequestReturnsNullOnRedirect; + bool m_windowIsKey; + bool m_alwaysAcceptCookies; + bool m_globalFlag; + bool m_isGeolocationPermissionSet; + bool m_geolocationPermission; + bool m_handlesAuthenticationChallenges; + bool m_isPrinting; + bool m_deferMainResourceDataLoad; + bool m_shouldPaintBrokenImage; + bool m_shouldStayOnPageAfterHandlingBeforeUnload; + bool m_areDesktopNotificationPermissionRequestsIgnored; + + std::string m_authenticationUsername; + std::string m_authenticationPassword; + std::string m_testPathOrURL; + std::string m_expectedPixelHash; // empty string if no hash + + std::set<std::string> m_willSendRequestClearHeaders; + + // base64 encoded WAV audio data is stored here. + std::string m_encodedAudioData; + + // origins which have been granted desktop notification access + std::vector<JSStringRef> m_desktopNotificationAllowedOrigins; + + std::map<std::string, std::string> m_URLsToRedirect; + + static JSClassRef getJSClass(); + static JSStaticValue* staticValues(); + static JSStaticFunction* staticFunctions(); +}; + +#endif // LayoutTestController_h diff --git a/Tools/DumpRenderTree/Makefile b/Tools/DumpRenderTree/Makefile new file mode 100644 index 000000000..1f1dbbcb3 --- /dev/null +++ b/Tools/DumpRenderTree/Makefile @@ -0,0 +1,2 @@ +SCRIPTS_PATH = ../Scripts +include ../../Makefile.shared diff --git a/Tools/DumpRenderTree/PixelDumpSupport.cpp b/Tools/DumpRenderTree/PixelDumpSupport.cpp new file mode 100644 index 000000000..ee38c235c --- /dev/null +++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupport.h" + +#include "CyclicRedundancyCheck.h" +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <cstdio> +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +#if USE(CG) +#include "PixelDumpSupportCG.h" +#elif USE(CAIRO) +#include "PixelDumpSupportCairo.h" +#endif + +void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash) +{ + RefPtr<BitmapContext> context; +#if PLATFORM(MAC) + if (gLayoutTestController->isPrinting()) + context = createPagedBitmapContext(); + else +#endif + context = createBitmapContextFromWebView(gLayoutTestController->testOnscreen(), gLayoutTestController->testRepaint(), gLayoutTestController->testRepaintSweepHorizontally(), gLayoutTestController->dumpSelectionRect()); + ASSERT(context); + + // Compute the hash of the bitmap context pixels + char actualHash[33]; + computeMD5HashStringForBitmapContext(context.get(), actualHash); + printf("\nActualHash: %s\n", actualHash); // FIXME: No need for the leading newline. + + // Check the computed hash against the expected one and dump image on mismatch + bool dumpImage = true; + if (expectedHash.length() > 0) { + ASSERT(expectedHash.length() == 32); + + printf("\nExpectedHash: %s\n", expectedHash.c_str()); // FIXME: No need for the leading newline. + + if (expectedHash == actualHash) // FIXME: do case insensitive compare + dumpImage = false; + } + + if (dumpImage) + dumpBitmap(context.get(), actualHash); +} + +static void appendIntToVector(unsigned number, Vector<unsigned char>& vector) +{ + size_t offset = vector.size(); + vector.grow(offset + 4); + vector[offset] = ((number >> 24) & 0xff); + vector[offset + 1] = ((number >> 16) & 0xff); + vector[offset + 2] = ((number >> 8) & 0xff); + vector[offset + 3] = (number & 0xff); +} + +static void convertChecksumToPNGComment(const char* checksum, Vector<unsigned char>& bytesToAdd) +{ + // Chunks of PNG files are <length>, <type>, <data>, <crc>. + static const char textCommentPrefix[] = "\x00\x00\x00\x29tEXtchecksum\x00"; + static const size_t prefixLength = sizeof(textCommentPrefix) - 1; // The -1 is for the null at the end of the char[]. + static const size_t checksumLength = 32; + + bytesToAdd.append(textCommentPrefix, prefixLength); + bytesToAdd.append(checksum, checksumLength); + + Vector<unsigned char> dataToCrc; + dataToCrc.append(textCommentPrefix + 4, prefixLength - 4); // Don't include the chunk length in the crc. + dataToCrc.append(checksum, checksumLength); + unsigned crc32 = computeCrc(dataToCrc); + + appendIntToVector(crc32, bytesToAdd); +} + +static size_t offsetAfterIHDRChunk(const unsigned char* data, const size_t dataLength) +{ + const int pngHeaderLength = 8; + const int pngIHDRChunkLength = 25; // chunk length + "IHDR" + 13 bytes of data + checksum + return pngHeaderLength + pngIHDRChunkLength; +} + +void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum) +{ + Vector<unsigned char> bytesToAdd; + convertChecksumToPNGComment(checksum, bytesToAdd); + + printf("Content-Type: %s\n", "image/png"); + printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size())); + + size_t insertOffset = offsetAfterIHDRChunk(data, dataLength); + + fwrite(data, 1, insertOffset, stdout); + fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout); + + const size_t bytesToWriteInOneChunk = 1 << 15; + data += insertOffset; + size_t dataRemainingToWrite = dataLength - insertOffset; + while (dataRemainingToWrite) { + size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk); + size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout); + if (bytesWritten != bytesToWriteInThisChunk) + break; + dataRemainingToWrite -= bytesWritten; + data += bytesWritten; + } +} diff --git a/Tools/DumpRenderTree/PixelDumpSupport.h b/Tools/DumpRenderTree/PixelDumpSupport.h new file mode 100644 index 000000000..87e640243 --- /dev/null +++ b/Tools/DumpRenderTree/PixelDumpSupport.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupport_h +#define PixelDumpSupport_h + +#include <string> + +#include <wtf/PassRefPtr.h> + +class BitmapContext; + +void computeMD5HashStringForBitmapContext(BitmapContext*, char hashString[33]); +PassRefPtr<BitmapContext> createPagedBitmapContext(); +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect); +void dumpBitmap(BitmapContext*, const char* checksum); +void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash); +void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum); + +#if PLATFORM(MAC) + +// Can be used as a signal handler +void restoreMainDisplayColorProfile(int ignored); + +// May change your color space, requiring a call to restoreMainDisplayColorProfile +void setupMainDisplayColorProfile(); + +#endif + +#endif // PixelDumpSupport_h diff --git a/Tools/DumpRenderTree/StorageTrackerDelegate.h b/Tools/DumpRenderTree/StorageTrackerDelegate.h new file mode 100644 index 000000000..e025a4476 --- /dev/null +++ b/Tools/DumpRenderTree/StorageTrackerDelegate.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +class LayoutTestController; + +@interface StorageTrackerDelegate : NSObject { + unsigned numberOfNotificationsToLog; + LayoutTestController* controllerToNotifyDone; +} + +- (void)logNotifications:(unsigned)number controller:(LayoutTestController*)controller; +- (void)originModified:(NSNotification *)notification; +- (void)setControllerToNotifyDone:(LayoutTestController*)controller; + +@end diff --git a/Tools/DumpRenderTree/StorageTrackerDelegate.mm b/Tools/DumpRenderTree/StorageTrackerDelegate.mm new file mode 100644 index 000000000..343880ba1 --- /dev/null +++ b/Tools/DumpRenderTree/StorageTrackerDelegate.mm @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#import "StorageTrackerDelegate.h" + +#import "LayoutTestController.h" +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebStorageManagerPrivate.h> + +@implementation StorageTrackerDelegate + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(originModified:) name:WebStorageDidModifyOriginNotification object:nil]; + + return self; +} + +- (void)logNotifications:(unsigned)number controller:(LayoutTestController*)controller +{ + controllerToNotifyDone = controller; + + numberOfNotificationsToLog = number; +} + +- (void)originModified:(NSNotification *)notification +{ + if (!numberOfNotificationsToLog) + return; + + numberOfNotificationsToLog--; + + if (numberOfNotificationsToLog == 0 && controllerToNotifyDone) { + NSArray *origins = [[WebStorageManager sharedWebStorageManager] origins]; + for (WebSecurityOrigin *origin in origins) + printf("Origin identifier: '%s'\n", [[origin databaseIdentifier] UTF8String]); + + controllerToNotifyDone->notifyDone(); + } +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:WebStorageDidModifyOriginNotification object:nil]; + + [super dealloc]; +} + +- (void)setControllerToNotifyDone:(LayoutTestController*)controller +{ + controllerToNotifyDone = controller; +} + + +@end diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp new file mode 100644 index 000000000..544218015 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp @@ -0,0 +1,1267 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2010 Collabora Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "PluginObject.h" + +#include "PluginTest.h" +#include "TestObject.h" +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// Helper function which takes in the plugin window object for logging to the console object. +static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message) +{ + NPVariant consoleVariant; + if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) { + fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message); + return; + } + + NPObject* consoleObject = NPVARIANT_TO_OBJECT(consoleVariant); + + NPVariant messageVariant; + STRINGZ_TO_NPVARIANT(message, messageVariant); + + NPVariant result; + if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) { + fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message); + browser->releaseobject(consoleObject); + return; + } + + browser->releasevariantvalue(&result); + browser->releaseobject(consoleObject); +} + +// Helper function which takes in the plugin window object for logging to the console object. This function supports variable +// arguments. +static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP instance, const char* format, ...) +{ + va_list args; + va_start(args, format); + char message[2048] = "PLUGIN: "; + vsprintf(message + strlen(message), format, args); + va_end(args); + + pluginLogWithWindowObject(windowObject, instance, message); +} + +void pluginLogWithArguments(NPP instance, const char* format, va_list args) +{ + char message[2048] = "PLUGIN: "; + vsprintf(message + strlen(message), format, args); + + NPObject* windowObject = 0; + NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject); + if (error != NPERR_NO_ERROR) { + fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message); + return; + } + + pluginLogWithWindowObject(windowObject, instance, message); + browser->releaseobject(windowObject); +} + +// Helper function to log to the console object. +void pluginLog(NPP instance, const char* format, ...) +{ + va_list args; + va_start(args, format); + pluginLogWithArguments(instance, format, args); + va_end(args); +} + +static void pluginInvalidate(NPObject*); +static bool pluginHasProperty(NPObject*, NPIdentifier name); +static bool pluginHasMethod(NPObject*, NPIdentifier name); +static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*); +static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*); +static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result); +static NPObject* pluginAllocate(NPP npp, NPClass*); +static void pluginDeallocate(NPObject*); + +NPNetscapeFuncs* browser; +NPPluginFuncs* pluginFunctions; + +static NPClass pluginClass = { + NP_CLASS_STRUCT_VERSION, + pluginAllocate, + pluginDeallocate, + pluginInvalidate, + pluginHasMethod, + pluginInvoke, + 0, // NPClass::invokeDefault, + pluginHasProperty, + pluginGetProperty, + pluginSetProperty, + 0, // NPClass::removeProperty + 0, // NPClass::enumerate + 0, // NPClass::construct +}; + +NPClass* getPluginClass(void) +{ + return &pluginClass; +} + +static bool identifiersInitialized = false; + +enum { + ID_PROPERTY_PROPERTY = 0, + ID_PROPERTY_EVENT_LOGGING, + ID_PROPERTY_HAS_STREAM, + ID_PROPERTY_TEST_OBJECT, + ID_PROPERTY_LOG_DESTROY, + ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM, + ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE, + ID_PROPERTY_THROW_EXCEPTION_PROPERTY, + ID_LAST_SET_WINDOW_ARGUMENTS, + ID_PROPERTY_WINDOWED_PLUGIN, + ID_PROPERTY_TEST_OBJECT_COUNT, + NUM_PROPERTY_IDENTIFIERS +}; + +static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; +static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { + "property", + "eventLoggingEnabled", + "hasStream", + "testObject", + "logDestroy", + "returnErrorFromNewStream", + "returnNegativeOneFromWrite", + "testThrowExceptionProperty", + "lastSetWindowArguments", + "windowedPlugin", + "testObjectCount", +}; + +enum { + ID_TEST_CALLBACK_METHOD = 0, + ID_TEST_CALLBACK_METHOD_RETURN, + ID_TEST_GETURL, + ID_TEST_DOM_ACCESS, + ID_TEST_GET_URL_NOTIFY, + ID_TEST_INVOKE_DEFAULT, + ID_DESTROY_STREAM, + ID_TEST_ENUMERATE, + ID_TEST_GETINTIDENTIFIER, + ID_TEST_GET_PROPERTY, + ID_TEST_HAS_PROPERTY, + ID_TEST_HAS_METHOD, + ID_TEST_EVALUATE, + ID_TEST_GET_PROPERTY_RETURN_VALUE, + ID_TEST_IDENTIFIER_TO_STRING, + ID_TEST_IDENTIFIER_TO_INT, + ID_TEST_PASS_TEST_OBJECT, + ID_TEST_POSTURL_FILE, + ID_TEST_CONSTRUCT, + ID_TEST_THROW_EXCEPTION_METHOD, + ID_TEST_FAIL_METHOD, + ID_TEST_CLONE_OBJECT, + ID_TEST_SCRIPT_OBJECT_INVOKE, + ID_TEST_CREATE_TEST_OBJECT, + ID_DESTROY_NULL_STREAM, + ID_TEST_RELOAD_PLUGINS_NO_PAGES, + ID_TEST_RELOAD_PLUGINS_AND_PAGES, + ID_TEST_GET_BROWSER_PROPERTY, + ID_TEST_SET_BROWSER_PROPERTY, + ID_REMEMBER, + ID_GET_REMEMBERED_OBJECT, + ID_GET_AND_FORGET_REMEMBERED_OBJECT, + ID_REF_COUNT, + ID_SET_STATUS, + ID_RESIZE_TO, + ID_NORMALIZE, + ID_INVALIDATE_RECT, + ID_OBJECTS_ARE_SAME, + NUM_METHOD_IDENTIFIERS +}; + +static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "testCallback", + "testCallbackReturn", + "getURL", + "testDOMAccess", + "getURLNotify", + "testInvokeDefault", + "destroyStream", + "testEnumerate", + "testGetIntIdentifier", + "testGetProperty", + "testHasProperty", + "testHasMethod", + "testEvaluate", + "testGetPropertyReturnValue", + "testIdentifierToString", + "testIdentifierToInt", + "testPassTestObject", + "testPostURLFile", + "testConstruct", + "testThrowException", + "testFail", + "testCloneObject", + "testScriptObjectInvoke", + "testCreateTestObject", + "destroyNullStream", + "reloadPluginsNoPages", + "reloadPluginsAndPages", + "testGetBrowserProperty", + "testSetBrowserProperty", + "remember", + "getRememberedObject", + "getAndForgetRememberedObject", + "refCount", + "setStatus", + "resizeTo", + "normalize", + "invalidateRect", + "objectsAreSame" +}; + +static NPUTF8* createCStringFromNPVariant(const NPVariant* variant) +{ + size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length; + NPUTF8* result = (NPUTF8*)malloc(length + 1); + memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length); + result[length] = '\0'; + return result; +} + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers); + browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers); +} + +static bool pluginHasProperty(NPObject *obj, NPIdentifier name) +{ + for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) + if (name == pluginPropertyIdentifiers[i]) + return true; + return false; +} + +static bool pluginHasMethod(NPObject *obj, NPIdentifier name) +{ + for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++) + if (name == pluginMethodIdentifiers[i]) + return true; + return false; +} + +static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(obj); + if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) { + static const char* originalString = "property"; + char* buf = static_cast<char*>(browser->memalloc(strlen(originalString) + 1)); + strcpy(buf, originalString); + STRINGZ_TO_NPVARIANT(buf, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { + BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) { + BOOLEAN_TO_NPVARIANT(plugin->stream, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + NPObject* testObject = plugin->testObject; + browser->retainobject(testObject); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { + BOOLEAN_TO_NPVARIANT(plugin->returnNegativeOneFromWrite, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { + browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS"); + return true; + } + if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) { + char* buf = static_cast<char*>(browser->memalloc(256)); + snprintf(buf, 256, "x: %d, y: %d, width: %u, height: %u, clipRect: (%u, %u, %u, %u)", (int)plugin->lastWindow.x, (int)plugin->lastWindow.y, (unsigned)plugin->lastWindow.width, (unsigned)plugin->lastWindow.height, + plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.top, plugin->lastWindow.clipRect.right - plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.bottom - plugin->lastWindow.clipRect.top); + + STRINGZ_TO_NPVARIANT(buf, *result); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT_COUNT]) { + INT32_TO_NPVARIANT(getTestObjectCount(), *result); + return true; + } + + return false; +} + +static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(obj); + if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { + plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { + plugin->returnNegativeOneFromWrite = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { + browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS"); + return true; + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_WINDOWED_PLUGIN]) { + browser->setvalue(plugin->npp, NPPVpluginWindowBool, (void *)NPVARIANT_TO_BOOLEAN(*variant)); + return true; + } + + return false; +} + +static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result) +{ + // Get plug-in's DOM element + NPObject* elementObject; + if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) { + // Get style + NPVariant styleVariant; + NPIdentifier styleIdentifier = browser->getstringidentifier("style"); + if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) { + // Set style.border + NPIdentifier borderIdentifier = browser->getstringidentifier("border"); + NPVariant borderVariant; + STRINGZ_TO_NPVARIANT("3px solid red", borderVariant); + browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant); + browser->releasevariantvalue(&styleVariant); + } + + browser->releaseobject(elementObject); + } + VOID_TO_NPVARIANT(*result); + return true; +} + +static NPIdentifier stringVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_STRING(variant)); + NPUTF8* utf8String = createCStringFromNPVariant(&variant); + NPIdentifier identifier = browser->getstringidentifier(utf8String); + free(utf8String); + return identifier; +} + +static NPIdentifier int32VariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_INT32(variant)); + int32_t integer = NPVARIANT_TO_INT32(variant); + return browser->getintidentifier(integer); +} + +static NPIdentifier doubleVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_DOUBLE(variant)); + double value = NPVARIANT_TO_DOUBLE(variant); + // Sadly there is no "getdoubleidentifier" + int32_t integer = static_cast<int32_t>(value); + return browser->getintidentifier(integer); +} + +static NPIdentifier variantToIdentifier(NPVariant variant) +{ + if (NPVARIANT_IS_STRING(variant)) + return stringVariantToIdentifier(variant); + if (NPVARIANT_IS_INT32(variant)) + return int32VariantToIdentifier(variant); + if (NPVARIANT_IS_DOUBLE(variant)) + return doubleVariantToIdentifier(variant); + return 0; +} + +static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1) + return true; + NPIdentifier identifier = variantToIdentifier(args[0]); + if (!identifier) + return true; + NPUTF8* utf8String = browser->utf8fromidentifier(identifier); + if (!utf8String) + return true; + STRINGZ_TO_NPVARIANT(utf8String, *result); + return true; +} + +static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1) + return false; + NPIdentifier identifier = variantToIdentifier(args[0]); + if (!identifier) + return false; + int32_t integer = browser->intfromidentifier(identifier); + INT32_TO_NPVARIANT(integer, *result); + return true; +} + +static bool testPassTestObject(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_STRING(args[0])) + return false; + + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant browserResult; + browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &browserResult); + browser->releasevariantvalue(&browserResult); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!argCount || !NPVARIANT_IS_STRING(args[0])) + return false; + + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant browserResult; + if (browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult)) + browser->releasevariantvalue(&browserResult); + + browser->releaseobject(windowScriptObject); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testCallbackReturn(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1 || !NPVARIANT_IS_STRING(args[0])) + return false; + + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant callbackArgs[1]; + OBJECT_TO_NPVARIANT(windowScriptObject, callbackArgs[0]); + + NPVariant browserResult; + browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, + callbackArgs, 1, &browserResult); + + if (NPVARIANT_IS_OBJECT(browserResult)) + OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(browserResult), *result); + else { + browser->releasevariantvalue(&browserResult); + VOID_TO_NPVARIANT(*result); + } + + return true; +} + +static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) { + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPUTF8* targetString = createCStringFromNPVariant(&args[1]); + NPError npErr = browser->geturl(obj->npp, urlString, targetString); + free(urlString); + free(targetString); + + INT32_TO_NPVARIANT(npErr, *result); + return true; + } + if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) { + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPError npErr = browser->geturl(obj->npp, urlString, 0); + free(urlString); + + INT32_TO_NPVARIANT(npErr, *result); + return true; + } + return false; +} + +static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 3 || !NPVARIANT_IS_STRING(args[0]) + || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1])) + || !NPVARIANT_IS_STRING(args[2])) + return false; + + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : 0); + NPUTF8* callbackString = createCStringFromNPVariant(&args[2]); + + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier); + + free(urlString); + free(targetString); + free(callbackString); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!NPVARIANT_IS_OBJECT(args[0])) + return false; + + NPObject* callback = NPVARIANT_TO_OBJECT(args[0]); + + NPVariant invokeArgs[1]; + NPVariant browserResult; + + STRINGZ_TO_NPVARIANT("test", invokeArgs[0]); + bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult); + + if (retval) + browser->releasevariantvalue(&browserResult); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK); + INT32_TO_NPVARIANT(npError, *result); + return true; +} + +static bool destroyNullStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + NPError npError = browser->destroystream(obj->npp, 0, NPRES_USER_BREAK); + INT32_TO_NPVARIANT(npError, *result); + return true; +} + +static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1])) + return false; + + uint32_t count; + NPIdentifier* identifiers; + if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) { + NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]); + NPIdentifier pushIdentifier = browser->getstringidentifier("push"); + + for (uint32_t i = 0; i < count; i++) { + NPUTF8* string = browser->utf8fromidentifier(identifiers[i]); + + if (!string) + continue; + + NPVariant args[1]; + STRINGZ_TO_NPVARIANT(string, args[0]); + NPVariant browserResult; + if (browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult)) + browser->releasevariantvalue(&browserResult); + browser->memfree(string); + } + + browser->memfree(identifiers); + } + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0])) + return false; + + NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0])); + INT32_TO_NPVARIANT((int32_t)(long long)identifier, *result); + return true; +} + +static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!argCount) + return false; + + NPObject* object; + browser->getvalue(obj->npp, NPNVWindowNPObject, &object); + + for (uint32_t i = 0; i < argCount; i++) { + assert(NPVARIANT_IS_STRING(args[i])); + NPUTF8* propertyString = createCStringFromNPVariant(&args[i]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + NPVariant variant; + bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant); + browser->releaseobject(object); + + if (!retval) + break; + + if (i + 1 < argCount) { + assert(NPVARIANT_IS_OBJECT(variant)); + object = NPVARIANT_TO_OBJECT(variant); + } else { + *result = variant; + return true; + } + } + + VOID_TO_NPVARIANT(*result); + return false; +} + +static bool testHasProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + bool retval = browser->hasproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool testHasMethod(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + bool retval = browser->hasmethod(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1 || !NPVARIANT_IS_STRING(args[0])) + return false; + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPString s = NPVARIANT_TO_STRING(args[0]); + + bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result); + browser->releaseobject(windowScriptObject); + return retval; +} + +static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + NPVariant variant; + bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant); + if (retval) + browser->releasevariantvalue(&variant); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static char* toCString(const NPString& string) +{ + char* result = static_cast<char*>(malloc(string.UTF8Length + 1)); + memcpy(result, string.UTF8Characters, string.UTF8Length); + result[string.UTF8Length] = '\0'; + + return result; +} + +static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3])) + return false; + + NPString urlString = NPVARIANT_TO_STRING(args[0]); + char* url = toCString(urlString); + + NPString targetString = NPVARIANT_TO_STRING(args[1]); + char* target = toCString(targetString); + + NPString pathString = NPVARIANT_TO_STRING(args[2]); + char* path = toCString(pathString); + + NPString contentsString = NPVARIANT_TO_STRING(args[3]); + + FILE* tempFile = fopen(path, "w"); + if (!tempFile) + return false; + + if (!fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile)) + return false; + + fclose(tempFile); + + NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE); + + free(path); + free(target); + free(url); + + BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result); + return true; +} + +static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!argCount || !NPVARIANT_IS_OBJECT(args[0])) + return false; + + return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result); +} + +// Invoke a script callback to get a script NPObject. Then call a method on the +// script NPObject passing it a freshly created NPObject. +static bool testScriptObjectInvoke(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + // Arg1 is the name of the callback + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + // Invoke a callback that returns a script object + NPVariant object_result; + browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &object_result); + + // Script object returned + NPObject* script_object = object_result.value.objectValue; + + // Arg2 is the name of the method to be called on the script object + NPUTF8* object_mehod_string = createCStringFromNPVariant(&args[1]); + NPIdentifier object_method = browser->getstringidentifier(object_mehod_string); + free(object_mehod_string); + + // Create a fresh NPObject to be passed as an argument + NPObject* object_arg = browser->createobject(obj->npp, &pluginClass); + NPVariant invoke_args[1]; + OBJECT_TO_NPVARIANT(object_arg, invoke_args[0]); + + // Invoke the script method + NPVariant object_method_result; + browser->invoke(obj->npp, script_object, object_method, invoke_args, 1, &object_method_result); + + browser->releasevariantvalue(&object_result); + VOID_TO_NPVARIANT(*result); + if (NPVARIANT_IS_OBJECT(object_method_result)) { + // Now return the callbacks return value back to our caller. + // BUG 897451: This should be the same as the + // windowScriptObject, but its not (in Chrome) - or at least, it + // has a different refcount. This means Chrome will delete the + // object before returning it and the calling JS gets a garbage + // value. Firefox handles it fine. + OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(object_method_result), *result); + } else { + browser->releasevariantvalue(&object_method_result); + VOID_TO_NPVARIANT(*result); + } + + browser->releaseobject(object_arg); + + return true; +} + +// Helper function to notify the layout test controller that the test completed. +void notifyTestCompletion(NPP npp, NPObject* object) +{ + NPVariant result; + NPString script; + script.UTF8Characters = "javascript:window.layoutTestController.notifyDone();"; + script.UTF8Length = strlen("javascript:window.layoutTestController.notifyDone();"); + browser->evaluate(npp, object, &script, &result); + browser->releasevariantvalue(&result); +} + +bool testDocumentOpen(NPP npp) +{ + NPIdentifier documentId = browser->getstringidentifier("document"); + NPIdentifier openId = browser->getstringidentifier("open"); + + NPObject* windowObject = 0; + browser->getvalue(npp, NPNVWindowNPObject, &windowObject); + if (!windowObject) + return false; + + NPVariant docVariant; + browser->getproperty(npp, windowObject, documentId, &docVariant); + if (docVariant.type != NPVariantType_Object) { + browser->releaseobject(windowObject); + return false; + } + + NPObject* documentObject = NPVARIANT_TO_OBJECT(docVariant); + + NPVariant openArgs[2]; + STRINGZ_TO_NPVARIANT("text/html", openArgs[0]); + STRINGZ_TO_NPVARIANT("_blank", openArgs[1]); + + NPVariant result; + if (!browser->invoke(npp, documentObject, openId, openArgs, 2, &result)) { + browser->releaseobject(windowObject); + browser->releaseobject(documentObject); + return false; + } + + browser->releaseobject(documentObject); + + if (result.type != NPVariantType_Object) { + browser->releaseobject(windowObject); + browser->releasevariantvalue(&result); + return false; + } + + pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS"); + notifyTestCompletion(npp, result.value.objectValue); + browser->releaseobject(result.value.objectValue); + browser->releaseobject(windowObject); + return true; +} + +bool testWindowOpen(NPP npp) +{ + NPIdentifier openId = browser->getstringidentifier("open"); + + NPObject* windowObject = 0; + browser->getvalue(npp, NPNVWindowNPObject, &windowObject); + if (!windowObject) + return false; + + NPVariant openArgs[2]; + STRINGZ_TO_NPVARIANT("about:blank", openArgs[0]); + STRINGZ_TO_NPVARIANT("_blank", openArgs[1]); + + NPVariant result; + if (!browser->invoke(npp, windowObject, openId, openArgs, 2, &result)) { + browser->releaseobject(windowObject); + return false; + } + + if (result.type != NPVariantType_Object) { + browser->releaseobject(windowObject); + browser->releasevariantvalue(&result); + return false; + } + + pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS"); + notifyTestCompletion(npp, result.value.objectValue); + browser->releaseobject(result.value.objectValue); + browser->releaseobject(windowObject); + return true; +} + +static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + char* message = 0; + if (argCount && NPVARIANT_IS_STRING(args[0])) { + NPString statusString = NPVARIANT_TO_STRING(args[0]); + message = toCString(statusString); + } + + browser->status(obj->npp, message); + + free(message); + return true; +} + +static bool testResizeTo(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + VOID_TO_NPVARIANT(*result); + + NPObject* windowObject; + if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject)) + return false; + + NPVariant callResult; + if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("resizePlugin"), args, argCount, &callResult)) + browser->releasevariantvalue(&callResult); + + // Force layout. + if (browser->getproperty(obj->npp, windowObject, browser->getstringidentifier("pageYOffset"), &callResult)) + browser->releasevariantvalue(&callResult); + + return true; +} + +static bool normalizeOverride(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + VOID_TO_NPVARIANT(*result); + + NPObject* windowObject; + if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject)) + return false; + + NPVariant callResult; + if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("pluginCallback"), args, argCount, &callResult)) + browser->releasevariantvalue(&callResult); + + return true; +} + +static bool invalidateRect(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 4) + return false; + + NPRect rect; + rect.left = static_cast<int>(NPVARIANT_TO_DOUBLE(args[0])); + rect.top = static_cast<int>(NPVARIANT_TO_DOUBLE(args[1])); + rect.right = static_cast<int>(NPVARIANT_TO_DOUBLE(args[2])); + rect.bottom = static_cast<int>(NPVARIANT_TO_DOUBLE(args[3])); + + browser->invalidaterect(obj->npp, &rect); + return true; +} + +static bool objectsAreSame(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1])) + return false; + + BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_OBJECT(args[0]) == NPVARIANT_TO_OBJECT(args[1]), *result); + return true; +} + +static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD]) + return testCallback(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD_RETURN]) + return testCallbackReturn(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_GETURL]) + return getURL(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS]) + return testDOMAccess(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY]) + return getURLNotify(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT]) + return testInvokeDefault(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE]) + return testEnumerate(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM]) + return destroyStream(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER]) + return testGetIntIdentifier(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE]) + return testEvaluate(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY]) + return testGetProperty(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE]) + return testGetPropertyReturnValue(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY]) + return testHasProperty(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD]) + return testHasMethod(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING]) + return testIdentifierToString(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT]) + return testIdentifierToInt(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_PASS_TEST_OBJECT]) + return testPassTestObject(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE]) + return testPostURLFile(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT]) + return testConstruct(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_SCRIPT_OBJECT_INVOKE]) + return testScriptObjectInvoke(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) { + browser->setexception(header, "plugin object testThrowException SUCCESS"); + return true; + } + if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) { + NPObject* windowScriptObject; + browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject); + browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result); + return false; + } + if (name == pluginMethodIdentifiers[ID_TEST_CLONE_OBJECT]) { + NPObject* new_object = browser->createobject(plugin->npp, &pluginClass); + assert(new_object->referenceCount == 1); + OBJECT_TO_NPVARIANT(new_object, *result); + return true; + } + if (name == pluginMethodIdentifiers[ID_TEST_CREATE_TEST_OBJECT]) { + NPObject* testObject = browser->createobject(plugin->npp, getTestClass()); + assert(testObject->referenceCount == 1); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } + if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM]) + return destroyNullStream(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) { + browser->reloadplugins(false); + return true; + } + if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) { + browser->reloadplugins(true); + return true; + } + if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) { + browser->getproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), result); + return true; + } + if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) { + browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]); + return true; + } + if (name == pluginMethodIdentifiers[ID_REMEMBER]) { + if (plugin->rememberedObject) + browser->releaseobject(plugin->rememberedObject); + plugin->rememberedObject = NPVARIANT_TO_OBJECT(args[0]); + browser->retainobject(plugin->rememberedObject); + VOID_TO_NPVARIANT(*result); + return true; + } + if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) { + assert(plugin->rememberedObject); + browser->retainobject(plugin->rememberedObject); + OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result); + return true; + } + if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) { + assert(plugin->rememberedObject); + OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result); + plugin->rememberedObject = 0; + return true; + } + if (name == pluginMethodIdentifiers[ID_REF_COUNT]) { + uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount; + INT32_TO_NPVARIANT(refCount, *result); + return true; + } + if (name == pluginMethodIdentifiers[ID_SET_STATUS]) + return testSetStatus(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_RESIZE_TO]) + return testResizeTo(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_NORMALIZE]) + return normalizeOverride(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_INVALIDATE_RECT]) + return invalidateRect(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_OBJECTS_ARE_SAME]) + return objectsAreSame(plugin, args, argCount, result); + + return false; +} + +static void pluginInvalidate(NPObject* header) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + plugin->testObject = 0; + plugin->rememberedObject = 0; +} + +static NPObject *pluginAllocate(NPP npp, NPClass *theClass) +{ + PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject)); + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + newInstance->pluginTest = 0; + newInstance->npp = npp; + newInstance->testObject = browser->createobject(npp, getTestClass()); + newInstance->rememberedObject = 0; + newInstance->eventLogging = FALSE; + newInstance->onStreamLoad = 0; + newInstance->onStreamDestroy = 0; + newInstance->onDestroy = 0; + newInstance->onURLNotify = 0; + newInstance->onSetWindow = 0; + newInstance->onPaintEvent = 0; + newInstance->logDestroy = FALSE; + newInstance->logSetWindow = FALSE; + newInstance->returnErrorFromNewStream = FALSE; + newInstance->returnNegativeOneFromWrite = FALSE; + newInstance->stream = 0; + + newInstance->firstUrl = 0; + newInstance->firstHeaders = 0; + newInstance->lastUrl = 0; + newInstance->lastHeaders = 0; + + newInstance->testGetURLOnDestroy = FALSE; + newInstance->testWindowOpen = FALSE; + newInstance->testKeyboardFocusForPlugins = FALSE; + + newInstance->mouseDownForEvaluateScript = FALSE; + newInstance->evaluateScriptOnMouseDownOrKeyDown = 0; + + return (NPObject*)newInstance; +} + +static void pluginDeallocate(NPObject* header) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + delete plugin->pluginTest; + if (plugin->testObject) + browser->releaseobject(plugin->testObject); + if (plugin->rememberedObject) + browser->releaseobject(plugin->rememberedObject); + + free(plugin->firstUrl); + free(plugin->firstHeaders); + free(plugin->lastUrl); + free(plugin->lastHeaders); + free(plugin); +} + +void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData) +{ + assert(object); + + NPVariant args[2]; + + NPObject* windowScriptObject; + browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject); + + NPIdentifier callbackIdentifier = notifyData; + + INT32_TO_NPVARIANT(reason, args[0]); + + char* strHdr = 0; + if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) { + // Format expected by JavaScript validator: four fields separated by \n\n: + // First URL; first header block; last URL; last header block. + // Note that header blocks already end with \n due to how NPStream::headers works. + int len = strlen(object->firstUrl) + 2 + + strlen(object->firstHeaders) + 1 + + strlen(object->lastUrl) + 2 + + strlen(object->lastHeaders) + 1; + strHdr = (char*)malloc(len + 1); + snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n", + object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders); + STRINGN_TO_NPVARIANT(strHdr, len, args[1]); + } else + NULL_TO_NPVARIANT(args[1]); + + NPVariant browserResult; + if (browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult)) + browser->releasevariantvalue(&browserResult); + + free(strHdr); +} + +void notifyStream(PluginObject* object, const char *url, const char *headers) +{ + if (!object->firstUrl) { + if (url) + object->firstUrl = strdup(url); + if (headers) + object->firstHeaders = strdup(headers); + } else { + free(object->lastUrl); + free(object->lastHeaders); + object->lastUrl = (url ? strdup(url) : 0); + object->lastHeaders = (headers ? strdup(headers) : 0); + } +} + +void testNPRuntime(NPP npp) +{ + NPObject* windowScriptObject; + browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject); + + // Invoke + NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke"); + NPVariant args[7]; + + VOID_TO_NPVARIANT(args[0]); + NULL_TO_NPVARIANT(args[1]); + BOOLEAN_TO_NPVARIANT(true, args[2]); + INT32_TO_NPVARIANT(242, args[3]); + DOUBLE_TO_NPVARIANT(242.242, args[4]); + STRINGZ_TO_NPVARIANT("Hello, World", args[5]); + OBJECT_TO_NPVARIANT(windowScriptObject, args[6]); + + NPVariant result; + if (browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result)) + browser->releasevariantvalue(&result); + + browser->releaseobject(windowScriptObject); +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h new file mode 100644 index 000000000..566537c2e --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 PluginObject_h +#define PluginObject_h + +#include <WebKit/npfunctions.h> +#include <stdarg.h> + +#if defined(XP_MACOSX) +#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 +#define BUILDING_ON_LEOPARD 1 +#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 +#define BUILDING_ON_SNOW_LEOPARD 1 +#endif +#endif // XP_MACOSX + +class PluginTest; + +extern NPNetscapeFuncs *browser; +extern NPPluginFuncs* pluginFunctions; + +typedef struct { + NPObject header; + + PluginTest* pluginTest; + + NPP npp; + NPBool eventLogging; + NPBool logSetWindow; + NPBool logDestroy; + NPBool returnNegativeOneFromWrite; + NPBool returnErrorFromNewStream; + NPObject* testObject; + NPObject* rememberedObject; + NPStream* stream; + NPBool testGetURLOnDestroy; + NPBool testWindowOpen; + NPBool testKeyboardFocusForPlugins; + NPBool mouseDownForEvaluateScript; + char* onStreamLoad; + char* onStreamDestroy; + char* onDestroy; + char* onURLNotify; + char* onSetWindow; + char* onPaintEvent; + char* firstUrl; + char* firstHeaders; + char* lastUrl; + char* lastHeaders; + char* evaluateScriptOnMouseDownOrKeyDown; +#ifdef XP_MACOSX + NPEventModel eventModel; +#endif +#ifdef XP_MACOSX + void* coreAnimationLayer; +#endif + NPWindow lastWindow; +} PluginObject; + +extern NPClass *getPluginClass(void); +extern void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData); +extern void notifyStream(PluginObject* object, const char *url, const char *headers); +extern void testNPRuntime(NPP npp); +extern void pluginLog(NPP instance, const char* format, ...); +extern void pluginLogWithArguments(NPP instance, const char* format, va_list args); +extern bool testDocumentOpen(NPP npp); +extern bool testWindowOpen(NPP npp); + +#ifdef XP_MACOSX +extern void* createCoreAnimationLayer(); +#endif + +#endif // PluginObject_h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm new file mode 100644 index 000000000..e7850e7a9 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. 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 "PluginObject.h" + + +#include <QuartzCore/QuartzCore.h> + +@interface TestPluginLayer : CALayer +@end + +@implementation TestPluginLayer + +- (void)drawInContext:(CGContextRef)context +{ + CGRect bounds = [self bounds]; + const char* text = "Test Plug-in"; + CGContextSelectFont(context, "Helvetica", 24, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, bounds.origin.x + 3.0f, bounds.origin.y + bounds.size.height - 30.0f, text, strlen(text)); +} + +@end + +void* createCoreAnimationLayer() +{ + CALayer *caLayer = [[TestPluginLayer alloc] init]; + + NSNull *nullValue = [NSNull null]; + NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys: + nullValue, @"anchorPoint", + nullValue, @"bounds", + nullValue, @"contents", + nullValue, @"contentsRect", + nullValue, @"opacity", + nullValue, @"position", + nullValue, @"shadowColor", + nullValue, @"sublayerTransform", + nullValue, @"sublayers", + nullValue, @"transform", + nullValue, @"zPosition", + nil]; + // Turn off default animations. + [caLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]]; + [caLayer setNeedsDisplayOnBoundsChange:YES]; + + [caLayer setBounds:CGRectMake(0, 0, 200, 100)]; + [caLayer setAnchorPoint:CGPointZero]; + + CGColorRef color = CGColorCreateGenericRGB(0.5, 0.5, 1, 1); + [caLayer setBackgroundColor:color]; + CGColorRelease(color); + + [caLayer setLayoutManager:[CAConstraintLayoutManager layoutManager]]; + + CALayer *sublayer = [CALayer layer]; + // Turn off default animations. + [sublayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]]; + + color = CGColorCreateGenericRGB(0, 0, 0, 0.75); + [sublayer setBackgroundColor:color]; + CGColorRelease(color); + [sublayer setBounds:CGRectMake(0, 0, 180, 20)]; + + [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY + relativeTo:@"superlayer" + attribute:kCAConstraintMinY]]; + [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX + relativeTo:@"superlayer" + attribute:kCAConstraintMinX]]; + [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX + relativeTo:@"superlayer" + attribute:kCAConstraintMaxX]]; + + [caLayer addSublayer:sublayer]; + return caLayer; +} + + diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp new file mode 100644 index 000000000..989e16d8f --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" +#include <assert.h> +#include <string.h> + +#if defined(ANDROID) +#include <unistd.h> +#endif + +using namespace std; +extern NPNetscapeFuncs *browser; + +static void (*shutdownFunction)(); + +PluginTest* PluginTest::create(NPP npp, const string& identifier) +{ + if (identifier.empty()) + return new PluginTest(npp, identifier); + + CreateTestFunction createTestFunction = createTestFunctions()[identifier]; + if (createTestFunction) + return createTestFunction(npp, identifier); + + return 0; +} + +PluginTest::PluginTest(NPP npp, const string& identifier) + : m_npp(npp) + , m_identifier(identifier) +{ + // Reset the shutdown function. + shutdownFunction = 0; +} + +PluginTest::~PluginTest() +{ +} + +void PluginTest::NP_Shutdown() +{ + if (shutdownFunction) + shutdownFunction(); +} + +void PluginTest::registerNPShutdownFunction(void (*func)()) +{ + assert(!shutdownFunction); + shutdownFunction = func; +} + +void PluginTest::indicateTestFailure() +{ + // This should really be an assert, but there's no way for the test framework + // to know that the plug-in process crashed, so we'll just sleep for a while + // to ensure that the test times out. +#if defined(XP_WIN) + ::Sleep(100000); +#else + sleep(1000); +#endif +} + +NPError PluginTest::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) +{ + return NPERR_NO_ERROR; +} + +NPError PluginTest::NPP_Destroy(NPSavedData**) +{ + return NPERR_NO_ERROR; +} + +NPError PluginTest::NPP_SetWindow(NPWindow*) +{ + return NPERR_NO_ERROR; +} + +NPError PluginTest::NPP_NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) +{ + return NPERR_NO_ERROR; +} + +NPError PluginTest::NPP_DestroyStream(NPStream *stream, NPReason reason) +{ + return NPERR_NO_ERROR; +} + +int32_t PluginTest::NPP_WriteReady(NPStream*) +{ + return 4096; +} + +int32_t PluginTest::NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer) +{ + return len; +} + +int16_t PluginTest::NPP_HandleEvent(void*) +{ + return 0; +} + +bool PluginTest::NPP_URLNotify(const char* url, NPReason, void* notifyData) +{ + // FIXME: Port the code from NPP_URLNotify in main.cpp over to always using + // PluginTest, so we don't have to use a return value to indicate whether the "default" NPP_URLNotify implementation should be invoked. + return false; +} + +NPError PluginTest::NPP_GetValue(NPPVariable variable, void *value) +{ + // We don't know anything about plug-in values so just return NPERR_GENERIC_ERROR. + return NPERR_GENERIC_ERROR; +} + +NPError PluginTest::NPP_SetValue(NPNVariable, void *value) +{ + return NPERR_GENERIC_ERROR; +} + +// NPN functions. + +NPError PluginTest::NPN_GetURL(const char* url, const char* target) +{ + return browser->geturl(m_npp, url, target); +} + +NPError PluginTest::NPN_GetURLNotify(const char *url, const char *target, void *notifyData) +{ + return browser->geturlnotify(m_npp, url, target, notifyData); +} + +NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value) +{ + return browser->getvalue(m_npp, variable, value); +} + +void PluginTest::NPN_InvalidateRect(NPRect* invalidRect) +{ + browser->invalidaterect(m_npp, invalidRect); +} + +// NPRuntime NPN functions. + +NPIdentifier PluginTest::NPN_GetStringIdentifier(const NPUTF8 *name) +{ + return browser->getstringidentifier(name); +} + +NPIdentifier PluginTest::NPN_GetIntIdentifier(int32_t intid) +{ + return browser->getintidentifier(intid); +} + +bool PluginTest::NPN_IdentifierIsString(NPIdentifier npIdentifier) +{ + return browser->identifierisstring(npIdentifier); +} + +NPUTF8* PluginTest::NPN_UTF8FromIdentifier(NPIdentifier npIdentifier) +{ + return browser->utf8fromidentifier(npIdentifier); +} + +int32_t PluginTest::NPN_IntFromIdentifier(NPIdentifier npIdentifier) +{ + return browser->intfromidentifier(npIdentifier); +} + +NPObject* PluginTest::NPN_CreateObject(NPClass* npClass) +{ + return browser->createobject(m_npp, npClass); +} + +NPObject* PluginTest::NPN_RetainObject(NPObject* npObject) +{ + return browser->retainobject(npObject); +} + +void PluginTest::NPN_ReleaseObject(NPObject* npObject) +{ + browser->releaseobject(npObject); +} + +bool PluginTest::NPN_RemoveProperty(NPObject* npObject, NPIdentifier propertyName) +{ + return browser->removeproperty(m_npp, npObject, propertyName); +} + +#ifdef XP_MACOSX +bool PluginTest::NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace) +{ + return browser->convertpoint(m_npp, sourceX, sourceY, sourceSpace, destX, destY, destSpace); +} +#endif + +bool PluginTest::executeScript(const NPString* script, NPVariant* result) +{ + NPObject* windowScriptObject; + browser->getvalue(m_npp, NPNVWindowNPObject, &windowScriptObject); + + return browser->evaluate(m_npp, windowScriptObject, const_cast<NPString*>(script), result); +} + +void PluginTest::executeScript(const char* script) +{ + NPString npScript; + npScript.UTF8Characters = script; + npScript.UTF8Length = strlen(script); + + NPVariant browserResult; + executeScript(&npScript, &browserResult); + browser->releasevariantvalue(&browserResult); +} + +void PluginTest::log(const char* format, ...) +{ + va_list args; + va_start(args, format); + pluginLogWithArguments(m_npp, format, args); + va_end(args); +} + +void PluginTest::waitUntilDone() +{ + executeScript("layoutTestController.waitUntilDone()"); +} + +void PluginTest::notifyDone() +{ + executeScript("layoutTestController.notifyDone()"); +} + +void PluginTest::registerCreateTestFunction(const string& identifier, CreateTestFunction createTestFunction) +{ + assert(!createTestFunctions().count(identifier)); + + createTestFunctions()[identifier] = createTestFunction; +} + +std::map<std::string, PluginTest::CreateTestFunction>& PluginTest::createTestFunctions() +{ + static std::map<std::string, CreateTestFunction> testFunctions; + + return testFunctions; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h new file mode 100644 index 000000000..e83e82cfe --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 PluginTest_h +#define PluginTest_h + +#include <WebKit/npfunctions.h> +#include <assert.h> +#include <map> +#include <string> + +// Helper classes for implementing has_member +typedef char (&no_tag)[1]; +typedef char (&yes_tag)[2]; + +#define DEFINE_HAS_MEMBER_CHECK(member, returnType, argumentTypes) \ +template<typename T, returnType (T::*member) argumentTypes> struct pmf_##member##_helper {}; \ +template<typename T> no_tag has_member_##member##_helper(...); \ +template<typename T> yes_tag has_member_##member##_helper(pmf_##member##_helper<T, &T::member >*); \ +template<typename T> struct has_member_##member { \ +static const bool value = sizeof(has_member_##member##_helper<T>(0)) == sizeof(yes_tag); \ +}; + +DEFINE_HAS_MEMBER_CHECK(hasMethod, bool, (NPIdentifier methodName)); +DEFINE_HAS_MEMBER_CHECK(invoke, bool, (NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result)); +DEFINE_HAS_MEMBER_CHECK(invokeDefault, bool, (const NPVariant*, uint32_t, NPVariant* result)); +DEFINE_HAS_MEMBER_CHECK(hasProperty, bool, (NPIdentifier propertyName)); +DEFINE_HAS_MEMBER_CHECK(getProperty, bool, (NPIdentifier propertyName, NPVariant* result)); +DEFINE_HAS_MEMBER_CHECK(removeProperty, bool, (NPIdentifier propertyName)); + +class PluginTest { +public: + static PluginTest* create(NPP, const std::string& identifier); + virtual ~PluginTest(); + + static void NP_Shutdown(); + + // NPP functions. + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved); + virtual NPError NPP_Destroy(NPSavedData**); + virtual NPError NPP_SetWindow(NPWindow*); + virtual NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype); + virtual NPError NPP_DestroyStream(NPStream*, NPReason); + virtual int32_t NPP_WriteReady(NPStream*); + virtual int32_t NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer); + + virtual int16_t NPP_HandleEvent(void* event); + virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData); + virtual NPError NPP_GetValue(NPPVariable, void* value); + virtual NPError NPP_SetValue(NPNVariable, void *value); + + // NPN functions. + NPError NPN_GetURL(const char* url, const char* target); + NPError NPN_GetURLNotify(const char* url, const char* target, void* notifyData); + NPError NPN_GetValue(NPNVariable, void* value); + void NPN_InvalidateRect(NPRect* invalidRect); + + // NPRuntime NPN functions. + NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name); + NPIdentifier NPN_GetIntIdentifier(int32_t intid); + bool NPN_IdentifierIsString(NPIdentifier); + NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier); + int32_t NPN_IntFromIdentifier(NPIdentifier); + + NPObject* NPN_CreateObject(NPClass*); + NPObject* NPN_RetainObject(NPObject*); + void NPN_ReleaseObject(NPObject*); + bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName); + +#ifdef XP_MACOSX + bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); +#endif + + bool executeScript(const NPString*, NPVariant* result); + void executeScript(const char*); + void log(const char* format, ...); + + void registerNPShutdownFunction(void (*)()); + + static void indicateTestFailure(); + + template<typename TestClassTy> class Register { + public: + Register(const std::string& identifier) + { + registerCreateTestFunction(identifier, Register::create); + } + + private: + static PluginTest* create(NPP npp, const std::string& identifier) + { + return new TestClassTy(npp, identifier); + } + }; + +protected: + PluginTest(NPP npp, const std::string& identifier); + + // FIXME: A plug-in test shouldn't need to know about it's NPP. Make this private. + NPP m_npp; + + const std::string& identifier() const { return m_identifier; } + + void waitUntilDone(); + void notifyDone(); + + // NPObject helper template. + template<typename T> struct Object : NPObject { + public: + static NPObject* create(PluginTest* pluginTest) + { + Object* object = static_cast<Object*>(pluginTest->NPN_CreateObject(npClass())); + + object->m_pluginTest = pluginTest; + return object; + } + + // These should never be called. + bool hasMethod(NPIdentifier methodName) + { + assert(false); + return false; + } + + bool invoke(NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result) + { + assert(false); + return false; + } + + bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result) + { + assert(false); + return false; + } + + bool hasProperty(NPIdentifier propertyName) + { + assert(false); + return false; + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + assert(false); + return false; + } + + bool removeProperty(NPIdentifier propertyName) + { + assert(false); + return false; + } + + // Helper functions. + bool identifierIs(NPIdentifier identifier, const char* value) + { + return pluginTest()->NPN_GetStringIdentifier(value) == identifier; + } + + protected: + Object() + : m_pluginTest(0) + { + } + + virtual ~Object() + { + } + + PluginTest* pluginTest() const { return m_pluginTest; } + + private: + static NPObject* NP_Allocate(NPP npp, NPClass* aClass) + { + return new T; + } + + static void NP_Deallocate(NPObject* npObject) + { + delete static_cast<T*>(npObject); + } + + static bool NP_HasMethod(NPObject* npObject, NPIdentifier methodName) + { + return static_cast<T*>(npObject)->hasMethod(methodName); + } + + static bool NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) + { + return static_cast<T*>(npObject)->invoke(methodName, arguments, argumentCount, result); + } + + static bool NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) + { + return static_cast<T*>(npObject)->invokeDefault(arguments, argumentCount, result); + } + + static bool NP_HasProperty(NPObject* npObject, NPIdentifier propertyName) + { + return static_cast<T*>(npObject)->hasProperty(propertyName); + } + + static bool NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result) + { + return static_cast<T*>(npObject)->getProperty(propertyName, result); + } + + static bool NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName) + { + return static_cast<T*>(npObject)->removeProperty(propertyName); + } + + static NPClass* npClass() + { + static NPClass npClass = { + NP_CLASS_STRUCT_VERSION, + NP_Allocate, + NP_Deallocate, + 0, // NPClass::invalidate + has_member_hasMethod<T>::value ? NP_HasMethod : 0, + has_member_invoke<T>::value ? NP_Invoke : 0, + has_member_invokeDefault<T>::value ? NP_InvokeDefault : 0, + has_member_hasProperty<T>::value ? NP_HasProperty : 0, + has_member_getProperty<T>::value ? NP_GetProperty : 0, + 0, // NPClass::setProperty + has_member_removeProperty<T>::value ? NP_RemoveProperty : 0, + 0, // NPClass::enumerate + 0 // NPClass::construct + }; + + return &npClass; + }; + + PluginTest* m_pluginTest; + }; + +private: + typedef PluginTest* (*CreateTestFunction)(NPP, const std::string&); + + static void registerCreateTestFunction(const std::string&, CreateTestFunction); + static std::map<std::string, CreateTestFunction>& createTestFunctions(); + + std::string m_identifier; +}; + +#endif // PluginTest_h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp new file mode 100644 index 000000000..9e65f1118 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "TestObject.h" +#include "PluginObject.h" + +#include <string.h> +#include <stdlib.h> + +static bool testEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count); +static bool testHasMethod(NPObject*, NPIdentifier name); +static bool testInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool testHasProperty(NPObject*, NPIdentifier name); +static bool testGetProperty(NPObject*, NPIdentifier name, NPVariant*); +static NPObject *testAllocate(NPP npp, NPClass *theClass); +static void testDeallocate(NPObject *obj); +static bool testConstruct(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result); + +static NPClass testClass = { + NP_CLASS_STRUCT_VERSION, + testAllocate, + testDeallocate, + 0, + testHasMethod, + testInvoke, + 0, + testHasProperty, + testGetProperty, + 0, + 0, + testEnumerate, + testConstruct +}; + +NPClass *getTestClass(void) +{ + return &testClass; +} + +static int testObjectCount = 0; + +int getTestObjectCount() +{ + return testObjectCount; +} + +typedef struct { + NPObject header; + NPObject* testObject; +} TestObject; + +static bool identifiersInitialized = false; + +#define NUM_ENUMERATABLE_TEST_IDENTIFIERS 2 + +enum { + ID_PROPERTY_FOO = 0, + ID_PROPERTY_BAR, + ID_PROPERTY_OBJECT_POINTER, + ID_PROPERTY_TEST_OBJECT, + ID_PROPERTY_REF_COUNT, + NUM_TEST_IDENTIFIERS, +}; + +static NPIdentifier testIdentifiers[NUM_TEST_IDENTIFIERS]; +static const NPUTF8 *testIdentifierNames[NUM_TEST_IDENTIFIERS] = { + "foo", + "bar", + "objectPointer", + "testObject", + "refCount", +}; + +#define ID_THROW_EXCEPTION_METHOD 0 +#define NUM_METHOD_IDENTIFIERS 1 + +static NPIdentifier testMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *testMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "throwException", +}; + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(testIdentifierNames, NUM_TEST_IDENTIFIERS, testIdentifiers); + browser->getstringidentifiers(testMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, testMethodIdentifiers); +} + +static NPObject* testAllocate(NPP /*npp*/, NPClass* /*theClass*/) +{ + TestObject* newInstance = static_cast<TestObject*>(malloc(sizeof(TestObject))); + newInstance->testObject = 0; + ++testObjectCount; + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + return reinterpret_cast<NPObject*>(newInstance); +} + +static void testDeallocate(NPObject *obj) +{ + TestObject* testObject = reinterpret_cast<TestObject*>(obj); + if (testObject->testObject) + browser->releaseobject(testObject->testObject); + + --testObjectCount; + free(obj); +} + +static bool testHasMethod(NPObject*, NPIdentifier name) +{ + for (unsigned i = 0; i < NUM_METHOD_IDENTIFIERS; i++) { + if (testMethodIdentifiers[i] == name) + return true; + } + return false; +} + +static bool testInvoke(NPObject* header, NPIdentifier name, const NPVariant* /*args*/, uint32_t /*argCount*/, NPVariant* /*result*/) +{ + if (name == testMethodIdentifiers[ID_THROW_EXCEPTION_METHOD]) { + browser->setexception(header, "test object throwException SUCCESS"); + return true; + } + return false; +} + +static bool testHasProperty(NPObject*, NPIdentifier name) +{ + for (unsigned i = 0; i < NUM_TEST_IDENTIFIERS; i++) { + if (testIdentifiers[i] == name) + return true; + } + + return false; +} + +static bool testGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result) +{ + if (name == testIdentifiers[ID_PROPERTY_FOO]) { + char* mem = static_cast<char*>(browser->memalloc(4)); + strcpy(mem, "foo"); + STRINGZ_TO_NPVARIANT(mem, *result); + return true; + } + if (name == testIdentifiers[ID_PROPERTY_OBJECT_POINTER]) { + int32_t objectPointer = static_cast<int32_t>(reinterpret_cast<long long>(npobj)); + + INT32_TO_NPVARIANT(objectPointer, *result); + return true; + } + if (name == testIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + TestObject* testObject = reinterpret_cast<TestObject*>(npobj); + if (!testObject->testObject) + testObject->testObject = browser->createobject(0, &testClass); + browser->retainobject(testObject->testObject); + OBJECT_TO_NPVARIANT(testObject->testObject, *result); + return true; + } + if (name == testIdentifiers[ID_PROPERTY_REF_COUNT]) { + INT32_TO_NPVARIANT(npobj->referenceCount, *result); + return true; + } + + return false; +} + +static bool testEnumerate(NPObject* /*npobj*/, NPIdentifier **value, uint32_t *count) +{ + *count = NUM_ENUMERATABLE_TEST_IDENTIFIERS; + + *value = (NPIdentifier*)browser->memalloc(NUM_ENUMERATABLE_TEST_IDENTIFIERS * sizeof(NPIdentifier)); + memcpy(*value, testIdentifiers, sizeof(NPIdentifier) * NUM_ENUMERATABLE_TEST_IDENTIFIERS); + + return true; +} + +static bool testConstruct(NPObject* npobj, const NPVariant* /*args*/, uint32_t /*argCount*/, NPVariant* result) +{ + browser->retainobject(npobj); + + // Just return the same object. + OBJECT_TO_NPVARIANT(npobj, *result); + return true; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h new file mode 100644 index 000000000..73748e009 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 <WebKit/npapi.h> +#include <WebKit/npruntime.h> + +NPClass* getTestClass(void); +int getTestObjectCount(); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp new file mode 100644 index 000000000..69e706ea4 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +extern bool testDocumentOpen(NPP npp); + +// Call document.open from NPP_DestroyStream. + +class DocumentOpenInDestroyStream : public PluginTest { +public: + DocumentOpenInDestroyStream(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_shouldOpen(true) + { + } + +private: + virtual NPError NPP_DestroyStream(NPStream*, NPReason) + { + if (m_shouldOpen) { + testDocumentOpen(m_npp); + m_shouldOpen = false; + } + + return NPERR_NO_ERROR; + } + + bool m_shouldOpen; +}; + +static PluginTest::Register<DocumentOpenInDestroyStream> documentOpenInDestroyStream("document-open-in-destroy-stream"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp new file mode 100644 index 000000000..4b5d3e01d --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Executing JS after removing the plugin element from the document should not crash. + +class EvaluateJSAfterRemovingPluginElement : public PluginTest { +public: + EvaluateJSAfterRemovingPluginElement(NPP, const string& identifier); + +private: + virtual NPError NPP_DestroyStream(NPStream*, NPReason); + + bool m_didExecuteScript; +}; + +static PluginTest::Register<EvaluateJSAfterRemovingPluginElement> registrar("evaluate-js-after-removing-plugin-element"); + +EvaluateJSAfterRemovingPluginElement::EvaluateJSAfterRemovingPluginElement(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didExecuteScript(false) +{ + waitUntilDone(); +} + +NPError EvaluateJSAfterRemovingPluginElement::NPP_DestroyStream(NPStream*, NPReason) +{ + if (m_didExecuteScript) + return NPERR_NO_ERROR; + m_didExecuteScript = true; + + executeScript("var plugin = document.getElementsByTagName('embed')[0]; plugin.parentElement.removeChild(plugin);"); + executeScript("document.body.appendChild(document.createTextNode('Executing script after removing the plugin element from the document succeeded.'));"); + notifyDone(); + + return NPERR_NO_ERROR; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp new file mode 100644 index 000000000..738e192eb --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" +#include <string.h> + +extern NPNetscapeFuncs *browser; + +class FormValue : public PluginTest { +public: + FormValue(NPP npp, const std::string& identifier) + : PluginTest(npp, identifier) + { + } + virtual NPError NPP_GetValue(NPPVariable, void*); +}; + +NPError FormValue::NPP_GetValue(NPPVariable variable, void *value) +{ + if (variable == NPPVformValue) { + static const char formValueText[] = "Plugin form value"; + *((void**)value) = browser->memalloc(sizeof(formValueText)); + if (!*((void**)value)) + return NPERR_OUT_OF_MEMORY_ERROR; + strncpy(*((char**)value), formValueText, sizeof(formValueText)); + return NPERR_NO_ERROR; + } + return NPERR_GENERIC_ERROR; +} + +static PluginTest::Register<FormValue> formValue("form-value"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp new file mode 100644 index 000000000..f6f39ab04 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include <string.h> + +using namespace std; + +// From NPP_New, call NPN_GetURLNotify with a URL that fails to load (NPP_NewStream won't be called). +// The plug-in should still get a NPP_URLNotify indicating that the load failed. +static const char *urlThatFailsToLoad = "foo://bar/"; + +class GetURLNotifyWithURLThatFailsToLoad : public PluginTest { +public: + GetURLNotifyWithURLThatFailsToLoad(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + NPN_GetURLNotify(urlThatFailsToLoad, 0, reinterpret_cast<void*>(0x12345678)); + return NPERR_NO_ERROR; + } + + bool NPP_URLNotify(const char* url, NPReason reason, void* notifyData) + { + bool didFail = false; + + if (strcmp(url, urlThatFailsToLoad)) + didFail = true; + + if (reason != NPRES_NETWORK_ERR) + didFail = true; + + if (notifyData != reinterpret_cast<void*>(0x12345678)) + didFail = true; + + if (!didFail) + executeScript("testSucceeded()"); + else + executeScript("notifyDone()"); + return true; + } +}; + +static PluginTest::Register<GetURLNotifyWithURLThatFailsToLoad> getURLWithJavaScriptURLDestroyingPlugin("get-url-notify-with-url-that-fails-to-load"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp new file mode 100644 index 000000000..b3a72b0d5 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include <string.h> +#include <vector> + +using namespace std; + +const char *javaScriptURL = "javascript:'Hello, ' + 'World!'"; +const char *javaScriptResult = "Hello, World!"; + +// Test that evaluating a javascript: URL will send a stream with the result of the evaluation. +// Test that evaluating JavaScript using NPN_GetURL will a stream with result of the evaluation. +class GetURLWithJavaScriptURL : public PluginTest { +public: + GetURLWithJavaScriptURL(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didFail(false) + { + } + +private: + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + NPN_GetURL(javaScriptURL, 0); + return NPERR_NO_ERROR; + } + + NPError NPP_NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) + { + stream->pdata = this; + + if (strcmp(stream->url, javaScriptURL)) + m_didFail = true; + + if (stream->end != strlen(javaScriptResult)) + m_didFail = true; + + *stype = NP_NORMAL; + return NPERR_NO_ERROR; + } + + NPError NPP_DestroyStream(NPStream* stream, NPReason reason) + { + if (stream->pdata != this) + m_didFail = true; + + if (reason != NPRES_DONE) + m_didFail = true; + + if (m_data.size() != stream->end) + m_didFail = true; + + m_data.push_back('\0'); + + if (strcmp(&m_data[0], javaScriptResult)) + m_didFail = true; + + if (!m_didFail) + executeScript("testSucceeded()"); + else + executeScript("notifyDone()"); + + return NPERR_NO_ERROR; + } + + int32_t NPP_WriteReady(NPStream* stream) + { + if (stream->pdata != this) + m_didFail = true; + + return 2; + } + + int32_t NPP_Write(NPStream* stream, int32_t offset, int32_t len, void* buffer) + { + if (stream->pdata != this) + m_didFail = true; + + m_data.insert(m_data.end(), static_cast<char*>(buffer), static_cast<char*>(buffer) + len); + return len; + } + + vector<char> m_data; + bool m_didFail; +}; + +static PluginTest::Register<GetURLWithJavaScriptURL> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp new file mode 100644 index 000000000..9d63198b1 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +// From NPP_New, call NPN_GetURL to evaluate JavaScript that destroys the plug-in. + +class GetURLWithJavaScriptURLDestroyingPlugin : public PluginTest { +public: + GetURLWithJavaScriptURLDestroyingPlugin(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + NPN_GetURL("javascript:removePlugin()", 0); + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<GetURLWithJavaScriptURLDestroyingPlugin> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url-destroying-plugin"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp new file mode 100644 index 000000000..322d3fec4 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Trying to get the user agent with a null instance from NPP_New. + +class GetUserAgentWithNullNPPFromNPPNew : public PluginTest { +public: + GetUserAgentWithNullNPPFromNPPNew(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + if (!browser->uagent(0)) + pluginLog(m_npp, "FAILURE: Null user agent returned."); + else + pluginLog(m_npp, "SUCCESS!"); + + return NPERR_NO_ERROR; + } + +}; + +static PluginTest::Register<GetUserAgentWithNullNPPFromNPPNew> getUserAgentWithNullNPPFromNPPNew("get-user-agent-with-null-npp-from-npp-new"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp new file mode 100644 index 000000000..91f47aff1 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +static bool wasShutdownCalled = false; + +class NPDeallocateCalledBeforeNPShutdown : public PluginTest { +public: + NPDeallocateCalledBeforeNPShutdown(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + // This is the test object. + class TestObject : public Object<TestObject> { + public: + ~TestObject() + { + if (wasShutdownCalled) + indicateTestFailure(); + } + }; + + // This is the scriptable object. It has a single "testObject" property. + class ScriptableObject : public Object<ScriptableObject> { + public: + bool hasProperty(NPIdentifier propertyName) + { + return propertyName == pluginTest()->NPN_GetStringIdentifier("testObject"); + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + if (propertyName != pluginTest()->NPN_GetStringIdentifier("testObject")) + return false; + + NPObject* testObject = TestObject::create(pluginTest()); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } + }; + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + registerNPShutdownFunction(shutdown); + + return NPERR_NO_ERROR; + } + + virtual NPError NPP_GetValue(NPPVariable variable, void *value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *(NPObject**)value = ScriptableObject::create(this); + + return NPERR_NO_ERROR; + } + + static void shutdown() + { + wasShutdownCalled = true; + } + +}; + +static PluginTest::Register<NPDeallocateCalledBeforeNPShutdown> npRuntimeObjectFromDestroyedPlugin("np-deallocate-called-before-np-shutdown"); + diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp new file mode 100644 index 000000000..50af95905 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// NPP_SetWindow should be called with a null window handle as destruction begins on non-Mac platforms. + +class NPPSetWindowCalledDuringDestruction : public PluginTest { +public: + NPPSetWindowCalledDuringDestruction(NPP, const string& identifier); + + void setWillBeDestroyed() { m_willBeDestroyed = true; } + +private: + struct ScriptObject : Object<ScriptObject> { + bool hasMethod(NPIdentifier); + bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*); + }; + + virtual NPError NPP_GetValue(NPPVariable, void*); + virtual NPError NPP_SetWindow(NPWindow*); + virtual NPError NPP_Destroy(NPSavedData**); + + bool m_willBeDestroyed; + bool m_setWindowCalledBeforeDestruction; + bool m_setWindowCalledDuringDestruction; +}; + +static PluginTest::Register<NPPSetWindowCalledDuringDestruction> registrar("npp-set-window-called-during-destruction"); + +NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_willBeDestroyed(false) + , m_setWindowCalledBeforeDestruction(false) + , m_setWindowCalledDuringDestruction(false) +{ +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_GetValue(NPPVariable variable, void* value) +{ + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *static_cast<NPObject**>(value) = ScriptObject::create(this); + + return NPERR_NO_ERROR; +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_SetWindow(NPWindow* window) +{ + if (m_willBeDestroyed) { + m_setWindowCalledDuringDestruction = true; + if (!m_setWindowCalledBeforeDestruction) { + log("Fail: setWillBeDestroyed() was called before the initial NPP_SetWindow call"); + return NPERR_NO_ERROR; + } +#ifndef XP_MACOSX + if (window->window) + log("Fail: NPP_SetWindow passed a non-null window during plugin destruction"); +#endif + return NPERR_NO_ERROR; + } + + if (m_setWindowCalledBeforeDestruction) { + log("Fail: NPP_SetWindow called more than once before plugin destruction"); + return NPERR_NO_ERROR; + } + + m_setWindowCalledBeforeDestruction = true; + return NPERR_NO_ERROR; +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_Destroy(NPSavedData**) +{ +#ifdef XP_MACOSX + bool shouldHaveBeenCalledDuringDestruction = false; +#else + bool shouldHaveBeenCalledDuringDestruction = true; +#endif + + if (m_setWindowCalledDuringDestruction == shouldHaveBeenCalledDuringDestruction) + log("Success: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was" : "was not"); + else + log("Fail: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was not" : "was"); + + return NPERR_NO_ERROR; +} + +bool NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod(NPIdentifier methodName) +{ + return methodName == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed"); +} + +bool NPPSetWindowCalledDuringDestruction::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*) +{ + assert(identifier == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed")); + static_cast<NPPSetWindowCalledDuringDestruction*>(pluginTest())->setWillBeDestroyed(); + return true; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp new file mode 100644 index 000000000..0e238e607 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +class NPRuntimeObjectFromDestroyedPlugin : public PluginTest { +public: + NPRuntimeObjectFromDestroyedPlugin(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + // This is the test object. + class TestObject : public Object<TestObject> { }; + + // This is the scriptable object. It has a single "testObject" property and an "evaluate" function. + class ScriptableObject : public Object<ScriptableObject> { + public: + bool hasMethod(NPIdentifier methodName) + { + return identifierIs(methodName, "evaluate"); + } + + bool invoke(NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) + { + if (!identifierIs(methodName, "evaluate")) + return false; + + if (argCount != 1 || !NPVARIANT_IS_STRING(args[0])) + return false; + + return pluginTest()->executeScript(&NPVARIANT_TO_STRING(args[0]), result); + } + + bool hasProperty(NPIdentifier propertyName) + { + return identifierIs(propertyName, "testObject"); + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + if (propertyName != pluginTest()->NPN_GetStringIdentifier("testObject")) + return false; + + NPObject* testObject = TestObject::create(pluginTest()); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } + }; + + virtual NPError NPP_GetValue(NPPVariable variable, void *value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *(NPObject**)value = ScriptableObject::create(this); + + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<NPRuntimeObjectFromDestroyedPlugin> npRuntimeObjectFromDestroyedPlugin("npruntime-object-from-destroyed-plugin"); + diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp new file mode 100644 index 000000000..8a923dc23 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include <string.h> + +using namespace std; + +class NPRuntimeRemoveProperty : public PluginTest { +public: + NPRuntimeRemoveProperty(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + struct TestObject : Object<TestObject> { + public: + TestObject() + : m_lastRemovedProperty(0) + { + } + + bool hasProperty(NPIdentifier propertyName) + { + if (identifierIs(propertyName, "lastRemovedProperty")) + return true; + + return false; + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + assert(identifierIs(propertyName, "lastRemovedProperty")); + + if (!m_lastRemovedProperty) + return false; + + if (pluginTest()->NPN_IdentifierIsString(m_lastRemovedProperty)) { + char* lastRemovedPropertyName = pluginTest()->NPN_UTF8FromIdentifier(m_lastRemovedProperty); + + STRINGZ_TO_NPVARIANT(lastRemovedPropertyName, *result); + return true; + } + + int intIdentifier = pluginTest()->NPN_IntFromIdentifier(m_lastRemovedProperty); + DOUBLE_TO_NPVARIANT(intIdentifier, *result); + return true; + } + + bool removeProperty(NPIdentifier propertyName) + { + m_lastRemovedProperty = propertyName; + return true; + } + + private: + NPIdentifier m_lastRemovedProperty; + }; + + struct PluginObject : Object<PluginObject> { + public: + PluginObject() + : m_testObject(0) + { + } + + ~PluginObject() + { + if (m_testObject) + pluginTest()->NPN_ReleaseObject(m_testObject); + } + + bool hasMethod(NPIdentifier methodName) + { + if (identifierIs(methodName, "testRemoveProperty")) + return true; + + return false; + } + + bool invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) + { + assert(identifierIs(methodName, "testRemoveProperty")); + + if (argumentCount != 2) + return false; + + if (!NPVARIANT_IS_OBJECT(arguments[0])) + return false; + + if (!NPVARIANT_IS_STRING(arguments[1]) && !NPVARIANT_IS_DOUBLE(arguments[1])) + return false; + + NPIdentifier propertyName; + if (NPVARIANT_IS_STRING(arguments[1])) { + string propertyNameString(arguments[1].value.stringValue.UTF8Characters, + arguments[1].value.stringValue.UTF8Length); + + propertyName = pluginTest()->NPN_GetStringIdentifier(propertyNameString.c_str()); + } else { + int32_t number = static_cast<int32_t>(arguments[1].value.doubleValue); + propertyName = pluginTest()->NPN_GetIntIdentifier(number); + } + + pluginTest()->NPN_RemoveProperty(NPVARIANT_TO_OBJECT(arguments[0]), propertyName); + + VOID_TO_NPVARIANT(*result); + return true; + } + + bool hasProperty(NPIdentifier propertyName) + { + if (identifierIs(propertyName, "testObject")) + return true; + + return false; + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + assert(identifierIs(propertyName, "testObject")); + + if (!m_testObject) + m_testObject = TestObject::create(pluginTest()); + + OBJECT_TO_NPVARIANT(pluginTest()->NPN_RetainObject(m_testObject), *result); + return true; + } + + private: + NPObject* m_testObject; + }; + + virtual NPError NPP_GetValue(NPPVariable variable, void *value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *(NPObject**)value = PluginObject::create(this); + + return NPERR_NO_ERROR; + } + +}; + +static PluginTest::Register<NPRuntimeRemoveProperty> npRuntimeRemoveProperty("npruntime-remove-property"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp new file mode 100644 index 000000000..9e4e976f0 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Passing null for our NPP_GetValue function pointer should not crash. + +class NullNPPGetValuePointer : public PluginTest { +public: + NullNPPGetValuePointer(NPP, const string& identifier); + +private: + virtual NPError NPP_Destroy(NPSavedData**); + virtual NPError NPP_GetValue(NPPVariable, void* value); + + NPP_GetValueProcPtr m_originalNPPGetValuePointer; +}; + +static PluginTest::Register<NullNPPGetValuePointer> registrar("null-npp-getvalue-pointer"); + +NullNPPGetValuePointer::NullNPPGetValuePointer(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_originalNPPGetValuePointer(pluginFunctions->getvalue) +{ + // Be sneaky and null out the getvalue pointer the browser is holding. This simulates a plugin + // that doesn't implement NPP_GetValue (like Shockwave Director 10.3 on Windows). Note that if + // WebKit copies the NPPluginFuncs struct this technique will have no effect and WebKit will + // call into our NPP_GetValue implementation. + pluginFunctions->getvalue = 0; +} + +NPError NullNPPGetValuePointer::NPP_Destroy(NPSavedData**) +{ + // Set the NPP_GetValue pointer back the way it was before we mucked with it so we don't mess + // up future uses of the plugin module. + pluginFunctions->getvalue = m_originalNPPGetValuePointer; + return NPERR_NO_ERROR; +} + +NPError NullNPPGetValuePointer::NPP_GetValue(NPPVariable, void*) +{ + pluginLog(m_npp, "NPP_GetValue was called but should not have been. Maybe WebKit copied the NPPluginFuncs struct, which would invalidate this test."); + return NPERR_GENERIC_ERROR; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp new file mode 100644 index 000000000..c9af49c59 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Passing a different NPP struct that has the same ndata value as the one passed to NPP_New should +// not trigger an assertion failure. + +class PassDifferentNPPStruct : public PluginTest { +public: + PassDifferentNPPStruct(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didReceiveInitialSetWindowCall(false) + { + } + +private: + virtual NPError NPP_SetWindow(NPWindow* window) + { + if (m_didReceiveInitialSetWindowCall) + return NPERR_NO_ERROR; + m_didReceiveInitialSetWindowCall = true; + + NPP oldNPP = m_npp; + NPP_t differentNPP = *m_npp; + m_npp = &differentNPP; + + NPBool privateMode; + NPError error = NPN_GetValue(NPNVprivateModeBool, &privateMode); + + m_npp = oldNPP; + + if (error != NPERR_NO_ERROR) { + log("NPN_GetValue(NPNVprivateModeBool) with a different NPP struct failed with error %d", error); + return NPERR_GENERIC_ERROR; + } + log("NPN_GetValue(NPNVprivateModeBool) with a different NPP struct succeeded"); + return NPERR_NO_ERROR; + } + + bool m_didReceiveInitialSetWindowCall; +}; + +static PluginTest::Register<PassDifferentNPPStruct> getValueNetscapeWindow("pass-different-npp-struct"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp new file mode 100644 index 000000000..959e182e4 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +// A test where the plug-ins scriptable object either has or doesn't have an invokeDefault function. +class PluginScriptableNPObjectInvokeDefault : public PluginTest { +public: + PluginScriptableNPObjectInvokeDefault(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + struct NPObjectWithoutInvokeDefault : Object<NPObjectWithoutInvokeDefault> { }; + + struct NPObjectWithInvokeDefault : Object<NPObjectWithInvokeDefault> { + public: + bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result) + { + INT32_TO_NPVARIANT(1, *result); + return true; + } + }; + + virtual NPError NPP_GetValue(NPPVariable variable, void *value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + NPObject* object; + if (identifier() == "plugin-scriptable-npobject-invoke-default") + object = NPObjectWithInvokeDefault::create(this); + else + object = NPObjectWithoutInvokeDefault::create(this); + + *(NPObject**)value = object; + + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<PluginScriptableNPObjectInvokeDefault> pluginScriptableNPObjectInvokeDefault("plugin-scriptable-npobject-invoke-default"); +static PluginTest::Register<PluginScriptableNPObjectInvokeDefault> pluginScriptableNPObjectNoInvokeDefault("plugin-scriptable-npobject-no-invoke-default"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp new file mode 100644 index 000000000..ea5ac1ccc --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +class PrivateBrowsing : public PluginTest { +public: + PrivateBrowsing(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_cachedPrivateBrowsingEnabled(false) + { + } + +private: + bool privateBrowsingEnabled() + { + NPBool privateBrowsingEnabled = FALSE; + NPN_GetValue(NPNVprivateModeBool, &privateBrowsingEnabled); + return privateBrowsingEnabled; + } + + bool cachedPrivateBrowsingEnabled() + { + return m_cachedPrivateBrowsingEnabled; + } + + class ScriptableObject : public Object<ScriptableObject> { + public: + bool hasProperty(NPIdentifier propertyName) + { + return identifierIs(propertyName, "privateBrowsingEnabled") + || identifierIs(propertyName, "cachedPrivateBrowsingEnabled"); + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + if (identifierIs(propertyName, "privateBrowsingEnabled")) { + BOOLEAN_TO_NPVARIANT(pluginTest()->privateBrowsingEnabled(), *result); + return true; + } + if (identifierIs(propertyName, "cachedPrivateBrowsingEnabled")) { + BOOLEAN_TO_NPVARIANT(pluginTest()->cachedPrivateBrowsingEnabled(), *result); + return true; + } + return false; + } + + private: + PrivateBrowsing* pluginTest() const { return static_cast<PrivateBrowsing*>(Object<ScriptableObject>::pluginTest()); } + }; + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved) + { + m_cachedPrivateBrowsingEnabled = privateBrowsingEnabled(); + return NPERR_NO_ERROR; + } + + virtual NPError NPP_GetValue(NPPVariable variable, void* value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *(NPObject**)value = ScriptableObject::create(this); + + return NPERR_NO_ERROR; + } + + virtual NPError NPP_SetValue(NPNVariable variable, void* value) + { + switch (variable) { + case NPNVprivateModeBool: + m_cachedPrivateBrowsingEnabled = *(NPBool*)value; + return NPERR_NO_ERROR; + default: + return NPERR_GENERIC_ERROR; + } + + } + bool m_cachedPrivateBrowsingEnabled; +}; + +static PluginTest::Register<PrivateBrowsing> privateBrowsing("private-browsing"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp new file mode 100644 index 000000000..5353d8333 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +class ContentsScaleFactor : public PluginTest { +public: + ContentsScaleFactor(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_cachedContentsScaleFactor(1.0) + { + } + +private: + double contentsScaleFactor() + { + double contentsScaleFactor = 1.0; + NPN_GetValue(NPNVcontentsScaleFactor, &contentsScaleFactor); + return contentsScaleFactor; + } + + double cachedContentsScaleFactor() + { + return m_cachedContentsScaleFactor; + } + + class ScriptableObject : public Object<ScriptableObject> { + public: + bool hasProperty(NPIdentifier propertyName) + { + return identifierIs(propertyName, "contentsScaleFactor") + || identifierIs(propertyName, "cachedContentsScaleFactor"); + } + + bool getProperty(NPIdentifier propertyName, NPVariant* result) + { + if (identifierIs(propertyName, "contentsScaleFactor")) { + DOUBLE_TO_NPVARIANT(pluginTest()->contentsScaleFactor(), *result); + return true; + } + + if (identifierIs(propertyName, "cachedContentsScaleFactor")) { + DOUBLE_TO_NPVARIANT(pluginTest()->cachedContentsScaleFactor(), *result); + return true; + } + return false; + } + + private: + ContentsScaleFactor* pluginTest() const { return static_cast<ContentsScaleFactor*>(Object<ScriptableObject>::pluginTest()); } + + }; + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved) + { + m_cachedContentsScaleFactor = contentsScaleFactor(); + return NPERR_NO_ERROR; + } + + virtual NPError NPP_GetValue(NPPVariable variable, void* value) + { + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *(NPObject**)value = ScriptableObject::create(this); + + return NPERR_NO_ERROR; + } + + virtual NPError NPP_SetValue(NPNVariable variable, void* value) + { + switch (variable) { + case NPNVcontentsScaleFactor: + m_cachedContentsScaleFactor = *(double*)value; + return NPERR_NO_ERROR; + default: + return NPERR_GENERIC_ERROR; + } + } + double m_cachedContentsScaleFactor; +}; + +static PluginTest::Register<ContentsScaleFactor> contentsScaleFactor("contents-scale-factor"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp new file mode 100644 index 000000000..96a6cc757 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +// Test that NPN_ConvertPoint converts correctly. +class ConvertPoint : public PluginTest { +public: + ConvertPoint(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + + bool testConvert(double x, double y, NPCoordinateSpace sourceSpace, NPCoordinateSpace destSpace) + { + // First convert from src to dest. + double destX, destY; + if (!NPN_ConvertPoint(x, y, sourceSpace, &destX, &destY, destSpace)) + return false; + + // Then convert back to src + double srcX, srcY; + if (!NPN_ConvertPoint(destX, destY, destSpace, &srcX, &srcY, sourceSpace)) + return false; + + + // Then compare. + if (srcX != x || srcY != y) + return false; + + return true; + } + + bool testConvert() + { + static const NPCoordinateSpace spaces[] = { NPCoordinateSpacePlugin, NPCoordinateSpaceWindow, NPCoordinateSpaceFlippedWindow, NPCoordinateSpaceScreen, NPCoordinateSpaceFlippedScreen }; + + static const size_t numSpaces = sizeof(spaces) / sizeof(spaces[0]); + for (size_t i = 0; i < numSpaces; ++i) { + for (size_t j = 0; j < numSpaces; ++j) { + if (!testConvert(1234, 5678, spaces[i], spaces[j])) + return false; + } + } + return true; + } +private: + virtual NPError NPP_SetWindow(NPWindow*) + { + if (testConvert()) + executeScript("document.getElementById('result').innerHTML = 'SUCCESS!'"); + + executeScript("setTimeout(function() { layoutTestController.notifyDone() }, 0)"); + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<ConvertPoint> convertPoint("convert-point"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp new file mode 100644 index 000000000..51cbce2bf --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +using namespace std; + +// Test that we report that we support the Carbon event model in 32-bit. +class SupportsCarbonEventModel : public PluginTest { +public: + SupportsCarbonEventModel(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + bool runTest() + { +#ifdef NP_NO_CARBON + // There's no support for Carbon, so we can't test anything. + return true; +#else + NPBool supportsCarbonEventModel = false; + if (NPN_GetValue(NPNVsupportsCarbonBool, &supportsCarbonEventModel) != NPERR_NO_ERROR) + return false; + + return supportsCarbonEventModel; +#endif + } + + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + if (runTest()) + executeScript("document.getElementById('result').innerHTML = 'SUCCESS!'"); + + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<SupportsCarbonEventModel> supportsCarbonEventModel("supports-carbon-event-model"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp new file mode 100644 index 000000000..2b0619832 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp @@ -0,0 +1,118 @@ +/* Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Just fills its window with some gradients + +class DrawsGradient : public WindowedPluginTest { +public: + DrawsGradient(NPP, const string& identifier); + +private: + void paint(HDC) const; + + LRESULT onPaint(WPARAM, LPARAM, bool& handled); + LRESULT onPrintClient(WPARAM, LPARAM, bool& handled); + + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); +}; + +static PluginTest::Register<DrawsGradient> registrar("draws-gradient"); + +DrawsGradient::DrawsGradient(NPP npp, const string& identifier) + : WindowedPluginTest(npp, identifier) +{ +} + +LRESULT DrawsGradient::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) +{ + LRESULT result = 0; + + switch (message) { + case WM_PAINT: + result = onPaint(wParam, lParam, handled); + break; + case WM_PRINTCLIENT: + result = onPrintClient(wParam, lParam, handled); + break; + default: + handled = false; + } + + return result; +} + +LRESULT DrawsGradient::onPaint(WPARAM, LPARAM, bool& handled) +{ + PAINTSTRUCT paintStruct; + HDC dc = ::BeginPaint(window(), &paintStruct); + if (!dc) + return 0; + + paint(dc); + ::EndPaint(window(), &paintStruct); + + handled = true; + return 0; +} + +LRESULT DrawsGradient::onPrintClient(WPARAM wParam, LPARAM, bool& handled) +{ + paint(reinterpret_cast<HDC>(wParam)); + + handled = true; + return 0; +} + +void DrawsGradient::paint(HDC dc) const +{ + RECT clientRect; + if (!::GetClientRect(window(), &clientRect)) + return; + + TRIVERTEX vertices[] = { + // Upper-left: green + { clientRect.left, clientRect.top, 0, 0xff00, 0, 0 }, + // Upper-right: blue + { clientRect.right, clientRect.top, 0, 0, 0xff00, 0 }, + // Lower-left: yellow + { clientRect.left, clientRect.bottom, 0xff00, 0xff00, 0, 0 }, + // Lower-right: red + { clientRect.right, clientRect.bottom, 0xff00, 0, 0, 0 }, + }; + + GRADIENT_TRIANGLE mesh[] = { + // Upper-left triangle + { 0, 1, 2 }, + // Lower-right triangle + { 1, 2, 3 }, + }; + + ::GradientFill(dc, vertices, _countof(vertices), mesh, _countof(mesh), GRADIENT_FILL_TRIANGLE); +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp new file mode 100644 index 000000000..fc2fd45a8 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h" + +#include "PluginObject.h" + +using namespace std; + +// This plugin dumps its window rect (relative to the test harness window) to the console when it +// is instantiated. + +class DumpWindowRect : public WindowGeometryTest { +public: + DumpWindowRect(NPP, const string& identifier); + +private: + virtual void performWindowGeometryTest(); +}; + +static PluginTest::Register<DumpWindowRect> registrar("dump-window-rect"); + +DumpWindowRect::DumpWindowRect(NPP npp, const string& identifier) + : WindowGeometryTest(npp, identifier) +{ +} + + +void DumpWindowRect::performWindowGeometryTest() +{ + RECT rect; + if (!::GetClientRect(window(), &rect)) { + log("::GetClientRect failed"); + return; + } + + // MSDN says that calling ::MapWindowPoints this way will tell it to treat the points as a rect. + if (!::MapWindowPoints(window(), testHarnessWindow(), reinterpret_cast<LPPOINT>(&rect), 2)) { + log("::MapWindowPoints failed"); + return; + } + + log("Plugin window rect: {left=%d, top=%d, right=%d, bottom=%d}", rect.left, rect.top, rect.right, rect.bottom); +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp new file mode 100644 index 000000000..32fd99b63 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// NPN_GetValue(NPNVnetscapeWindow) should return a valid HWND. + +class GetValueNetscapeWindow : public PluginTest { +public: + GetValueNetscapeWindow(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didReceiveInitialSetWindowCall(false) + { + } + +private: + virtual NPError NPP_SetWindow(NPP instance, NPWindow* window) + { + if (m_didReceiveInitialSetWindowCall) + return NPERR_NO_ERROR; + m_didReceiveInitialSetWindowCall = true; + + HWND hwnd; + NPError error = NPN_GetValue(NPNVnetscapeWindow, &hwnd); + if (error != NPERR_NO_ERROR) { + pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) failed with error %d", error); + return NPERR_GENERIC_ERROR; + } + + if (!::IsWindow(hwnd)) { + pluginLog(instance, "::IsWindow returned FALSE"); + return NPERR_GENERIC_ERROR; + } + + if (hwnd == window->window) { + pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) returned the same value as NPWindow::window"); + return NPERR_GENERIC_ERROR; + } + + pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) succeeded"); + return NPERR_NO_ERROR; + } + + bool m_didReceiveInitialSetWindowCall; +}; + +static PluginTest::Register<GetValueNetscapeWindow> getValueNetscapeWindow("get-value-netscape-window"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp new file mode 100644 index 000000000..6d5484b1f --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// NPN_InvalidateRect should invalidate the plugin's HWND. + +static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.NPNInvalidateRectInvalidatesWindow.InstancePointer"; + +class TemporaryWindowMover { +public: + TemporaryWindowMover(HWND); + ~TemporaryWindowMover(); + + bool moveSucceeded() const { return m_moveSucceeded; } + +private: + static const UINT standardSetWindowPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER; + bool m_moveSucceeded; + HWND m_window; + RECT m_savedWindowRect; +}; + +TemporaryWindowMover::TemporaryWindowMover(HWND window) + : m_window(window) +{ + m_moveSucceeded = false; + + if (!::GetWindowRect(m_window, &m_savedWindowRect)) + return; + + if (!::SetWindowPos(m_window, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | standardSetWindowPosFlags)) + return; + + m_moveSucceeded = true; +}; + +TemporaryWindowMover::~TemporaryWindowMover() +{ + if (!m_moveSucceeded) + return; + + ::SetWindowPos(m_window, 0, m_savedWindowRect.left, m_savedWindowRect.top, 0, 0, SWP_HIDEWINDOW | standardSetWindowPosFlags); +} + +class NPNInvalidateRectInvalidatesWindow : public WindowedPluginTest { +public: + NPNInvalidateRectInvalidatesWindow(NPP, const string& identifier); + ~NPNInvalidateRectInvalidatesWindow(); + +private: + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); + + void onPaint(); + void testInvalidateRect(); + + virtual NPError NPP_SetWindow(NPP, NPWindow*); + + TemporaryWindowMover* m_windowMover; +}; + +NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow(NPP npp, const string& identifier) + : WindowedPluginTest(npp, identifier) + , m_windowMover(0) +{ +} + +NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow() +{ + delete m_windowMover; +} + +NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* npWindow) +{ + NPError error = WindowedPluginTest::NPP_SetWindow(instance, npWindow); + if (error != NPERR_NO_ERROR) + return error; + + if (!window()) + return NPERR_NO_ERROR; + + // The test harness's window (the one that contains the WebView) is off-screen and hidden. + // We need to move it on-screen and make it visible in order for the plugin's window to + // accumulate an update region when the DWM is disabled. + + HWND testHarnessWindow = this->testHarnessWindow(); + if (!testHarnessWindow) { + pluginLog(instance, "Failed to get test harness window"); + return NPERR_GENERIC_ERROR; + } + + m_windowMover = new TemporaryWindowMover(testHarnessWindow); + if (!m_windowMover->moveSucceeded()) { + pluginLog(instance, "Failed to move test harness window on-screen"); + return NPERR_GENERIC_ERROR; + } + + // Wait until we receive a WM_PAINT message to ensure that the window is on-screen before we do + // the NPN_InvalidateRect test. + waitUntilDone(); + return NPERR_NO_ERROR; +} + +LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) +{ + if (message == WM_PAINT) + onPaint(); + + handled = false; + return 0; +} + +void NPNInvalidateRectInvalidatesWindow::onPaint() +{ + testInvalidateRect(); + notifyDone(); + delete m_windowMover; + m_windowMover = 0; +} + +void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() +{ + RECT clientRect; + if (!::GetClientRect(window(), &clientRect)) { + pluginLog(m_npp, "::GetClientRect failed"); + return; + } + + if (::IsRectEmpty(&clientRect)) { + pluginLog(m_npp, "Plugin's HWND has not been sized when NPP_SetWindow is called"); + return; + } + + // Clear the invalid region. + if (!::ValidateRect(window(), 0)) { + pluginLog(m_npp, "::ValidateRect failed"); + return; + } + + // Invalidate our lower-right quadrant. + NPRect rectToInvalidate; + rectToInvalidate.left = (clientRect.right - clientRect.left) / 2; + rectToInvalidate.top = (clientRect.bottom - clientRect.top) / 2; + rectToInvalidate.right = clientRect.right; + rectToInvalidate.bottom = clientRect.bottom; + NPN_InvalidateRect(&rectToInvalidate); + + RECT invalidRect; + if (!::GetUpdateRect(window(), &invalidRect, FALSE)) { + pluginLog(m_npp, "::GetUpdateRect failed"); + return; + } + + if (invalidRect.left != rectToInvalidate.left || invalidRect.top != rectToInvalidate.top || invalidRect.right != rectToInvalidate.right || invalidRect.bottom != rectToInvalidate.bottom) { + pluginLog(m_npp, "Expected invalid rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", rectToInvalidate.left, rectToInvalidate.top, rectToInvalidate.right, rectToInvalidate.bottom, invalidRect.left, invalidRect.top, invalidRect.right, invalidRect.bottom); + return; + } + + pluginLog(m_npp, "Plugin's HWND has been invalidated as expected"); +} + +static PluginTest::Register<NPNInvalidateRectInvalidatesWindow> registrar("npn-invalidate-rect-invalidates-window"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp new file mode 100644 index 000000000..1c75d27a8 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Plugin's HWND should be sized/positioned before NPP_SetWindow is called. + +class WindowGeometryInitializedBeforeSetWindow : public PluginTest { +public: + WindowGeometryInitializedBeforeSetWindow(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didReceiveInitialSetWindowCall(false) + { + } + +private: + virtual NPError NPP_SetWindow(NPP instance, NPWindow* window) + { + if (m_didReceiveInitialSetWindowCall) + return NPERR_NO_ERROR; + m_didReceiveInitialSetWindowCall = true; + + if (window->type != NPWindowTypeWindow) { + pluginLog(instance, "window->type should be NPWindowTypeWindow but was %d", window->type); + return NPERR_GENERIC_ERROR; + } + + HWND hwnd = reinterpret_cast<HWND>(window->window); + RECT rect; + if (!::GetClientRect(hwnd, &rect)) { + pluginLog(instance, "::GetClientRect failed"); + return NPERR_GENERIC_ERROR; + } + + if (::IsRectEmpty(&rect)) { + pluginLog(instance, "Plugin's HWND has not been sized when NPP_SetWindow is called"); + return NPERR_GENERIC_ERROR; + } + + if ((rect.right - rect.left) != window->width || (rect.bottom - rect.top) != window->height) { + pluginLog(instance, "Size of HWND's rect and size of NPWindow's rect are not equal"); + return NPERR_GENERIC_ERROR; + } + + pluginLog(instance, "Plugin's HWND has been sized before NPP_SetWindow was called"); + return NPERR_NO_ERROR; + } + + bool m_didReceiveInitialSetWindowCall; +}; + +static PluginTest::Register<WindowGeometryInitializedBeforeSetWindow> windowGeometryInitializedBeforeSetWindow("window-geometry-initialized-before-set-window"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp new file mode 100644 index 000000000..7a0098b84 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h" + +#include "PluginObject.h" + +using namespace std; + +// The plugin's window's window region should be set to the plugin's clip rect. + +class WindowRegionIsSetToClipRect : public WindowGeometryTest { +public: + WindowRegionIsSetToClipRect(NPP, const string& identifier); + +private: + virtual void performWindowGeometryTest(); +}; + +static PluginTest::Register<WindowRegionIsSetToClipRect> registrar("window-region-is-set-to-clip-rect"); + +WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect(NPP npp, const string& identifier) + : WindowGeometryTest(npp, identifier) +{ +} + +void WindowRegionIsSetToClipRect::performWindowGeometryTest() +{ + RECT regionRect; + if (::GetWindowRgnBox(window(), ®ionRect) == ERROR) { + log("::GetWindowRgnBox failed, or window has no window region"); + return; + } + + // This expected rect is based on the layout of window-region-is-set-to-clip-rect.html. + RECT expectedRect = { 50, 50, 100, 100 }; + if (!::EqualRect(®ionRect, &expectedRect)) { + log("Expected region rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom, regionRect.left, regionRect.top, regionRect.right, regionRect.bottom); + return; + } + + log("PASS: Plugin's window's window region has been set as expected"); + + // While we're here, check that our window class doesn't have the CS_PARENTDC style, which + // defeats clipping by ignoring the window region and always clipping to the parent window. + // FIXME: It would be nice to have a pixel test that shows that we're + // getting clipped correctly, but unfortunately window regions are ignored + // during WM_PRINT (see <http://webkit.org/b/49034>). + wchar_t className[512]; + if (!::GetClassNameW(window(), className, _countof(className))) { + log("::GetClassName failed with error %u", ::GetLastError()); + return; + } + +#ifdef DEBUG_ALL + const wchar_t webKitDLLName[] = L"WebKit_debug.dll"; +#else + const wchar_t webKitDLLName[] = L"WebKit.dll"; +#endif + HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName); + if (!webKitModule) { + log("::GetModuleHandleW failed with error %u", ::GetLastError()); + return; + } + + WNDCLASSW wndClass; + if (!::GetClassInfoW(webKitModule, className, &wndClass)) { + log("::GetClassInfoW failed with error %u", ::GetLastError()); + return; + } + + if (wndClass.style & CS_PARENTDC) + log("FAIL: Plugin's window's class has the CS_PARENTDC style, which will defeat clipping"); + else + log("PASS: Plugin's window's class does not have the CS_PARENTDC style"); +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp new file mode 100644 index 000000000..ffc92ea2e --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// The rect passed in the WM_PAINT event for a windowless plugin should be relative to the page's +// HWND and clipped to the plugin's bounds. + +class WindowlessPaintRectCoordinates : public PluginTest { +public: + WindowlessPaintRectCoordinates(NPP, const string& identifier); + +private: + virtual NPError NPP_New(NPMIMEType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData*); + virtual int16_t NPP_HandleEvent(void* event); +}; + +static PluginTest::Register<WindowlessPaintRectCoordinates> registrar("windowless-paint-rect-coordinates"); + +WindowlessPaintRectCoordinates::WindowlessPaintRectCoordinates(NPP npp, const string& identifier) + : PluginTest(npp, identifier) +{ +} + +NPError WindowlessPaintRectCoordinates::NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*) +{ + browser->setvalue(m_npp, NPPVpluginWindowBool, 0); + return NPERR_NO_ERROR; +} + +int16_t WindowlessPaintRectCoordinates::NPP_HandleEvent(void* typelessEvent) +{ + NPEvent* event = static_cast<NPEvent*>(typelessEvent); + if (!event) { + pluginLog(m_npp, "NPP_HandleEvent was passed a null event pointer"); + return 0; + } + + if (event->event != WM_PAINT) + return 0; + + RECT* paintRect = reinterpret_cast<RECT*>(event->lParam); + if (!paintRect) { + pluginLog(m_npp, "A null paint rect was passed in the WM_PAINT event"); + return 1; + } + + // Keep these values in sync with windowless-paint-rect-coordinates.html. + RECT expectedRect = { 100, 100, 200, 200 }; + + if (::EqualRect(paintRect, &expectedRect)) + pluginLog(m_npp, "Success"); + else + pluginLog(m_npp, "Expected paint rect {left=%d, top=%d, right=%d, bottom=%d}, but got {left=%d, top=%d, right=%d, bottom=%d}", expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom, paintRect->left, paintRect->top, paintRect->right, paintRect->bottom); + + return 1; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp new file mode 100644 index 000000000..8d25d3906 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +class CallInvalidateRectWithNullNPPArgument : public PluginTest { +public: + CallInvalidateRectWithNullNPPArgument(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + NPRect rect; + browser->invalidaterect(0, &rect); + pluginLog(m_npp, "SUCCESS!"); + return NPERR_NO_ERROR; + } + +}; + +static PluginTest::Register<CallInvalidateRectWithNullNPPArgument> callInvalidateRectWithNullNPPArgument("call-invalidate-rect-with-null-npp-argument"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist new file mode 100644 index 000000000..ef45e66d2 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>TestNetscapePlugIn</string> + <key>CFBundleGetInfoString</key> + <string>420+, Copyright 2006-2009 Apple Inc.</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>com.apple.testnetscapeplugin</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>BRPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>CFPlugInDynamicRegisterFunction</key> + <string></string> + <key>CFPlugInDynamicRegistration</key> + <string>NO</string> + <key>CFPlugInFactories</key> + <dict> + <key>00000000-0000-0000-0000-000000000000</key> + <string>MyFactoryFunction</string> + </dict> + <key>CFPlugInTypes</key> + <dict> + <key>00000000-0000-0000-0000-000000000000</key> + <array> + <string>00000000-0000-0000-0000-000000000000</string> + </array> + </dict> + <key>CFPlugInUnloadFunction</key> + <string></string> + <key>WebPluginDescription</key> + <string>Simple Netscape plug-in that handles test content for WebKit</string> + <key>WebPluginMIMETypes</key> + <dict> + <key>image/png</key> + <dict> + <key>WebPluginExtensions</key> + <array> + <string>png</string> + </array> + <key>WebPluginTypeDescription</key> + <string>PNG image</string> + </dict> + <key>application/x-webkit-test-netscape</key> + <dict> + <key>WebPluginExtensions</key> + <array> + <string>testnetscape</string> + </array> + <key>WebPluginTypeDescription</key> + <string>test netscape content</string> + </dict> + </dict> + <key>WebPluginName</key> + <string>WebKit Test PlugIn</string> +</dict> +</plist> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp new file mode 100644 index 000000000..c07bb2739 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp @@ -0,0 +1,833 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "PluginObject.h" + +#include "PluginTest.h" +#include <cstdlib> +#include <cstring> +#include <string> + +#ifdef XP_UNIX +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#endif + +#if !defined(NP_NO_CARBON) && defined(QD_HEADERS_ARE_PRIVATE) && QD_HEADERS_ARE_PRIVATE +extern "C" void GlobalToLocal(Point*); +#endif + +using namespace std; + +#define CRASH() do { \ + *(int *)(uintptr_t)0xbbadbeef = 0; \ + ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ +} while(false) + +static bool getEntryPointsWasCalled; +static bool initializeWasCalled; + +#if defined(XP_WIN) +#define STDCALL __stdcall + +static inline int strcasecmp(const char* s1, const char* s2) +{ + return _stricmp(s1, s2); +} + +#else +#define STDCALL +#endif + +extern "C" { +NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); +} + +// Entry points +extern "C" +NPError STDCALL NP_Initialize(NPNetscapeFuncs *browserFuncs +#ifdef XP_UNIX + , NPPluginFuncs *pluginFuncs +#endif + ) +{ + initializeWasCalled = true; + +#if defined(XP_WIN) + // Simulate Flash and QuickTime's behavior of crashing when NP_Initialize is called before NP_GetEntryPoints. + if (!getEntryPointsWasCalled) + CRASH(); +#endif + + browser = browserFuncs; + +#ifdef XP_UNIX + return NP_GetEntryPoints(pluginFuncs); +#else + return NPERR_NO_ERROR; +#endif +} + +extern "C" +NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) +{ + getEntryPointsWasCalled = true; + +#ifdef XP_MACOSX + // Simulate Silverlight's behavior of crashing when NP_GetEntryPoints is called before NP_Initialize. + if (!initializeWasCalled) + CRASH(); +#endif + + pluginFunctions = pluginFuncs; + + pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; + pluginFuncs->size = sizeof(pluginFuncs); + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + return NPERR_NO_ERROR; +} + +extern "C" +void STDCALL NP_Shutdown(void) +{ + PluginTest::NP_Shutdown(); +} + +static void executeScript(const PluginObject* obj, const char* script); + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) +{ +#ifdef XP_MACOSX + NPEventModel eventModel; + + // Always turn on the CG model + NPBool supportsCoreGraphics; + if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR) + supportsCoreGraphics = false; + + if (!supportsCoreGraphics) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + NPDrawingModel drawingModelToUse = NPDrawingModelCoreGraphics; + + NPBool supportsCoreAnimation; + if (browser->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR) + supportsCoreAnimation = false; + +#ifndef NP_NO_CARBON + NPBool supportsCarbon = false; +#endif + NPBool supportsCocoa = false; + +#ifndef NP_NO_CARBON + // A browser that doesn't know about NPNVsupportsCarbonBool is one that only supports Carbon event model. + if (browser->getvalue(instance, NPNVsupportsCarbonBool, &supportsCarbon) != NPERR_NO_ERROR) + supportsCarbon = true; +#endif + + if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR) + supportsCocoa = false; + + if (supportsCocoa) { + eventModel = NPEventModelCocoa; +#ifndef NP_NO_CARBON + } else if (supportsCarbon) { + eventModel = NPEventModelCarbon; +#endif + } else { + return NPERR_INCOMPATIBLE_VERSION_ERROR; + } + + browser->setvalue(instance, NPPVpluginEventModel, (void *)eventModel); +#endif // XP_MACOSX + + PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass()); + instance->pdata = obj; + +#ifdef XP_MACOSX + obj->eventModel = eventModel; + obj->coreAnimationLayer = 0; +#endif // XP_MACOSX + + string testIdentifier; + const char* onNewScript = 0; + + for (int i = 0; i < argc; i++) { + if (strcasecmp(argn[i], "test") == 0) + testIdentifier = argv[i]; + if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad) + obj->onStreamLoad = strdup(argv[i]); + else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy) + obj->onStreamDestroy = strdup(argv[i]); + else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify) + obj->onURLNotify = strdup(argv[i]); + else if (strcasecmp(argn[i], "src") == 0 && + strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0) + obj->returnErrorFromNewStream = TRUE; + else if (strcasecmp(argn[i], "src") == 0 && + strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded") == 0) + executeScript(obj, "alert('Plugin Loaded!')"); + else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow) + obj->onSetWindow = strdup(argv[i]); + else if (strcasecmp(argn[i], "onNew") == 0 && !onNewScript) + onNewScript = argv[i]; + else if (strcasecmp(argn[i], "onPaintEvent") == 0 && !obj->onPaintEvent) + obj->onPaintEvent = strdup(argv[i]); + else if (strcasecmp(argn[i], "logfirstsetwindow") == 0) + obj->logSetWindow = TRUE; + else if (strcasecmp(argn[i], "testnpruntime") == 0) + testNPRuntime(instance); + else if (strcasecmp(argn[i], "logSrc") == 0) { + for (int i = 0; i < argc; i++) + if (strcasecmp(argn[i], "src") == 0) + pluginLog(instance, "src: %s", argv[i]); + } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0) + executeScript(obj, "document.body.innerHTML = ''"); + else if (!strcasecmp(argn[i], "ondestroy")) + obj->onDestroy = strdup(argv[i]); + else if (strcasecmp(argn[i], "testwindowopen") == 0) + obj->testWindowOpen = TRUE; + else if (strcasecmp(argn[i], "drawingmodel") == 0) { +#ifdef XP_MACOSX + const char* value = argv[i]; + if (strcasecmp(value, "coreanimation") == 0) { + if (supportsCoreAnimation) + drawingModelToUse = NPDrawingModelCoreAnimation; + else + return NPERR_INCOMPATIBLE_VERSION_ERROR; + } else if (strcasecmp(value, "coregraphics") == 0) { + if (supportsCoreGraphics) + drawingModelToUse = NPDrawingModelCoreGraphics; + else + return NPERR_INCOMPATIBLE_VERSION_ERROR; + } else + return NPERR_INCOMPATIBLE_VERSION_ERROR; +#endif + } else if (strcasecmp(argn[i], "testGetURLOnDestroy") == 0) { +#if defined(XP_WIN) + // FIXME: When https://bugs.webkit.org/show_bug.cgi?id=41831 is fixed, this #ifdef can be removed. + obj->testGetURLOnDestroy = TRUE; +#endif + } else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl")) + obj->testKeyboardFocusForPlugins = TRUE; + else if (!strcasecmp(argn[i], "evaluatescript")) { + char* script = argv[i]; + if (script == strstr(script, "mouse::")) { + obj->mouseDownForEvaluateScript = true; + obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("mouse::") - 1); + } else if (script == strstr(script, "key::")) { + obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("key::") - 1); + } + // When testing evaluate script on mouse-down or key-down, allow event logging to handle events. + if (obj->evaluateScriptOnMouseDownOrKeyDown) + obj->eventLogging = true; + } else if (!strcasecmp(argn[i], "windowedPlugin")) { + void* windowed = 0; + if (!strcasecmp(argv[i], "false") || !strcasecmp(argv[i], "0")) + windowed = 0; + else if (!strcasecmp(argv[i], "true") || !strcasecmp(argv[i], "1")) + windowed = reinterpret_cast<void*>(1); + else + assert(false); + browser->setvalue(instance, NPPVpluginWindowBool, windowed); + } + } + +#ifdef XP_MACOSX + browser->setvalue(instance, NPPVpluginDrawingModel, (void *)drawingModelToUse); + if (drawingModelToUse == NPDrawingModelCoreAnimation) + obj->coreAnimationLayer = createCoreAnimationLayer(); +#endif + + obj->pluginTest = PluginTest::create(instance, testIdentifier); + + if (!obj->pluginTest) { + pluginLog(instance, "NPP_New: Could not find a test named \"%s\", maybe its .cpp file wasn't added to the build system?", testIdentifier.c_str()); + return NPERR_GENERIC_ERROR; + } + + if (onNewScript) + executeScript(obj, onNewScript); + + return obj->pluginTest->NPP_New(pluginType, mode, argc, argn, argv, saved); +} + +NPError NPP_Destroy(NPP instance, NPSavedData **save) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + if (obj) { + if (obj->testGetURLOnDestroy) + browser->geturlnotify(obj->npp, "about:blank", "", 0); + + if (obj->onDestroy) { + executeScript(obj, obj->onDestroy); + free(obj->onDestroy); + } + + if (obj->onStreamLoad) + free(obj->onStreamLoad); + + if (obj->onStreamDestroy) + free(obj->onStreamDestroy); + + if (obj->onURLNotify) + free(obj->onURLNotify); + + if (obj->onSetWindow) + free(obj->onSetWindow); + + if (obj->onPaintEvent) + free(obj->onPaintEvent); + + if (obj->logDestroy) + pluginLog(instance, "NPP_Destroy"); + +#ifdef XP_MACOSX + if (obj->coreAnimationLayer) + CFRelease(obj->coreAnimationLayer); +#endif + + if (obj->pluginTest) + obj->pluginTest->NPP_Destroy(save); + + browser->releaseobject(&obj->header); + } + return NPERR_NO_ERROR; +} + +NPError NPP_SetWindow(NPP instance, NPWindow *window) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + if (obj) { + obj->lastWindow = *window; + + if (obj->logSetWindow) { + pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height); + obj->logSetWindow = FALSE; + } + + if (obj->onSetWindow) + executeScript(obj, obj->onSetWindow); + + if (obj->testWindowOpen) { + testWindowOpen(instance); + obj->testWindowOpen = FALSE; + } + + if (obj->testKeyboardFocusForPlugins) { + obj->eventLogging = true; + executeScript(obj, "eventSender.keyDown('A');"); + } + } + + return obj->pluginTest->NPP_SetWindow(window); +} + +static void executeScript(const PluginObject* obj, const char* script) +{ + NPObject *windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPString npScript; + npScript.UTF8Characters = script; + npScript.UTF8Length = strlen(script); + + NPVariant browserResult; + browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult); + browser->releasevariantvalue(&browserResult); +} + +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + obj->stream = stream; + *stype = NP_NORMAL; + + if (obj->returnErrorFromNewStream) + return NPERR_GENERIC_ERROR; + + if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS) + notifyStream(obj, stream->url, stream->headers); + + if (obj->onStreamLoad) + executeScript(obj, obj->onStreamLoad); + + return obj->pluginTest->NPP_NewStream(type, stream, seekable, stype); +} + +NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) +{ + PluginObject* obj = (PluginObject*)instance->pdata; + + if (obj->onStreamDestroy) { + NPObject* windowObject = 0; + NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject); + + if (error == NPERR_NO_ERROR) { + NPVariant onStreamDestroyVariant; + if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) { + if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) { + NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant); + + NPVariant reasonVariant; + INT32_TO_NPVARIANT(reason, reasonVariant); + + NPVariant result; + browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result); + browser->releasevariantvalue(&result); + } + browser->releasevariantvalue(&onStreamDestroyVariant); + } + browser->releaseobject(windowObject); + } + } + + return obj->pluginTest->NPP_DestroyStream(stream, reason); +} + +int32_t NPP_WriteReady(NPP instance, NPStream *stream) +{ + PluginObject* obj = (PluginObject*)instance->pdata; + return obj->pluginTest->NPP_WriteReady(stream); +} + +int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer) +{ + PluginObject* obj = (PluginObject*)instance->pdata; + + if (obj->returnNegativeOneFromWrite) + return -1; + + return obj->pluginTest->NPP_Write(stream, offset, len, buffer); +} + +void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) +{ +} + +void NPP_Print(NPP instance, NPPrint *platformPrint) +{ +} + +#ifdef XP_MACOSX +#ifndef NP_NO_CARBON +static int16_t handleEventCarbon(NPP instance, PluginObject* obj, EventRecord* event) +{ + Point pt = { event->where.v, event->where.h }; + + switch (event->what) { + case nullEvent: + // these are delivered non-deterministically, don't log. + break; + case mouseDown: + if (obj->eventLogging) { + GlobalToLocal(&pt); + pluginLog(instance, "mouseDown at (%d, %d)", pt.h, pt.v); + } + if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case mouseUp: + if (obj->eventLogging) { + GlobalToLocal(&pt); + pluginLog(instance, "mouseUp at (%d, %d)", pt.h, pt.v); + } + break; + case keyDown: + if (obj->eventLogging) + pluginLog(instance, "keyDown '%c'", (char)(event->message & 0xFF)); + if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case keyUp: + if (obj->eventLogging) + pluginLog(instance, "keyUp '%c'", (char)(event->message & 0xFF)); + if (obj->testKeyboardFocusForPlugins) { + obj->eventLogging = false; + obj->testKeyboardFocusForPlugins = FALSE; + executeScript(obj, "layoutTestController.notifyDone();"); + } + break; + case autoKey: + if (obj->eventLogging) + pluginLog(instance, "autoKey '%c'", (char)(event->message & 0xFF)); + break; + case updateEvt: + if (obj->eventLogging) + pluginLog(instance, "updateEvt"); + break; + case diskEvt: + if (obj->eventLogging) + pluginLog(instance, "diskEvt"); + break; + case activateEvt: + if (obj->eventLogging) + pluginLog(instance, "activateEvt"); + break; + case osEvt: + if (!obj->eventLogging) + break; + printf("PLUGIN: osEvt - "); + switch ((event->message & 0xFF000000) >> 24) { + case suspendResumeMessage: + printf("%s\n", (event->message & 0x1) ? "resume" : "suspend"); + break; + case mouseMovedMessage: + printf("mouseMoved\n"); + break; + default: + printf("%08lX\n", event->message); + } + break; + case kHighLevelEvent: + if (obj->eventLogging) + pluginLog(instance, "kHighLevelEvent"); + break; + // NPAPI events + case NPEventType_GetFocusEvent: + if (obj->eventLogging) + pluginLog(instance, "getFocusEvent"); + break; + case NPEventType_LoseFocusEvent: + if (obj->eventLogging) + pluginLog(instance, "loseFocusEvent"); + break; + case NPEventType_AdjustCursorEvent: + if (obj->eventLogging) + pluginLog(instance, "adjustCursorEvent"); + break; + default: + if (obj->eventLogging) + pluginLog(instance, "event %d", event->what); + } + + return 0; +} +#endif + +static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* event) +{ + switch (event->type) { + case NPCocoaEventWindowFocusChanged: + + case NPCocoaEventFocusChanged: + if (obj->eventLogging) { + if (event->data.focus.hasFocus) + pluginLog(instance, "getFocusEvent"); + else + pluginLog(instance, "loseFocusEvent"); + } + return 1; + + case NPCocoaEventDrawRect: { + if (obj->onPaintEvent) + executeScript(obj, obj->onPaintEvent); + return 1; + } + + case NPCocoaEventKeyDown: + if (obj->eventLogging && event->data.key.characters) + pluginLog(instance, "keyDown '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0)); + if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + return 1; + + case NPCocoaEventKeyUp: + if (obj->eventLogging && event->data.key.characters) { + pluginLog(instance, "keyUp '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0)); + if (obj->testKeyboardFocusForPlugins) { + obj->eventLogging = false; + obj->testKeyboardFocusForPlugins = FALSE; + executeScript(obj, "layoutTestController.notifyDone();"); + } + } + return 1; + + case NPCocoaEventFlagsChanged: + return 1; + + case NPCocoaEventMouseDown: + if (obj->eventLogging) { + pluginLog(instance, "mouseDown at (%d, %d)", + (int)event->data.mouse.pluginX, + (int)event->data.mouse.pluginY); + } + if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + return 1; + case NPCocoaEventMouseUp: + if (obj->eventLogging) { + pluginLog(instance, "mouseUp at (%d, %d)", + (int)event->data.mouse.pluginX, + (int)event->data.mouse.pluginY); + } + return 1; + + case NPCocoaEventMouseMoved: + case NPCocoaEventMouseEntered: + case NPCocoaEventMouseExited: + case NPCocoaEventMouseDragged: + case NPCocoaEventScrollWheel: + case NPCocoaEventTextInput: + return 1; + } + + return 0; +} + +#endif // XP_MACOSX + +#ifdef XP_UNIX + +static char keyEventToChar(XKeyEvent* event) +{ + char c = ' '; + XLookupString(event, &c, sizeof(c), 0, 0); + return c; +} + +static int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event) +{ + switch (event->type) { + case ButtonPress: + if (obj->eventLogging) + pluginLog(instance, "mouseDown at (%d, %d)", event->xbutton.x, event->xbutton.y); + if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case ButtonRelease: + if (obj->eventLogging) + pluginLog(instance, "mouseUp at (%d, %d)", event->xbutton.x, event->xbutton.y); + break; + case KeyPress: + // FIXME: extract key code + if (obj->eventLogging) + pluginLog(instance, "keyDown '%c'", keyEventToChar(&event->xkey)); + if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case KeyRelease: + // FIXME: extract key code + if (obj->eventLogging) + pluginLog(instance, "keyUp '%c'", keyEventToChar(&event->xkey)); + break; + case GraphicsExpose: + if (obj->eventLogging) + pluginLog(instance, "updateEvt"); + if (obj->onPaintEvent) + executeScript(obj, obj->onPaintEvent); + break; + // NPAPI events + case FocusIn: + if (obj->eventLogging) + pluginLog(instance, "getFocusEvent"); + break; + case FocusOut: + if (obj->eventLogging) + pluginLog(instance, "loseFocusEvent"); + break; + case EnterNotify: + case LeaveNotify: + case MotionNotify: + break; + default: + if (obj->eventLogging) + pluginLog(instance, "event %d", event->type); + } + + fflush(stdout); + return 0; +} +#endif // XP_UNIX + +#ifdef XP_WIN +static int16_t handleEventWin(NPP instance, PluginObject* obj, NPEvent* event) +{ + switch (event->event) { + case WM_PAINT: + if (obj->onPaintEvent) + executeScript(obj, obj->onPaintEvent); + break; + case WM_KEYDOWN: + if (obj->eventLogging) + pluginLog(instance, "keyDown '%c'", event->wParam); + if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case WM_CHAR: + break; + case WM_KEYUP: + if (obj->eventLogging) + pluginLog(instance, "keyUp '%c'", event->wParam); + if (obj->testKeyboardFocusForPlugins) { + obj->eventLogging = false; + obj->testKeyboardFocusForPlugins = FALSE; + executeScript(obj, "layoutTestController.notifyDone();"); + } + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + if (obj->eventLogging) + pluginLog(instance, "mouseDown at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam)); + if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + if (obj->eventLogging) + pluginLog(instance, "mouseUp at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam)); + break; + case WM_SETFOCUS: + if (obj->eventLogging) + pluginLog(instance, "getFocusEvent"); + break; + case WM_KILLFOCUS: + if (obj->eventLogging) + pluginLog(instance, "loseFocusEvent"); + break; + } + return 0; +} +#endif // XP_WIN + +int16_t NPP_HandleEvent(NPP instance, void *event) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + if (obj->pluginTest->NPP_HandleEvent(event) == 1) + return 1; + +#ifdef XP_MACOSX +#ifndef NP_NO_CARBON + if (obj->eventModel == NPEventModelCarbon) + return handleEventCarbon(instance, obj, static_cast<EventRecord*>(event)); +#endif + + assert(obj->eventModel == NPEventModelCocoa); + return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event)); +#elif defined(XP_UNIX) + return handleEventX11(instance, obj, static_cast<XEvent*>(event)); +#elif defined(XP_WIN) + return handleEventWin(instance, obj, static_cast<NPEvent*>(event)); +#else + // FIXME: Implement for other platforms. + return 0; +#endif // XP_MACOSX +} + +void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + if (obj->pluginTest->NPP_URLNotify(url, reason, notifyData)) + return; + + if (obj->onURLNotify) + executeScript(obj, obj->onURLNotify); + + handleCallback(obj, url, reason, notifyData); +} + +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ +#ifdef XP_UNIX + if (variable == NPPVpluginNameString) { + *((char **)value) = const_cast<char*>("WebKit Test PlugIn"); + return NPERR_NO_ERROR; + } + if (variable == NPPVpluginDescriptionString) { + *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit"); + return NPERR_NO_ERROR; + } + if (variable == NPPVpluginNeedsXEmbed) { + *((NPBool *)value) = TRUE; + return NPERR_NO_ERROR; + } +#endif + + if (!instance) + return NPERR_GENERIC_ERROR; + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + // First, check if the PluginTest object supports getting this value. + if (obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR) + return NPERR_NO_ERROR; + + if (variable == NPPVpluginScriptableNPObject) { + void **v = (void **)value; + // Return value is expected to be retained + browser->retainobject((NPObject *)obj); + *v = obj; + return NPERR_NO_ERROR; + } + +#ifdef XP_MACOSX + if (variable == NPPVpluginCoreAnimationLayer) { + if (!obj->coreAnimationLayer) + return NPERR_GENERIC_ERROR; + + void **v = (void **)value; + *v = (void*)CFRetain(obj->coreAnimationLayer); + return NPERR_NO_ERROR; + } +#endif + + return NPERR_GENERIC_ERROR; +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + return obj->pluginTest->NPP_SetValue(variable, value); +} + +#ifdef XP_UNIX +extern "C" +const char* NP_GetMIMEDescription(void) +{ + return "application/x-webkit-test-netscape:testnetscape:test netscape content;image/png:png:PNG image"; +} + +extern "C" +NPError NP_GetValue(NPP instance, NPPVariable variable, void* value) +{ + return NPP_GetValue(instance, variable, value); +} +#endif diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp new file mode 100644 index 000000000..39c6365a6 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h" + +#include <string.h> +#include <vector> + +using namespace std; + +// Test that evaluating JavaScript that removes the plug-in from the page +// destroys the plug-in asynchronously. +class CallJSThatDestroysPlugin : public PluginTest { +public: + CallJSThatDestroysPlugin(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_isDestroyed(false) + , m_window(0) + { + } + ~CallJSThatDestroysPlugin(); + + void runTest(); + +private: + virtual NPError NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*); + virtual NPError NPP_Destroy(NPSavedData**); + + bool m_isDestroyed; + HWND m_window; +}; + +static PluginTest::Register<CallJSThatDestroysPlugin> registrar("call-javascript-that-destroys-plugin"); + +static const LPCWSTR pluginTestProperty = L"PluginTestProperty"; +static const UINT runTestWindowMessage = WM_USER + 1; +static const LPCWSTR messageWindowClassName = L"CallJSThatDestroysPluginMessageWindow"; + +CallJSThatDestroysPlugin::~CallJSThatDestroysPlugin() +{ + ::RemovePropW(m_window, pluginTestProperty); + ::DestroyWindow(m_window); +} + +void CallJSThatDestroysPlugin::runTest() +{ + executeScript("var plugin = document.getElementsByTagName('embed')[0]; plugin.parentElement.removeChild(plugin);"); + if (!m_isDestroyed) + log("Success: executed script, and plug-in is not yet destroyed."); +} + +static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg != runTestWindowMessage) + return ::DefWindowProcW(hwnd, msg, wParam, lParam); + + CallJSThatDestroysPlugin* pluginTest = reinterpret_cast<CallJSThatDestroysPlugin*>(::GetPropW(hwnd, pluginTestProperty)); + pluginTest->runTest(); + return 0; +} + +NPError CallJSThatDestroysPlugin::NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*) +{ + assert(!m_window); + + waitUntilDone(); + + WNDCLASSEXW wndClass = {0}; + wndClass.cbSize = sizeof(wndClass); + wndClass.lpfnWndProc = wndProc; + wndClass.hCursor = LoadCursor(0, IDC_ARROW); + wndClass.hInstance = GetModuleHandle(0); + wndClass.lpszClassName = messageWindowClassName; + + ::RegisterClassExW(&wndClass); + m_window = ::CreateWindowExW(0, messageWindowClassName, 0, WS_CHILD, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandle(0), 0); + + ::SetPropW(m_window, pluginTestProperty, reinterpret_cast<HANDLE>(this)); + ::PostMessageW(m_window, runTestWindowMessage, 0, 0); + + return NPERR_NO_ERROR; +} + +NPError CallJSThatDestroysPlugin::NPP_Destroy(NPSavedData**) +{ + m_isDestroyed = true; + log("Plug-in destroyed."); + notifyDone(); + return NPERR_NO_ERROR; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def new file mode 100644 index 000000000..ac41e7ede --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def @@ -0,0 +1,6 @@ +LIBRARY "npTestNetscapePlugin"
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc new file mode 100644 index 000000000..c0b38ee5f --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "windows.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""windows.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "Apple Inc."
+ VALUE "FileDescription", "Simple Netscape plug-in that handles test content for WebKit"
+ VALUE "FileExtents", "testnetscape|png"
+ VALUE "FileOpenName", "test netscape content|PNG image"
+ VALUE "LegalCopyright", "Copyright Apple Inc. 2007-2009"
+ VALUE "MIMEType", "application/x-webkit-test-netscape|image/png"
+ VALUE "OriginalFilename", "npTestNetscapePlugin.dll"
+ VALUE "ProductName", "WebKit Test PlugIn"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj new file mode 100644 index 000000000..28416b242 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj @@ -0,0 +1,556 @@ +<?xml version="1.0" encoding="windows-1251"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePlugin" + ProjectGUID="{C0737398-3565-439E-A2B8-AB2BE4D5430C}" + RootNamespace="TestNetscapePlugin" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginDebug.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginRelease.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Cairo_CFLite|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginDebugCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_All|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginDebugAll.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Production|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginProduction.vsprops" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Cairo_CFLite|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\TestNetscapePluginReleaseCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Tests" + > + <File + RelativePath=".\CallJSThatDestroysPlugin.cpp" + > + </File> + <File + RelativePath="..\Tests\DocumentOpenInDestroyStream.cpp" + > + </File> + <File + RelativePath="..\Tests\EvaluateJSAfterRemovingPluginElement.cpp" + > + </File> + <File + RelativePath="..\Tests\FormValue.cpp" + > + </File> + <File + RelativePath="..\Tests\GetURLNotifyWithURLThatFailsToLoad.cpp" + > + </File> + <File + RelativePath="..\Tests\GetURLWithJavaScriptURL.cpp" + > + </File> + <File + RelativePath="..\Tests\GetURLWithJavaScriptURLDestroyingPlugin.cpp" + > + </File> + <File + RelativePath="..\Tests\GetUserAgentWithNullNPPFromNPPNew.cpp" + > + </File> + <File + RelativePath="..\Tests\NPDeallocateCalledBeforeNPShutdown.cpp" + > + </File> + <File + RelativePath="..\Tests\NPPSetWindowCalledDuringDestruction.cpp" + > + </File> + <File + RelativePath="..\Tests\NPRuntimeObjectFromDestroyedPlugin.cpp" + > + </File> + <File + RelativePath="..\Tests\NPRuntimeRemoveProperty.cpp" + > + </File> + <File + RelativePath="..\Tests\NullNPPGetValuePointer.cpp" + > + </File> + <File + RelativePath="..\Tests\PassDifferentNPPStruct.cpp" + > + </File> + <File + RelativePath="..\Tests\PluginScriptableNPObjectInvokeDefault.cpp" + > + </File> + <File + RelativePath="..\Tests\PrivateBrowsing.cpp" + > + </File> + <Filter + Name="win" + > + <File + RelativePath="..\Tests\win\DrawsGradient.cpp" + > + </File> + <File + RelativePath="..\Tests\win\DumpWindowRect.cpp" + > + </File> + <File + RelativePath="..\Tests\win\GetValueNetscapeWindow.cpp" + > + </File> + <File + RelativePath="..\Tests\win\NPNInvalidateRectInvalidatesWindow.cpp" + > + </File> + <File + RelativePath="..\Tests\win\WindowGeometryInitializedBeforeSetWindow.cpp" + > + </File> + <File + RelativePath="..\Tests\win\WindowlessPaintRectCoordinates.cpp" + > + </File> + <File + RelativePath="..\Tests\win\WindowRegionIsSetToClipRect.cpp" + > + </File> + </Filter> + </Filter> + <Filter + Name="win" + > + <File + RelativePath=".\WindowedPluginTest.cpp" + > + </File> + <File + RelativePath=".\WindowedPluginTest.h" + > + </File> + <File + RelativePath=".\WindowGeometryTest.cpp" + > + </File> + <File + RelativePath=".\WindowGeometryTest.h" + > + </File> + </Filter> + <File + RelativePath="..\main.cpp" + > + </File> + <File + RelativePath="..\PluginObject.cpp" + > + </File> + <File + RelativePath="..\PluginObject.h" + > + </File> + <File + RelativePath="..\PluginTest.cpp" + > + </File> + <File + RelativePath="..\PluginTest.h" + > + </File> + <File + RelativePath=".\resource.h" + > + </File> + <File + RelativePath=".\TestNetscapePlugin.def" + > + </File> + <File + RelativePath=".\TestNetscapePlugin.rc" + > + </File> + <File + RelativePath=".\TestNetscapePlugin_debug.def" + > + </File> + <File + RelativePath="..\TestObject.cpp" + > + </File> + <File + RelativePath="..\TestObject.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops new file mode 100644 index 000000000..4608b320a --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginCommon" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(ConfigurationBuildDir)\Include";"$(ConfigurationBuildDir)\Include\JavaScriptCore";"$(ConfigurationBuildDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include"" + PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf" + DisableSpecificWarnings="4819" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Msimg32.lib" + OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll" + ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops new file mode 100644 index 000000000..1d69ebbbf --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginDebug" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops new file mode 100644 index 000000000..92e186e30 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginDebugAll" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops new file mode 100644 index 000000000..f9b45b320 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginDebugCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd new file mode 100644 index 000000000..26707cac6 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd @@ -0,0 +1 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd new file mode 100644 index 000000000..a77077674 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd @@ -0,0 +1,6 @@ +%SystemDrive%\cygwin\bin\which.exe bash +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops new file mode 100644 index 000000000..a0699e3e2 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginProduction" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops new file mode 100644 index 000000000..a6ab3a2ee --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginRelease" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops new file mode 100644 index 000000000..99f879d77 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="TestNetscapePluginReleaseCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\TestNetscapePluginCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def new file mode 100644 index 000000000..158fb7c2b --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def @@ -0,0 +1,6 @@ +LIBRARY "npTestNetscapePlugin_debug" + +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp new file mode 100644 index 000000000..be7bfb31c --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h" + +#include "PluginObject.h" + +using namespace std; + +WindowGeometryTest::WindowGeometryTest(NPP npp, const string& identifier) + : WindowedPluginTest(npp, identifier) + , m_testHarnessWindowWasVisible(false) +{ +} + +void WindowGeometryTest::startTest() +{ + // In WebKit1, our window's window region will be set immediately. In WebKit2, it won't be set + // until the UI process paints. Since the UI process will also show our window when it paints, + // we can detect when the paint occurs (and thus when our window region should be set) by + // starting with our plugin element hidden, then making it visible and waiting for a + // WM_WINDOWPOSCHANGED event to tell us our window has been shown. + + waitUntilDone(); + + // If the test harness window isn't visible, we might not receive a WM_WINDOWPOSCHANGED message + // when our window is made visible. So we temporarily show the test harness window during this test. + showTestHarnessWindowIfNeeded(); + + // Make our window visible. (In WebKit2, this won't take effect immediately.) + executeScript("document.getElementsByTagName('embed')[0].style.visibility = 'visible';"); + + // We trigger a UI process paint after a slight delay to ensure that the UI process has + // received the "make the plugin window visible" message before it paints. + // FIXME: It would be nice to have a way to guarantee that the UI process had received that + // message before we triggered a paint. Hopefully that would let us get rid of this semi- + // arbitrary timeout. + ::SetTimer(window(), triggerPaintTimerID, 250, 0); +} + +void WindowGeometryTest::finishTest() +{ + performWindowGeometryTest(); + hideTestHarnessWindowIfNeeded(); + notifyDone(); +} + +void WindowGeometryTest::showTestHarnessWindowIfNeeded() +{ + HWND testHarnessWindow = this->testHarnessWindow(); + m_testHarnessWindowWasVisible = ::IsWindowVisible(testHarnessWindow); + if (m_testHarnessWindowWasVisible) + return; + ::ShowWindow(testHarnessWindow, SW_SHOWNA); +} + +void WindowGeometryTest::hideTestHarnessWindowIfNeeded() +{ + if (m_testHarnessWindowWasVisible) + return; + ::ShowWindow(testHarnessWindow(), SW_HIDE); +} + +LRESULT WindowGeometryTest::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) +{ + switch (message) { + case WM_TIMER: + if (wParam != triggerPaintTimerID) + break; + handled = true; + ::KillTimer(window(), wParam); + // Tell the UI process to paint. + ::PostMessageW(::GetParent(window()), WM_PAINT, 0, 0); + break; + case WM_WINDOWPOSCHANGED: { + WINDOWPOS* windowPos = reinterpret_cast<WINDOWPOS*>(lParam); + if (!(windowPos->flags & SWP_SHOWWINDOW)) + break; + finishTest(); + break; + } + + } + + return 0; +} + +NPError WindowGeometryTest::NPP_GetValue(NPPVariable variable, void* value) +{ + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *static_cast<NPObject**>(value) = ScriptObject::create(this); + + return NPERR_NO_ERROR; +} + +bool WindowGeometryTest::ScriptObject::hasMethod(NPIdentifier methodName) +{ + return methodName == pluginTest()->NPN_GetStringIdentifier("startTest"); +} + +bool WindowGeometryTest::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*) +{ + assert(identifier == pluginTest()->NPN_GetStringIdentifier("startTest")); + static_cast<WindowGeometryTest*>(pluginTest())->startTest(); + return true; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h new file mode 100644 index 000000000..4878a6941 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WindowGeometryTest_h +#define WindowGeometryTest_h + +#include "WindowedPluginTest.h" + +class WindowGeometryTest : public WindowedPluginTest { +public: + WindowGeometryTest(NPP, const std::string& identifier); + +private: + struct ScriptObject : Object<ScriptObject> { + bool hasMethod(NPIdentifier); + bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*); + }; + + static const UINT_PTR triggerPaintTimerID = 1; + + void startTest(); + void finishTest(); + + void showTestHarnessWindowIfNeeded(); + void hideTestHarnessWindowIfNeeded(); + + // For subclasses to implement + virtual void performWindowGeometryTest() = 0; + + // WindowedPluginTest + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); + + // PluginTest + virtual NPError NPP_GetValue(NPPVariable, void*); + + bool m_testHarnessWindowWasVisible; +}; + +#endif // WindowGeometryTest_h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp new file mode 100644 index 000000000..2e75ca162 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h" + +using namespace std; + +static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.WindowedPluginTest.InstancePointer"; + +WindowedPluginTest::WindowedPluginTest(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_window(0) + , m_originalWndProc(0) +{ +} + +HWND WindowedPluginTest::testHarnessWindow() const +{ + return ::GetAncestor(window(), GA_ROOT); +} + +NPError WindowedPluginTest::NPP_SetWindow(NPP instance, NPWindow* window) +{ + HWND newWindow = reinterpret_cast<HWND>(window->window); + if (newWindow == m_window) + return NPERR_NO_ERROR; + + if (m_window) { + ::RemovePropW(m_window, instancePointerProperty); + ::SetWindowLongPtr(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_originalWndProc)); + m_originalWndProc = 0; + } + + m_window = newWindow; + if (!m_window) + return NPERR_NO_ERROR; + + m_originalWndProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtrW(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(staticWndProc))); + ::SetPropW(m_window, instancePointerProperty, this); + + return NPERR_NO_ERROR; +} + +LRESULT WindowedPluginTest::staticWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WindowedPluginTest* instance = reinterpret_cast<WindowedPluginTest*>(::GetPropW(hwnd, instancePointerProperty)); + + bool handled = false; + LRESULT result = instance->wndProc(message, wParam, lParam, handled); + if (handled) + return result; + + return ::CallWindowProcW(instance->m_originalWndProc, hwnd, message, wParam, lParam); +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h new file mode 100644 index 000000000..b50746ae3 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WindowedPluginTest_h +#define WindowedPluginTest_h + +#include "PluginTest.h" + +class WindowedPluginTest : public PluginTest { +protected: + WindowedPluginTest(NPP, const std::string& identifier); + + HWND window() const { return m_window; } + HWND testHarnessWindow() const; + + // For derived classes to override + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled) = 0; + + // PluginTest + virtual NPError NPP_SetWindow(NPP, NPWindow*); + +private: + static LRESULT CALLBACK staticWndProc(HWND, UINT message, WPARAM, LPARAM); + + HWND m_window; + WNDPROC m_originalWndProc; +}; + +#endif // WindowedPluginTest_h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h new file mode 100644 index 000000000..b0ce34048 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by TestNetscapePlugin.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Tools/DumpRenderTree/WorkQueue.cpp b/Tools/DumpRenderTree/WorkQueue.cpp new file mode 100644 index 000000000..f38d81a34 --- /dev/null +++ b/Tools/DumpRenderTree/WorkQueue.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueue.h" + +#if PLATFORM(QT) +#include "WorkQueueItemQt.h" +#else +#include "WorkQueueItem.h" +#endif +#include <wtf/Assertions.h> + +static const unsigned queueLength = 1024; + +static WorkQueueItem* theQueue[queueLength]; +static unsigned startOfQueue; +static unsigned endOfQueue; + +WorkQueue* WorkQueue::shared() +{ + static WorkQueue* sharedInstance = new WorkQueue; + return sharedInstance; +} + +WorkQueue::WorkQueue() + : m_frozen(false) +{ +} + +void WorkQueue::queue(WorkQueueItem* item) +{ + ASSERT(endOfQueue < queueLength); + ASSERT(endOfQueue >= startOfQueue); + + if (m_frozen) { + delete item; + return; + } + + theQueue[endOfQueue++] = item; +} + +WorkQueueItem* WorkQueue::dequeue() +{ + ASSERT(endOfQueue >= startOfQueue); + + if (startOfQueue == endOfQueue) + return 0; + + return theQueue[startOfQueue++]; +} + +unsigned WorkQueue::count() +{ + return endOfQueue - startOfQueue; +} + +void WorkQueue::clear() +{ + for (unsigned i = startOfQueue; i < endOfQueue; ++i) { + delete theQueue[i]; + theQueue[i] = 0; + } + + startOfQueue = 0; + endOfQueue = 0; +} + +bool WorkQueue::processWork() +{ + bool startedLoad = false; + + while (!startedLoad && count()) { + WorkQueueItem* item = dequeue(); + ASSERT(item); + startedLoad = item->invoke(); + delete item; + } + + // If we're done and we didn't start a load, then we're really done, so return true. + return !startedLoad; +} diff --git a/Tools/DumpRenderTree/WorkQueue.h b/Tools/DumpRenderTree/WorkQueue.h new file mode 100644 index 000000000..649c6c1f5 --- /dev/null +++ b/Tools/DumpRenderTree/WorkQueue.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WorkQueue_h +#define WorkQueue_h + +class WorkQueueItem; + +class WorkQueue { +public: + static WorkQueue* shared(); + + void queue(WorkQueueItem*); + WorkQueueItem* dequeue(); + void clear(); + unsigned count(); + + void setFrozen(bool b) { m_frozen = b; } + + bool processWork(); // Returns true if all work is done, false if we started a load. + +private: + WorkQueue(); + + bool m_frozen; +}; + +#endif // !defined(WorkQueue_h) diff --git a/Tools/DumpRenderTree/WorkQueueItem.h b/Tools/DumpRenderTree/WorkQueueItem.h new file mode 100644 index 000000000..a5823c156 --- /dev/null +++ b/Tools/DumpRenderTree/WorkQueueItem.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WorkQueueItem_h +#define WorkQueueItem_h + +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSBase.h> + +class WorkQueueItem { +public: + virtual ~WorkQueueItem() { } + virtual bool invoke() const = 0; // Returns true if this started a load. +}; + +class LoadItem : public WorkQueueItem { +public: + LoadItem(const JSStringRef url, const JSStringRef target) + : m_url(url) + , m_target(target) + { + } + +private: + virtual bool invoke() const; + + JSRetainPtr<JSStringRef> m_url; + JSRetainPtr<JSStringRef> m_target; +}; + +class LoadHTMLStringItem : public WorkQueueItem { +public: + LoadHTMLStringItem(const JSStringRef content, const JSStringRef baseURL) + : m_content(content) + , m_baseURL(baseURL) + { + } + + LoadHTMLStringItem(const JSStringRef content, const JSStringRef baseURL, const JSStringRef unreachableURL) + : m_content(content) + , m_baseURL(baseURL) + , m_unreachableURL(unreachableURL) + { + } + +private: + virtual bool invoke() const; + + JSRetainPtr<JSStringRef> m_content; + JSRetainPtr<JSStringRef> m_baseURL; + JSRetainPtr<JSStringRef> m_unreachableURL; +}; + +class ReloadItem : public WorkQueueItem { +private: + virtual bool invoke() const; +}; + +class ScriptItem : public WorkQueueItem { +protected: + ScriptItem(const JSStringRef script) + : m_script(script) + { + } + +protected: + virtual bool invoke() const; + +private: + JSRetainPtr<JSStringRef> m_script; +}; + +class LoadingScriptItem : public ScriptItem { +public: + LoadingScriptItem(const JSStringRef script) + : ScriptItem(script) + { + } + +private: + virtual bool invoke() const { return ScriptItem::invoke(); } +}; + +class NonLoadingScriptItem : public ScriptItem { +public: + NonLoadingScriptItem(const JSStringRef script) + : ScriptItem(script) + { + } + +private: + virtual bool invoke() const { ScriptItem::invoke(); return false; } +}; + +class BackForwardItem : public WorkQueueItem { +protected: + BackForwardItem(int howFar) + : m_howFar(howFar) + { + } + +private: + virtual bool invoke() const; + + int m_howFar; +}; + +class BackItem : public BackForwardItem { +public: + BackItem(unsigned howFar) + : BackForwardItem(-howFar) + { + } +}; + +class ForwardItem : public BackForwardItem { +public: + ForwardItem(unsigned howFar) + : BackForwardItem(howFar) + { + } +}; + +#endif // !defined(WorkQueueItem_h) diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp new file mode 100644 index 000000000..c10a3a7dc --- /dev/null +++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * (C) 2010 Igalia S.L + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupportCairo.h" + +#include "DumpRenderTree.h" +#include "PixelDumpSupport.h" +#include <algorithm> +#include <ctype.h> +#include <wtf/Assertions.h> +#include <wtf/MD5.h> +#include <wtf/RefPtr.h> +#include <wtf/StringExtras.h> + +using namespace std; + +static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length) +{ + Vector<unsigned char>* in = reinterpret_cast<Vector<unsigned char>*>(closure); + in->append(data, length); + return CAIRO_STATUS_SUCCESS; +} + +static void printPNG(cairo_surface_t* image, const char* checksum) +{ + Vector<unsigned char> pixelData; + // Only PNG output is supported for now. + cairo_surface_write_to_png_stream(image, writeFunction, &pixelData); + + const size_t dataLength = pixelData.size(); + const unsigned char* data = pixelData.data(); + + printPNG(data, dataLength, checksum); +} + +void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33]) +{ + cairo_t* bitmapContext = context->cairoContext(); + cairo_surface_t* surface = cairo_get_target(bitmapContext); + + ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32); // ImageDiff assumes 32 bit RGBA, we must as well. + + size_t pixelsHigh = cairo_image_surface_get_height(surface); + size_t pixelsWide = cairo_image_surface_get_width(surface); + size_t bytesPerRow = cairo_image_surface_get_stride(surface); + + MD5 md5Context; + unsigned char* bitmapData = static_cast<unsigned char*>(cairo_image_surface_get_data(surface)); + for (unsigned row = 0; row < pixelsHigh; row++) { + md5Context.addBytes(bitmapData, 4 * pixelsWide); + bitmapData += bytesPerRow; + } + Vector<uint8_t, 16> hash; + md5Context.checksum(hash); + + snprintf(hashString, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], + hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]); +} + +void dumpBitmap(BitmapContext* context, const char* checksum) +{ + cairo_surface_t* surface = cairo_get_target(context->cairoContext()); + printPNG(surface, checksum); +} diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h new file mode 100644 index 000000000..071e874d0 --- /dev/null +++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupportCairo_h +#define PixelDumpSupportCairo_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#if PLATFORM(WIN) +#include <windows.h> +#include <cairo-win32.h> +#elif PLATFORM(GTK) || PLATFORM(EFL) +#include <cairo.h> +#endif + +#if PLATFORM(WIN) +typedef HBITMAP PlatformBitmapBuffer; +#else +typedef void* PlatformBitmapBuffer; +#endif + +class BitmapContext : public RefCounted<BitmapContext> { +public: + static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, cairo_t* context) + { + return adoptRef(new BitmapContext(buffer, context)); + } + + ~BitmapContext() + { + if (m_buffer) +#if PLATFORM(WIN) + DeleteObject(m_buffer); +#else + free(m_buffer); +#endif + cairo_destroy(m_context); + } + + cairo_t* cairoContext() const { return m_context; } + +private: + + BitmapContext(PlatformBitmapBuffer buffer, cairo_t* context) + : m_buffer(buffer) + , m_context(context) + { + } + + PlatformBitmapBuffer m_buffer; + cairo_t* m_context; +}; + +#endif // PixelDumpSupportCairo_h diff --git a/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp new file mode 100644 index 000000000..33dc28a4c --- /dev/null +++ b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WebArchiveDumpSupport.h" + +#include <CoreFoundation/CoreFoundation.h> +#include <CFNetwork/CFNetwork.h> +#include <wtf/RetainPtr.h> + +extern "C" { + +CFURLRef CFURLResponseGetURL(CFURLResponseRef response); +CFStringRef CFURLResponseGetMIMEType(CFURLResponseRef response); +CFStringRef CFURLResponseGetTextEncodingName(CFURLResponseRef response); +SInt64 CFURLResponseGetExpectedContentLength(CFURLResponseRef response); +CFHTTPMessageRef CFURLResponseGetHTTPResponse(CFURLResponseRef response); + +CFTypeID CFURLResponseGetTypeID(void); + +} + +static void convertMIMEType(CFMutableStringRef mimeType) +{ +#ifdef BUILDING_ON_LEOPARD + // Workaround for <rdar://problem/5539824> on Leopard + if (CFStringCompare(mimeType, CFSTR("text/xml"), kCFCompareAnchored | kCFCompareCaseInsensitive) == kCFCompareEqualTo) + CFStringReplaceAll(mimeType, CFSTR("application/xml")); +#endif + // Workaround for <rdar://problem/6234318> with Dashcode 2.0 + if (CFStringCompare(mimeType, CFSTR("application/x-javascript"), kCFCompareAnchored | kCFCompareCaseInsensitive) == kCFCompareEqualTo) + CFStringReplaceAll(mimeType, CFSTR("text/javascript")); +} + +static void convertWebResourceDataToString(CFMutableDictionaryRef resource) +{ + CFMutableStringRef mimeType = (CFMutableStringRef)CFDictionaryGetValue(resource, CFSTR("WebResourceMIMEType")); + CFStringLowercase(mimeType, CFLocaleGetSystem()); + convertMIMEType(mimeType); + + CFArrayRef supportedMIMETypes = supportedNonImageMIMETypes(); + if (CFStringHasPrefix(mimeType, CFSTR("text/")) || CFArrayContainsValue(supportedMIMETypes, CFRangeMake(0, CFArrayGetCount(supportedMIMETypes)), mimeType)) { + CFStringRef textEncodingName = static_cast<CFStringRef>(CFDictionaryGetValue(resource, CFSTR("WebResourceTextEncodingName"))); + CFStringEncoding stringEncoding; + if (textEncodingName && CFStringGetLength(textEncodingName)) + stringEncoding = CFStringConvertIANACharSetNameToEncoding(textEncodingName); + else + stringEncoding = kCFStringEncodingUTF8; + + CFDataRef data = static_cast<CFDataRef>(CFDictionaryGetValue(resource, CFSTR("WebResourceData"))); + RetainPtr<CFStringRef> dataAsString(AdoptCF, CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, stringEncoding)); + if (dataAsString) + CFDictionarySetValue(resource, CFSTR("WebResourceData"), dataAsString.get()); + } +} + +static void normalizeHTTPResponseHeaderFields(CFMutableDictionaryRef fields) +{ + // Normalize headers + if (CFDictionaryContainsKey(fields, CFSTR("Date"))) + CFDictionarySetValue(fields, CFSTR("Date"), CFSTR("Sun, 16 Nov 2008 17:00:00 GMT")); + if (CFDictionaryContainsKey(fields, CFSTR("Last-Modified"))) + CFDictionarySetValue(fields, CFSTR("Last-Modified"), CFSTR("Sun, 16 Nov 2008 16:55:00 GMT")); + if (CFDictionaryContainsKey(fields, CFSTR("Etag"))) + CFDictionarySetValue(fields, CFSTR("Etag"), CFSTR("\"301925-21-45c7d72d3e780\"")); + if (CFDictionaryContainsKey(fields, CFSTR("Server"))) + CFDictionarySetValue(fields, CFSTR("Server"), CFSTR("Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l PHP/5.2.6")); + + // Remove headers + CFDictionaryRemoveValue(fields, CFSTR("Connection")); + CFDictionaryRemoveValue(fields, CFSTR("Keep-Alive")); +} + +static void normalizeWebResourceURL(CFMutableStringRef webResourceURL) +{ + static CFIndex fileUrlLength = CFStringGetLength(CFSTR("file://")); + CFRange layoutTestsWebArchivePathRange = CFStringFind(webResourceURL, CFSTR("/LayoutTests/"), kCFCompareBackwards); + if (layoutTestsWebArchivePathRange.location == kCFNotFound) + return; + CFRange currentWorkingDirectoryRange = CFRangeMake(fileUrlLength, layoutTestsWebArchivePathRange.location - fileUrlLength); + CFStringReplace(webResourceURL, currentWorkingDirectoryRange, CFSTR("")); +} + +static void convertWebResourceResponseToDictionary(CFMutableDictionaryRef propertyList) +{ + CFDataRef responseData = static_cast<CFDataRef>(CFDictionaryGetValue(propertyList, CFSTR("WebResourceResponse"))); // WebResourceResponseKey in WebResource.m + if (CFGetTypeID(responseData) != CFDataGetTypeID()) + return; + + RetainPtr<CFURLResponseRef> response(AdoptCF, createCFURLResponseFromResponseData(responseData)); + if (!response) + return; + + RetainPtr<CFMutableDictionaryRef> responseDictionary(AdoptCF, CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + + RetainPtr<CFMutableStringRef> urlString(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFURLGetString(CFURLResponseGetURL(response.get())))); + normalizeWebResourceURL(urlString.get()); + CFDictionarySetValue(responseDictionary.get(), CFSTR("URL"), urlString.get()); + + RetainPtr<CFMutableStringRef> mimeTypeString(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFURLResponseGetMIMEType(response.get()))); + convertMIMEType(mimeTypeString.get()); + CFDictionarySetValue(responseDictionary.get(), CFSTR("MIMEType"), mimeTypeString.get()); + + CFStringRef textEncodingName = CFURLResponseGetTextEncodingName(response.get()); + if (textEncodingName) + CFDictionarySetValue(responseDictionary.get(), CFSTR("textEncodingName"), textEncodingName); + + SInt64 expectedContentLength = CFURLResponseGetExpectedContentLength(response.get()); + RetainPtr<CFNumberRef> expectedContentLengthNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &expectedContentLength)); + CFDictionarySetValue(responseDictionary.get(), CFSTR("expectedContentLength"), expectedContentLengthNumber.get()); + + if (CFHTTPMessageRef httpMessage = CFURLResponseGetHTTPResponse(response.get())) { + RetainPtr<CFDictionaryRef> allHeaders(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpMessage)); + RetainPtr<CFMutableDictionaryRef> allHeaderFields(AdoptCF, CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, allHeaders.get())); + normalizeHTTPResponseHeaderFields(allHeaderFields.get()); + CFDictionarySetValue(responseDictionary.get(), CFSTR("allHeaderFields"), allHeaderFields.get()); + + CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(httpMessage); + RetainPtr<CFNumberRef> statusCodeNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &statusCode)); + CFDictionarySetValue(responseDictionary.get(), CFSTR("statusCode"), statusCodeNumber.get()); + } + + CFDictionarySetValue(propertyList, CFSTR("WebResourceResponse"), responseDictionary.get()); +} + +static CFComparisonResult compareResourceURLs(const void *val1, const void *val2, void *context) +{ + CFStringRef url1 = static_cast<CFStringRef>(CFDictionaryGetValue(static_cast<CFDictionaryRef>(val1), CFSTR("WebResourceURL"))); + CFStringRef url2 = static_cast<CFStringRef>(CFDictionaryGetValue(static_cast<CFDictionaryRef>(val2), CFSTR("WebResourceURL"))); + + return CFStringCompare(url1, url2, kCFCompareAnchored); +} + +CFStringRef createXMLStringFromWebArchiveData(CFDataRef webArchiveData) +{ + CFErrorRef error = 0; + CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; + +#ifdef BUILDING_ON_LEOPARD + CFIndex bytesCount = CFDataGetLength(webArchiveData); + RetainPtr<CFReadStreamRef> readStream(AdoptCF, CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, CFDataGetBytePtr(webArchiveData), bytesCount, kCFAllocatorNull)); + CFReadStreamOpen(readStream.get()); + RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, (CFMutableDictionaryRef)CFPropertyListCreateFromStream(kCFAllocatorDefault, readStream.get(), bytesCount, kCFPropertyListMutableContainersAndLeaves, &format, 0)); + CFReadStreamClose(readStream.get()); +#else + RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, (CFMutableDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorDefault, webArchiveData, kCFPropertyListMutableContainersAndLeaves, &format, &error)); +#endif + + if (!propertyList) { + if (error) + return CFErrorCopyDescription(error); + return static_cast<CFStringRef>(CFRetain(CFSTR("An unknown error occurred converting data to property list."))); + } + + RetainPtr<CFMutableArrayRef> resources(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); + CFArrayAppendValue(resources.get(), propertyList.get()); + + while (CFArrayGetCount(resources.get())) { + RetainPtr<CFMutableDictionaryRef> resourcePropertyList = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(resources.get(), 0); + CFArrayRemoveValueAtIndex(resources.get(), 0); + + CFMutableDictionaryRef mainResource = (CFMutableDictionaryRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebMainResource")); + normalizeWebResourceURL((CFMutableStringRef)CFDictionaryGetValue(mainResource, CFSTR("WebResourceURL"))); + convertWebResourceDataToString(mainResource); + + // Add subframeArchives to list for processing + CFMutableArrayRef subframeArchives = (CFMutableArrayRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebSubframeArchives")); // WebSubframeArchivesKey in WebArchive.m + if (subframeArchives) + CFArrayAppendArray(resources.get(), subframeArchives, CFRangeMake(0, CFArrayGetCount(subframeArchives))); + + CFMutableArrayRef subresources = (CFMutableArrayRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebSubresources")); // WebSubresourcesKey in WebArchive.m + if (!subresources) + continue; + + CFIndex subresourcesCount = CFArrayGetCount(subresources); + for (CFIndex i = 0; i < subresourcesCount; ++i) { + CFMutableDictionaryRef subresourcePropertyList = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(subresources, i); + normalizeWebResourceURL((CFMutableStringRef)CFDictionaryGetValue(subresourcePropertyList, CFSTR("WebResourceURL"))); + convertWebResourceResponseToDictionary(subresourcePropertyList); + convertWebResourceDataToString(subresourcePropertyList); + } + + // Sort the subresources so they're always in a predictable order for the dump + CFArraySortValues(subresources, CFRangeMake(0, CFArrayGetCount(subresources)), compareResourceURLs, 0); + } + + error = 0; + +#ifdef BUILDING_ON_LEOPARD + RetainPtr<CFDataRef> xmlData(AdoptCF, CFPropertyListCreateXMLData(kCFAllocatorDefault, propertyList.get())); +#else + RetainPtr<CFDataRef> xmlData(AdoptCF, CFPropertyListCreateData(kCFAllocatorDefault, propertyList.get(), kCFPropertyListXMLFormat_v1_0, 0, &error)); +#endif + + if (!xmlData) { + if (error) + return CFErrorCopyDescription(error); + return static_cast<CFStringRef>(CFRetain(CFSTR("An unknown error occurred converting property list to data."))); + } + + RetainPtr<CFStringRef> xmlString(AdoptCF, CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, xmlData.get(), kCFStringEncodingUTF8)); + RetainPtr<CFMutableStringRef> string(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, xmlString.get())); + + // Replace "Apple Computer" with "Apple" in the DTD declaration. + CFStringFindAndReplace(string.get(), CFSTR("-//Apple Computer//"), CFSTR("-//Apple//"), CFRangeMake(0, CFStringGetLength(string.get())), 0); + + return string.leakRef(); +} diff --git a/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h new file mode 100644 index 000000000..00c58184e --- /dev/null +++ b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 WebArchiveDumpSupport_h +#define WebArchiveDumpSupport_h + +#include <CoreFoundation/CoreFoundation.h> + +typedef struct _CFURLResponse* CFURLResponseRef; + +CFStringRef createXMLStringFromWebArchiveData(CFDataRef webArchiveData); + +// MARK: - +// MARK: Platform-specific methods + +CFURLResponseRef createCFURLResponseFromResponseData(CFDataRef responseData); +CFArrayRef supportedNonImageMIMETypes(); + +#endif /* WebArchiveDumpSupport_h */ diff --git a/Tools/DumpRenderTree/cg/ImageDiffCG.cpp b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp new file mode 100644 index 000000000..07e51130c --- /dev/null +++ b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#define min min + +// FIXME: We need to be able to include these defines from a config.h somewhere. +#define JS_EXPORT_PRIVATE +#define WTF_EXPORT_PRIVATE + +#include <stdio.h> +#include <wtf/Platform.h> +#include <wtf/RetainPtr.h> + +#if PLATFORM(WIN) +#include <winsock2.h> +#include <windows.h> +#include <fcntl.h> +#include <io.h> +#include <wtf/MathExtras.h> +#endif + +#include <CoreGraphics/CGBitmapContext.h> +#include <CoreGraphics/CGImage.h> +#include <ImageIO/CGImageDestination.h> + +#if PLATFORM(MAC) +#include <LaunchServices/UTCoreTypes.h> +#endif + +#ifndef CGFLOAT_DEFINED +#ifdef __LP64__ +typedef double CGFloat; +#else +typedef float CGFloat; +#endif +#define CGFLOAT_DEFINED 1 +#endif + +using namespace std; + +#if PLATFORM(WIN) +static inline float strtof(const char *nptr, char **endptr) +{ + return strtod(nptr, endptr); +} +static const CFStringRef kUTTypePNG = CFSTR("public.png"); +#endif + +static RetainPtr<CGImageRef> createImageFromStdin(int bytesRemaining) +{ + unsigned char buffer[2048]; + RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining)); + + while (bytesRemaining > 0) { + size_t bytesToRead = min(bytesRemaining, 2048); + size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); + CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead)); + bytesRemaining -= static_cast<int>(bytesRead); + } + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault)); +} + +static void releaseMallocBuffer(void* info, const void* data, size_t size) +{ + free((void*)data); +} + +static RetainPtr<CGImageRef> createDifferenceImage(CGImageRef baseImage, CGImageRef testImage, float& difference) +{ + size_t width = CGImageGetWidth(baseImage); + size_t height = CGImageGetHeight(baseImage); + size_t rowBytes = width * 4; + + // Draw base image in bitmap context + void* baseBuffer = calloc(height, rowBytes); + RetainPtr<CGContextRef> baseContext(AdoptCF, CGBitmapContextCreate(baseBuffer, width, height, 8, rowBytes, CGImageGetColorSpace(baseImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + CGContextDrawImage(baseContext.get(), CGRectMake(0, 0, width, height), baseImage); + + // Draw test image in bitmap context + void* buffer = calloc(height, rowBytes); + RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(buffer, width, height, 8, rowBytes, CGImageGetColorSpace(testImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + CGContextDrawImage(context.get(), CGRectMake(0, 0, width, height), testImage); + + // Compare the content of the 2 bitmaps + void* diffBuffer = malloc(width * height); + float count = 0.0f; + float sum = 0.0f; + float maxDistance = 0.0f; + unsigned char* basePixel = (unsigned char*)baseBuffer; + unsigned char* pixel = (unsigned char*)buffer; + unsigned char* diff = (unsigned char*)diffBuffer; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + float red = (pixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]); + float green = (pixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]); + float blue = (pixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]); + float alpha = (pixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]); + float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; + + *diff++ = (unsigned char)(distance * 255.0f); + + if (distance >= 1.0f / 255.0f) { + count += 1.0f; + sum += distance; + if (distance > maxDistance) + maxDistance = distance; + } + + basePixel += 4; + pixel += 4; + } + } + + // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image + if (count > 0.0f) + difference = 100.0f * sum / (height * width); + else + difference = 0.0f; + + RetainPtr<CGImageRef> diffImage; + // Generate a normalized diff image if there is any difference + if (difference > 0.0f) { + if (maxDistance < 1.0f) { + diff = (unsigned char*)diffBuffer; + for(size_t p = 0; p < height * width; ++p) + diff[p] = diff[p] / maxDistance; + } + + static CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray(); + RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithData(0, diffBuffer, width * height, releaseMallocBuffer)); + diffImage.adoptCF(CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider.get(), 0, false, kCGRenderingIntentDefault)); + } + else + free(diffBuffer); + + // Destroy drawing buffers + if (buffer) + free(buffer); + if (baseBuffer) + free(baseBuffer); + + return diffImage; +} + +static inline bool imageHasAlpha(CGImageRef image) +{ + CGImageAlphaInfo info = CGImageGetAlphaInfo(image); + + return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst); +} + +int main(int argc, const char* argv[]) +{ +#if PLATFORM(WIN) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + + float tolerance = 0.0f; + + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { + if (i >= argc - 1) + exit(1); + tolerance = strtof(argv[i + 1], 0); + ++i; + continue; + } + } + + char buffer[2048]; + RetainPtr<CGImageRef> actualImage; + RetainPtr<CGImageRef> baselineImage; + + while (fgets(buffer, sizeof(buffer), stdin)) { + // remove the CR + char* newLineCharacter = strchr(buffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strncmp("Content-Length: ", buffer, 16)) { + strtok(buffer, " "); + int imageSize = strtol(strtok(0, " "), 0, 10); + + if (imageSize > 0 && !actualImage) + actualImage = createImageFromStdin(imageSize); + else if (imageSize > 0 && !baselineImage) + baselineImage = createImageFromStdin(imageSize); + else + fputs("error, image size must be specified.\n", stderr); + } + + if (actualImage && baselineImage) { + RetainPtr<CGImageRef> diffImage; + float difference = 100.0f; + + if ((CGImageGetWidth(actualImage.get()) == CGImageGetWidth(baselineImage.get())) && (CGImageGetHeight(actualImage.get()) == CGImageGetHeight(baselineImage.get())) && (imageHasAlpha(actualImage.get()) == imageHasAlpha(baselineImage.get()))) { + diffImage = createDifferenceImage(actualImage.get(), baselineImage.get(), difference); // difference is passed by reference + if (difference <= tolerance) + difference = 0.0f; + else { + difference = roundf(difference * 100.0f) / 100.0f; + difference = max(difference, 0.01f); // round to 2 decimal places + } + } else + fputs("error, test and reference image have different properties.\n", stderr); + + if (difference > 0.0f) { + if (diffImage) { + RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); + RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); + CGImageDestinationAddImage(imageDest.get(), diffImage.get(), 0); + CGImageDestinationFinalize(imageDest.get()); + printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); + fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); + } + + fprintf(stdout, "diff: %01.2f%% failed\n", difference); + } else + fprintf(stdout, "diff: %01.2f%% passed\n", difference); + + actualImage = 0; + baselineImage = 0; + } + + fflush(stdout); + } + + return 0; +} diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp new file mode 100644 index 000000000..bf59b03ec --- /dev/null +++ b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupportCG.h" + +#include "DumpRenderTree.h" +#include "PixelDumpSupport.h" +#include <ImageIO/CGImageDestination.h> +#include <algorithm> +#include <ctype.h> +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> +#include <wtf/StringExtras.h> + +#if PLATFORM(WIN) +#include "MD5.h" +#elif PLATFORM(MAC) +#include <LaunchServices/UTCoreTypes.h> +#define COMMON_DIGEST_FOR_OPENSSL +#include <CommonCrypto/CommonDigest.h> +#endif + +using namespace std; + +#if PLATFORM(WIN) +static const CFStringRef kUTTypePNG = CFSTR("public.png"); +#endif + +static void printPNG(CGImageRef image, const char* checksum) +{ + RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); + RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); + CGImageDestinationAddImage(imageDest.get(), image, 0); + CGImageDestinationFinalize(imageDest.get()); + + const UInt8* data = CFDataGetBytePtr(imageData.get()); + CFIndex dataLength = CFDataGetLength(imageData.get()); + + printPNG(static_cast<const unsigned char*>(data), static_cast<size_t>(dataLength), checksum); +} + +void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33]) +{ + CGContextRef bitmapContext = context->cgContext(); + + ASSERT(CGBitmapContextGetBitsPerPixel(bitmapContext) == 32); // ImageDiff assumes 32 bit RGBA, we must as well. + size_t pixelsHigh = CGBitmapContextGetHeight(bitmapContext); + size_t pixelsWide = CGBitmapContextGetWidth(bitmapContext); + size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext); + + // We need to swap the bytes to ensure consistent hashes independently of endianness + MD5_CTX md5Context; + MD5_Init(&md5Context); + unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext)); +#if PLATFORM(MAC) + if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) { + for (unsigned row = 0; row < pixelsHigh; row++) { + uint32_t buffer[pixelsWide]; + for (unsigned column = 0; column < pixelsWide; column++) + buffer[column] = OSReadLittleInt32(bitmapData, 4 * column); + MD5_Update(&md5Context, buffer, 4 * pixelsWide); + bitmapData += bytesPerRow; + } + } else +#endif + { + for (unsigned row = 0; row < pixelsHigh; row++) { + MD5_Update(&md5Context, bitmapData, 4 * pixelsWide); + bitmapData += bytesPerRow; + } + } + unsigned char hash[16]; + MD5_Final(hash, &md5Context); + + hashString[0] = '\0'; + for (int i = 0; i < 16; i++) + snprintf(hashString, 33, "%s%02x", hashString, hash[i]); +} + +void dumpBitmap(BitmapContext* context, const char* checksum) +{ + RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context->cgContext())); + printPNG(image.get(), checksum); +} diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h new file mode 100644 index 000000000..f0c974631 --- /dev/null +++ b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupportCG_h +#define PixelDumpSupportCG_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> + +#if PLATFORM(WIN) +#include <windows.h> +#endif + +typedef struct CGContext* CGContextRef; + +#if PLATFORM(MAC) +typedef void* PlatformBitmapBuffer; +#elif PLATFORM(WIN) +typedef HBITMAP PlatformBitmapBuffer; +#endif + +class BitmapContext : public RefCounted<BitmapContext> { +public: + static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, CGContextRef context) + { + return adoptRef(new BitmapContext(buffer, context)); + } + + ~BitmapContext() + { + if (m_buffer) +#if PLATFORM(MAC) + free(m_buffer); +#elif PLATFORM(WIN) + DeleteObject(m_buffer); +#endif + } + + CGContextRef cgContext() const { return m_context.get(); } + +private: + + BitmapContext(PlatformBitmapBuffer buffer, CGContextRef context) + : m_buffer(buffer) + , m_context(AdoptCF, context) + { + } + + PlatformBitmapBuffer m_buffer; + RetainPtr<CGContextRef> m_context; + +}; + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect); + +#endif // PixelDumpSupportCG_h diff --git a/Tools/DumpRenderTree/chromium/AccessibilityController.cpp b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp new file mode 100644 index 000000000..860a747aa --- /dev/null +++ b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp @@ -0,0 +1,151 @@ +/* + * 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 "WebAccessibilityObject.h" +#include "WebFrame.h" +#include "platform/WebString.h" +#include "WebView.h" + +using namespace WebKit; + +AccessibilityController::AccessibilityController(TestShell* shell) + : m_logAccessibilityEvents(false) + , m_shell(shell) +{ + + bindMethod("logAccessibilityEvents", &AccessibilityController::logAccessibilityEventsCallback); + bindMethod("addNotificationListener", &AccessibilityController::addNotificationListenerCallback); + bindMethod("removeNotificationListener", &AccessibilityController::removeNotificationListenerCallback); + + bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback); + bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback); + + bindFallbackMethod(&AccessibilityController::fallbackCallback); +} + +void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname) +{ + WebAccessibilityObject::enableAccessibility(); + CppBoundClass::bindToJavascript(frame, classname); +} + +void AccessibilityController::reset() +{ + m_rootElement = WebAccessibilityObject(); + m_focusedElement = WebAccessibilityObject(); + m_elements.clear(); + + m_logAccessibilityEvents = false; +} + +void AccessibilityController::setFocusedElement(const WebAccessibilityObject& focusedElement) +{ + m_focusedElement = focusedElement; +} + +AccessibilityUIElement* AccessibilityController::getFocusedElement() +{ + if (m_focusedElement.isNull()) + m_focusedElement = m_shell->webView()->accessibilityObject(); + return m_elements.getOrCreate(m_focusedElement); +} + +AccessibilityUIElement* AccessibilityController::getRootElement() +{ + if (m_rootElement.isNull()) + m_rootElement = m_shell->webView()->accessibilityObject(); + return m_elements.createRoot(m_rootElement); +} + +bool AccessibilityController::shouldLogAccessibilityEvents() +{ + return m_logAccessibilityEvents; +} + +void AccessibilityController::notificationReceived(const WebKit::WebAccessibilityObject& target, const char* notificationName) +{ + // Call notification listeners on the element. + AccessibilityUIElement* element = m_elements.getOrCreate(target); + element->notificationReceived(notificationName); + + // Call global notification listeners. + size_t callbackCount = m_notificationCallbacks.size(); + for (size_t i = 0; i < callbackCount; i++) { + CppVariant arguments[2]; + arguments[0].set(*element->getAsCppVariant()); + arguments[1].set(notificationName); + CppVariant invokeResult; + m_notificationCallbacks[i].invokeDefault(arguments, 2, invokeResult); + } +} + +void AccessibilityController::logAccessibilityEventsCallback(const CppArgumentList&, CppVariant* result) +{ + m_logAccessibilityEvents = true; + result->setNull(); +} + +void AccessibilityController::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 1 || !arguments[0].isObject()) { + result->setNull(); + return; + } + + m_notificationCallbacks.push_back(arguments[0]); + result->setNull(); +} + +void AccessibilityController::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void AccessibilityController::focusedElementGetterCallback(CppVariant* result) +{ + result->set(*(getFocusedElement()->getAsCppVariant())); +} + +void AccessibilityController::rootElementGetterCallback(CppVariant* result) +{ + result->set(*(getRootElement()->getAsCppVariant())); +} + +void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result) +{ + printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on " + "AccessibilityController\n"); + result->setNull(); +} diff --git a/Tools/DumpRenderTree/chromium/AccessibilityController.h b/Tools/DumpRenderTree/chromium/AccessibilityController.h new file mode 100644 index 000000000..954edb9ca --- /dev/null +++ b/Tools/DumpRenderTree/chromium/AccessibilityController.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef 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(); + + bool shouldLogAccessibilityEvents(); + + void notificationReceived(const WebKit::WebAccessibilityObject& target, const char* notificationName); + +private: + // If true, will log all accessibility notifications. + bool m_logAccessibilityEvents; + + // Bound methods and properties + void logAccessibilityEventsCallback(const CppArgumentList&, CppVariant*); + void fallbackCallback(const CppArgumentList&, CppVariant*); + void addNotificationListenerCallback(const CppArgumentList&, CppVariant*); + void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*); + + void focusedElementGetterCallback(CppVariant*); + void rootElementGetterCallback(CppVariant*); + + WebKit::WebAccessibilityObject m_focusedElement; + WebKit::WebAccessibilityObject m_rootElement; + + AccessibilityUIElementList m_elements; + + std::vector<CppVariant> m_notificationCallbacks; + + TestShell* m_shell; +}; + +#endif // AccessibilityController_h diff --git a/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp new file mode 100644 index 000000000..3ca1ee72a --- /dev/null +++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp @@ -0,0 +1,817 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AccessibilityUIElement.h" + +#include "WebAccessibilityObject.h" +#include "platform/WebCString.h" +#include "platform/WebRect.h" +#include "platform/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 getHelpText(const WebAccessibilityObject& object) +{ + string helpText = object.helpText().utf8(); + return helpText.insert(0, "AXHelp: "); +} + +string getStringValue(const WebAccessibilityObject& object) +{ + string value = object.stringValue().utf8(); + return value.insert(0, "AXValue: "); +} + +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 getOrientation(const WebAccessibilityObject& object) +{ + if (object.isVertical()) + return "AXOrientation: AXVerticalOrientation"; + + return "AXOrientation: AXHorizontalOrientation"; +} + +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); + + // + // Properties + // + + bindProperty("role", &AccessibilityUIElement::roleGetterCallback); + bindProperty("title", &AccessibilityUIElement::titleGetterCallback); + bindProperty("description", &AccessibilityUIElement::descriptionGetterCallback); + bindProperty("helpText", &AccessibilityUIElement::helpTextGetterCallback); + bindProperty("stringValue", &AccessibilityUIElement::stringValueGetterCallback); + bindProperty("x", &AccessibilityUIElement::xGetterCallback); + bindProperty("y", &AccessibilityUIElement::yGetterCallback); + bindProperty("width", &AccessibilityUIElement::widthGetterCallback); + bindProperty("height", &AccessibilityUIElement::heightGetterCallback); + bindProperty("intValue", &AccessibilityUIElement::intValueGetterCallback); + bindProperty("minValue", &AccessibilityUIElement::minValueGetterCallback); + bindProperty("maxValue", &AccessibilityUIElement::maxValueGetterCallback); + bindProperty("childrenCount", &AccessibilityUIElement::childrenCountGetterCallback); + bindProperty("insertionPointLineNumber", &AccessibilityUIElement::insertionPointLineNumberGetterCallback); + bindProperty("selectedTextRange", &AccessibilityUIElement::selectedTextRangeGetterCallback); + bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback); + bindProperty("isRequired", &AccessibilityUIElement::isRequiredGetterCallback); + bindProperty("isFocused", &AccessibilityUIElement::isFocusedGetterCallback); + bindProperty("isFocusable", &AccessibilityUIElement::isFocusableGetterCallback); + bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback); + bindProperty("isSelectable", &AccessibilityUIElement::isSelectableGetterCallback); + bindProperty("isMultiSelectable", &AccessibilityUIElement::isMultiSelectableGetterCallback); + bindProperty("isSelectedOptionActive", &AccessibilityUIElement::isSelectedOptionActiveGetterCallback); + bindProperty("isExpanded", &AccessibilityUIElement::isExpandedGetterCallback); + bindProperty("isChecked", &AccessibilityUIElement::isCheckedGetterCallback); + bindProperty("isVisible", &AccessibilityUIElement::isVisibleGetterCallback); + bindProperty("isOffScreen", &AccessibilityUIElement::isOffScreenGetterCallback); + bindProperty("isCollapsed", &AccessibilityUIElement::isCollapsedGetterCallback); + bindProperty("hasPopup", &AccessibilityUIElement::hasPopupGetterCallback); + bindProperty("isValid", &AccessibilityUIElement::isValidGetterCallback); + bindProperty("orientation", &AccessibilityUIElement::orientationGetterCallback); + + // + // Methods + // + + bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback); + bindMethod("attributesOfLinkedUIElements", &AccessibilityUIElement::attributesOfLinkedUIElementsCallback); + bindMethod("attributesOfDocumentLinks", &AccessibilityUIElement::attributesOfDocumentLinksCallback); + bindMethod("attributesOfChildren", &AccessibilityUIElement::attributesOfChildrenCallback); + 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); + bindMethod("showMenu", &AccessibilityUIElement::showMenuCallback); + bindMethod("press", &AccessibilityUIElement::pressCallback); + bindMethod("isEqual", &AccessibilityUIElement::isEqualCallback); + bindMethod("addNotificationListener", &AccessibilityUIElement::addNotificationListenerCallback); + bindMethod("removeNotificationListener", &AccessibilityUIElement::removeNotificationListenerCallback); + bindMethod("takeFocus", &AccessibilityUIElement::takeFocusCallback); + + bindFallbackMethod(&AccessibilityUIElement::fallbackCallback); +} + +AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + return m_factory->getOrCreate(accessibilityObject().childAt(index)); +} + +bool AccessibilityUIElement::isEqual(const WebKit::WebAccessibilityObject& other) +{ + return accessibilityObject().equals(other); +} + +void AccessibilityUIElement::notificationReceived(const char* notificationName) +{ + size_t callbackCount = m_notificationCallbacks.size(); + for (size_t i = 0; i < callbackCount; i++) { + CppVariant notificationNameArgument; + notificationNameArgument.set(notificationName); + CppVariant invokeResult; + m_notificationCallbacks[i].invokeDefault(¬ificationNameArgument, 1, invokeResult); + } +} + +// +// Properties +// + +void AccessibilityUIElement::roleGetterCallback(CppVariant* result) +{ + result->set(getRole(accessibilityObject())); +} + +void AccessibilityUIElement::titleGetterCallback(CppVariant* result) +{ + result->set(getTitle(accessibilityObject())); +} + +void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result) +{ + result->set(getDescription(accessibilityObject())); +} + +void AccessibilityUIElement::helpTextGetterCallback(CppVariant* result) +{ + result->set(getHelpText(accessibilityObject())); +} + +void AccessibilityUIElement::stringValueGetterCallback(CppVariant* result) +{ + result->set(getStringValue(accessibilityObject())); +} + +void AccessibilityUIElement::xGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().boundingBoxRect().x); +} + +void AccessibilityUIElement::yGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().boundingBoxRect().y); +} + +void AccessibilityUIElement::widthGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().boundingBoxRect().width); +} + +void AccessibilityUIElement::heightGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().boundingBoxRect().height); +} + +void AccessibilityUIElement::intValueGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().valueForRange()); +} + +void AccessibilityUIElement::minValueGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().minValueForRange()); +} + +void AccessibilityUIElement::maxValueGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().maxValueForRange()); +} + +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::insertionPointLineNumberGetterCallback(CppVariant* result) +{ + WebVector<int> lineBreaks; + accessibilityObject().lineBreaks(lineBreaks); + int cursor = accessibilityObject().selectionEnd(); + int line = 0; + while (line < static_cast<int>(lineBreaks.size()) && lineBreaks[line] <= cursor) + line++; + result->set(line); +} + +void AccessibilityUIElement::selectedTextRangeGetterCallback(CppVariant* result) +{ + // FIXME: Implement this. + result->set(std::string()); +} + +void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isEnabled()); +} + +void AccessibilityUIElement::isRequiredGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isRequired()); +} + +void AccessibilityUIElement::isFocusedGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isFocused()); +} + +void AccessibilityUIElement::isFocusableGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().canSetFocusAttribute()); +} + +void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isSelected()); +} + +void AccessibilityUIElement::isSelectableGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().canSetSelectedAttribute()); +} + +void AccessibilityUIElement::isMultiSelectableGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isMultiSelectable()); +} + +void AccessibilityUIElement::isSelectedOptionActiveGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isSelectedOptionActive()); +} + +void AccessibilityUIElement::isExpandedGetterCallback(CppVariant* result) +{ + result->set(!accessibilityObject().isCollapsed()); +} + +void AccessibilityUIElement::isCheckedGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isChecked()); +} + +void AccessibilityUIElement::isVisibleGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isVisible()); +} + +void AccessibilityUIElement::isOffScreenGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isOffScreen()); +} + +void AccessibilityUIElement::isCollapsedGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isCollapsed()); +} + +void AccessibilityUIElement::hasPopupGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().ariaHasPopup()); +} + +void AccessibilityUIElement::isValidGetterCallback(CppVariant* result) +{ + result->set(accessibilityObject().isValid()); +} + +void AccessibilityUIElement::orientationGetterCallback(CppVariant* result) +{ + result->set(getOrientation(accessibilityObject())); +} + +// +// Methods +// + +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::showMenuCallback(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); +} + +void AccessibilityUIElement::pressCallback(const CppArgumentList&, CppVariant* result) +{ + accessibilityObject().performDefaultAction(); + result->setNull(); +} + +void AccessibilityUIElement::isEqualCallback(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 1 || !arguments[0].isObject()) { + result->setNull(); + return; + } + + result->set(arguments[0].isEqual(*getAsCppVariant())); +} + +void AccessibilityUIElement::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 1 || !arguments[0].isObject()) { + result->setNull(); + return; + } + + m_notificationCallbacks.push_back(arguments[0]); + result->setNull(); +} + +void AccessibilityUIElement::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void AccessibilityUIElement::takeFocusCallback(const CppArgumentList&, CppVariant* result) +{ + accessibilityObject().setFocused(true); + result->setNull(); +} + +void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory) + : AccessibilityUIElement(object, factory) { } + +AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index) +{ + if (index) + return 0; + + return factory()->getOrCreate(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::getOrCreate(const WebAccessibilityObject& object) +{ + if (object.isNull()) + return 0; + + size_t elementCount = m_elements.size(); + for (size_t i = 0; i < elementCount; i++) { + if (m_elements[i]->isEqual(object)) + return m_elements[i]; + } + + AccessibilityUIElement* element = new AccessibilityUIElement(object, this); + m_elements.append(element); + return element; +} + +AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object) +{ + AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this); + m_elements.append(element); + return element; +} diff --git a/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h new file mode 100644 index 000000000..b5fce86f0 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityUIElement_h +#define AccessibilityUIElement_h + +#include "CppBoundClass.h" +#include "WebAccessibilityObject.h" +#include <vector> +#include <wtf/Vector.h> + +class AccessibilityUIElement : public CppBoundClass { +public: + class Factory { + public: + virtual ~Factory() { } + virtual AccessibilityUIElement* getOrCreate(const WebKit::WebAccessibilityObject&) = 0; + }; + + AccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*); + + virtual AccessibilityUIElement* getChildAtIndex(unsigned); + virtual bool isRoot() const { return false; } + virtual bool isEqual(const WebKit::WebAccessibilityObject&); + + virtual void notificationReceived(const char *notificationName); + +protected: + const WebKit::WebAccessibilityObject& accessibilityObject() const { return m_accessibilityObject; } + + Factory* factory() const { return m_factory; } + +private: + // Bound properties. + void roleGetterCallback(CppVariant*); + void titleGetterCallback(CppVariant*); + void descriptionGetterCallback(CppVariant*); + void helpTextGetterCallback(CppVariant*); + void stringValueGetterCallback(CppVariant*); + void xGetterCallback(CppVariant*); + void yGetterCallback(CppVariant*); + void widthGetterCallback(CppVariant*); + void heightGetterCallback(CppVariant*); + void intValueGetterCallback(CppVariant*); + void minValueGetterCallback(CppVariant*); + void maxValueGetterCallback(CppVariant*); + void childrenCountGetterCallback(CppVariant*); + void insertionPointLineNumberGetterCallback(CppVariant*); + void selectedTextRangeGetterCallback(CppVariant*); + void isEnabledGetterCallback(CppVariant*); + void isRequiredGetterCallback(CppVariant*); + void isFocusedGetterCallback(CppVariant*); + void isFocusableGetterCallback(CppVariant*); + void isSelectedGetterCallback(CppVariant*); + void isSelectableGetterCallback(CppVariant*); + void isMultiSelectableGetterCallback(CppVariant*); + void isSelectedOptionActiveGetterCallback(CppVariant*); + void isExpandedGetterCallback(CppVariant*); + void isCheckedGetterCallback(CppVariant*); + void isVisibleGetterCallback(CppVariant*); + void isOffScreenGetterCallback(CppVariant*); + void isCollapsedGetterCallback(CppVariant*); + void hasPopupGetterCallback(CppVariant*); + void isValidGetterCallback(CppVariant*); + void orientationGetterCallback(CppVariant*); + + // Bound methods. + 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 showMenuCallback(const CppArgumentList&, CppVariant*); + void pressCallback(const CppArgumentList&, CppVariant*); + void isEqualCallback(const CppArgumentList&, CppVariant*); + void addNotificationListenerCallback(const CppArgumentList&, CppVariant*); + void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*); + void takeFocusCallback(const CppArgumentList&, CppVariant*); + + void fallbackCallback(const CppArgumentList&, CppVariant*); + + WebKit::WebAccessibilityObject m_accessibilityObject; + Factory* m_factory; + std::vector<CppVariant> m_notificationCallbacks; +}; + + +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* getOrCreate(const WebKit::WebAccessibilityObject&); + AccessibilityUIElement* createRoot(const WebKit::WebAccessibilityObject&); + +private: + typedef Vector<AccessibilityUIElement*> ElementList; + ElementList m_elements; +}; + +#endif // AccessibilityUIElement_h diff --git a/Tools/DumpRenderTree/chromium/CppBoundClass.cpp b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp new file mode 100644 index 000000000..9b4a3b646 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file contains definitions for CppBoundClass + +// Here's the control flow of a JS method getting forwarded to a class. +// - Something calls our NPObject with a function like "Invoke". +// - CppNPObject's static invoke() function forwards it to its attached +// CppBoundClass's invoke() method. +// - CppBoundClass has then overridden invoke() to look up the function +// name in its internal map of methods, and then calls the appropriate +// method. + +#include "config.h" +#include "CppBoundClass.h" + +#include "WebBindings.h" +#include "WebFrame.h" +#include "platform/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(PassOwnPtr<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, PassOwnPtr<GetterCallback> callback) +{ + PropertyCallback* propertyCallback = callback ? new GetterPropertyCallback(callback) : 0; + bindProperty(name, propertyCallback); +} + +void CppBoundClass::bindProperty(const string& name, CppVariant* prop) +{ + PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0; + bindProperty(name, propertyCallback); +} + +void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback) +{ + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); + PropertyList::iterator oldCallback = m_properties.find(ident); + if (oldCallback != m_properties.end()) { + delete oldCallback->second; + if (!callback) { + m_properties.remove(oldCallback); + return; + } + } + + m_properties.set(ident, callback); +} + +bool CppBoundClass::isMethodRegistered(const string& name) const +{ + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); + MethodList::const_iterator callback = m_methods.find(ident); + return callback != m_methods.end(); +} + +CppVariant* CppBoundClass::getAsCppVariant() +{ + if (!m_selfVariant.isObject()) { + // Create an NPObject using our static NPClass. The first argument (a + // plugin's instance handle) is passed through to the allocate function + // directly, and we don't use it, so it's ok to be 0. + NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass); + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj); + obj->boundClass = this; + m_selfVariant.set(npObj); + WebBindings::releaseObject(npObj); // CppVariant takes the reference. + } + ASSERT(m_selfVariant.isObject()); + return &m_selfVariant; +} + +void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname) +{ + // BindToWindowObject will take its own reference to the NPObject, and clean + // up after itself. It will also (indirectly) register the object with V8, + // so we must remember this so we can unregister it when we're destroyed. + frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant())); + m_boundToFrame = true; +} diff --git a/Tools/DumpRenderTree/chromium/CppBoundClass.h b/Tools/DumpRenderTree/chromium/CppBoundClass.h new file mode 100644 index 000000000..4fb5361e1 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/CppBoundClass.h @@ -0,0 +1,245 @@ +/* + * 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/PassOwnPtr.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 { + WTF_MAKE_NONCOPYABLE(CppBoundClass); +public: + class PropertyCallback { + public: + virtual ~PropertyCallback() { } + + // Sets |value| to the value of the property. Returns false in case of + // failure. |value| is always non-0. + virtual bool getValue(CppVariant* result) = 0; + + // sets the property value to |value|. Returns false in case of failure. + virtual bool setValue(const CppVariant&) = 0; + }; + + // Callback class for "void function(CppVariant*)" + class GetterCallback { + public: + virtual ~GetterCallback() { } + virtual void run(CppVariant*) = 0; + }; + + // The constructor should call BindMethod, BindProperty, and + // SetFallbackMethod as needed to set up the methods, properties, and + // fallback method. + CppBoundClass() : 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 the specified name exists, + // regardless of whether a fallback is registered. + bool isMethodRegistered(const std::string&) const; + +protected: + // Callback for "void function(const CppArguemntList&, CppVariant*)" + class Callback { + public: + virtual ~Callback() { } + virtual void run(const CppArgumentList&, CppVariant*) = 0; + }; + + // Callback for "void T::method(const CppArguemntList&, CppVariant*)" + template <class T> class MemberCallback : public Callback { + public: + typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*); + MemberCallback(T* object, MethodType method) + : m_object(object) + , m_method(method) { } + virtual ~MemberCallback() { } + + virtual void run(const CppArgumentList& arguments, CppVariant* result) + { + (m_object->*m_method)(arguments, result); + } + + private: + T* m_object; + MethodType m_method; + }; + + // Callback class for "void T::method(CppVariant*)" + template <class T> class MemberGetterCallback : public GetterCallback { + public: + typedef void (T::*MethodType)(CppVariant*); + MemberGetterCallback(T* object, MethodType method) + : m_object(object) + , m_method(method) { } + virtual ~MemberGetterCallback() { } + + virtual void run(CppVariant* result) { (m_object->*m_method)(result); } + + private: + T* m_object; + MethodType m_method; + }; + + // Bind the Javascript method called the string parameter to the C++ method. + void bindCallback(const std::string&, Callback*); + + // A wrapper for bindCallback, to simplify the common case of binding a + // method on the current object. Though not verified here, the method parameter + // must be a method of this CppBoundClass subclass. + template<class T> + void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*)) + { + Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method); + bindCallback(name, callback); + } + + // Bind Javascript property |name| to the C++ getter callback |callback|. + // This can be used to create read-only properties. + void bindGetterCallback(const std::string&, PassOwnPtr<GetterCallback>); + + // A wrapper for BindGetterCallback, to simplify the common case of binding a + // property on the current object. Though not verified here, the method parameter + // must be a method of this CppBoundClass subclass. + template<class T> + void bindProperty(const std::string& name, void (T::*method)(CppVariant*)) + { + OwnPtr<GetterCallback> callback = adoptPtr(new MemberGetterCallback<T>(static_cast<T*>(this), method)); + bindGetterCallback(name, callback.release()); + } + + // 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(PassOwnPtr<Callback> fallbackCallback) + { + m_fallbackCallback = fallbackCallback; + } + + // A wrapper for BindFallbackCallback, to simplify the common case of + // binding a method on the current object. Though not verified here, + // |method| must be a method of this CppBoundClass subclass. + // Passing 0 for |method| clears out any existing binding. + template<class T> + void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*)) + { + if (method) { + OwnPtr<Callback> callback = adoptPtr(new MemberCallback<T>(static_cast<T*>(this), method)); + bindFallbackCallback(callback.release()); + } else + bindFallbackCallback(nullptr); + } + + // Some fields are protected because some tests depend on accessing them, + // but otherwise they should be considered private. + + typedef HashMap<NPIdentifier, PropertyCallback*> PropertyList; + typedef HashMap<NPIdentifier, Callback*> MethodList; + // These maps associate names with property and method pointers to be + // exposed to JavaScript. + PropertyList m_properties; + MethodList m_methods; + + // The callback gets invoked when a call is made to an nonexistent method. + OwnPtr<Callback> m_fallbackCallback; + +private: + // NPObject callbacks. + friend struct CppNPObject; + bool hasMethod(NPIdentifier) const; + bool invoke(NPIdentifier, const NPVariant* args, size_t argCount, + NPVariant* result); + bool hasProperty(NPIdentifier) const; + bool getProperty(NPIdentifier, NPVariant* result) const; + bool setProperty(NPIdentifier, const NPVariant*); + + // A lazily-initialized CppVariant representing this class. We retain 1 + // reference to this object, and it is released on deletion. + CppVariant m_selfVariant; + + // True if our np_object has been bound to a WebFrame, in which case it must + // be unregistered with V8 when we delete it. + bool m_boundToFrame; +}; + +#endif // CppBoundClass_h diff --git a/Tools/DumpRenderTree/chromium/CppVariant.cpp b/Tools/DumpRenderTree/chromium/CppVariant.cpp new file mode 100644 index 000000000..b587d75aa --- /dev/null +++ b/Tools/DumpRenderTree/chromium/CppVariant.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CppVariant.h" + +#include "WebBindings.h" +#include <limits> +#include <wtf/Assertions.h> +#include <wtf/StringExtras.h> + +using namespace WebKit; +using namespace std; + +CppVariant::CppVariant() +{ + type = NPVariantType_Null; +} + +// Note that Set() performs a deep copy, which is necessary to safely +// call FreeData() on the value in the destructor. +CppVariant::CppVariant(const CppVariant& original) +{ + type = NPVariantType_Null; + set(original); +} + +// See comment for copy constructor, above. +CppVariant& CppVariant::operator=(const CppVariant& original) +{ + if (&original != this) + set(original); + return *this; +} + +CppVariant::~CppVariant() +{ + freeData(); +} + +void CppVariant::freeData() +{ + WebBindings::releaseVariantValue(this); +} + +bool CppVariant::isEqual(const CppVariant& other) const +{ + if (type != other.type) + return false; + + switch (type) { + case NPVariantType_Bool: + return (value.boolValue == other.value.boolValue); + case NPVariantType_Int32: + return (value.intValue == other.value.intValue); + case NPVariantType_Double: + return (value.doubleValue == other.value.doubleValue); + case NPVariantType_String: { + const NPString *this_value = &value.stringValue; + const NPString *other_value = &other.value.stringValue; + uint32_t len = this_value->UTF8Length; + return len == other_value->UTF8Length + && !strncmp(this_value->UTF8Characters, + other_value->UTF8Characters, len); + } + case NPVariantType_Null: + case NPVariantType_Void: + return true; + case NPVariantType_Object: { + NPObject* thisValue = value.objectValue; + NPObject* otherValue = other.value.objectValue; + return thisValue->_class == otherValue->_class + && thisValue->referenceCount == otherValue->referenceCount; + } + } + return false; +} + +void CppVariant::copyToNPVariant(NPVariant* result) const +{ + result->type = type; + switch (type) { + case NPVariantType_Bool: + result->value.boolValue = value.boolValue; + break; + case NPVariantType_Int32: + result->value.intValue = value.intValue; + break; + case NPVariantType_Double: + result->value.doubleValue = value.doubleValue; + break; + case NPVariantType_String: + WebBindings::initializeVariantWithStringCopy(result, &value.stringValue); + break; + case NPVariantType_Null: + case NPVariantType_Void: + // Nothing to set. + break; + case NPVariantType_Object: + result->type = NPVariantType_Object; + result->value.objectValue = WebBindings::retainObject(value.objectValue); + break; + } +} + +void CppVariant::set(const NPVariant& newValue) +{ + freeData(); + switch (newValue.type) { + case NPVariantType_Bool: + set(newValue.value.boolValue); + break; + case NPVariantType_Int32: + set(newValue.value.intValue); + break; + case NPVariantType_Double: + set(newValue.value.doubleValue); + break; + case NPVariantType_String: + set(newValue.value.stringValue); + break; + case NPVariantType_Null: + case NPVariantType_Void: + type = newValue.type; + break; + case NPVariantType_Object: + set(newValue.value.objectValue); + break; + } +} + +void CppVariant::setNull() +{ + freeData(); + type = NPVariantType_Null; +} + +void CppVariant::set(bool newValue) +{ + freeData(); + type = NPVariantType_Bool; + value.boolValue = newValue; +} + +void CppVariant::set(int32_t newValue) +{ + freeData(); + type = NPVariantType_Int32; + value.intValue = newValue; +} + +void CppVariant::set(double newValue) +{ + freeData(); + type = NPVariantType_Double; + value.doubleValue = newValue; +} + +// The newValue must be a null-terminated string. +void CppVariant::set(const char* newValue) +{ + freeData(); + type = NPVariantType_String; + NPString newString = {newValue, + static_cast<uint32_t>(strlen(newValue))}; + WebBindings::initializeVariantWithStringCopy(this, &newString); +} + +void CppVariant::set(const string& newValue) +{ + freeData(); + type = NPVariantType_String; + NPString newString = {newValue.data(), + static_cast<uint32_t>(newValue.size())}; + WebBindings::initializeVariantWithStringCopy(this, &newString); +} + +void CppVariant::set(const NPString& newValue) +{ + freeData(); + type = NPVariantType_String; + WebBindings::initializeVariantWithStringCopy(this, &newValue); +} + +void CppVariant::set(NPObject* newValue) +{ + freeData(); + type = NPVariantType_Object; + value.objectValue = WebBindings::retainObject(newValue); +} + +string CppVariant::toString() const +{ + ASSERT(isString()); + return string(value.stringValue.UTF8Characters, + value.stringValue.UTF8Length); +} + +int32_t CppVariant::toInt32() const +{ + if (isInt32()) + return value.intValue; + if (isDouble()) + return static_cast<int32_t>(value.doubleValue); + ASSERT_NOT_REACHED(); + return 0; +} + +double CppVariant::toDouble() const +{ + if (isInt32()) + return static_cast<double>(value.intValue); + if (isDouble()) + return value.doubleValue; + ASSERT_NOT_REACHED(); + return 0; +} + +bool CppVariant::toBoolean() const +{ + ASSERT(isBool()); + return value.boolValue; +} + +Vector<string> CppVariant::toStringVector() const +{ + + ASSERT(isObject()); + Vector<string> stringVector; + NPObject* npValue = value.objectValue; + NPIdentifier lengthId = WebBindings::getStringIdentifier("length"); + + if (!WebBindings::hasProperty(0, npValue, lengthId)) + return stringVector; + + NPVariant lengthValue; + if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue)) + return stringVector; + + int length = 0; + // The length is a double in some cases. + if (NPVARIANT_IS_DOUBLE(lengthValue)) + length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue)); + else if (NPVARIANT_IS_INT32(lengthValue)) + length = NPVARIANT_TO_INT32(lengthValue); + WebBindings::releaseVariantValue(&lengthValue); + + // For sanity, only allow 100 items. + length = min(100, length); + for (int i = 0; i < length; ++i) { + // Get each of the items. + char indexInChar[20]; // Enough size to store 32-bit integer + snprintf(indexInChar, 20, "%d", i); + string index(indexInChar); + NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str()); + if (!WebBindings::hasProperty(0, npValue, indexId)) + continue; + NPVariant indexValue; + if (!WebBindings::getProperty(0, npValue, indexId, &indexValue)) + continue; + if (NPVARIANT_IS_STRING(indexValue)) { + string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters, + NPVARIANT_TO_STRING(indexValue).UTF8Length); + stringVector.append(item); + } + WebBindings::releaseVariantValue(&indexValue); + } + return stringVector; +} + +bool CppVariant::invoke(const string& method, const CppVariant* arguments, + uint32_t argumentCount, CppVariant& result) const +{ + ASSERT(isObject()); + NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str()); + NPObject* npObject = value.objectValue; + if (!WebBindings::hasMethod(0, npObject, methodName)) + return false; + NPVariant r; + bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r); + result.set(r); + return status; +} + +bool CppVariant::invokeDefault(const CppVariant* arguments, uint32_t argumentCount, + CppVariant& result) const +{ + ASSERT(isObject()); + NPObject* npObject = value.objectValue; + NPVariant r; + bool status = WebBindings::invokeDefault(0, npObject, arguments, argumentCount, &r); + result.set(r); + return status; +} diff --git a/Tools/DumpRenderTree/chromium/CppVariant.h b/Tools/DumpRenderTree/chromium/CppVariant.h new file mode 100644 index 000000000..60cc6271e --- /dev/null +++ b/Tools/DumpRenderTree/chromium/CppVariant.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + This file contains the declaration for CppVariant, a type used by C++ classes + that are to be bound to JavaScript objects. + + CppVariant exists primarily as an interface between C++ callers and the + corresponding NPVariant type. CppVariant also provides a number of + convenience constructors and accessors, so that the NPVariantType values + don't need to be exposed, and a destructor to free any memory allocated for + string values. +*/ + +#ifndef CppVariant_h +#define CppVariant_h + +#include "WebBindings.h" +#include "webkit/support/webkit_support.h" +#include <string> +#include <wtf/Vector.h> + +class CppVariant : public NPVariant { +public: + CppVariant(); + ~CppVariant(); + void setNull(); + void set(bool); + void set(int32_t); + void set(double); + + // Note that setting a CppVariant to a string value involves copying the + // string data, which must be freed with a call to freeData() when the + // CppVariant is set to a different value or is no longer needed. Normally + // this is handled by the other set() methods and by the destructor. + void set(const char*); // Must be a null-terminated string. + void set(const std::string&); + void set(const NPString&); + void set(const NPVariant&); + + // Note that setting a CppVariant to an NPObject involves ref-counting + // the actual object. freeData() should only be called if the CppVariant + // is no longer needed. The other set() methods handle this internally. + // Also, the object's NPClass is expected to be a static object: neither + // the NP runtime nor CppVariant will ever free it. + void set(NPObject*_value); + + // These three methods all perform deep copies of any string data. This + // allows local CppVariants to be released by the destructor without + // corrupting their sources. In performance-critical code, or when strings + // are very long, avoid creating new CppVariants. + // In case of NPObject as the data, the copying involves ref-counting + // as opposed to deep-copying. The ref-counting ensures that sources don't + // get corrupted when the copies get destroyed. + void copyToNPVariant(NPVariant* result) const; + CppVariant& operator=(const CppVariant& original); + CppVariant(const CppVariant& original); + + // Calls NPN_ReleaseVariantValue, which frees any string data + // held by the object and sets its type to null. + // In case of NPObject, the NPN_ReleaseVariantValue decrements + // the ref-count (releases when ref-count becomes 0) + void freeData(); + + // Compares this CppVariant's type and value to another's. They must be + // identical in both type and value to be considered equal. For string and + // object types, a deep comparison is performed; that is, the contents of the + // strings, or the classes and refcounts of the objects, must be the same, + // but they need not be the same pointers. + bool isEqual(const CppVariant&) const; + + // The value of a CppVariant may be read directly from its NPVariant (but + // should only be set using one of the set() methods above). Although the + // type of a CppVariant is likewise public, it can be accessed through these + // functions rather than directly if a caller wishes to avoid dependence on + // the NPVariantType values. + bool isBool() const { return (type == NPVariantType_Bool); } + bool isInt32() const { return (type == NPVariantType_Int32); } + bool isDouble() const { return (type == NPVariantType_Double); } + bool isNumber() const { return (isInt32() || isDouble()); } + bool isString() const { return (type == NPVariantType_String); } + bool isVoid() const { return (type == NPVariantType_Void); } + bool isNull() const { return (type == NPVariantType_Null); } + bool isEmpty() const { return (isVoid() || isNull()); } + bool isObject() const { return (type == NPVariantType_Object); } + + // Converters. The CppVariant must be of a type convertible to these values. + // For example, toInt32() works only if isNumber() is true. + std::string toString() const; + int32_t toInt32() const; + double toDouble() const; + bool toBoolean() const; + // Returns a vector of strings for the specified argument. This is useful + // for converting a JavaScript array of strings into a vector of strings. + Vector<std::string> toStringVector() const; + + // Invoke method of the given name on an object with the supplied arguments. + // The first argument should be the object on which the method is to be + // invoked. Returns whether the method was successfully invoked. If the + // method was invoked successfully, any return value is stored in the + // CppVariant specified by result. + bool invoke(const std::string&, const CppVariant* arguments, + uint32_t argumentCount, CppVariant& result) const; + + // Invoke an object's default method with the supplied arguments. + // The first argument should be the object on which the method is to be + // invoked. Returns whether the method was successfully invoked. If the + // method was invoked successfully, any return value is stored in the + // CppVariant specified by result. + bool invokeDefault(const CppVariant* arguments, + uint32_t argumentCount, CppVariant& result) const; +}; + +#endif // CppVariant_h diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp new file mode 100644 index 000000000..21aed1b9d --- /dev/null +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DRTDevToolsAgent.h" + +#include "DRTDevToolsClient.h" + +#include "platform/WebCString.h" +#include "WebDevToolsAgent.h" +#include "WebView.h" +#include "webkit/support/webkit_support.h" + +using namespace WebKit; + +DRTDevToolsAgent::DRTDevToolsAgent() + : m_drtDevToolsClient(0) + , m_webView(0) +{ + static int devToolsAgentCounter = 0; + + m_routingID = ++devToolsAgentCounter; +} + +void DRTDevToolsAgent::reset() +{ + m_taskList.revokeAll(); +} + +void DRTDevToolsAgent::setWebView(WebView* webView) +{ + m_webView = webView; +} + +void DRTDevToolsAgent::sendMessageToInspectorFrontend(const WebString& data) +{ + if (m_drtDevToolsClient) + m_drtDevToolsClient->asyncCall(data); +} + +void DRTDevToolsAgent::runtimePropertyChanged(const WebString& name, const WebString& value) +{ + // FIXME: Implement. +} + +WebDevToolsAgentClient::WebKitClientMessageLoop* DRTDevToolsAgent::createClientMessageLoop() +{ + return webkit_support::CreateDevToolsMessageLoop(); +} + +void DRTDevToolsAgent::asyncCall(const WebString& args) +{ + postTask(new AsyncCallTask(this, args)); +} + +void DRTDevToolsAgent::call(const WebString& args) +{ + WebDevToolsAgent* agent = webDevToolsAgent(); + if (agent) + agent->dispatchOnInspectorBackend(args); +} + +WebDevToolsAgent* DRTDevToolsAgent::webDevToolsAgent() +{ + if (!m_webView) + return 0; + return m_webView->devToolsAgent(); +} + +void DRTDevToolsAgent::attach(DRTDevToolsClient* client) +{ + ASSERT(!m_drtDevToolsClient); + m_drtDevToolsClient = client; + WebDevToolsAgent* agent = webDevToolsAgent(); + if (agent) + agent->attach(); +} + +void DRTDevToolsAgent::detach() +{ + ASSERT(m_drtDevToolsClient); + WebDevToolsAgent* agent = webDevToolsAgent(); + if (agent) + agent->detach(); + m_drtDevToolsClient = 0; +} + +bool DRTDevToolsAgent::setJavaScriptProfilingEnabled(bool enabled) +{ + WebDevToolsAgent* agent = webDevToolsAgent(); + if (!agent) + return false; + agent->setJavaScriptProfilingEnabled(enabled); + return true; +} + +bool DRTDevToolsAgent::evaluateInWebInspector(long callID, const std::string& script) +{ + WebDevToolsAgent* agent = webDevToolsAgent(); + if (!agent) + return false; + agent->evaluateInWebInspector(callID, WebString::fromUTF8(script)); + return true; +} diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h new file mode 100644 index 000000000..6e491ad53 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DRTDevToolsAgent_h +#define DRTDevToolsAgent_h + +#include "Task.h" +#include "WebDevToolsAgentClient.h" +#include "platform/WebString.h" +#include <wtf/HashMap.h> +#include <wtf/Noncopyable.h> + +namespace WebKit { + +class WebCString; +class WebDevToolsAgent; +class WebView; +struct WebDevToolsMessageData; + +} // namespace WebKit + +class DRTDevToolsClient; + +class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient { + WTF_MAKE_NONCOPYABLE(DRTDevToolsAgent); +public: + DRTDevToolsAgent(); + virtual ~DRTDevToolsAgent() { } + void reset(); + + void setWebView(WebKit::WebView*); + + // WebDevToolsAgentClient implementation. + virtual void sendMessageToInspectorFrontend(const WebKit::WebString&); + virtual int hostIdentifier() { return m_routingID; } + virtual void runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value); + virtual WebKitClientMessageLoop* createClientMessageLoop(); + + void asyncCall(const WebKit::WebString& args); + + void attach(DRTDevToolsClient*); + void detach(); + + bool evaluateInWebInspector(long callID, const std::string& script); + bool setJavaScriptProfilingEnabled(bool); + TaskList* taskList() { return &m_taskList; } + +private: + void call(const WebKit::WebString& args); + WebKit::WebDevToolsAgent* webDevToolsAgent(); + + class AsyncCallTask: public MethodTask<DRTDevToolsAgent> { + public: + AsyncCallTask(DRTDevToolsAgent* object, const WebKit::WebString& args) + : MethodTask<DRTDevToolsAgent>(object), m_args(args) { } + virtual void runIfValid() { m_object->call(m_args); } + + private: + WebKit::WebString m_args; + }; + + TaskList m_taskList; + DRTDevToolsClient* m_drtDevToolsClient; + int m_routingID; + WebKit::WebDevToolsAgent* m_webDevToolsAgent; + WebKit::WebView* m_webView; +}; + +#endif // DRTDevToolsAgent_h diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp new file mode 100644 index 000000000..a7fc4d048 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DRTDevToolsClient.h" + +#include "DRTDevToolsAgent.h" +#include "WebDevToolsAgent.h" +#include "WebDevToolsFrontend.h" +#include "WebFrame.h" +#include "WebScriptSource.h" +#include "WebView.h" +#include "webkit/support/webkit_support.h" +#include <wtf/PassOwnPtr.h> + +using namespace WebKit; + +DRTDevToolsClient::DRTDevToolsClient(DRTDevToolsAgent* agent, WebView* webView) + : m_webView(webView) + , m_drtDevToolsAgent(agent) +{ + m_webDevToolsFrontend = adoptPtr(WebDevToolsFrontend::create(m_webView, this, WebString::fromUTF8("en-US"))); + m_drtDevToolsAgent->attach(this); +} + +DRTDevToolsClient::~DRTDevToolsClient() +{ + // There is a chance that the page will be destroyed at detach step of + // m_drtDevToolsAgent and we should clean pending requests a bit earlier. + m_taskList.revokeAll(); + if (m_drtDevToolsAgent) + m_drtDevToolsAgent->detach(); +} + +void DRTDevToolsClient::reset() +{ + m_taskList.revokeAll(); +} + +void DRTDevToolsClient::sendMessageToBackend(const WebString& data) +{ + if (m_drtDevToolsAgent) + m_drtDevToolsAgent->asyncCall(data); +} + +void DRTDevToolsClient::activateWindow() +{ + // Not implemented. +} + +void DRTDevToolsClient::closeWindow() +{ + // Not implemented. +} + +void DRTDevToolsClient::dockWindow() +{ + // Not implemented. +} + +void DRTDevToolsClient::undockWindow() +{ + // Not implemented. +} + +void DRTDevToolsClient::asyncCall(const WebString& args) +{ + postTask(new AsyncCallTask(this, args)); +} + +void DRTDevToolsClient::call(const WebString& args) +{ + m_webDevToolsFrontend->dispatchOnInspectorFrontend(args); +} + diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h new file mode 100644 index 000000000..97a1edc0b --- /dev/null +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DRTDevToolsClient_h +#define DRTDevToolsClient_h + +#include "Task.h" +#include "WebDevToolsFrontendClient.h" +#include "platform/WebString.h" +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +namespace WebKit { + +class WebDevToolsFrontend; +struct WebDevToolsMessageData; +class WebView; + +} // namespace WebKit + +class DRTDevToolsAgent; + +class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient { + WTF_MAKE_NONCOPYABLE(DRTDevToolsClient); +public: + DRTDevToolsClient(DRTDevToolsAgent*, WebKit::WebView*); + virtual ~DRTDevToolsClient(); + void reset(); + + // WebDevToolsFrontendClient implementation + virtual void sendMessageToBackend(const WebKit::WebString&); + + virtual void activateWindow(); + virtual void closeWindow(); + virtual void dockWindow(); + virtual void undockWindow(); + + void asyncCall(const WebKit::WebString& args); + + void allMessagesProcessed(); + TaskList* taskList() { return &m_taskList; } + + private: + void call(const WebKit::WebString& args); + class AsyncCallTask: public MethodTask<DRTDevToolsClient> { + public: + AsyncCallTask(DRTDevToolsClient* object, const WebKit::WebString& args) + : MethodTask<DRTDevToolsClient>(object), m_args(args) { } + virtual void runIfValid() { m_object->call(m_args); } + + private: + WebKit::WebString m_args; + }; + + TaskList m_taskList; + WebKit::WebView* m_webView; + DRTDevToolsAgent* m_drtDevToolsAgent; + WTF::OwnPtr<WebKit::WebDevToolsFrontend> m_webDevToolsFrontend; +}; + +#endif // DRTDevToolsClient_h diff --git a/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp new file mode 100644 index 000000000..f9f6f5a69 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "TestShell.h" +#include "webkit/support/webkit_support.h" +#include <v8/include/v8-testing.h> +#include <v8/include/v8.h> +#include <wtf/Vector.h> + +using namespace std; + +static const char optionComplexText[] = "--complex-text"; +static const char optionDumpAllPixels[] = "--dump-all-pixels"; +static const char optionNotree[] = "--notree"; +static const char optionPixelTests[] = "--pixel-tests"; +static const char optionThreaded[] = "--threaded"; +static const char optionDebugRenderTree[] = "--debug-render-tree"; +static const char optionDebugLayerTree[] = "--debug-layer-tree"; + +static const char optionPixelTestsWithName[] = "--pixel-tests="; +static const char optionTestShell[] = "--test-shell"; +static const char optionAllowExternalPages[] = "--allow-external-pages"; +static const char optionStartupDialog[] = "--testshell-startup-dialog"; +static const char optionCheckLayoutTestSystemDeps[] = "--check-layout-test-sys-deps"; + +static const char optionHardwareAcceleratedGL[] = "--enable-hardware-gpu"; +static const char optionEnableThreadedCompositing[] = "--enable-threaded-compositing"; +static const char optionForceCompositingMode[] = "--force-compositing-mode"; +static const char optionEnableAccelerated2DCanvas[] = "--enable-accelerated-2d-canvas"; +static const char optionEnableLegacyAccelerated2DCanvas[] = "--enable-legacy-accelerated-2d-canvas"; +static const char optionEnableAcceleratedPainting[] = "--enable-accelerated-painting"; +static const char optionEnableAcceleratedCompositingForVideo[] = "--enable-accelerated-video"; +static const char optionEnableCompositeToTexture[] = "--enable-composite-to-texture"; +static const char optionUseGraphicsContext3DImplementation[] = "--use-graphics-context-3d-implementation="; +static const char optionEnablePerTilePainting[] = "--enable-per-tile-painting"; + +static const char optionStressOpt[] = "--stress-opt"; +static const char optionStressDeopt[] = "--stress-deopt"; +static const char optionJavaScriptFlags[] = "--js-flags="; +static const char optionNoTimeout[] = "--no-timeout"; +static const char optionWebCoreLogChannels[] = "--webcore-log-channels="; + +class WebKitSupportTestEnvironment { +public: + WebKitSupportTestEnvironment() + { + webkit_support::SetUpTestEnvironment(); + } + ~WebKitSupportTestEnvironment() + { + webkit_support::TearDownTestEnvironment(); + } +}; + +static void runTest(TestShell& shell, TestParams& params, const string& testName, bool testShellMode) +{ + int oldTimeoutMsec = shell.layoutTestTimeout(); + params.pixelHash = ""; + string pathOrURL = testName; + if (testShellMode) { + string timeOut; + string::size_type separatorPosition = pathOrURL.find(' '); + if (separatorPosition != string::npos) { + timeOut = pathOrURL.substr(separatorPosition + 1); + pathOrURL.erase(separatorPosition); + separatorPosition = timeOut.find_first_of(' '); + if (separatorPosition != string::npos) { + params.pixelHash = timeOut.substr(separatorPosition + 1); + timeOut.erase(separatorPosition); + } + shell.setLayoutTestTimeout(atoi(timeOut.c_str())); + } + } else { + string::size_type separatorPosition = pathOrURL.find("'"); + if (separatorPosition != string::npos) { + params.pixelHash = pathOrURL.substr(separatorPosition + 1); + pathOrURL.erase(separatorPosition); + } + } + params.testUrl = webkit_support::CreateURLForPathOrURL(pathOrURL); + webkit_support::SetCurrentDirectoryForFileURL(params.testUrl); + v8::V8::SetFlagsFromString(shell.javaScriptFlags().c_str(), shell.javaScriptFlags().length()); + if (shell.stressOpt() || shell.stressDeopt()) { + if (shell.stressOpt()) + v8::Testing::SetStressRunType(v8::Testing::kStressTypeOpt); + else + v8::Testing::SetStressRunType(v8::Testing::kStressTypeDeopt); + for (int i = 0; i < v8::Testing::GetStressRuns(); i++) { + v8::Testing::PrepareStressRun(i); + bool isLastLoad = (i == (v8::Testing::GetStressRuns() - 1)); + shell.setDumpWhenFinished(isLastLoad); + shell.resetTestController(); + shell.runFileTest(params); + } + } else { + shell.resetTestController(); + shell.runFileTest(params); + } + shell.setLayoutTestTimeout(oldTimeoutMsec); +} + +int main(int argc, char* argv[]) +{ + WebKitSupportTestEnvironment testEnvironment; + platformInit(&argc, &argv); + + TestParams params; + Vector<string> tests; + bool serverMode = false; + bool testShellMode = false; + bool allowExternalPages = false; + bool startupDialog = false; + bool acceleratedCompositingForVideoEnabled = false; + bool threadedCompositingEnabled = false; + bool compositeToTexture = false; + bool forceCompositingMode = false; + bool accelerated2DCanvasEnabled = false; + bool legacyAccelerated2DCanvasEnabled = false; + bool acceleratedPaintingEnabled = false; + bool perTilePaintingEnabled = false; + bool stressOpt = false; + bool stressDeopt = false; + bool hardwareAcceleratedGL = false; + string javaScriptFlags; + bool noTimeout = 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.find(optionPixelTestsWithName)) { + params.dumpPixels = true; + params.pixelFileName = argument.substr(strlen(optionPixelTestsWithName)); + } else if (argument == optionDebugRenderTree) + params.debugRenderTree = true; + else if (argument == optionDebugLayerTree) + params.debugLayerTree = true; + else if (argument == optionTestShell) { + testShellMode = true; + serverMode = true; + } else if (argument == optionAllowExternalPages) + allowExternalPages = true; + else if (argument == optionStartupDialog) + startupDialog = true; + else if (argument == optionCheckLayoutTestSystemDeps) + return checkLayoutTestSystemDependencies() ? EXIT_SUCCESS : EXIT_FAILURE; + else if (argument == optionHardwareAcceleratedGL) + hardwareAcceleratedGL = true; + else if (argument == optionEnableAcceleratedCompositingForVideo) + acceleratedCompositingForVideoEnabled = true; + else if (argument == optionEnableThreadedCompositing) + threadedCompositingEnabled = true; + else if (argument == optionEnableCompositeToTexture) + compositeToTexture = true; + else if (argument == optionForceCompositingMode) + forceCompositingMode = true; + else if (argument == optionEnableAccelerated2DCanvas) + accelerated2DCanvasEnabled = true; + else if (argument == optionEnableLegacyAccelerated2DCanvas) + legacyAccelerated2DCanvasEnabled = true; + else if (argument == optionEnableAcceleratedPainting) + acceleratedPaintingEnabled = true; + else if (!argument.find(optionUseGraphicsContext3DImplementation)) { + string implementation = argument.substr(strlen(optionUseGraphicsContext3DImplementation)); + if (!implementation.compare("IN_PROCESS")) + webkit_support::SetGraphicsContext3DImplementation(webkit_support::IN_PROCESS); + else if (!implementation.compare("IN_PROCESS_COMMAND_BUFFER")) + webkit_support::SetGraphicsContext3DImplementation(webkit_support::IN_PROCESS_COMMAND_BUFFER); + else + fprintf(stderr, "Unknown GraphicContext3D implementation %s\n", implementation.c_str()); + } else if (argument == optionEnablePerTilePainting) + perTilePaintingEnabled = true; + else if (argument == optionStressOpt) + stressOpt = true; + else if (argument == optionStressDeopt) + stressDeopt = true; + else if (!argument.find(optionJavaScriptFlags)) + javaScriptFlags = argument.substr(strlen(optionJavaScriptFlags)); + else if (argument == optionNoTimeout) + noTimeout = true; + else if (!argument.find(optionWebCoreLogChannels)) { + string channels = argument.substr(strlen(optionWebCoreLogChannels)); + webkit_support::EnableWebCoreLogChannels(channels); + } else if (argument.size() && argument[0] == '-') + fprintf(stderr, "Unknown option: %s\n", argv[i]); + else + tests.append(argument); + } + if (testShellMode && params.dumpPixels && params.pixelFileName.empty()) { + fprintf(stderr, "--pixel-tests with --test-shell requires a file name.\n"); + return EXIT_FAILURE; + } + if (stressOpt && stressDeopt) { + fprintf(stderr, "--stress-opt and --stress-deopt are mutually exclusive.\n"); + return EXIT_FAILURE; + } + + webkit_support::SetUpGLBindings(hardwareAcceleratedGL ? webkit_support::GL_BINDING_DEFAULT : webkit_support::GL_BINDING_SOFTWARE_RENDERER); + + if (startupDialog) + openStartupDialog(); + + { // Explicit scope for the TestShell instance. + TestShell shell(testShellMode); + shell.setAllowExternalPages(allowExternalPages); + shell.setAcceleratedCompositingForVideoEnabled(acceleratedCompositingForVideoEnabled); + shell.setThreadedCompositingEnabled(threadedCompositingEnabled); + shell.setCompositeToTexture(compositeToTexture); + shell.setForceCompositingMode(forceCompositingMode); + shell.setAccelerated2dCanvasEnabled(accelerated2DCanvasEnabled); + shell.setLegacyAccelerated2dCanvasEnabled(legacyAccelerated2DCanvasEnabled); + shell.setAcceleratedPaintingEnabled(acceleratedPaintingEnabled); + shell.setPerTilePaintingEnabled(perTilePaintingEnabled); + shell.setJavaScriptFlags(javaScriptFlags); + shell.setStressOpt(stressOpt); + shell.setStressDeopt(stressDeopt); + if (noTimeout) { + // 0x20000000ms is big enough for the purpose to avoid timeout in debugging. + shell.setLayoutTestTimeout(0x20000000); + } + if (serverMode && !tests.size()) { +#if OS(ANDROID) + // Send a signal to host to indicate DRT is ready to process commands. + puts("#READY"); + fflush(stdout); +#endif + 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; + // Explicitly quit on platforms where EOF is not reliable. + if (!strcmp(testString, "QUIT")) + break; + runTest(shell, params, testString, testShellMode); + } + } else if (!tests.size()) + puts("#EOF"); + else { + params.printSeparators = tests.size() > 1; + for (unsigned i = 0; i < tests.size(); i++) + runTest(shell, params, tests[i], testShellMode); + } + + shell.callJSGC(); + shell.callJSGC(); + + // When we finish the last test, cleanup the LayoutTestController. + // It may have references to not-yet-cleaned up windows. By cleaning up + // here we help purify reports. + shell.resetTestController(); + } + + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/chromium/EventSender.cpp b/Tools/DumpRenderTree/chromium/EventSender.cpp new file mode 100644 index 000000000..9acc42dfb --- /dev/null +++ b/Tools/DumpRenderTree/chromium/EventSender.cpp @@ -0,0 +1,1130 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file contains the definition for EventSender. +// +// Some notes about drag and drop handling: +// Windows drag and drop goes through a system call to doDragDrop. At that +// point, program control is given to Windows which then periodically makes +// callbacks into the webview. This won't work for layout tests, so instead, +// we queue up all the mouse move and mouse up events. When the test tries to +// start a drag (by calling EvenSendingController::doDragDrop), we take the +// events in the queue and replay them. +// The behavior of queuing events and replaying them can be disabled by a +// layout test by setting eventSender.dragMode to false. + +#include "config.h" +#include "EventSender.h" + +#include "TestShell.h" +#include "WebContextMenuData.h" +#include "platform/WebDragData.h" +#include "WebDragOperation.h" +#include "platform/WebPoint.h" +#include "platform/WebString.h" +#include "WebTouchPoint.h" +#include "WebView.h" +#include "webkit/support/webkit_support.h" +#include <wtf/Deque.h> +#include <wtf/StringExtras.h> + +#if OS(WINDOWS) +#include "win/WebInputEventFactory.h" +#endif + +// FIXME: layout before each event? + +using namespace std; +using namespace WebKit; + +WebPoint EventSender::lastMousePos; +WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone; +WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone; + +struct SavedEvent { + enum SavedEventType { + Unspecified, + MouseUp, + MouseMove, + LeapForward + }; + + SavedEventType type; + WebMouseEvent::Button buttonType; // For MouseUp. + WebPoint pos; // For MouseMove. + int milliseconds; // For LeapForward. + + SavedEvent() + : type(Unspecified) + , buttonType(WebMouseEvent::ButtonNone) + , milliseconds(0) { } +}; + +static WebDragData currentDragData; +static WebDragOperation currentDragEffect; +static WebDragOperationsMask currentDragEffectsAllowed; +static bool replayingSavedEvents = false; +static Deque<SavedEvent> mouseEventQueue; +static int touchModifiers; +static Vector<WebTouchPoint> touchPoints; + +// Time and place of the last mouse up event. +static double lastClickTimeSec = 0; +static WebPoint lastClickPos; +static int clickCount = 0; + +// maximum distance (in space and time) for a mouse click +// to register as a double or triple click +static const double multipleClickTimeSec = 1; +static const int multipleClickRadiusPixels = 5; + +// How much we should scroll per event - the value here is chosen to +// match the WebKit impl and layout test results. +static const float scrollbarPixelsPerTick = 40.0f; + +inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b) +{ + return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) > + multipleClickRadiusPixels * multipleClickRadiusPixels; +} + +// Used to offset the time the event hander things an event happened. This is +// done so tests can run without a delay, but bypass checks that are time +// dependent (e.g., dragging has a timeout vs selection). +static uint32 timeOffsetMs = 0; + +static double getCurrentEventTimeSec() +{ + return (webkit_support::GetCurrentTimeInMillisecond() + timeOffsetMs) / 1000.0; +} + +static void advanceEventTime(int32_t deltaMs) +{ + timeOffsetMs += deltaMs; +} + +static void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b, + const WebPoint& pos, WebMouseEvent* e) +{ + e->type = t; + e->button = b; + e->modifiers = 0; + e->x = pos.x; + e->y = pos.y; + e->globalX = pos.x; + e->globalY = pos.y; + e->timeStampSeconds = getCurrentEventTimeSec(); + e->clickCount = clickCount; +} + +// Returns true if the specified key is the system key. +static bool applyKeyModifier(const string& modifierName, WebInputEvent* event) +{ + bool isSystemKey = false; + const char* characters = modifierName.c_str(); + if (!strcmp(characters, "ctrlKey") +#if !OS(MAC_OS_X) + || !strcmp(characters, "addSelectionKey") +#endif + ) { + event->modifiers |= WebInputEvent::ControlKey; + } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey")) + event->modifiers |= WebInputEvent::ShiftKey; + else if (!strcmp(characters, "altKey")) { + event->modifiers |= WebInputEvent::AltKey; +#if !OS(MAC_OS_X) + // On Windows all keys with Alt modifier will be marked as system key. + // We keep the same behavior on Linux and everywhere non-Mac, see: + // WebKit/chromium/src/gtk/WebInputEventFactory.cpp + // If we want to change this behavior on Linux, this piece of code must be + // kept in sync with the related code in above file. + isSystemKey = true; +#endif +#if OS(MAC_OS_X) + } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) { + event->modifiers |= WebInputEvent::MetaKey; + // On Mac only command key presses are marked as system key. + // See the related code in: WebKit/chromium/src/mac/WebInputEventFactory.cpp + // It must be kept in sync with the related code in above file. + isSystemKey = true; +#else + } else if (!strcmp(characters, "metaKey")) { + event->modifiers |= WebInputEvent::MetaKey; +#endif + } + return isSystemKey; +} + +static bool applyKeyModifiers(const CppVariant* argument, WebInputEvent* event) +{ + bool isSystemKey = false; + if (argument->isObject()) { + Vector<string> modifiers = argument->toStringVector(); + for (Vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i) + isSystemKey |= applyKeyModifier(*i, event); + } else if (argument->isString()) + isSystemKey = applyKeyModifier(argument->toString(), event); + return isSystemKey; +} + +// Get the edit command corresponding to a keyboard event. +// Returns true if the specified event corresponds to an edit command, the name +// of the edit command will be stored in |*name|. +bool getEditCommand(const WebKeyboardEvent& event, string* name) +{ +#if OS(MAC_OS_X) + // We only cares about Left,Right,Up,Down keys with Command or Command+Shift + // modifiers. These key events correspond to some special movement and + // selection editor commands, and was supposed to be handled in + // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked + // as system key, which prevents them from being handled. Thus they must be + // handled specially. + if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey) + return false; + + switch (event.windowsKeyCode) { + case webkit_support::VKEY_LEFT: + *name = "MoveToBeginningOfLine"; + break; + case webkit_support::VKEY_RIGHT: + *name = "MoveToEndOfLine"; + break; + case webkit_support::VKEY_UP: + *name = "MoveToBeginningOfDocument"; + break; + case webkit_support::VKEY_DOWN: + *name = "MoveToEndOfDocument"; + break; + default: + return false; + } + + if (event.modifiers & WebKeyboardEvent::ShiftKey) + name->append("AndModifySelection"); + + return true; +#else + return false; +#endif +} + +// Key event location code introduced in DOM Level 3. +// See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents +enum KeyLocationCode { + DOMKeyLocationStandard = 0x00, + DOMKeyLocationLeft = 0x01, + DOMKeyLocationRight = 0x02, + DOMKeyLocationNumpad = 0x03 +}; + +EventSender::EventSender(TestShell* shell) + : m_shell(shell) +{ + // Initialize the map that associates methods of this class with the names + // they will use when called by JavaScript. The actual binding of those + // names to their methods will be done by calling bindToJavaScript() (defined + // by CppBoundClass, the parent to EventSender). + bindMethod("addTouchPoint", &EventSender::addTouchPoint); + bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles); + bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint); + bindMethod("clearKillRing", &EventSender::clearKillRing); + bindMethod("clearTouchPoints", &EventSender::clearTouchPoints); + bindMethod("contextClick", &EventSender::contextClick); + bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy); + bindMethod("dispatchMessage", &EventSender::dispatchMessage); + bindMethod("dumpFilenameBeingDragged", &EventSender::dumpFilenameBeingDragged); + bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging); + bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement); + bindMethod("keyDown", &EventSender::keyDown); + bindMethod("leapForward", &EventSender::leapForward); + bindMethod("mouseDown", &EventSender::mouseDown); + bindMethod("mouseMoveTo", &EventSender::mouseMoveTo); + bindMethod("mouseScrollBy", &EventSender::mouseScrollBy); + bindMethod("mouseUp", &EventSender::mouseUp); + bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint); + bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick); + bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown); + bindMethod("setTouchModifier", &EventSender::setTouchModifier); + bindMethod("textZoomIn", &EventSender::textZoomIn); + bindMethod("textZoomOut", &EventSender::textZoomOut); + bindMethod("touchCancel", &EventSender::touchCancel); + bindMethod("touchEnd", &EventSender::touchEnd); + bindMethod("touchMove", &EventSender::touchMove); + bindMethod("touchStart", &EventSender::touchStart); + bindMethod("updateTouchPoint", &EventSender::updateTouchPoint); + bindMethod("gestureScrollBegin", &EventSender::gestureScrollBegin); + bindMethod("gestureScrollEnd", &EventSender::gestureScrollEnd); + bindMethod("gestureScrollUpdate", &EventSender::gestureScrollUpdate); + bindMethod("gestureTap", &EventSender::gestureTap); + bindMethod("zoomPageIn", &EventSender::zoomPageIn); + bindMethod("zoomPageOut", &EventSender::zoomPageOut); + bindMethod("scalePageBy", &EventSender::scalePageBy); + + // When set to true (the default value), we batch mouse move and mouse up + // events so we can simulate drag & drop. + bindProperty("dragMode", &dragMode); +#if OS(WINDOWS) + bindProperty("WM_KEYDOWN", &wmKeyDown); + bindProperty("WM_KEYUP", &wmKeyUp); + bindProperty("WM_CHAR", &wmChar); + bindProperty("WM_DEADCHAR", &wmDeadChar); + bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown); + bindProperty("WM_SYSKEYUP", &wmSysKeyUp); + bindProperty("WM_SYSCHAR", &wmSysChar); + bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar); +#endif +} + +void EventSender::reset() +{ + // The test should have finished a drag and the mouse button state. + ASSERT(currentDragData.isNull()); + currentDragData.reset(); + currentDragEffect = WebKit::WebDragOperationNone; + currentDragEffectsAllowed = WebKit::WebDragOperationNone; + pressedButton = WebMouseEvent::ButtonNone; + dragMode.set(true); +#if OS(WINDOWS) + wmKeyDown.set(WM_KEYDOWN); + wmKeyUp.set(WM_KEYUP); + wmChar.set(WM_CHAR); + wmDeadChar.set(WM_DEADCHAR); + wmSysKeyDown.set(WM_SYSKEYDOWN); + wmSysKeyUp.set(WM_SYSKEYUP); + wmSysChar.set(WM_SYSCHAR); + wmSysDeadChar.set(WM_SYSDEADCHAR); +#endif + lastMousePos = WebPoint(0, 0); + lastClickTimeSec = 0; + lastClickPos = WebPoint(0, 0); + clickCount = 0; + lastButtonType = WebMouseEvent::ButtonNone; + timeOffsetMs = 0; + touchModifiers = 0; + touchPoints.clear(); + m_taskList.revokeAll(); + m_gestureStartLocation = WebPoint(0, 0); +} + +WebView* EventSender::webview() +{ + return m_shell->webView(); +} + +void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask) +{ + WebMouseEvent event; + initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event); + WebPoint clientPoint(event.x, event.y); + WebPoint screenPoint(event.globalX, event.globalY); + currentDragData = dragData; + currentDragEffectsAllowed = mask; + currentDragEffect = webview()->dragTargetDragEnter(dragData, clientPoint, screenPoint, currentDragEffectsAllowed); + + // Finish processing events. + replaySavedEvents(); +} + +void EventSender::dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*) +{ + printf("Filename being dragged: %s\n", currentDragData.fileContentFilename().utf8().data()); +} + +WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode) +{ + if (!buttonCode) + return WebMouseEvent::ButtonLeft; + if (buttonCode == 2) + return WebMouseEvent::ButtonRight; + return WebMouseEvent::ButtonMiddle; +} + +int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments) +{ + int buttonCode = 0; + if (arguments.size() > 0 && arguments[0].isNumber()) + buttonCode = arguments[0].toInt32(); + return buttonCode; +} + +void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType) +{ + if ((getCurrentEventTimeSec() - lastClickTimeSec < multipleClickTimeSec) + && (!outsideMultiClickRadius(lastMousePos, lastClickPos)) + && (buttonType == lastButtonType)) + ++clickCount; + else { + clickCount = 1; + lastButtonType = buttonType; + } +} + +// +// Implemented javascript methods. +// + +void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result) +{ + if (result) // Could be 0 if invoked asynchronously. + result->setNull(); + + webview()->layout(); + + int buttonNumber = getButtonNumberFromSingleArg(arguments); + ASSERT(buttonNumber != -1); + + WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber); + + updateClickCountForButton(buttonType); + + WebMouseEvent event; + pressedButton = buttonType; + initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event); + if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) + applyKeyModifiers(&(arguments[1]), &event); + webview()->handleInputEvent(event); +} + +void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result) +{ + if (result) // Could be 0 if invoked asynchronously. + result->setNull(); + + webview()->layout(); + + int buttonNumber = getButtonNumberFromSingleArg(arguments); + ASSERT(buttonNumber != -1); + + WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber); + + if (isDragMode() && !replayingSavedEvents) { + SavedEvent savedEvent; + savedEvent.type = SavedEvent::MouseUp; + savedEvent.buttonType = buttonType; + mouseEventQueue.append(savedEvent); + replaySavedEvents(); + } else { + WebMouseEvent event; + initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event); + if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) + applyKeyModifiers(&(arguments[1]), &event); + doMouseUp(event); + } +} + +void EventSender::doMouseUp(const WebMouseEvent& e) +{ + webview()->handleInputEvent(e); + + pressedButton = WebMouseEvent::ButtonNone; + lastClickTimeSec = e.timeStampSeconds; + lastClickPos = lastMousePos; + + // If we're in a drag operation, complete it. + if (currentDragData.isNull()) + return; + WebPoint clientPoint(e.x, e.y); + WebPoint screenPoint(e.globalX, e.globalY); + + currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed); + if (currentDragEffect) + webview()->dragTargetDrop(clientPoint, screenPoint); + else + webview()->dragTargetDragLeave(); + webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect); + webview()->dragSourceSystemDragEnded(); + + currentDragData.reset(); +} + +void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + webview()->layout(); + + WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32()); + + if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) { + SavedEvent savedEvent; + savedEvent.type = SavedEvent::MouseMove; + savedEvent.pos = mousePos; + mouseEventQueue.append(savedEvent); + } else { + WebMouseEvent event; + initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event); + doMouseMove(event); + } +} + +void EventSender::doMouseMove(const WebMouseEvent& e) +{ + lastMousePos = WebPoint(e.x, e.y); + + webview()->handleInputEvent(e); + + if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull()) + return; + WebPoint clientPoint(e.x, e.y); + WebPoint screenPoint(e.globalX, e.globalY); + currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed); +} + +void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result) +{ + if (result) + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isString()) + return; + bool generateChar = false; + + // FIXME: I'm not exactly sure how we should convert the string to a key + // event. This seems to work in the cases I tested. + // FIXME: Should we also generate a KEY_UP? + string codeStr = arguments[0].toString(); + + // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when + // Windows uses \r for "Enter". + int code = 0; + int text = 0; + bool needsShiftKeyModifier = false; + if ("\n" == codeStr) { + generateChar = true; + text = code = webkit_support::VKEY_RETURN; + } else if ("rightArrow" == codeStr) + code = webkit_support::VKEY_RIGHT; + else if ("downArrow" == codeStr) + code = webkit_support::VKEY_DOWN; + else if ("leftArrow" == codeStr) + code = webkit_support::VKEY_LEFT; + else if ("upArrow" == codeStr) + code = webkit_support::VKEY_UP; + else if ("insert" == codeStr) + code = webkit_support::VKEY_INSERT; + else if ("delete" == codeStr) + code = webkit_support::VKEY_DELETE; + else if ("pageUp" == codeStr) + code = webkit_support::VKEY_PRIOR; + else if ("pageDown" == codeStr) + code = webkit_support::VKEY_NEXT; + else if ("home" == codeStr) + code = webkit_support::VKEY_HOME; + else if ("end" == codeStr) + code = webkit_support::VKEY_END; + else if ("printScreen" == codeStr) + code = webkit_support::VKEY_SNAPSHOT; + else if ("menu" == codeStr) + // FIXME: Change this to webkit_support::VKEY_APPS. + code = 0x5D; + else { + // Compare the input string with the function-key names defined by the + // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key + // name, set its key code. + for (int i = 1; i <= 24; ++i) { + char functionChars[10]; + snprintf(functionChars, 10, "F%d", i); + string functionKeyName(functionChars); + if (functionKeyName == codeStr) { + code = webkit_support::VKEY_F1 + (i - 1); + break; + } + } + if (!code) { + WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size()); + ASSERT(webCodeStr.length() == 1); + text = code = webCodeStr.data()[0]; + needsShiftKeyModifier = needsShiftModifier(code); + if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z') + code -= 'a' - 'A'; + generateChar = true; + } + } + + // For one generated keyboard event, we need to generate a keyDown/keyUp + // pair; refer to EventSender.cpp in Tools/DumpRenderTree/win. + // On Windows, we might also need to generate a char event to mimic the + // Windows event flow; on other platforms we create a merged event and test + // the event flow that that platform provides. + WebKeyboardEvent eventDown, eventChar, eventUp; + eventDown.type = WebInputEvent::RawKeyDown; + eventDown.modifiers = 0; + eventDown.windowsKeyCode = code; +#if OS(LINUX) && USE(GTK) + eventDown.nativeKeyCode = webkit_support::NativeKeyCodeForWindowsKeyCode(code, needsShiftKeyModifier); +#endif + + 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/Source/WebKit/chromium/src/EditorClientImpl.cpp. + // We just simulate the same behavior here. + string editCommand; + if (getEditCommand(eventDown, &editCommand)) + m_shell->webViewHost()->setEditCommand(editCommand, ""); + + webview()->handleInputEvent(eventDown); + + m_shell->webViewHost()->clearEditCommand(); + + if (generateChar) { + eventChar.type = WebInputEvent::Char; + eventChar.keyIdentifier[0] = '\0'; + webview()->handleInputEvent(eventChar); + } + + webview()->handleInputEvent(eventUp); +} + +void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + +#if OS(WINDOWS) + if (arguments.size() == 3) { + // Grab the message id to see if we need to dispatch it. + int msg = arguments[0].toInt32(); + + // WebKit's version of this function stuffs a MSG struct and uses + // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which + // doesn't need to receive the DeadChar and SysDeadChar messages. + if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR) + return; + + webview()->layout(); + + unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble()); + webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam)); + } else + ASSERT_NOT_REACHED(); +#endif +} + +bool EventSender::needsShiftModifier(int keyCode) +{ + // If code is an uppercase letter, assign a SHIFT key to + // eventDown.modifier, this logic comes from + // Tools/DumpRenderTree/win/EventSender.cpp + return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z'; +} + +void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() < 1 || !arguments[0].isNumber()) + return; + + int milliseconds = arguments[0].toInt32(); + if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) { + SavedEvent savedEvent; + savedEvent.type = SavedEvent::LeapForward; + savedEvent.milliseconds = milliseconds; + mouseEventQueue.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::scalePageBy(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber()) + return; + + float scaleFactor = static_cast<float>(arguments[0].toDouble()); + int x = arguments[1].toInt32(); + int y = arguments[2].toInt32(); + webview()->setPageScaleFactor(scaleFactor, WebPoint(x, y)); + result->setNull(); +} + +void EventSender::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result) +{ + handleMouseWheel(arguments, result, false); +} + +void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result) +{ + handleMouseWheel(arguments, result, true); +} + +void EventSender::replaySavedEvents() +{ + replayingSavedEvents = true; + while (!mouseEventQueue.isEmpty()) { + SavedEvent e = mouseEventQueue.takeFirst(); + + switch (e.type) { + case SavedEvent::MouseMove: { + WebMouseEvent event; + initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event); + doMouseMove(event); + break; + } + case SavedEvent::LeapForward: + doLeapForward(e.milliseconds); + break; + case SavedEvent::MouseUp: { + WebMouseEvent event; + initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event); + doMouseUp(event); + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + replayingSavedEvents = false; +} + +// Because actual context menu is implemented by the browser side, +// this function does only what LayoutTests are expecting: +// - Many test checks the count of items. So returning non-zero value makes sense. +// - Some test compares the count before and after some action. So changing the count based on flags +// also makes sense. This function is doing such for some flags. +// - Some test even checks actual string content. So providing it would be also helpful. +// +static Vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, MockSpellCheck* spellcheck) +{ + // These constants are based on Safari's context menu because tests are made for it. + static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 }; + static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 }; + + // This is possible because mouse events are cancelleable. + if (!contextMenu) + return Vector<WebString>(); + + Vector<WebString> strings; + + if (contextMenu->isEditable) { + for (const char** item = editableMenuStrings; *item; ++item) + strings.append(WebString::fromUTF8(*item)); + Vector<WebString> suggestions; + spellcheck->fillSuggestionList(contextMenu->misspelledWord, &suggestions); + for (size_t i = 0; i < suggestions.size(); ++i) + strings.append(suggestions[i]); + } else { + for (const char** item = nonEditableMenuStrings; *item; ++item) + strings.append(WebString::fromUTF8(*item)); + } + + return strings; +} + + +void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result) +{ + webview()->layout(); + + updateClickCountForButton(WebMouseEvent::ButtonRight); + + // Clears last context menu data because we need to know if the context menu be requested + // after following mouse events. + m_shell->webViewHost()->clearContextMenuData(); + + // Generate right mouse down and up. + WebMouseEvent event; + pressedButton = WebMouseEvent::ButtonRight; + initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event); + webview()->handleInputEvent(event); + + initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event); + webview()->handleInputEvent(event); + + pressedButton = WebMouseEvent::ButtonNone; + + WebContextMenuData* lastContextMenu = m_shell->webViewHost()->lastContextMenuData(); + result->set(WebBindings::makeStringArray(makeMenuItemStringsFor(lastContextMenu, m_shell->webViewHost()->mockSpellCheck()))); +} + +class MouseDownTask: public MethodTask<EventSender> { +public: + MouseDownTask(EventSender* obj, const CppArgumentList& arg) + : MethodTask<EventSender>(obj), m_arguments(arg) { } + virtual void runIfValid() { m_object->mouseDown(m_arguments, 0); } + +private: + CppArgumentList m_arguments; +}; + +class MouseUpTask: public MethodTask<EventSender> { +public: + MouseUpTask(EventSender* obj, const CppArgumentList& arg) + : MethodTask<EventSender>(obj), m_arguments(arg) { } + virtual void runIfValid() { m_object->mouseUp(m_arguments, 0); } + +private: + CppArgumentList m_arguments; +}; + +void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + postTask(new MouseDownTask(this, arguments)); + postTask(new MouseUpTask(this, arguments)); +} + +class KeyDownTask : public MethodTask<EventSender> { +public: + KeyDownTask(EventSender* obj, const CppArgumentList& arg) + : MethodTask<EventSender>(obj), m_arguments(arg) { } + virtual void runIfValid() { m_object->keyDown(m_arguments, 0); } + +private: + CppArgumentList m_arguments; +}; + +void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + postTask(new KeyDownTask(this, arguments)); +} + +void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result) +{ + currentDragData.initialize(); + Vector<string> files = arguments[0].toStringVector(); + for (size_t i = 0; i < files.size(); ++i) + currentDragData.appendToFilenames(webkit_support::GetAbsoluteWebStringFromUTF8Path(files[i])); + currentDragEffectsAllowed = WebKit::WebDragOperationCopy; + + // Provide a drag source. + webview()->dragTargetDragEnter(currentDragData, lastMousePos, lastMousePos, currentDragEffectsAllowed); + + // dragMode saves events and then replays them later. We don't need/want that. + dragMode.set(false); + + // Make the rest of eventSender think a drag is in progress. + pressedButton = WebMouseEvent::ButtonLeft; + + result->setNull(); +} + +void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + WebTouchPoint touchPoint; + touchPoint.state = WebTouchPoint::StatePressed; + touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32()); + touchPoint.screenPosition = touchPoint.position; + + int lowestId = 0; + for (size_t i = 0; i < touchPoints.size(); i++) { + if (touchPoints[i].id == lowestId) + lowestId++; + } + touchPoint.id = lowestId; + touchPoints.append(touchPoint); +} + +void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + touchPoints.clear(); +} + +void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + const unsigned index = arguments[0].toInt32(); + ASSERT(index < touchPoints.size()); + + WebTouchPoint* touchPoint = &touchPoints[index]; + touchPoint->state = WebTouchPoint::StateReleased; +} + +void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + int mask = 0; + const string keyName = arguments[0].toString(); + if (keyName == "shift") + mask = WebInputEvent::ShiftKey; + else if (keyName == "alt") + mask = WebInputEvent::AltKey; + else if (keyName == "ctrl") + mask = WebInputEvent::ControlKey; + else if (keyName == "meta") + mask = WebInputEvent::MetaKey; + + if (arguments[1].toBoolean()) + touchModifiers |= mask; + else + touchModifiers &= ~mask; +} + +void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + const unsigned index = arguments[0].toInt32(); + ASSERT(index < touchPoints.size()); + + WebPoint position(arguments[1].toInt32(), arguments[2].toInt32()); + WebTouchPoint* touchPoint = &touchPoints[index]; + touchPoint->state = WebTouchPoint::StateMoved; + touchPoint->position = position; + touchPoint->screenPosition = position; +} + +void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + const unsigned index = arguments[0].toInt32(); + ASSERT(index < touchPoints.size()); + + WebTouchPoint* touchPoint = &touchPoints[index]; + touchPoint->state = WebTouchPoint::StateCancelled; +} + +void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type) +{ + ASSERT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap) > touchPoints.size()); + webview()->layout(); + + WebTouchEvent touchEvent; + touchEvent.type = type; + touchEvent.modifiers = touchModifiers; + touchEvent.timeStampSeconds = getCurrentEventTimeSec(); + touchEvent.touchesLength = touchPoints.size(); + for (unsigned i = 0; i < touchPoints.size(); ++i) + touchEvent.touches[i] = touchPoints[i]; + webview()->handleInputEvent(touchEvent); + + for (unsigned i = 0; i < touchPoints.size(); ++i) { + WebTouchPoint* touchPoint = &touchPoints[i]; + if (touchPoint->state == WebTouchPoint::StateReleased) { + touchPoints.remove(i); + --i; + } else + touchPoint->state = WebTouchPoint::StateStationary; + } +} + +void EventSender::handleMouseWheel(const CppArgumentList& arguments, CppVariant* result, bool continuous) +{ + result->setNull(); + + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + + // Force a layout here just to make sure every position has been + // determined before we send events (as well as all the other methods + // that send an event do). + webview()->layout(); + + int horizontal = arguments[0].toInt32(); + int vertical = arguments[1].toInt32(); + int paged = false; + + if (arguments.size() > 2 && arguments[2].isBool()) + paged = arguments[2].toBoolean(); + + WebMouseWheelEvent event; + initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, &event); + event.wheelTicksX = static_cast<float>(horizontal); + event.wheelTicksY = static_cast<float>(vertical); + event.deltaX = event.wheelTicksX; + event.deltaY = event.wheelTicksY; + event.scrollByPage = paged; + if (continuous) { + event.wheelTicksX /= scrollbarPixelsPerTick; + event.wheelTicksY /= scrollbarPixelsPerTick; + } else { + event.deltaX *= scrollbarPixelsPerTick; + event.deltaY *= scrollbarPixelsPerTick; + } + webview()->handleInputEvent(event); +} + +void EventSender::touchEnd(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + sendCurrentTouchEvent(WebInputEvent::TouchEnd); +} + +void EventSender::touchMove(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + sendCurrentTouchEvent(WebInputEvent::TouchMove); +} + +void EventSender::touchStart(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + sendCurrentTouchEvent(WebInputEvent::TouchStart); +} + +void EventSender::touchCancel(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + sendCurrentTouchEvent(WebInputEvent::TouchCancel); +} + +void EventSender::gestureScrollBegin(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + gestureEvent(WebInputEvent::GestureScrollBegin, arguments); +} + +void EventSender::gestureScrollEnd(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + gestureEvent(WebInputEvent::GestureScrollEnd, arguments); +} + +void EventSender::gestureScrollUpdate(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + gestureEvent(WebInputEvent::GestureScrollUpdate, arguments); +} + +void EventSender::gestureTap(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + gestureEvent(WebInputEvent::GestureTap, arguments); +} + +void EventSender::gestureEvent(WebInputEvent::Type type, const CppArgumentList& arguments) +{ + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + + WebPoint point(arguments[0].toInt32(), arguments[1].toInt32()); + + WebGestureEvent event; + event.type = type; + + switch (type) { + case WebInputEvent::GestureScrollUpdate: + event.deltaX = static_cast<float>(arguments[0].toDouble()); + event.deltaY = static_cast<float>(arguments[1].toDouble()); + event.x = m_gestureStartLocation.x + event.deltaX; + event.y = m_gestureStartLocation.y + event.deltaY; + break; + + case WebInputEvent::GestureScrollBegin: + m_gestureStartLocation = WebPoint(point.x, point.y); + // Fallthrough + case WebInputEvent::GestureScrollEnd: + case WebInputEvent::GestureTap: + event.x = point.x; + event.y = point.y; + break; + default: + ASSERT_NOT_REACHED(); + } + + event.globalX = event.x; + event.globalY = event.y; + event.timeStampSeconds = getCurrentEventTimeSec(); + webview()->handleInputEvent(event); +} + +// +// Unimplemented stubs +// + +void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); +} + +void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); +} + +void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); +} diff --git a/Tools/DumpRenderTree/chromium/EventSender.h b/Tools/DumpRenderTree/chromium/EventSender.h new file mode 100644 index 000000000..bbecc5488 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/EventSender.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + EventSender class: + Bound to a JavaScript window.eventSender object using + CppBoundClass::bindToJavascript(), this allows layout tests to fire DOM events. +*/ + +#ifndef EventSender_h +#define EventSender_h + +#include "CppBoundClass.h" +#include "Task.h" +#include "WebDragOperation.h" +#include "WebInputEvent.h" +#include "platform/WebPoint.h" + +class TestShell; + +namespace WebKit { +class WebDragData; +class WebView; +} + +class EventSender : public CppBoundClass { +public: + // Builds the property and method lists needed to bind this class to a JS + // object. + EventSender(TestShell*); + + // Resets some static variable state. + void reset(); + + // Simulate drag&drop system call. + void doDragDrop(const WebKit::WebDragData&, WebKit::WebDragOperationsMask); + + // Test helper for dragging out images. + void dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*); + + // JS callback methods. + void mouseDown(const CppArgumentList&, CppVariant*); + void mouseUp(const CppArgumentList&, CppVariant*); + void mouseMoveTo(const CppArgumentList&, CppVariant*); + void leapForward(const CppArgumentList&, CppVariant*); + void keyDown(const CppArgumentList&, CppVariant*); + void dispatchMessage(const CppArgumentList&, CppVariant*); + // FIXME: These aren't really events. They should be moved to layout controller. + void textZoomIn(const CppArgumentList&, CppVariant*); + void textZoomOut(const CppArgumentList&, CppVariant*); + void zoomPageIn(const CppArgumentList&, CppVariant*); + void zoomPageOut(const CppArgumentList&, CppVariant*); + void scalePageBy(const CppArgumentList&, CppVariant*); + + void mouseScrollBy(const CppArgumentList&, CppVariant*); + void continuousMouseScrollBy(const CppArgumentList&, CppVariant*); + void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*); + void scheduleAsynchronousKeyDown(const CppArgumentList&, CppVariant*); + void beginDragWithFiles(const CppArgumentList&, CppVariant*); + CppVariant dragMode; + + void addTouchPoint(const CppArgumentList&, CppVariant*); + void cancelTouchPoint(const CppArgumentList&, CppVariant*); + void clearTouchPoints(const CppArgumentList&, CppVariant*); + void releaseTouchPoint(const CppArgumentList&, CppVariant*); + void setTouchModifier(const CppArgumentList&, CppVariant*); + void touchCancel(const CppArgumentList&, CppVariant*); + void touchEnd(const CppArgumentList&, CppVariant*); + void touchMove(const CppArgumentList&, CppVariant*); + void touchStart(const CppArgumentList&, CppVariant*); + void updateTouchPoint(const CppArgumentList&, CppVariant*); + + void gestureScrollBegin(const CppArgumentList&, CppVariant*); + void gestureScrollEnd(const CppArgumentList&, CppVariant*); + void gestureScrollUpdate(const CppArgumentList&, CppVariant*); + void gestureTap(const CppArgumentList&, CppVariant*); + void gestureEvent(WebKit::WebInputEvent::Type, const CppArgumentList&); + + // Unimplemented stubs + void contextClick(const CppArgumentList&, CppVariant*); + void enableDOMUIEventLogging(const CppArgumentList&, CppVariant*); + void fireKeyboardEventsToElement(const CppArgumentList&, CppVariant*); + void clearKillRing(const CppArgumentList&, CppVariant*); + + // Properties used in layout tests. +#if defined(OS_WIN) + CppVariant wmKeyDown; + CppVariant wmKeyUp; + CppVariant wmChar; + CppVariant wmDeadChar; + CppVariant wmSysKeyDown; + CppVariant wmSysKeyUp; + CppVariant wmSysChar; + CppVariant wmSysDeadChar; +#endif + + TaskList* taskList() { return &m_taskList; } + +private: + // Returns the test shell's webview. + WebKit::WebView* webview(); + + // Returns true if dragMode is true. + bool isDragMode() { return dragMode.isBool() && dragMode.toBoolean(); } + + // Sometimes we queue up mouse move and mouse up events for drag drop + // handling purposes. These methods dispatch the event. + void doMouseMove(const WebKit::WebMouseEvent&); + void doMouseUp(const WebKit::WebMouseEvent&); + static void doLeapForward(int milliseconds); + void replaySavedEvents(); + + // Helper to return the button type given a button code + static WebKit::WebMouseEvent::Button getButtonTypeFromButtonNumber(int); + + // Helper to extract the button number from the optional argument in + // mouseDown and mouseUp + static int getButtonNumberFromSingleArg(const CppArgumentList&); + + // Returns true if the specified key code passed in needs a shift key + // modifier to be passed into the generated event. + bool needsShiftModifier(int); + + void updateClickCountForButton(WebKit::WebMouseEvent::Button); + + // Compose a touch event from the current touch points and send it. + void sendCurrentTouchEvent(const WebKit::WebInputEvent::Type); + + // Handle a request to send a wheel event. + void handleMouseWheel(const CppArgumentList&, CppVariant*, bool continuous); + + TaskList m_taskList; + + // Non-owning pointer. The EventSender is owned by the TestShell. + TestShell* m_shell; + + // Location of the touch point that initiated a gesture. + WebKit::WebPoint m_gestureStartLocation; + + // Location of last mouseMoveTo event. + static WebKit::WebPoint lastMousePos; + + // Currently pressed mouse button (Left/Right/Middle or None) + static WebKit::WebMouseEvent::Button pressedButton; + + // The last button number passed to mouseDown and mouseUp. + // Used to determine whether the click count continues to + // increment or not. + static WebKit::WebMouseEvent::Button lastButtonType; +}; + +#endif // EventSender_h diff --git a/Tools/DumpRenderTree/chromium/GamepadController.cpp b/Tools/DumpRenderTree/chromium/GamepadController.cpp new file mode 100644 index 000000000..2974d3bcd --- /dev/null +++ b/Tools/DumpRenderTree/chromium/GamepadController.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2011 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 "GamepadController.h" + +#include "TestShell.h" + +using namespace WebKit; + +GamepadController::GamepadController(TestShell* shell) + : m_shell(shell) +{ + bindMethod("connect", &GamepadController::connect); + bindMethod("disconnect", &GamepadController::disconnect); + bindMethod("setId", &GamepadController::setId); + bindMethod("setButtonCount", &GamepadController::setButtonCount); + bindMethod("setButtonData", &GamepadController::setButtonData); + bindMethod("setAxisCount", &GamepadController::setAxisCount); + bindMethod("setAxisData", &GamepadController::setAxisData); + + bindFallbackMethod(&GamepadController::fallbackCallback); + + reset(); +} + +void GamepadController::bindToJavascript(WebFrame* frame, const WebString& classname) +{ + CppBoundClass::bindToJavascript(frame, classname); +} + +void GamepadController::reset() +{ + memset(&internalData, 0, sizeof(internalData)); +} + +void GamepadController::connect(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 1) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + internalData.items[index].connected = true; + internalData.length = 0; + for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) + if (internalData.items[i].connected) + internalData.length = i + 1; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::disconnect(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 1) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + internalData.items[index].connected = false; + internalData.length = 0; + for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) + if (internalData.items[i].connected) + internalData.length = i + 1; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::setId(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 2) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + std::string src = args[1].toString(); + const char* p = src.c_str(); + memset(internalData.items[index].id, 0, sizeof(internalData.items[index].id)); + for (unsigned i = 0; *p && i < WebKit::WebGamepad::idLengthCap - 1; ++i) + internalData.items[index].id[i] = *p++; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::setButtonCount(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 2) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + int buttons = args[1].toInt32(); + internalData.items[index].buttonsLength = buttons; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::setButtonData(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 3) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + int button = args[1].toInt32(); + double data = args[2].toDouble(); + internalData.items[index].buttons[button] = data; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::setAxisCount(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 2) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + int axes = args[1].toInt32(); + internalData.items[index].axesLength = axes; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::setAxisData(const CppArgumentList& args, CppVariant* result) +{ + if (args.size() < 3) { + printf("Invalid args"); + return; + } + int index = args[0].toInt32(); + int axis = args[1].toInt32(); + double data = args[2].toDouble(); + internalData.items[index].axes[axis] = data; + webkit_support::SetGamepadData(internalData); + result->setNull(); +} + +void GamepadController::fallbackCallback(const CppArgumentList&, CppVariant* result) +{ + printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on " + "GamepadController\n"); + result->setNull(); +} diff --git a/Tools/DumpRenderTree/chromium/GamepadController.h b/Tools/DumpRenderTree/chromium/GamepadController.h new file mode 100644 index 000000000..414228855 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/GamepadController.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 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 GamepadController_h +#define GamepadController_h + +#include "CppBoundClass.h" +#include "platform/WebGamepads.h" + +namespace WebKit { +class WebGamepads; +class WebFrame; +} + +class TestShell; + +class GamepadController : public CppBoundClass { +public: + explicit GamepadController(TestShell*); + + void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname); + void reset(); + +private: + // Bound methods and properties + void connect(const CppArgumentList&, CppVariant*); + void disconnect(const CppArgumentList&, CppVariant*); + void setId(const CppArgumentList&, CppVariant*); + void setButtonCount(const CppArgumentList&, CppVariant*); + void setButtonData(const CppArgumentList&, CppVariant*); + void setAxisCount(const CppArgumentList&, CppVariant*); + void setAxisData(const CppArgumentList&, CppVariant*); + void fallbackCallback(const CppArgumentList&, CppVariant*); + + TestShell* m_shell; + + WebKit::WebGamepads internalData; +}; + +#endif // GamepadController_h diff --git a/Tools/DumpRenderTree/chromium/ImageDiff.cpp b/Tools/DumpRenderTree/chromium/ImageDiff.cpp new file mode 100644 index 000000000..966554bab --- /dev/null +++ b/Tools/DumpRenderTree/chromium/ImageDiff.cpp @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file input format is based loosely on +// WebKitTools/DumpRenderTree/ImageDiff.m + +// The exact format of this tool's output to stdout is important, to match +// what the run-webkit-tests script expects. + +#include "config.h" + +#include "webkit/support/webkit_support_gfx.h" +#include <algorithm> +#include <iterator> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <vector> + +#if OS(WINDOWS) +#include <windows.h> +#define PATH_MAX MAX_PATH +#endif + +// Define macro here to make ImageDiff independent of JavaScriptCore. +#ifdef NDEBUG +#define ASSERT(assertion) do { } while (0) +#else +#define ASSERT(assertion) do \ + if (!(assertion)) { \ + fprintf(stderr, "ASSERT failed at %s:%d: " #assertion ".", __FILE__, __LINE__); \ + exit(1); \ + } \ +while (0) +#endif + +using namespace std; + +// Causes the app to remain open, waiting for pairs of filenames on stdin. +// The caller is then responsible for terminating this app. +static const char optionPollStdin[] = "--use-stdin"; +static const char optionGenerateDiff[] = "--diff"; + +// If --diff is passed, causes the app to output the image difference +// metric (percentageDifferent()) on stdout. +static const char optionWrite[] = "--write-image-diff-metrics"; + +// Use weightedPercentageDifferent() instead of the default image +// comparator proc. +static const char optionWeightedIntensity[] = "--weighted-intensity"; + +// 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 unsigned int rgbaRed = 0x000000ff; +static const unsigned int 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 createFromStdin(size_t byteLength) + { + if (!byteLength) + return false; + + unsigned char* source = new unsigned char[byteLength]; + if (fread(source, 1, byteLength, stdin) != byteLength) { + delete [] source; + return false; + } + + if (!webkit_support::DecodePNG(source, byteLength, &m_data, &m_width, &m_height)) { + delete [] source; + clear(); + return false; + } + delete [] source; + return true; + } + + // Creates the image from the given filename on disk, and returns true on + // success. + bool createFromFilename(const char* filename) + { + FILE* f = fopen(filename, "rb"); + if (!f) + return false; + + vector<unsigned char> compressed; + const int bufSize = 1024; + unsigned char buf[bufSize]; + size_t numRead = 0; + while ((numRead = fread(buf, 1, bufSize, f)) > 0) + std::copy(buf, &buf[numRead], std::back_inserter(compressed)); + + fclose(f); + + if (!webkit_support::DecodePNG(&compressed[0], compressed.size(), &m_data, &m_width, &m_height)) { + clear(); + return false; + } + return true; + } + + void clear() + { + m_width = m_height = 0; + m_data.clear(); + } + + // Returns the RGBA value of the pixel at the given location + const unsigned int pixelAt(int x, int y) const + { + ASSERT(x >= 0 && x < m_width); + ASSERT(y >= 0 && y < m_height); + return *reinterpret_cast<const unsigned int*>(&(m_data[(y * m_width + x) * 4])); + } + + void setPixelAt(int x, int y, unsigned int 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<unsigned int*>(addr) = color; + } + +private: + // pixel dimensions of the image + int m_width, m_height; + + vector<unsigned char> m_data; +}; + +typedef float (*ImageComparisonProc) (const Image&, const Image&); + +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; +} + +inline unsigned int maxOf3(unsigned int a, unsigned int b, unsigned int c) +{ + if (a < b) + return std::max(b, c); + return std::max(a, c); +} + +inline unsigned int getRedComponent(unsigned int color) +{ + return (color << 24) >> 24; +} + +inline unsigned int getGreenComponent(unsigned int color) +{ + return (color << 16) >> 24; +} + +inline unsigned int getBlueComponent(unsigned int color) +{ + return (color << 8) >> 24; +} + +/// Rank small-pixel-count high-intensity changes as more important than +/// large-pixel-count low-intensity changes. +float weightedPercentageDifferent(const Image& baseline, const Image& actual) +{ + int w = min(baseline.width(), actual.width()); + int h = min(baseline.height(), actual.height()); + + float weightedPixelsDifferent = 0; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + unsigned int actualColor = actual.pixelAt(x, y); + unsigned int baselineColor = baseline.pixelAt(x, y); + if (baselineColor != actualColor) { + unsigned int actualR = getRedComponent(actualColor); + unsigned int actualG = getGreenComponent(actualColor); + unsigned int actualB = getBlueComponent(actualColor); + unsigned int baselineR = getRedComponent(baselineColor); + unsigned int baselineG = getGreenComponent(baselineColor); + unsigned int baselineB = getBlueComponent(baselineColor); + unsigned int deltaR = std::max(actualR, baselineR) + - std::min(actualR, baselineR); + unsigned int deltaG = std::max(actualG, baselineG) + - std::min(actualG, baselineG); + unsigned int deltaB = std::max(actualB, baselineB) + - std::min(actualB, baselineB); + weightedPixelsDifferent += + static_cast<float>(maxOf3(deltaR, deltaG, deltaB)) / 255; + } + } + } + + int maxWidth = max(baseline.width(), actual.width()); + int maxHeight = max(baseline.height(), actual.height()); + + weightedPixelsDifferent += (maxWidth - w) * h; + + weightedPixelsDifferent += (maxHeight - h) * maxWidth; + + float totalPixels = static_cast<float>(actual.width()) + * static_cast<float>(actual.height()); + if (!totalPixels) + return 100.0f; + return weightedPixelsDifferent / 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" + " --write-image-diff-metrics prints a difference metric to stdout\n" + " --weighted-intensity weights the difference metric by intensity\n" + " at each pixel\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, + ImageComparisonProc comparator) +{ + 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 = (*comparator)(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(ImageComparisonProc comparator) +{ + 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.createFromStdin(imageSize)) { + fputs("Error, input image can't be decoded.\n", stderr); + return 1; + } + } else if (imageSize > 0 && !baselineImage.hasImage()) { + if (!baselineImage.createFromStdin(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 = (*comparator)(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) { + unsigned int 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. + unsigned int alpha = basePixel & rgbaAlpha; + unsigned int newPixel = basePixel - ((alpha / 2) & rgbaAlpha); + out->setPixelAt(x, y, newPixel); + } + } + } + + return same; +} + +static bool writeFile(const char* outFile, const unsigned char* data, size_t dataSize) +{ + FILE* file = fopen(outFile, "wb"); + if (!file) { + fprintf(stderr, "ImageDiff: Unable to create file \"%s\"\n", outFile); + return false; + } + if (dataSize != fwrite(data, 1, dataSize, file)) { + fclose(file); + fprintf(stderr, "ImageDiff: Unable to write data to file \"%s\"\n", outFile); + return false; + } + fclose(file); + return true; +} + +int diffImages(const char* file1, const char* file2, const char* outFile, + bool shouldWritePercentages, ImageComparisonProc comparator) +{ + Image actualImage; + Image baselineImage; + + if (!actualImage.createFromFilename(file1)) { + fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1); + return statusError; + } + if (!baselineImage.createFromFilename(file2)) { + fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2); + return statusError; + } + + Image diffImage; + bool same = createImageDiff(baselineImage, actualImage, &diffImage); + if (same) + return statusSame; + + vector<unsigned char> pngData; + webkit_support::EncodeRGBAPNG(diffImage.data(), diffImage.width(), diffImage.height(), + diffImage.width() * 4, &pngData); + if (!writeFile(outFile, &pngData.front(), pngData.size())) + return statusError; + + if (shouldWritePercentages) { + float percent = (*comparator)(actualImage, baselineImage); + fprintf(stdout, "%.3f\n", percent); + } + + return statusDifferent; +} + +int main(int argc, const char* argv[]) +{ + std::vector<const char*> values; + bool pollStdin = false; + bool generateDiff = false; + bool shouldWritePercentages = false; + ImageComparisonProc comparator = percentageDifferent; + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], optionPollStdin)) + pollStdin = true; + else if (!strcmp(argv[i], optionGenerateDiff)) + generateDiff = true; + else if (!strcmp(argv[i], optionWrite)) + shouldWritePercentages = true; + else if (!strcmp(argv[i], optionWeightedIntensity)) + comparator = weightedPercentageDifferent; + else + values.push_back(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, + comparator) == 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], + shouldWritePercentages, comparator); + } else if (values.size() == 2) + return compareImages(argv[1], argv[2], comparator); + + printHelp(); + return statusError; +} diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp new file mode 100644 index 000000000..7fc21362f --- /dev/null +++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -0,0 +1,2152 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LayoutTestController.h" + +#include "DRTDevToolsAgent.h" +#include "TestShell.h" +#include "WebAnimationController.h" +#include "WebBindings.h" +#include "WebConsoleMessage.h" +#include "platform/WebData.h" +#include "WebDeviceOrientation.h" +#include "WebDeviceOrientationClientMock.h" +#include "WebDocument.h" +#include "WebElement.h" +#include "WebFindOptions.h" +#include "WebFrame.h" +#include "WebGeolocationClientMock.h" +#include "WebIDBFactory.h" +#include "WebInputElement.h" +#include "WebKit.h" +#include "WebNotificationPresenter.h" +#include "WebPermissions.h" +#include "WebScriptSource.h" +#include "WebSecurityPolicy.h" +#include "WebSettings.h" +#include "platform/WebSize.h" +#include "WebSpeechInputControllerMock.h" +#include "platform/WebURL.h" +#include "WebView.h" +#include "WebViewHost.h" +#include "webkit/support/webkit_support.h" +#include <algorithm> +#include <cctype> +#include <clocale> +#include <cstdlib> +#include <limits> +#include <sstream> +#include <wtf/text/WTFString.h> + +#if OS(WINDOWS) +#include <wtf/OwnArrayPtr.h> +#endif + +using namespace WebCore; +using namespace WebKit; +using namespace std; + +LayoutTestController::LayoutTestController(TestShell* shell) + : m_shell(shell) + , m_closeRemainingWindows(false) + , m_deferMainResourceDataLoad(false) + , m_showDebugLayerTree(false) + , m_workQueue(this) + , m_shouldStayOnPageAfterHandlingBeforeUnload(false) +{ + + // Initialize the map that associates methods of this class with the names + // they will use when called by JavaScript. The actual binding of those + // names to their methods will be done by calling bindToJavaScript() (defined + // by CppBoundClass, the parent to LayoutTestController). + bindMethod("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag); + bindMethod("addMockSpeechInputResult", &LayoutTestController::addMockSpeechInputResult); + bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry); + bindMethod("addUserScript", &LayoutTestController::addUserScript); + bindMethod("addUserStyleSheet", &LayoutTestController::addUserStyleSheet); + bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases); + bindMethod("closeWebInspector", &LayoutTestController::closeWebInspector); + bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById); + bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading); + bindMethod("display", &LayoutTestController::display); + bindMethod("displayInvalidatedRegion", &LayoutTestController::displayInvalidatedRegion); + bindMethod("dumpAsText", &LayoutTestController::dumpAsText); + bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList); + bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText); + bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions); + bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks); + bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks); + bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks); + bindMethod("dumpProgressFinishedCallback", &LayoutTestController::dumpProgressFinishedCallback); + bindMethod("dumpUserGestureInFrameLoadCallbacks", &LayoutTestController::dumpUserGestureInFrameLoadCallbacks); + bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks); + bindMethod("dumpResourceResponseMIMETypes", &LayoutTestController::dumpResourceResponseMIMETypes); + bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect); + bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges); + bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges); + bindMethod("dumpPermissionClientCallbacks", &LayoutTestController::dumpPermissionClientCallbacks); + bindMethod("dumpCreateView", &LayoutTestController::dumpCreateView); + bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId); + bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector); + bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld); + bindMethod("setIsolatedWorldSecurityOrigin", &LayoutTestController::setIsolatedWorldSecurityOrigin); + bindMethod("execCommand", &LayoutTestController::execCommand); + bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors); + bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission); + bindMethod("hasSpellingMarker", &LayoutTestController::hasSpellingMarker); + bindMethod("findString", &LayoutTestController::findString); + bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled); + bindMethod("hasCustomPageSizeStyle", &LayoutTestController::hasCustomPageSizeStyle); + bindMethod("isPageBoxVisible", &LayoutTestController::isPageBoxVisible); + bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText); + bindMethod("loseCompositorContext", &LayoutTestController::loseCompositorContext); + bindMethod("markerTextForListItem", &LayoutTestController::markerTextForListItem); + bindMethod("notifyDone", &LayoutTestController::notifyDone); + bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations); + bindMethod("numberOfPages", &LayoutTestController::numberOfPages); + bindMethod("numberOfPendingGeolocationPermissionRequests", &LayoutTestController:: numberOfPendingGeolocationPermissionRequests); + bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual); + bindMethod("overridePreference", &LayoutTestController::overridePreference); + bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById); + bindMethod("pageProperty", &LayoutTestController::pageProperty); + bindMethod("pageSizeAndMarginsInPixels", &LayoutTestController::pageSizeAndMarginsInPixels); + bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource); + bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId); + bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId); + bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation); + bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation); + bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript); + bindMethod("queueLoad", &LayoutTestController::queueLoad); + bindMethod("queueLoadHTMLString", &LayoutTestController::queueLoadHTMLString); + bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript); + bindMethod("queueReload", &LayoutTestController::queueReload); + bindMethod("removeOriginAccessWhitelistEntry", &LayoutTestController::removeOriginAccessWhitelistEntry); + bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally); + bindMethod("resetPageVisibility", &LayoutTestController::resetPageVisibility); + bindMethod("resumeAnimations", &LayoutTestController::resumeAnimations); + bindMethod("sampleSVGAnimationForElementAtTime", &LayoutTestController::sampleSVGAnimationForElementAtTime); + bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing); + bindMethod("setAllowDisplayOfInsecureContent", &LayoutTestController::setAllowDisplayOfInsecureContent); + bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs); + bindMethod("setAllowRunningOfInsecureContent", &LayoutTestController::setAllowRunningOfInsecureContent); + bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs); + bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies); + bindMethod("setAuthorAndUserStylesEnabled", &LayoutTestController::setAuthorAndUserStylesEnabled); + bindMethod("setAutofilled", &LayoutTestController::setAutofilled); + bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows); + bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete); + bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate); + bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota); + bindMethod("setDeferMainResourceDataLoad", &LayoutTestController::setDeferMainResourceDataLoad); + bindMethod("setDomainRelaxationForbiddenForURLScheme", &LayoutTestController::setDomainRelaxationForbiddenForURLScheme); + bindMethod("setEditingBehavior", &LayoutTestController::setEditingBehavior); + bindMethod("setAudioData", &LayoutTestController::setAudioData); + bindMethod("setGeolocationPermission", &LayoutTestController::setGeolocationPermission); + bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled); + bindMethod("setJavaScriptCanAccessClipboard", &LayoutTestController::setJavaScriptCanAccessClipboard); + bindMethod("setJavaScriptProfilingEnabled", &LayoutTestController::setJavaScriptProfilingEnabled); + bindMethod("setMinimumTimerInterval", &LayoutTestController::setMinimumTimerInterval); + bindMethod("setMockDeviceOrientation", &LayoutTestController::setMockDeviceOrientation); + bindMethod("setMockGeolocationError", &LayoutTestController::setMockGeolocationError); + bindMethod("setMockGeolocationPosition", &LayoutTestController::setMockGeolocationPosition); + bindMethod("setPageVisibility", &LayoutTestController::setPageVisibility); + bindMethod("setPluginsEnabled", &LayoutTestController::setPluginsEnabled); + bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled); + bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale); + bindMethod("setPrinting", &LayoutTestController::setPrinting); + bindMethod("setScrollbarPolicy", &LayoutTestController::setScrollbarPolicy); + bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled); + bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled); + bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads); + bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements); + bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled); + bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation); + bindMethod("setValueForUser", &LayoutTestController::setValueForUser); + bindMethod("setWillSendRequestClearHeader", &LayoutTestController::setWillSendRequestClearHeader); + bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull); + bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect); + bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey); + bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled); + bindMethod("setAsynchronousSpellCheckingEnabled", &LayoutTestController::setAsynchronousSpellCheckingEnabled); + bindMethod("showWebInspector", &LayoutTestController::showWebInspector); + bindMethod("simulateDesktopNotificationClick", &LayoutTestController::simulateDesktopNotificationClick); + bindMethod("startSpeechInput", &LayoutTestController::startSpeechInput); + bindMethod("suspendAnimations", &LayoutTestController::suspendAnimations); + bindMethod("testRepaint", &LayoutTestController::testRepaint); + bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate); + bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone); + bindMethod("windowCount", &LayoutTestController::windowCount); + bindMethod("setTextDirection", &LayoutTestController::setTextDirection); + bindMethod("setImagesAllowed", &LayoutTestController::setImagesAllowed); + bindMethod("setScriptsAllowed", &LayoutTestController::setScriptsAllowed); + bindMethod("setStorageAllowed", &LayoutTestController::setStorageAllowed); + bindMethod("setPluginsAllowed", &LayoutTestController::setPluginsAllowed); + + // The following are stubs. + bindMethod("abortModal", &LayoutTestController::abortModal); + bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject); + bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL); + bindMethod("applicationCacheDiskUsageForOrigin", &LayoutTestController::applicationCacheDiskUsageForOrigin); + bindMethod("callShouldCloseOnWebView", &LayoutTestController::callShouldCloseOnWebView); + bindMethod("clearAllApplicationCaches", &LayoutTestController::clearAllApplicationCaches); + bindMethod("clearApplicationCacheForOrigin", &LayoutTestController::clearApplicationCacheForOrigin); + bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList); + bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive); + bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory); + bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf); + bindMethod("setApplicationCacheOriginQuota", &LayoutTestController::setApplicationCacheOriginQuota); + bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews); + bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder); + bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled); + bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode); + bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject); + bindMethod("deleteAllLocalStorage", &LayoutTestController::deleteAllLocalStorage); + bindMethod("localStorageDiskUsageForOrigin", &LayoutTestController::localStorageDiskUsageForOrigin); + bindMethod("originsWithLocalStorage", &LayoutTestController::originsWithLocalStorage); + bindMethod("deleteLocalStorageForOrigin", &LayoutTestController::deleteLocalStorageForOrigin); + bindMethod("observeStorageTrackerNotifications", &LayoutTestController::observeStorageTrackerNotifications); + bindMethod("syncLocalStorage", &LayoutTestController::syncLocalStorage); + bindMethod("setShouldStayOnPageAfterHandlingBeforeUnload", &LayoutTestController::setShouldStayOnPageAfterHandlingBeforeUnload); + bindMethod("enableFixedLayoutMode", &LayoutTestController::enableFixedLayoutMode); + bindMethod("setFixedLayoutSize", &LayoutTestController::setFixedLayoutSize); + + // 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); + bindProperty("titleTextDirection", &m_titleTextDirection); + bindProperty("platformName", &m_platformName); + bindProperty("interceptPostMessage", &m_interceptPostMessage); +} + +LayoutTestController::~LayoutTestController() +{ +} + +LayoutTestController::WorkQueue::~WorkQueue() +{ + reset(); +} + +void LayoutTestController::WorkQueue::processWorkSoon() +{ + if (m_controller->m_shell->webViewHost()->topLoadingFrame()) + return; + + if (!m_queue.isEmpty()) { + // We delay processing queued work to avoid recursion problems. + postTask(new WorkQueueTask(this)); + } else if (!m_controller->m_waitUntilDone) + m_controller->m_shell->testFinished(); +} + +void LayoutTestController::WorkQueue::processWork() +{ + TestShell* shell = m_controller->m_shell; + // Quit doing work once a load is in progress. + while (!m_queue.isEmpty()) { + bool startedLoad = m_queue.first()->run(shell); + delete m_queue.takeFirst(); + if (startedLoad) + return; + } + + if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame()) + shell->testFinished(); +} + +void LayoutTestController::WorkQueue::reset() +{ + m_frozen = false; + while (!m_queue.isEmpty()) + delete m_queue.takeFirst(); +} + +void LayoutTestController::WorkQueue::addWork(WorkItem* work) +{ + if (m_frozen) { + delete work; + return; + } + m_queue.append(work); +} + +void LayoutTestController::dumpAsText(const CppArgumentList& arguments, CppVariant* result) +{ + m_dumpAsText = true; + m_generatePixelResults = false; + + // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode. + if (arguments.size() > 0 && arguments[0].isBool()) + m_generatePixelResults = arguments[0].value.boolValue; + + result->setNull(); +} + +void LayoutTestController::dumpDatabaseCallbacks(const CppArgumentList&, CppVariant* result) +{ + // Do nothing; we don't use this flag anywhere for now + result->setNull(); +} + +void LayoutTestController::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result) +{ + m_dumpEditingCallbacks = true; + result->setNull(); +} + +void LayoutTestController::dumpBackForwardList(const CppArgumentList&, CppVariant* result) +{ + m_dumpBackForwardList = true; + result->setNull(); +} + +void LayoutTestController::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result) +{ + m_dumpFrameLoadCallbacks = true; + result->setNull(); +} + +void LayoutTestController::dumpProgressFinishedCallback(const CppArgumentList&, CppVariant* result) +{ + m_dumpProgressFinishedCallback = true; + result->setNull(); +} + +void LayoutTestController::dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant* result) +{ + m_dumpUserGestureInFrameLoadCallbacks = true; + result->setNull(); +} + +void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result) +{ + m_dumpResourceLoadCallbacks = true; + result->setNull(); +} + +void LayoutTestController::dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant* result) +{ + m_dumpResourceResponseMIMETypes = true; + result->setNull(); +} + +void LayoutTestController::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result) +{ + m_dumpChildFrameScrollPositions = true; + result->setNull(); +} + +void LayoutTestController::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result) +{ + m_dumpChildFramesAsText = true; + result->setNull(); +} + +void LayoutTestController::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result) +{ + m_dumpWindowStatusChanges = true; + result->setNull(); +} + +void LayoutTestController::dumpTitleChanges(const CppArgumentList&, CppVariant* result) +{ + m_dumpTitleChanges = true; + result->setNull(); +} + +void LayoutTestController::dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant* result) +{ + m_dumpPermissionClientCallbacks = true; + result->setNull(); +} + +void LayoutTestController::dumpCreateView(const CppArgumentList&, CppVariant* result) +{ + m_dumpCreateView = true; + result->setNull(); +} + +void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_acceptsEditing = arguments[0].value.boolValue; + result->setNull(); +} + +void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result) +{ + if (!webkit_support::BeingDebugged()) + postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout()); + m_waitUntilDone = true; + result->setNull(); +} + +void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result) +{ + // Test didn't timeout. Kill the timeout timer. + m_taskList.revokeAll(); + + completeNotifyDone(false); + result->setNull(); +} + +void LayoutTestController::completeNotifyDone(bool isTimeout) +{ + if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) { + if (isTimeout) + m_shell->testTimedOut(); + else + m_shell->testFinished(); + } + m_waitUntilDone = false; +} + +class WorkItemBackForward : public LayoutTestController::WorkItem { +public: + WorkItemBackForward(int distance) : m_distance(distance) { } + bool run(TestShell* shell) + { + shell->goToOffset(m_distance); + return true; // FIXME: Did it really start a navigation? + } + +private: + int m_distance; +}; + +void LayoutTestController::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isNumber()) + m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32())); + result->setNull(); +} + +void LayoutTestController::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isNumber()) + m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32())); + result->setNull(); +} + +class WorkItemReload : public LayoutTestController::WorkItem { +public: + bool run(TestShell* shell) + { + shell->reload(); + return true; + } +}; + +void LayoutTestController::queueReload(const CppArgumentList&, CppVariant* result) +{ + m_workQueue.addWork(new WorkItemReload); + result->setNull(); +} + +class WorkItemLoadingScript : public LayoutTestController::WorkItem { +public: + WorkItemLoadingScript(const string& script) : m_script(script) { } + bool run(TestShell* shell) + { + shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script))); + return true; // FIXME: Did it really start a navigation? + } + +private: + string m_script; +}; + +class WorkItemNonLoadingScript : public LayoutTestController::WorkItem { +public: + WorkItemNonLoadingScript(const string& script) : m_script(script) { } + bool run(TestShell* shell) + { + shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script))); + return false; + } + +private: + string m_script; +}; + +void LayoutTestController::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) + m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString())); + result->setNull(); +} + +void LayoutTestController::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) + m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString())); + result->setNull(); +} + +class WorkItemLoad : public LayoutTestController::WorkItem { +public: + WorkItemLoad(const WebURL& url, const WebString& target) + : m_url(url) + , m_target(target) { } + bool run(TestShell* shell) + { + shell->webViewHost()->loadURLForFrame(m_url, m_target); + return true; // FIXME: Did it really start a navigation? + } + +private: + WebURL m_url; + WebString m_target; +}; + +void LayoutTestController::queueLoad(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) { + // FIXME: Implement WebURL::resolve() and avoid GURL. + GURL currentURL = m_shell->webView()->mainFrame()->document().url(); + GURL fullURL = currentURL.Resolve(arguments[0].toString()); + + string target = ""; + if (arguments.size() > 1 && arguments[1].isString()) + target = arguments[1].toString(); + + m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target))); + } + result->setNull(); +} + +class WorkItemLoadHTMLString : public LayoutTestController::WorkItem { +public: + WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL) + : m_html(html) + , m_baseURL(baseURL) { } + WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL, const WebURL& unreachableURL) + : m_html(html) + , m_baseURL(baseURL) + , m_unreachableURL(unreachableURL) { } + bool run(TestShell* shell) + { + shell->webView()->mainFrame()->loadHTMLString( + WebKit::WebData(m_html.data(), m_html.length()), m_baseURL, m_unreachableURL); + return true; + } + +private: + std::string m_html; + WebURL m_baseURL; + WebURL m_unreachableURL; +}; + +void LayoutTestController::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) { + string html = arguments[0].toString(); + WebURL baseURL(GURL("")); + if (arguments.size() > 1 && arguments[1].isString()) + baseURL = WebURL(GURL(arguments[1].toString())); + if (arguments.size() > 2 && arguments[2].isString()) + m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL, WebURL(GURL(arguments[2].toString())))); + else + m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL)); + } + result->setNull(); +} + +void LayoutTestController::objCIdentityIsEqual(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 2) { + // This is the best we can do to return an error. + result->setNull(); + return; + } + result->set(arguments[0].isEqual(arguments[1])); +} + +void LayoutTestController::reset() +{ + if (m_shell) { + m_shell->webView()->setZoomLevel(false, 0); + m_shell->webView()->setTabKeyCyclesThroughElements(true); +#if !OS(DARWIN) && !OS(WINDOWS) // Actually, TOOLKIT_GTK + // (Constants copied because we can't depend on the header that defined + // them from this file.) + m_shell->webView()->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232); +#endif + m_shell->webView()->removeAllUserContent(); + } + m_dumpAsText = false; + m_dumpAsAudio = false; + m_dumpCreateView = false; + m_dumpEditingCallbacks = false; + m_dumpFrameLoadCallbacks = false; + m_dumpProgressFinishedCallback = false; + m_dumpUserGestureInFrameLoadCallbacks = false; + m_dumpResourceLoadCallbacks = false; + m_dumpResourceResponseMIMETypes = false; + m_dumpBackForwardList = false; + m_dumpChildFrameScrollPositions = false; + m_dumpChildFramesAsText = false; + m_dumpWindowStatusChanges = false; + m_dumpSelectionRect = false; + m_dumpTitleChanges = false; + m_dumpPermissionClientCallbacks = false; + m_generatePixelResults = true; + m_acceptsEditing = true; + m_waitUntilDone = false; + m_canOpenWindows = false; + m_testRepaint = false; + m_sweepHorizontally = false; + m_shouldAddFileToPasteboard = false; + m_stopProvisionalFrameLoads = false; + m_deferMainResourceDataLoad = true; + m_globalFlag.set(false); + m_webHistoryItemCount.set(0); + m_titleTextDirection.set("ltr"); + m_platformName.set("chromium"); + m_interceptPostMessage.set(false); + m_userStyleSheetLocation = WebURL(); + m_isPrinting = false; + + webkit_support::SetAcceptAllCookies(false); + WebSecurityPolicy::resetOriginAccessWhitelists(); + + // Reset the default quota for each origin to 5MB + webkit_support::SetDatabaseQuota(5 * 1024 * 1024); + + setlocale(LC_ALL, ""); + + if (m_closeRemainingWindows) + m_shell->closeRemainingWindows(); + else + m_closeRemainingWindows = true; + m_workQueue.reset(); + m_taskList.revokeAll(); + m_shouldStayOnPageAfterHandlingBeforeUnload = false; +} + +void LayoutTestController::locationChangeDone() +{ + m_webHistoryItemCount.set(m_shell->navigationEntryCount()); + + // No more new work after the first complete load. + m_workQueue.setFrozen(true); + + if (!m_waitUntilDone) + m_workQueue.processWorkSoon(); +} + +void LayoutTestController::policyDelegateDone() +{ + ASSERT(m_waitUntilDone); + m_shell->testFinished(); + m_waitUntilDone = false; +} + +void LayoutTestController::setCanOpenWindows(const CppArgumentList&, CppVariant* result) +{ + m_canOpenWindows = true; + result->setNull(); +} + +void LayoutTestController::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webView()->setTabKeyCyclesThroughElements(arguments[0].toBoolean()); + result->setNull(); +} + +void LayoutTestController::windowCount(const CppArgumentList&, CppVariant* result) +{ + result->set(static_cast<int>(m_shell->windowCount())); +} + +void LayoutTestController::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_closeRemainingWindows = arguments[0].value.boolValue; + result->setNull(); +} + +void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0) + webkit_support::SetAcceptAllCookies(cppVariantToBool(arguments[0])); + result->setNull(); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webView()->settings()->setAsynchronousSpellCheckingEnabled(cppVariantToBool(arguments[0])); + result->setNull(); +} + +void LayoutTestController::showWebInspector(const CppArgumentList&, CppVariant* result) +{ + m_shell->showDevTools(); + result->setNull(); +} + +void LayoutTestController::closeWebInspector(const CppArgumentList& args, CppVariant* result) +{ + m_shell->closeDevTools(); + result->setNull(); +} + +void LayoutTestController::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->setFocus(m_shell->webView(), arguments[0].value.boolValue); + result->setNull(); +} + +void LayoutTestController::setUserStyleSheetEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->userStyleSheetLocation = arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL(); + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) { + m_userStyleSheetLocation = webkit_support::LocalFileToDataURL( + webkit_support::RewriteLayoutTestsURL(arguments[0].toString())); + m_shell->preferences()->userStyleSheetLocation = m_userStyleSheetLocation; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->authorAndUserStylesEnabled = arguments[0].value.boolValue; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::execCommand(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() <= 0 || !arguments[0].isString()) + return; + + std::string command = arguments[0].toString(); + std::string value(""); + // Ignore the second parameter (which is userInterface) + // since this command emulates a manual action. + if (arguments.size() >= 3 && arguments[2].isString()) + value = arguments[2].toString(); + + // Note: webkit's version does not return the boolean, so neither do we. + m_shell->webView()->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value)); +} + +void LayoutTestController::isCommandEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() <= 0 || !arguments[0].isString()) { + result->setNull(); + return; + } + + std::string command = arguments[0].toString(); + bool rv = m_shell->webView()->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command)); + result->set(rv); +} + +void LayoutTestController::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + bool blockPopups = arguments[0].toBoolean(); + m_shell->preferences()->javaScriptCanOpenWindowsAutomatically = !blockPopups; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setImagesAllowed(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setImagesAllowed(arguments[0].toBoolean()); + result->setNull(); +} + +void LayoutTestController::setScriptsAllowed(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setScriptsAllowed(arguments[0].toBoolean()); + result->setNull(); +} + +void LayoutTestController::setStorageAllowed(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setStorageAllowed(arguments[0].toBoolean()); + result->setNull(); +} + +void LayoutTestController::setPluginsAllowed(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setPluginsAllowed(arguments[0].toBoolean()); + result->setNull(); +} + +void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result) +{ + // We have no need to support Dashboard Compatibility Mode (mac-only) + result->setNull(); +} + +void LayoutTestController::clearAllApplicationCaches(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement to support application cache quotas. + result->setNull(); +} + +void LayoutTestController::clearApplicationCacheForOrigin(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement to support deleting all application cache for an origin. + result->setNull(); +} + +void LayoutTestController::setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement to support application cache quotas. + result->setNull(); +} + +void LayoutTestController::originsWithApplicationCache(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement to support getting origins that have application caches. + result->setNull(); +} + +void LayoutTestController::applicationCacheDiskUsageForOrigin(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement to support getting disk usage by all application cache for an origin. + result->setNull(); +} + +void LayoutTestController::setScrollbarPolicy(const CppArgumentList&, CppVariant* result) +{ + // FIXME: implement. + // Currently only has a non-null implementation on QT. + result->setNull(); +} + +void LayoutTestController::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + bool enable = arguments[0].value.boolValue; + bool permissive = false; + if (arguments.size() > 1 && arguments[1].isBool()) + permissive = arguments[1].value.boolValue; + m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive); + } + result->setNull(); +} + +void LayoutTestController::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result) +{ + m_shell->webViewHost()->waitForPolicyDelegate(); + m_waitUntilDone = true; + result->setNull(); +} + +void LayoutTestController::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) { + string header = arguments[0].toString(); + if (!header.empty()) + m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str())); + } + result->setNull(); +} + +void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue); + result->setNull(); +} + +void LayoutTestController::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue); + result->setNull(); +} + +void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() <= 0 || !arguments[0].isString()) + return; + + string url = arguments[0].toString(); +#if OS(WINDOWS) + if (!url.find("/tmp/")) { + // We want a temp file. + const unsigned tempPrefixLength = 5; + size_t bufferSize = MAX_PATH; + OwnArrayPtr<WCHAR> tempPath = adoptArrayPtr(new WCHAR[bufferSize]); + DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get()); + if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) { + bufferSize = tempLength + url.length() - tempPrefixLength + 1; + tempPath = adoptArrayPtr(new WCHAR[bufferSize]); + tempLength = GetTempPathW(bufferSize, tempPath.get()); + ASSERT(tempLength < bufferSize); + } + string resultPath(WebString(tempPath.get(), tempLength).utf8()); + resultPath.append(url.substr(tempPrefixLength)); + result->set(resultPath); + return; + } +#endif + + // Some layout tests use file://// which we resolve as a UNC path. Normalize + // them to just file:///. + string lowerUrl = url; + transform(lowerUrl.begin(), lowerUrl.end(), lowerUrl.begin(), ::tolower); + while (!lowerUrl.find("file:////")) { + url = url.substr(0, 8) + url.substr(9); + lowerUrl = lowerUrl.substr(0, 8) + lowerUrl.substr(9); + } + result->set(webkit_support::RewriteLayoutTestsURL(url).spec()); +} + +void LayoutTestController::addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + m_shouldAddFileToPasteboard = true; +} + +void LayoutTestController::setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + m_stopProvisionalFrameLoads = true; +} + +void LayoutTestController::setSmartInsertDeleteEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webViewHost()->setSmartInsertDeleteEnabled(arguments[0].value.boolValue); + result->setNull(); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webViewHost()->setSelectTrailingWhitespaceEnabled(arguments[0].value.boolValue); + result->setNull(); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const WebString& animationName, double time, const WebString& elementId) +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return false; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return false; + + WebElement element = webFrame->document().getElementById(elementId); + if (element.isNull()) + return false; + return controller->pauseAnimationAtTime(element, animationName, time); +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const WebString& propertyName, double time, const WebString& elementId) +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return false; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return false; + + WebElement element = webFrame->document().getElementById(elementId); + if (element.isNull()) + return false; + return controller->pauseTransitionAtTime(element, propertyName, time); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const WebString& elementId) +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return false; + + WebElement element = webFrame->document().getElementById(elementId); + if (element.isNull() || !element.hasTagName("input")) + return false; + + WebInputElement inputElement = element.to<WebInputElement>(); + return inputElement.autoComplete(); +} + +int LayoutTestController::numberOfActiveAnimations() +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return -1; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return -1; + + return controller->numberOfActiveAnimations(); +} + +void LayoutTestController::suspendAnimations() +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return; + + controller->suspendAnimations(); +} + +void LayoutTestController::resumeAnimations() +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return; + + controller->resumeAnimations(); +} + +void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result) +{ + result->set(false); + if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) { + WebString animationName = cppVariantToWebString(arguments[0]); + double time = arguments[1].toDouble(); + WebString elementId = cppVariantToWebString(arguments[2]); + result->set(pauseAnimationAtTimeOnElementWithId(animationName, time, elementId)); + } +} + +void LayoutTestController::pauseTransitionAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result) +{ + result->set(false); + if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) { + WebString propertyName = cppVariantToWebString(arguments[0]); + double time = arguments[1].toDouble(); + WebString elementId = cppVariantToWebString(arguments[2]); + result->set(pauseTransitionAtTimeOnElementWithId(propertyName, time, elementId)); + } +} + +void LayoutTestController::elementDoesAutoCompleteForElementWithId(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() != 1 || !arguments[0].isString()) { + result->set(false); + return; + } + WebString elementId = cppVariantToWebString(arguments[0]); + result->set(elementDoesAutoCompleteForElementWithId(elementId)); +} + +void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppVariant* result) +{ + result->set(numberOfActiveAnimations()); +} + +void LayoutTestController::suspendAnimations(const CppArgumentList&, CppVariant* result) +{ + suspendAnimations(); + result->setNull(); +} + +void LayoutTestController::resumeAnimations(const CppArgumentList&, CppVariant* result) +{ + resumeAnimations(); + result->setNull(); +} + +void LayoutTestController::sampleSVGAnimationForElementAtTime(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() != 3) { + result->setNull(); + return; + } + WebString animationId = cppVariantToWebString(arguments[0]); + double time = arguments[1].toDouble(); + WebString elementId = cppVariantToWebString(arguments[2]); + bool success = m_shell->webView()->mainFrame()->pauseSVGAnimation(animationId, time, elementId); + result->set(success); +} + +void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result) +{ + m_shell->preferences()->loadsImagesAutomatically = false; + m_shell->applyPreferences(); + result->setNull(); +} + +void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result) +{ + // We don't use the WebKit icon database. + result->setNull(); +} + +void LayoutTestController::callShouldCloseOnWebView(const CppArgumentList&, CppVariant* result) +{ + result->set(m_shell->webView()->dispatchBeforeUnloadEvent()); +} + +void LayoutTestController::grantDesktopNotificationPermission(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() != 1 || !arguments[0].isString()) { + result->set(false); + return; + } +#if ENABLE(NOTIFICATIONS) + m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0])); +#endif + result->set(true); +} + +void LayoutTestController::simulateDesktopNotificationClick(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() != 1 || !arguments[0].isString()) { + result->set(false); + return; + } +#if ENABLE(NOTIFICATIONS) + if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0]))) + result->set(true); + else +#endif + result->set(false); +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() != 2 || !arguments[0].isBool() || !arguments[1].isString()) + return; + m_shell->webView()->setDomainRelaxationForbidden(cppVariantToBool(arguments[0]), cppVariantToWebString(arguments[1])); +} + +void LayoutTestController::setDeferMainResourceDataLoad(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() == 1) + m_deferMainResourceDataLoad = cppVariantToBool(arguments[0]); +} + +// +// Unimplemented stubs +// + +void LayoutTestController::dumpAsWebArchive(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::setMainFrameIsFirstResponder(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result) +{ + m_dumpSelectionRect = true; + result->setNull(); +} + +void LayoutTestController::display(const CppArgumentList& arguments, CppVariant* result) +{ + WebViewHost* host = m_shell->webViewHost(); + const WebKit::WebSize& size = m_shell->webView()->size(); + WebRect rect(0, 0, size.width, size.height); + host->updatePaintRect(rect); + host->paintInvalidatedRegion(); + host->displayRepaintMask(); + result->setNull(); +} + +void LayoutTestController::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result) +{ + WebViewHost* host = m_shell->webViewHost(); + host->paintInvalidatedRegion(); + host->displayRepaintMask(); + result->setNull(); +} + +void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result) +{ + m_testRepaint = true; + result->setNull(); +} + +void LayoutTestController::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result) +{ + m_sweepHorizontally = true; + result->setNull(); +} + +void LayoutTestController::clearBackForwardList(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::keepWebHistory(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::storeWebScriptObject(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::accessStoredWebScriptObject(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::objCClassNameOf(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::addDisallowedURL(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::setCallCloseOnWebViews(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::setPrivateBrowsingEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->javaScriptCanAccessClipboard = arguments[0].value.boolValue; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->XSSAuditorEnabled = arguments[0].value.boolValue; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) { + WebScriptSource source(cppVariantToWebString(arguments[1])); + // This relies on the iframe focusing itself when it loads. This is a bit + // sketchy, but it seems to be what other tests do. + m_shell->webView()->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1); + } + result->setNull(); +} + +void LayoutTestController::setIsolatedWorldSecurityOrigin(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isString()) + return; + + m_shell->webView()->focusedFrame()->setIsolatedWorldSecurityOrigin( + arguments[0].toInt32(), + WebSecurityOrigin::createFromString(cppVariantToWebString(arguments[1]))); +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->allowUniversalAccessFromFileURLs = arguments[0].value.boolValue; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setAllowDisplayOfInsecureContent(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setDisplayingInsecureContentAllowed(arguments[0].toBoolean()); + + result->setNull(); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->allowFileAccessFromFileURLs = arguments[0].value.boolValue; + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::setAllowRunningOfInsecureContent(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) + m_shell->webPermissions()->setRunningInsecureContentAllowed(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.isNumber()) + return value.toInt32(); + if (value.isString()) { + string valueString = value.toString(); + if (valueString == "true" || valueString == "1") + return true; + if (valueString == "false" || valueString == "0") + return false; + } + logErrorToConsole("Invalid value. Expected boolean value."); + return false; +} + +int32_t LayoutTestController::cppVariantToInt32(const CppVariant& value) +{ + if (value.isNumber()) + return value.toInt32(); + if (value.isString()) { + string stringSource = value.toString(); + const char* source = stringSource.data(); + char* end; + long number = strtol(source, &end, 10); + if (end == source + stringSource.length() && number >= numeric_limits<int32_t>::min() && number <= numeric_limits<int32_t>::max()) + return static_cast<int32_t>(number); + } + logErrorToConsole("Invalid value for preference. Expected integer value."); + return 0; +} + +WebString LayoutTestController::cppVariantToWebString(const CppVariant& value) +{ + if (!value.isString()) { + logErrorToConsole("Invalid value for preference. Expected string value."); + return WebString(); + } + return WebString::fromUTF8(value.toString()); +} + +Vector<WebString> LayoutTestController::cppVariantToWebStringArray(const CppVariant& value) +{ + if (!value.isObject()) { + logErrorToConsole("Invalid value for preference. Expected object value."); + return Vector<WebString>(); + } + Vector<WebString> resultVector; + Vector<string> stringVector = value.toStringVector(); + for (size_t i = 0; i < stringVector.size(); ++i) + resultVector.append(WebString::fromUTF8(stringVector[i].c_str())); + return resultVector; +} + +// Sets map based on scriptFontPairs, a collapsed vector of pairs of ISO 15924 +// four-letter script code and font such as: +// { "Arab", "My Arabic Font", "Grek", "My Greek Font" } +static void setFontMap(WebPreferences::ScriptFontFamilyMap& map, const Vector<WebString>& scriptFontPairs) +{ + map.clear(); + size_t i = 0; + while (i + 1 < scriptFontPairs.size()) { + const WebString& script = scriptFontPairs[i++]; + const WebString& font = scriptFontPairs[i++]; + + int32_t code = u_getPropertyValueEnum(UCHAR_SCRIPT, script.utf8().data()); + if (code >= 0 && code < USCRIPT_CODE_LIMIT) + map.set(static_cast<int>(code), font); + } +} + +void LayoutTestController::overridePreference(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() != 2 || !arguments[0].isString()) + return; + + string key = arguments[0].toString(); + CppVariant value = arguments[1]; + WebPreferences* prefs = m_shell->preferences(); + if (key == "WebKitStandardFont") + prefs->standardFontFamily = cppVariantToWebString(value); + else if (key == "WebKitFixedFont") + prefs->fixedFontFamily = cppVariantToWebString(value); + else if (key == "WebKitSerifFont") + prefs->serifFontFamily = cppVariantToWebString(value); + else if (key == "WebKitSansSerifFont") + prefs->sansSerifFontFamily = cppVariantToWebString(value); + else if (key == "WebKitCursiveFont") + prefs->cursiveFontFamily = cppVariantToWebString(value); + else if (key == "WebKitFantasyFont") + prefs->fantasyFontFamily = cppVariantToWebString(value); + else if (key == "WebKitStandardFontMap") + setFontMap(prefs->standardFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitFixedFontMap") + setFontMap(prefs->fixedFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitSerifFontMap") + setFontMap(prefs->serifFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitSansSerifFontMap") + setFontMap(prefs->sansSerifFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitCursiveFontMap") + setFontMap(prefs->cursiveFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitFantasyFontMap") + setFontMap(prefs->fantasyFontMap, cppVariantToWebStringArray(value)); + else if (key == "WebKitDefaultFontSize") + prefs->defaultFontSize = cppVariantToInt32(value); + else if (key == "WebKitDefaultFixedFontSize") + prefs->defaultFixedFontSize = cppVariantToInt32(value); + else if (key == "WebKitMinimumFontSize") + prefs->minimumFontSize = cppVariantToInt32(value); + else if (key == "WebKitMinimumLogicalFontSize") + prefs->minimumLogicalFontSize = cppVariantToInt32(value); + else if (key == "WebKitDefaultTextEncodingName") + prefs->defaultTextEncodingName = cppVariantToWebString(value); + else if (key == "WebKitJavaScriptEnabled") + prefs->javaScriptEnabled = cppVariantToBool(value); + else if (key == "WebKitWebSecurityEnabled") + prefs->webSecurityEnabled = cppVariantToBool(value); + else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically") + prefs->javaScriptCanOpenWindowsAutomatically = cppVariantToBool(value); + else if (key == "WebKitDisplayImagesKey") + prefs->loadsImagesAutomatically = cppVariantToBool(value); + else if (key == "WebKitPluginsEnabled") + prefs->pluginsEnabled = cppVariantToBool(value); + else if (key == "WebKitDOMPasteAllowedPreferenceKey") + prefs->DOMPasteAllowed = cppVariantToBool(value); + else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey") + prefs->developerExtrasEnabled = cppVariantToBool(value); + else if (key == "WebKitShrinksStandaloneImagesToFit") + prefs->shrinksStandaloneImagesToFit = cppVariantToBool(value); + else if (key == "WebKitTextAreasAreResizable") + prefs->textAreasAreResizable = cppVariantToBool(value); + else if (key == "WebKitJavaEnabled") + prefs->javaEnabled = cppVariantToBool(value); + else if (key == "WebKitUsesPageCachePreferenceKey") + prefs->usesPageCache = cppVariantToBool(value); + else if (key == "WebKitPageCacheSupportsPluginsPreferenceKey") + prefs->pageCacheSupportsPlugins = cppVariantToBool(value); + else if (key == "WebKitJavaScriptCanAccessClipboard") + prefs->javaScriptCanAccessClipboard = cppVariantToBool(value); + else if (key == "WebKitXSSAuditorEnabled") + prefs->XSSAuditorEnabled = cppVariantToBool(value); + else if (key == "WebKitLocalStorageEnabledPreferenceKey") + prefs->localStorageEnabled = cppVariantToBool(value); + else if (key == "WebKitOfflineWebApplicationCacheEnabled") + prefs->offlineWebApplicationCacheEnabled = cppVariantToBool(value); + else if (key == "WebKitTabToLinksPreferenceKey") + prefs->tabsToLinks = cppVariantToBool(value); + else if (key == "WebKitWebGLEnabled") + prefs->experimentalWebGLEnabled = cppVariantToBool(value); + else if (key == "WebKitHyperlinkAuditingEnabled") + prefs->hyperlinkAuditingEnabled = cppVariantToBool(value); + else if (key == "WebKitEnableCaretBrowsing") + prefs->caretBrowsingEnabled = cppVariantToBool(value); + else if (key == "WebKitAllowDisplayingInsecureContent") + prefs->allowDisplayOfInsecureContent = cppVariantToBool(value); + else if (key == "WebKitAllowRunningInsecureContent") + prefs->allowRunningOfInsecureContent = cppVariantToBool(value); + else if (key == "WebKitHixie76WebSocketProtocolEnabled") + prefs->hixie76WebSocketProtocolEnabled = cppVariantToBool(value); + else if (key == "WebKitWebAudioEnabled") { + ASSERT(cppVariantToBool(value)); + } else { + string message("Invalid name for preference: "); + message.append(key); + logErrorToConsole(message); + } + m_shell->applyPreferences(); +} + +void LayoutTestController::fallbackMethod(const CppArgumentList&, CppVariant* result) +{ + printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on LayoutTestController\n"); + result->setNull(); +} + +void LayoutTestController::addOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString() + || !arguments[2].isString() || !arguments[3].isBool()) + return; + + WebKit::WebURL url(GURL(arguments[0].toString())); + if (!url.isValid()) + return; + + WebSecurityPolicy::addOriginAccessWhitelistEntry( + url, + cppVariantToWebString(arguments[1]), + cppVariantToWebString(arguments[2]), + arguments[3].toBoolean()); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString() + || !arguments[2].isString() || !arguments[3].isBool()) + return; + + WebKit::WebURL url(GURL(arguments[0].toString())); + if (!url.isValid()) + return; + + WebSecurityPolicy::removeOriginAccessWhitelistEntry( + url, + cppVariantToWebString(arguments[1]), + cppVariantToWebString(arguments[2]), + arguments[3].toBoolean()); +} + +void LayoutTestController::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + webkit_support::ClearAllDatabases(); +} + +void LayoutTestController::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if ((arguments.size() >= 1) && arguments[0].isNumber()) + webkit_support::SetDatabaseQuota(arguments[0].toInt32()); +} + +void LayoutTestController::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() == 1 && arguments[0].isString()) + setlocale(LC_ALL, arguments[0].toString().c_str()); +} + +void LayoutTestController::counterValueForElementById(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isString()) + return; + WebFrame* frame = m_shell->webView()->mainFrame(); + if (!frame) + return; + WebString counterValue = frame->counterValueForElementById(cppVariantToWebString(arguments[0])); + if (counterValue.isNull()) + return; + result->set(counterValue.utf8()); +} + +// Parse a single argument. The method returns true if there is an argument that +// is a number or if there is no argument at all. It returns false only if there +// is some argument that is not a number. The value parameter is filled with the +// parsed number, or given the default if there is no argument. +static bool parseCppArgumentInt32(const CppArgumentList& arguments, int argIndex, int* value, int defaultValue) +{ + if (static_cast<int>(arguments.size()) > argIndex) { + if (!arguments[argIndex].isNumber()) + return false; + *value = arguments[argIndex].toInt32(); + return true; + } + *value = defaultValue; + return true; +} + +static bool parsePageSizeParameters(const CppArgumentList& arguments, + int argOffset, + int* pageWidthInPixels, + int* pageHeightInPixels) +{ + // WebKit is using the window width/height of DumpRenderTree as the + // default value of the page size. + // FIXME: share the default values with other ports. + int argCount = static_cast<int>(arguments.size()) - argOffset; + if (argCount && argCount != 2) + return false; + if (!parseCppArgumentInt32(arguments, argOffset, pageWidthInPixels, 800) + || !parseCppArgumentInt32(arguments, argOffset + 1, pageHeightInPixels, 600)) + return false; + return true; +} + +static bool parsePageNumber(const CppArgumentList& arguments, int argOffset, int* pageNumber) +{ + if (static_cast<int>(arguments.size()) > argOffset + 1) + return false; + if (!parseCppArgumentInt32(arguments, argOffset, pageNumber, 0)) + return false; + return true; +} + +static bool parsePageNumberSizeMargins(const CppArgumentList& arguments, int argOffset, + int* pageNumber, int* width, int* height, + int* marginTop, int* marginRight, int* marginBottom, int* marginLeft) +{ + int argCount = static_cast<int>(arguments.size()) - argOffset; + if (argCount && argCount != 7) + return false; + if (!parseCppArgumentInt32(arguments, argOffset, pageNumber, 0) + || !parseCppArgumentInt32(arguments, argOffset + 1, width, 0) + || !parseCppArgumentInt32(arguments, argOffset + 2, height, 0) + || !parseCppArgumentInt32(arguments, argOffset + 3, marginTop, 0) + || !parseCppArgumentInt32(arguments, argOffset + 4, marginRight, 0) + || !parseCppArgumentInt32(arguments, argOffset + 5, marginBottom, 0) + || !parseCppArgumentInt32(arguments, argOffset + 6, marginLeft, 0)) + return false; + return true; +} + +void LayoutTestController::setPrinting(const CppArgumentList& arguments, CppVariant* result) +{ + setIsPrinting(true); + result->setNull(); +} + +void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + int pageWidthInPixels = 0; + int 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]), + static_cast<float>(pageWidthInPixels), + static_cast<float>(pageHeightInPixels))); +} + +void LayoutTestController::pageSizeAndMarginsInPixels(const CppArgumentList& arguments, CppVariant* result) +{ + result->set(""); + int pageNumber = 0; + int width = 0; + int height = 0; + int marginTop = 0; + int marginRight = 0; + int marginBottom = 0; + int marginLeft = 0; + if (!parsePageNumberSizeMargins(arguments, 0, &pageNumber, &width, &height, &marginTop, &marginRight, &marginBottom, + &marginLeft)) + return; + + WebFrame* frame = m_shell->webView()->mainFrame(); + if (!frame) + return; + WebSize pageSize(width, height); + frame->pageSizeAndMarginsInPixels(pageNumber, pageSize, marginTop, marginRight, marginBottom, marginLeft); + stringstream resultString; + resultString << "(" << pageSize.width << ", " << pageSize.height << ") " << marginTop << " " << marginRight << " " + << marginBottom << " " << marginLeft; + result->set(resultString.str()); +} + +void LayoutTestController::hasCustomPageSizeStyle(const CppArgumentList& arguments, CppVariant* result) +{ + result->set(false); + int pageIndex = 0; + if (!parsePageNumber(arguments, 0, &pageIndex)) + return; + WebFrame* frame = m_shell->webView()->mainFrame(); + if (!frame) + return; + result->set(frame->hasCustomPageSizeStyle(pageIndex)); +} + +void LayoutTestController::isPageBoxVisible(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + int pageNumber = 0; + if (!parsePageNumber(arguments, 0, &pageNumber)) + return; + WebFrame* frame = m_shell->webView()->mainFrame(); + if (!frame) + return; + result->set(frame->isPageBoxVisible(pageNumber)); +} + +void LayoutTestController::pageProperty(const CppArgumentList& arguments, CppVariant* result) +{ + result->set(""); + int pageNumber = 0; + if (!parsePageNumber(arguments, 1, &pageNumber)) + return; + if (!arguments[0].isString()) + return; + WebFrame* frame = m_shell->webView()->mainFrame(); + if (!frame) + return; + WebSize pageSize(800, 800); + frame->printBegin(pageSize); + result->set(frame->pageProperty(cppVariantToWebString(arguments[0]), pageNumber).utf8()); + frame->printEnd(); +} + +void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + int pageWidthInPixels = 0; + int 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::numberOfPendingGeolocationPermissionRequests(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + Vector<WebViewHost*> windowList = m_shell->windowList(); + int numberOfRequests = 0; + for (size_t i = 0; i < windowList.size(); i++) + numberOfRequests += windowList[i]->geolocationClientMock()->numberOfPendingPermissionRequests(); + result->set(numberOfRequests); +} + +void LayoutTestController::logErrorToConsole(const std::string& text) +{ + m_shell->webViewHost()->didAddMessageToConsole( + WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)), + WebString(), 0); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isBool()) + return; + m_shell->drtDevToolsAgent()->setJavaScriptProfilingEnabled(arguments[0].toBoolean()); +} + +void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString()) + return; + m_shell->drtDevToolsAgent()->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString()); +} + +void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0); +} + +void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isBool() || !arguments[2].isBool()) + return; + WebView::addUserScript( + cppVariantToWebString(arguments[0]), WebVector<WebString>(), + arguments[1].toBoolean() ? WebView::UserScriptInjectAtDocumentStart : WebView::UserScriptInjectAtDocumentEnd, + arguments[2].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly); +} + +void LayoutTestController::addUserStyleSheet(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isBool()) + return; + WebView::addUserStyleSheet( + cppVariantToWebString(arguments[0]), WebVector<WebString>(), + arguments[1].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly, + // Chromium defaults to InjectInSubsequentDocuments, but for compatibility + // with the other ports' DRTs, we use UserStyleInjectInExistingDocuments. + WebView::UserStyleInjectInExistingDocuments); +} + +void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, CppVariant* results) +{ + string key = arguments[0].toString(); + if (key == "mac") { + m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorMac; + m_shell->applyPreferences(); + } else if (key == "win") { + m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorWin; + m_shell->applyPreferences(); + } else if (key == "unix") { + m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorUnix; + m_shell->applyPreferences(); + } else + logErrorToConsole("Passed invalid editing behavior. Should be 'mac', 'win', or 'unix'."); +} + +void LayoutTestController::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 6 || !arguments[0].isBool() || !arguments[1].isNumber() || !arguments[2].isBool() || !arguments[3].isNumber() || !arguments[4].isBool() || !arguments[5].isNumber()) + return; + + WebDeviceOrientation orientation(arguments[0].toBoolean(), arguments[1].toDouble(), arguments[2].toBoolean(), arguments[3].toDouble(), arguments[4].toBoolean(), arguments[5].toDouble()); + // Note that we only call setOrientation on the main page's mock since this is all that the + // tests require. If necessary, we could get a list of WebViewHosts from the TestShell and + // call setOrientation on each DeviceOrientationClientMock. + m_shell->webViewHost()->deviceOrientationClientMock()->setOrientation(orientation); +} + +// FIXME: For greater test flexibility, we should be able to set each page's geolocation mock individually. +// https://bugs.webkit.org/show_bug.cgi?id=52368 +void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isBool()) + return; + Vector<WebViewHost*> windowList = m_shell->windowList(); + for (size_t i = 0; i < windowList.size(); i++) + windowList[i]->geolocationClientMock()->setPermission(arguments[0].toBoolean()); +} + +void LayoutTestController::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber()) + return; + Vector<WebViewHost*> windowList = m_shell->windowList(); + for (size_t i = 0; i < windowList.size(); i++) + windowList[i]->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble()); +} + +void LayoutTestController::setMockGeolocationError(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString()) + return; + Vector<WebViewHost*> windowList = m_shell->windowList(); + for (size_t i = 0; i < windowList.size(); i++) + windowList[i]->geolocationClientMock()->setError(arguments[0].toInt32(), cppVariantToWebString(arguments[1])); +} + +void LayoutTestController::abortModal(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); +} + +void LayoutTestController::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString()) + return; + + if (WebSpeechInputControllerMock* controller = m_shell->webViewHost()->speechInputControllerMock()) + controller->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2])); +} + +void LayoutTestController::startSpeechInput(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() != 1) + return; + + WebElement element; + if (!WebBindings::getElement(arguments[0].value.objectValue, &element)) + return; + + WebInputElement* input = toWebInputElement(&element); + if (!input) + return; + + if (!input->isSpeechInputEnabled()) + return; + + input->startSpeechInput(); +} + +void LayoutTestController::layerTreeAsText(const CppArgumentList& args, CppVariant* result) +{ + result->set(m_shell->webView()->mainFrame()->layerTreeAsText(m_showDebugLayerTree).utf8()); +} + +void LayoutTestController::loseCompositorContext(const CppArgumentList& args, CppVariant*) +{ + int numTimes; + if (args.size() == 1 || !args[0].isNumber()) + numTimes = 1; + else + numTimes = args[0].toInt32(); + m_shell->webView()->loseCompositorContext(numTimes); +} + +void LayoutTestController::markerTextForListItem(const CppArgumentList& args, CppVariant* result) +{ + WebElement element; + if (!WebBindings::getElement(args[0].value.objectValue, &element)) + result->setNull(); + else + result->set(element.document().frame()->markerTextForListItem(element).utf8()); +} + +void LayoutTestController::hasSpellingMarker(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + result->set(m_shell->webView()->mainFrame()->selectionStartHasSpellingMarkerFor(arguments[0].toInt32(), arguments[1].toInt32())); +} + +void LayoutTestController::findString(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() < 1 || !arguments[0].isString()) + return; + + WebFindOptions findOptions; + bool wrapAround = false; + if (arguments.size() >= 2) { + Vector<std::string> optionsArray = arguments[1].toStringVector(); + findOptions.matchCase = true; + + for (size_t i = 0; i < optionsArray.size(); ++i) { + const std::string& option = optionsArray[i]; + // FIXME: Support all the options, so we can run findString.html too. + if (option == "CaseInsensitive") + findOptions.matchCase = false; + else if (option == "Backwards") + findOptions.forward = false; + else if (option == "WrapAround") + wrapAround = true; + } + } + + WebFrame* frame = m_shell->webView()->mainFrame(); + const bool findResult = frame->find(0, cppVariantToWebString(arguments[0]), findOptions, wrapAround, 0); + result->set(findResult); +} + +void LayoutTestController::setMinimumTimerInterval(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isNumber()) + return; + m_shell->webView()->settings()->setMinimumTimerInterval(arguments[0].toDouble()); +} + +void LayoutTestController::setAutofilled(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() != 2 || !arguments[1].isBool()) + return; + + WebElement element; + if (!WebBindings::getElement(arguments[0].value.objectValue, &element)) + return; + + WebInputElement* input = toWebInputElement(&element); + if (!input) + return; + + input->setAutofilled(arguments[1].value.boolValue); +} + +void LayoutTestController::setValueForUser(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() != 2) + return; + + WebElement element; + if (!WebBindings::getElement(arguments[0].value.objectValue, &element)) + return; + + WebInputElement* input = toWebInputElement(&element); + if (!input) + return; + + input->setValue(cppVariantToWebString(arguments[1]), true); +} + +void LayoutTestController::deleteAllLocalStorage(const CppArgumentList& arguments, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::localStorageDiskUsageForOrigin(const CppArgumentList& arguments, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::originsWithLocalStorage(const CppArgumentList& arguments, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::deleteLocalStorageForOrigin(const CppArgumentList& arguments, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::observeStorageTrackerNotifications(const CppArgumentList&, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::syncLocalStorage(const CppArgumentList&, CppVariant*) +{ + // Not Implemented +} + +void LayoutTestController::setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() == 1 && arguments[0].isBool()) + m_shouldStayOnPageAfterHandlingBeforeUnload = arguments[0].toBoolean(); + + result->setNull(); +} + +void LayoutTestController::enableFixedLayoutMode(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 1 || !arguments[0].isBool()) + return; + bool enableFixedLayout = arguments[0].toBoolean(); + m_shell->webView()->enableFixedLayoutMode(enableFixedLayout); +} + +void LayoutTestController::setFixedLayoutSize(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + int width = arguments[0].toInt32(); + int height = arguments[1].toInt32(); + m_shell->webView()->setFixedLayoutSize(WebSize(width, height)); +} + +void LayoutTestController::setPluginsEnabled(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isBool()) { + m_shell->preferences()->pluginsEnabled = arguments[0].toBoolean(); + m_shell->applyPreferences(); + } + result->setNull(); +} + +void LayoutTestController::resetPageVisibility(const CppArgumentList& arguments, CppVariant* result) +{ + m_shell->webView()->setVisibilityState(WebPageVisibilityStateVisible, true); +} + +void LayoutTestController::setPageVisibility(const CppArgumentList& arguments, CppVariant* result) +{ + if (arguments.size() > 0 && arguments[0].isString()) { + string newVisibility = arguments[0].toString(); + if (newVisibility == "visible") + m_shell->webView()->setVisibilityState(WebPageVisibilityStateVisible, false); + else if (newVisibility == "hidden") + m_shell->webView()->setVisibilityState(WebPageVisibilityStateHidden, false); + else if (newVisibility == "prerender") + m_shell->webView()->setVisibilityState(WebPageVisibilityStatePrerender, false); + } +} + +void LayoutTestController::setTextDirection(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + if (arguments.size() != 1 || !arguments[0].isString()) + return; + + // Map a direction name to a WebTextDirection value. + std::string directionName = arguments[0].toString(); + WebKit::WebTextDirection direction; + if (directionName == "auto") + direction = WebKit::WebTextDirectionDefault; + else if (directionName == "rtl") + direction = WebKit::WebTextDirectionRightToLeft; + else if (directionName == "ltr") + direction = WebKit::WebTextDirectionLeftToRight; + else + return; + + m_shell->webView()->setTextDirection(direction); +} + +void LayoutTestController::setAudioData(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() < 1 || !arguments[0].isObject()) + return; + + // Check that passed-in object is, in fact, an ArrayBufferView. + NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]); + if (!npobject) + return; + if (!WebBindings::getArrayBufferView(npobject, &m_audioData)) + return; + + setShouldDumpAsAudio(true); +} diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h new file mode 100644 index 000000000..71b1b4226 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h @@ -0,0 +1,701 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + LayoutTestController class: + Bound to a JavaScript window.layoutTestController object using the + CppBoundClass::bindToJavascript(), this allows layout tests that are run in + the test_shell (or, in principle, any web page loaded into a client app built + with this class) to control various aspects of how the tests are run and what + sort of output they produce. +*/ + +#ifndef LayoutTestController_h +#define LayoutTestController_h + +#include "CppBoundClass.h" +#include "Task.h" +#include "platform/WebArrayBufferView.h" +#include "platform/WebString.h" +#include "WebTextDirection.h" +#include "platform/WebURL.h" +#include <wtf/Deque.h> +#include <wtf/OwnPtr.h> + +namespace WebKit { +class WebGeolocationClientMock; +class WebSpeechInputController; +class WebSpeechInputControllerMock; +class WebSpeechInputListener; +} + +namespace webkit_support { +class ScopedTempDirectory; +} + +class TestShell; + +class LayoutTestController : public CppBoundClass { +public: + // Builds the property and method lists needed to bind this class to a JS + // object. + LayoutTestController(TestShell*); + + ~LayoutTestController(); + + // This function sets a flag that tells the test_shell to dump pages as + // plain text, rather than as a text representation of the renderer's state. + // It takes an optional argument, whether to dump pixels results or not. + void dumpAsText(const CppArgumentList&, CppVariant*); + + // This function should set a flag that tells the test_shell to print a line + // of descriptive text for each database command. It should take no + // arguments, and ignore any that may be present. However, at the moment, we + // don't have any DB function that prints messages, so for now this function + // doesn't do anything. + void dumpDatabaseCallbacks(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print a line of + // descriptive text for each editing command. It takes no arguments, and + // ignores any that may be present. + void dumpEditingCallbacks(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print a line of + // descriptive text for each frame load callback. It takes no arguments, and + // ignores any that may be present. + void dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print a line of + // descriptive text for the progress finished callback. It takes no + // arguments, and ignores any that may be present. + void dumpProgressFinishedCallback(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print a line of + // user gesture status text for some frame load callbacks. It takes no + // arguments, and ignores any that may be present. + void dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print out a text + // representation of the back/forward list. It ignores all arguments. + void dumpBackForwardList(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to print out the + // scroll offsets of the child frames. It ignores all. + void dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to recursively + // dump all frames as plain text if the dumpAsText flag is set. + // It takes no arguments, and ignores any that may be present. + void dumpChildFramesAsText(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to dump a descriptive + // line for each resource load callback. It takes no arguments, and ignores + // any that may be present. + void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to dump the MIME type + // for each resource that was loaded. It takes no arguments, and ignores any + // that may be present. + void dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to dump all calls + // to window.status(). + // It takes no arguments, and ignores any that may be present. + void dumpWindowStatusChanges(const CppArgumentList&, CppVariant*); + + // This function sets a flag that tells the test_shell to dump all calls to + // WebViewClient::createView(). + // It takes no arguments, and ignores any that may be present. + void dumpCreateView(const CppArgumentList&, CppVariant*); + + // When called with a boolean argument, this sets a flag that controls + // whether content-editable elements accept editing focus when an editing + // attempt is made. It ignores any additional arguments. + void setAcceptsEditing(const CppArgumentList&, CppVariant*); + + // Functions for dealing with windows. By default we block all new windows. + void windowCount(const CppArgumentList&, CppVariant*); + void setCanOpenWindows(const CppArgumentList&, CppVariant*); + void setCloseRemainingWindowsWhenComplete(const CppArgumentList&, CppVariant*); + + // By default, tests end when page load is complete. These methods are used + // to delay the completion of the test until notifyDone is called. + void waitUntilDone(const CppArgumentList&, CppVariant*); + void notifyDone(const CppArgumentList&, CppVariant*); + + // Methods for adding actions to the work queue. Used in conjunction with + // waitUntilDone/notifyDone above. + void queueBackNavigation(const CppArgumentList&, CppVariant*); + void queueForwardNavigation(const CppArgumentList&, CppVariant*); + void queueReload(const CppArgumentList&, CppVariant*); + void queueLoadingScript(const CppArgumentList&, CppVariant*); + void queueNonLoadingScript(const CppArgumentList&, CppVariant*); + void queueLoad(const CppArgumentList&, CppVariant*); + void queueLoadHTMLString(const CppArgumentList&, CppVariant*); + + // Although this is named "objC" to match the Mac version, it actually tests + // the identity of its two arguments in C++. + void objCIdentityIsEqual(const CppArgumentList&, CppVariant*); + + // Changes the cookie policy from the default to allow all cookies. + void setAlwaysAcceptCookies(const CppArgumentList&, CppVariant*); + + // Changes asynchronous spellchecking flag on the settings. + void setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*); + + // Shows DevTools window. + void showWebInspector(const CppArgumentList&, CppVariant*); + void closeWebInspector(const CppArgumentList&, CppVariant*); + + // Gives focus to the window. + void setWindowIsKey(const CppArgumentList&, CppVariant*); + + // Method that controls whether pressing Tab key cycles through page elements + // or inserts a '\t' char in text area + void setTabKeyCyclesThroughElements(const CppArgumentList&, CppVariant*); + + // Passes through to WebPreferences which allows the user to have a custom + // style sheet. + void setUserStyleSheetEnabled(const CppArgumentList&, CppVariant*); + void setUserStyleSheetLocation(const CppArgumentList&, CppVariant*); + + // Passes this preference through to WebSettings. + void setAuthorAndUserStylesEnabled(const CppArgumentList&, CppVariant*); + + // Puts Webkit in "dashboard compatibility mode", which is used in obscure + // Mac-only circumstances. It's not really necessary, and will most likely + // never be used by Chrome, but some layout tests depend on its presence. + void setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant*); + + void setScrollbarPolicy(const CppArgumentList&, CppVariant*); + + // Causes navigation actions just printout the intended navigation instead + // of taking you to the page. This is used for cases like mailto, where you + // don't actually want to open the mail program. + void setCustomPolicyDelegate(const CppArgumentList&, CppVariant*); + + // Delays completion of the test until the policy delegate runs. + void waitForPolicyDelegate(const CppArgumentList&, CppVariant*); + + // Causes WillSendRequest to clear certain headers. + void setWillSendRequestClearHeader(const CppArgumentList&, CppVariant*); + + // Causes WillSendRequest to block redirects. + void setWillSendRequestReturnsNullOnRedirect(const CppArgumentList&, CppVariant*); + + // Causes WillSendRequest to return an empty request. + void setWillSendRequestReturnsNull(const CppArgumentList&, CppVariant*); + + // Converts a URL starting with file:///tmp/ to the local mapping. + void pathToLocalResource(const CppArgumentList&, CppVariant*); + + // Sets a bool such that when a drag is started, we fill the drag clipboard + // with a fake file object. + void addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant*); + + // Executes an internal command (superset of document.execCommand() commands). + void execCommand(const CppArgumentList&, CppVariant*); + + // Checks if an internal command is currently available. + void isCommandEnabled(const CppArgumentList&, CppVariant*); + + // Set the WebPreference that controls webkit's popup blocking. + void setPopupBlockingEnabled(const CppArgumentList&, CppVariant*); + + // If true, causes provisional frame loads to be stopped for the remainder of + // the test. + void setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant*); + + // Enable or disable smart insert/delete. This is enabled by default. + void setSmartInsertDeleteEnabled(const CppArgumentList&, CppVariant*); + + // Enable or disable trailing whitespace selection on double click. + void setSelectTrailingWhitespaceEnabled(const CppArgumentList&, CppVariant*); + + void pauseAnimationAtTimeOnElementWithId(const CppArgumentList&, CppVariant*); + void pauseTransitionAtTimeOnElementWithId(const CppArgumentList&, CppVariant*); + void elementDoesAutoCompleteForElementWithId(const CppArgumentList&, CppVariant*); + void numberOfActiveAnimations(const CppArgumentList&, CppVariant*); + void suspendAnimations(const CppArgumentList&, CppVariant*); + void resumeAnimations(const CppArgumentList&, CppVariant*); + void sampleSVGAnimationForElementAtTime(const CppArgumentList&, CppVariant*); + void disableImageLoading(const CppArgumentList&, CppVariant*); + void setIconDatabaseEnabled(const CppArgumentList&, CppVariant*); + void dumpSelectionRect(const CppArgumentList&, CppVariant*); + + // Grants permission for desktop notifications to an origin + void grantDesktopNotificationPermission(const CppArgumentList&, CppVariant*); + // Simulates a click on a desktop notification. + void simulateDesktopNotificationClick(const CppArgumentList&, CppVariant*); + + void setDomainRelaxationForbiddenForURLScheme(const CppArgumentList&, CppVariant*); + void setDeferMainResourceDataLoad(const CppArgumentList&, CppVariant*); + void setEditingBehavior(const CppArgumentList&, CppVariant*); + + // Deals with Web Audio WAV file data. + void setAudioData(const CppArgumentList&, CppVariant*); + const WebKit::WebArrayBufferView& audioData() const { return m_audioData; } + + // The following are only stubs. + // FIXME: Implement any of these that are needed to pass the layout tests. + void dumpAsWebArchive(const CppArgumentList&, CppVariant*); + void dumpTitleChanges(const CppArgumentList&, CppVariant*); + void setMainFrameIsFirstResponder(const CppArgumentList&, CppVariant*); + void display(const CppArgumentList&, CppVariant*); + void displayInvalidatedRegion(const CppArgumentList&, CppVariant*); + void testRepaint(const CppArgumentList&, CppVariant*); + void repaintSweepHorizontally(const CppArgumentList&, CppVariant*); + void clearBackForwardList(const CppArgumentList&, CppVariant*); + void keepWebHistory(const CppArgumentList&, CppVariant*); + void storeWebScriptObject(const CppArgumentList&, CppVariant*); + void accessStoredWebScriptObject(const CppArgumentList&, CppVariant*); + void objCClassNameOf(const CppArgumentList&, CppVariant*); + void addDisallowedURL(const CppArgumentList&, CppVariant*); + void callShouldCloseOnWebView(const CppArgumentList&, CppVariant*); + void setCallCloseOnWebViews(const CppArgumentList&, CppVariant*); + void setPrivateBrowsingEnabled(const CppArgumentList&, CppVariant*); + + void setJavaScriptCanAccessClipboard(const CppArgumentList&, CppVariant*); + void setXSSAuditorEnabled(const CppArgumentList&, CppVariant*); + void overridePreference(const CppArgumentList&, CppVariant*); + void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*); + void setAllowDisplayOfInsecureContent(const CppArgumentList&, CppVariant*); + void setAllowFileAccessFromFileURLs(const CppArgumentList&, CppVariant*); + void setAllowRunningOfInsecureContent(const CppArgumentList&, CppVariant*); + + void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*); + void setIsolatedWorldSecurityOrigin(const CppArgumentList&, CppVariant*); + + // The fallback method is called when a nonexistent method is called on + // the layout test controller object. + // It is usefull to catch typos in the JavaScript code (a few layout tests + // do have typos in them) and it allows the script to continue running in + // that case (as the Mac does). + void fallbackMethod(const CppArgumentList&, CppVariant*); + + // Allows layout tests to manage origins' whitelisting. + void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*); + void removeOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*); + + // Clears all application caches. + void clearAllApplicationCaches(const CppArgumentList&, CppVariant*); + // Clears an application cache for an origin. + void clearApplicationCacheForOrigin(const CppArgumentList&, CppVariant*); + // Returns origins that have application caches. + void originsWithApplicationCache(const CppArgumentList&, CppVariant*); + // Sets the application cache quota for the localhost origin. + void setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant*); + // Returns disk usage by all application caches for an origin. + void applicationCacheDiskUsageForOrigin(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*); + + // Causes layout to happen as if targetted to printed pages. + void setPrinting(const CppArgumentList&, CppVariant*); + + // Gets the number of page where the specified element will be put. + void pageNumberForElementById(const CppArgumentList&, CppVariant*); + + // Gets the page size and margins for a printed page. + void pageSizeAndMarginsInPixels(const CppArgumentList&, CppVariant*); + + // Returns true if the current page box has custom page size style for + // printing. + void hasCustomPageSizeStyle(const CppArgumentList&, CppVariant*); + + // Returns the visibililty status of a page box for printing + void isPageBoxVisible(const CppArgumentList&, CppVariant*); + + // Gets the page-related property for printed content + void pageProperty(const CppArgumentList&, CppVariant*); + + // Gets the number of pages to be printed. + void numberOfPages(const CppArgumentList&, CppVariant*); + + // Gets the number of geolocation permissions requests pending. + void numberOfPendingGeolocationPermissionRequests(const CppArgumentList&, CppVariant*); + + // Allows layout tests to start JavaScript profiling. + void setJavaScriptProfilingEnabled(const CppArgumentList&, CppVariant*); + + // Allows layout tests to exec scripts at WebInspector side. + void evaluateInWebInspector(const CppArgumentList&, CppVariant*); + + // Forces the selection colors for testing under Linux. + void forceRedSelectionColors(const CppArgumentList&, CppVariant*); + + // Adds a user script or user style sheet to be injected into new documents. + void addUserScript(const CppArgumentList&, CppVariant*); + void addUserStyleSheet(const CppArgumentList&, CppVariant*); + + // DeviceOrientation related functions + void setMockDeviceOrientation(const CppArgumentList&, CppVariant*); + + // Geolocation related functions. + void setGeolocationPermission(const CppArgumentList&, CppVariant*); + void setMockGeolocationPosition(const CppArgumentList&, CppVariant*); + void setMockGeolocationError(const CppArgumentList&, CppVariant*); + + // Empty stub method to keep parity with object model exposed by global LayoutTestController. + void abortModal(const CppArgumentList&, CppVariant*); + + // Speech input related functions. + void addMockSpeechInputResult(const CppArgumentList&, CppVariant*); + void startSpeechInput(const CppArgumentList&, CppVariant*); + + void layerTreeAsText(const CppArgumentList& args, CppVariant* result); + + void loseCompositorContext(const CppArgumentList& args, CppVariant* result); + + void markerTextForListItem(const CppArgumentList&, CppVariant*); + void hasSpellingMarker(const CppArgumentList&, CppVariant*); + void findString(const CppArgumentList&, CppVariant*); + + void setMinimumTimerInterval(const CppArgumentList&, CppVariant*); + + // Expects the first argument to be an input element and the second argument to be a boolean. + // Forwards the setAutofilled() call to the element. + void setAutofilled(const CppArgumentList&, CppVariant*); + + // Expects the first argument to be an input element and the second argument to be a string value. + // Forwards the setValueForUser() call to the element. + void setValueForUser(const CppArgumentList&, CppVariant*); + + // LocalStorage origin-related + void deleteAllLocalStorage(const CppArgumentList&, CppVariant*); + void originsWithLocalStorage(const CppArgumentList&, CppVariant*); + void deleteLocalStorageForOrigin(const CppArgumentList&, CppVariant*); + void localStorageDiskUsageForOrigin(const CppArgumentList&, CppVariant*); + void observeStorageTrackerNotifications(const CppArgumentList&, CppVariant*); + void syncLocalStorage(const CppArgumentList&, CppVariant*); + + // WebPermissionClient related. + void setImagesAllowed(const CppArgumentList&, CppVariant*); + void setScriptsAllowed(const CppArgumentList&, CppVariant*); + void setStorageAllowed(const CppArgumentList&, CppVariant*); + void setPluginsAllowed(const CppArgumentList&, CppVariant*); + void dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant*); + + // Enable or disable plugins. + void setPluginsEnabled(const CppArgumentList&, CppVariant*); + + // Switch the visibility of the page. + void setPageVisibility(const CppArgumentList&, CppVariant*); + void resetPageVisibility(const CppArgumentList&, CppVariant*); + + // Changes the direction of the focused element. + void setTextDirection(const CppArgumentList&, CppVariant*); + + void setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList&, CppVariant*); + + void enableFixedLayoutMode(const CppArgumentList&, CppVariant*); + void setFixedLayoutSize(const CppArgumentList&, CppVariant*); + +public: + // The following methods are not exposed to JavaScript. + void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); } + + WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*); + bool shouldDumpAsAudio() const { return m_dumpAsAudio; } + void setShouldDumpAsAudio(bool dumpAsAudio) { m_dumpAsAudio = dumpAsAudio; } + bool shouldDumpAsText() { return m_dumpAsText; } + void setShouldDumpAsText(bool value) { m_dumpAsText = value; } + bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; } + bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; } + void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; } + bool shouldDumpProgressFinishedCallback() { return m_dumpProgressFinishedCallback; } + void setShouldDumpProgressFinishedCallback(bool value) { m_dumpProgressFinishedCallback = value; } + bool shouldDumpUserGestureInFrameLoadCallbacks() { return m_dumpUserGestureInFrameLoadCallbacks; } + void setShouldDumpUserGestureInFrameLoadCallbacks(bool value) { m_dumpUserGestureInFrameLoadCallbacks = value; } + bool shouldDumpResourceLoadCallbacks() {return m_dumpResourceLoadCallbacks; } + void setShouldDumpResourceResponseMIMETypes(bool value) { m_dumpResourceResponseMIMETypes = value; } + bool shouldDumpResourceResponseMIMETypes() {return m_dumpResourceResponseMIMETypes; } + bool shouldDumpStatusCallbacks() { return m_dumpWindowStatusChanges; } + bool shouldDumpSelectionRect() { return m_dumpSelectionRect; } + bool shouldDumpBackForwardList() { return m_dumpBackForwardList; } + bool shouldDumpTitleChanges() { return m_dumpTitleChanges; } + bool shouldDumpPermissionClientCallbacks() { return m_dumpPermissionClientCallbacks; } + bool shouldDumpChildFrameScrollPositions() { return m_dumpChildFrameScrollPositions; } + bool shouldDumpChildFramesAsText() { return m_dumpChildFramesAsText; } + bool shouldGeneratePixelResults() { return m_generatePixelResults; } + void setShouldGeneratePixelResults(bool value) { m_generatePixelResults = value; } + bool shouldDumpCreateView() { return m_dumpCreateView; } + bool acceptsEditing() { return m_acceptsEditing; } + bool canOpenWindows() { return m_canOpenWindows; } + bool shouldAddFileToPasteboard() { return m_shouldAddFileToPasteboard; } + bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; } + bool deferMainResourceDataLoad() { return m_deferMainResourceDataLoad; } + void setShowDebugLayerTree(bool value) { m_showDebugLayerTree = value; } + void setTitleTextDirection(WebKit::WebTextDirection dir) + { + m_titleTextDirection.set(dir == WebKit::WebTextDirectionLeftToRight ? "ltr" : "rtl"); + } + + bool shouldInterceptPostMessage() + { + return m_interceptPostMessage.isBool() && m_interceptPostMessage.toBoolean(); + } + + void setIsPrinting(bool value) { m_isPrinting = value; } + bool isPrinting() { return m_isPrinting; } + + 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*) = 0; + }; + + TaskList* taskList() { return &m_taskList; } + + bool shouldStayOnPageAfterHandlingBeforeUnload() const { return m_shouldStayOnPageAfterHandlingBeforeUnload; } + +private: + friend class WorkItem; + friend class WorkQueue; + + // Helper class for managing events queued by methods like queueLoad or + // queueScript. + class WorkQueue { + public: + WorkQueue(LayoutTestController* controller) : m_frozen(false), m_controller(controller) { } + virtual ~WorkQueue(); + void processWorkSoon(); + + // Reset the state of the class between tests. + void reset(); + + void addWork(WorkItem*); + + void setFrozen(bool frozen) { m_frozen = frozen; } + bool isEmpty() { return m_queue.isEmpty(); } + TaskList* taskList() { return &m_taskList; } + + private: + void processWork(); + class WorkQueueTask: public MethodTask<WorkQueue> { + public: + WorkQueueTask(WorkQueue* object): MethodTask<WorkQueue>(object) { } + virtual void runIfValid() { m_object->processWork(); } + }; + + TaskList m_taskList; + Deque<WorkItem*> m_queue; + bool m_frozen; + LayoutTestController* m_controller; + }; + + // Support for overridePreference. + bool cppVariantToBool(const CppVariant&); + int32_t cppVariantToInt32(const CppVariant&); + WebKit::WebString cppVariantToWebString(const CppVariant&); + Vector<WebKit::WebString> cppVariantToWebStringArray(const CppVariant&); + + void logErrorToConsole(const std::string&); + void completeNotifyDone(bool isTimeout); + class NotifyDoneTimedOutTask: public MethodTask<LayoutTestController> { + public: + NotifyDoneTimedOutTask(LayoutTestController* object): MethodTask<LayoutTestController>(object) { } + virtual void runIfValid() { m_object->completeNotifyDone(true); } + }; + + + bool pauseAnimationAtTimeOnElementWithId(const WebKit::WebString& animationName, double time, const WebKit::WebString& elementId); + bool pauseTransitionAtTimeOnElementWithId(const WebKit::WebString& propertyName, double time, const WebKit::WebString& elementId); + bool elementDoesAutoCompleteForElementWithId(const WebKit::WebString&); + int numberOfActiveAnimations(); + void suspendAnimations(); + void resumeAnimations(); + + // Used for test timeouts. + TaskList m_taskList; + + // Non-owning pointer. The LayoutTestController is owned by the host. + TestShell* m_shell; + + // If true, the test_shell will produce a plain text dump rather than a + // text representation of the renderer. + bool m_dumpAsText; + + // If true, the test_shell will output a base64 encoded WAVE file. + bool m_dumpAsAudio; + + // 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 the progress + // finished callback. + bool m_dumpProgressFinishedCallback; + + // If true, the test_shell will output a line of the user gesture status + // text for some frame load callbacks. + bool m_dumpUserGestureInFrameLoadCallbacks; + + // If true, the test_shell will output a descriptive line for each resource + // load callback. + bool m_dumpResourceLoadCallbacks; + + // If true, the test_shell will output the MIME type for each resource that + // was loaded. + bool m_dumpResourceResponseMIMETypes; + + // If true, the test_shell will produce a dump of the back forward list as + // well. + bool m_dumpBackForwardList; + + // If true, the test_shell will print out the child frame scroll offsets as + // well. + bool m_dumpChildFrameScrollPositions; + + // If true and if dump_as_text_ is true, the test_shell will recursively + // dump all frames as plain text. + bool m_dumpChildFramesAsText; + + // If true, the test_shell will dump all changes to window.status. + bool m_dumpWindowStatusChanges; + + // If true, output a message when the page title is changed. + bool m_dumpTitleChanges; + + // If true, output a descriptive line each time a permission client + // callback is invoked. Currently only implemented for allowImage. + bool m_dumpPermissionClientCallbacks; + + // If true, the test_shell will generate pixel results in dumpAsText mode + bool m_generatePixelResults; + + // If true, output a descriptive line each time WebViewClient::createView + // is invoked. + bool m_dumpCreateView; + + // If true, the element will be treated as editable. This value is returned + // from various editing callbacks that are called just before edit operations + // are allowed. + bool m_acceptsEditing; + + // If true, new windows can be opened via javascript or by plugins. By + // default, set to false and can be toggled to true using + // setCanOpenWindows(). + bool m_canOpenWindows; + + // When reset is called, go through and close all but the main test shell + // window. By default, set to true but toggled to false using + // setCloseRemainingWindowsWhenComplete(). + bool m_closeRemainingWindows; + + // If true, pixel dump will be produced as a series of 1px-tall, view-wide + // individual paints over the height of the view. + bool m_testRepaint; + // If true and test_repaint_ is true as well, pixel dump will be produced as + // a series of 1px-wide, view-tall paints across the width of the view. + bool m_sweepHorizontally; + + // If true and a drag starts, adds a file to the drag&drop clipboard. + bool m_shouldAddFileToPasteboard; + + // If true, stops provisional frame loads during the + // DidStartProvisionalLoadForFrame callback. + bool m_stopProvisionalFrameLoads; + + // If true, don't dump output until notifyDone is called. + bool m_waitUntilDone; + + // If false, all new requests will not defer the main resource data load. + bool m_deferMainResourceDataLoad; + + // If true, we will show extended information in the graphics layer tree. + bool m_showDebugLayerTree; + + // If true, layout is to target printed pages. + bool m_isPrinting; + + WorkQueue m_workQueue; + + CppVariant m_globalFlag; + + // Bound variable counting the number of top URLs visited. + CppVariant m_webHistoryItemCount; + + // Bound variable tracking the directionality of the <title> tag. + CppVariant m_titleTextDirection; + + // Bound variable to return the name of this platform (chromium). + CppVariant m_platformName; + + // Bound variable to set whether postMessages should be intercepted or not + CppVariant m_interceptPostMessage; + + WebKit::WebURL m_userStyleSheetLocation; + + OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock; + + // WAV audio data is stored here. + WebKit::WebArrayBufferView m_audioData; + + bool m_shouldStayOnPageAfterHandlingBeforeUnload; +}; + +#endif // LayoutTestController_h diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm new file mode 100644 index 000000000..e34cf5fca --- /dev/null +++ b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <AppKit/AppKit.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +// This is a simple helper app that changes the color sync profile to the +// generic profile and back when done. This program is managed by the layout +// test script, so it can do the job for multiple DumpRenderTree while they are +// running layout tests. + +static CMProfileRef userColorProfile = 0; + +static void saveCurrentColorProfile() +{ + CGDirectDisplayID displayID = CGMainDisplayID(); + CMProfileRef previousProfile; + CMError error = CMGetProfileByAVID((UInt32)displayID, &previousProfile); + if (error) { + NSLog(@"failed to get the current color profile, pixmaps won't match. " + @"Error: %d", (int)error); + } else { + userColorProfile = previousProfile; + } +} + +static void installLayoutTestColorProfile() +{ + // To make sure we get consistent colors (not dependent on the Main display), + // we force the generic rgb color profile. This cases a change the user can + // see. + + CGDirectDisplayID displayID = CGMainDisplayID(); + NSColorSpace* genericSpace = [NSColorSpace genericRGBColorSpace]; + CMProfileRef genericProfile = (CMProfileRef)[genericSpace colorSyncProfile]; + CMError error = CMSetProfileByAVID((UInt32)displayID, genericProfile); + if (error) { + NSLog(@"failed install the generic color profile, pixmaps won't match. " + @"Error: %d", (int)error); + } +} + +static void restoreUserColorProfile(void) +{ + if (!userColorProfile) + return; + CGDirectDisplayID displayID = CGMainDisplayID(); + CMError error = CMSetProfileByAVID((UInt32)displayID, userColorProfile); + CMCloseProfile(userColorProfile); + if (error) { + NSLog(@"Failed to restore color profile, use System Preferences -> " + @"Displays -> Color to reset. Error: %d", (int)error); + } + userColorProfile = 0; +} + +static void simpleSignalHandler(int sig) +{ + // Try to restore the color profile and try to go down cleanly + restoreUserColorProfile(); + exit(128 + sig); +} + +int main(int argc, char* argv[]) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + // Hooks the ways we might get told to clean up... + signal(SIGINT, simpleSignalHandler); + signal(SIGHUP, simpleSignalHandler); + signal(SIGTERM, simpleSignalHandler); + + // Save off the current profile, and then install the layout test profile. + saveCurrentColorProfile(); + installLayoutTestColorProfile(); + + // Let the script know we're ready + printf("ready\n"); + fflush(stdout); + + // Wait for any key (or signal) + getchar(); + + // Restore the profile + restoreUserColorProfile(); + + [pool release]; + return 0; +} diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp new file mode 100644 index 000000000..25efdcdcb --- /dev/null +++ b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <windows.h> + +static BOOL fontSmoothingEnabled = FALSE; + +static void saveInitialSettings(void) +{ + ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); +} + +// Technically, all we need to do is disable ClearType. However, +// for some reason, the call to SPI_SETFONTSMOOTHINGTYPE doesn't +// seem to work, so we just disable font smoothing all together +// (which works reliably) +static void installLayoutTestSettings(void) +{ + ::SystemParametersInfo(SPI_SETFONTSMOOTHING, FALSE, 0, 0); +} + +static void restoreInitialSettings(void) +{ + ::SystemParametersInfo(SPI_SETFONTSMOOTHING, static_cast<UINT>(fontSmoothingEnabled), 0, 0); +} + +static void simpleSignalHandler(int signalNumber) +{ + // Try to restore the settings and then go down cleanly + restoreInitialSettings(); + exit(128 + signalNumber); +} + +int main(int, char*[]) +{ + // Hooks the ways we might get told to clean up... + signal(SIGINT, simpleSignalHandler); + signal(SIGTERM, simpleSignalHandler); + + saveInitialSettings(); + + installLayoutTestSettings(); + + // Let the script know we're ready + printf("ready\n"); + fflush(stdout); + + // Wait for any key (or signal) + getchar(); + + restoreInitialSettings(); + + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp new file mode 100644 index 000000000..56b0f1eff --- /dev/null +++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp @@ -0,0 +1,164 @@ +/* + * 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 "platform/WebString.h" +#include <wtf/ASCIICType.h> +#include <wtf/Assertions.h> +#include <wtf/text/WTFString.h> + +using namespace WebKit; + +MockSpellCheck::MockSpellCheck() + : m_initialized(false) { } + +MockSpellCheck::~MockSpellCheck() { } + +static bool isNotASCIIAlpha(UChar ch) { return !isASCIIAlpha(ch); } + +bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset, int* misspelledLength) +{ + ASSERT(misspelledOffset); + ASSERT(misspelledLength); + + // Initialize this spellchecker. + initializeIfNeeded(); + + // Reset the result values as our spellchecker does. + *misspelledOffset = 0; + *misspelledLength = 0; + + // Convert to a String because we store String instances in + // m_misspelledWords and WebString has no find(). + WTF::String stringText(text.data(), text.length()); + int skippedLength = 0; + + while (!stringText.isEmpty()) { + // 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 ? static_cast<int>(stringText.length()) - wordOffset : wordEnd - wordOffset; + + // Look up our misspelled-word table to check if the extracted word is a + // known misspelled word, and return the offset and the length of the + // extracted word if this word is a known misspelled word. + // (See the comment in MockSpellCheck::initializeIfNeeded() why we use a + // misspelled-word table.) + WTF::String word = stringText.substring(wordOffset, wordLength); + if (m_misspelledWords.contains(word)) { + *misspelledOffset = wordOffset + skippedLength; + *misspelledLength = wordLength; + break; + } + + ASSERT(0 < wordOffset + wordLength); + stringText = stringText.substring(wordOffset + wordLength); + skippedLength += wordOffset + wordLength; + } + + return false; +} + +void MockSpellCheck::fillSuggestionList(const WebString& word, Vector<WebString>* suggestions) +{ + if (word == WebString::fromUTF8("wellcome")) + suggestions->append(WebString::fromUTF8("welcome")); +} + +bool MockSpellCheck::initializeIfNeeded() +{ + // Exit if we have already initialized this object. + if (m_initialized) + return false; + + // Create a table that consists of misspelled words used in WebKit layout + // tests. + // Since WebKit layout tests don't have so many misspelled words as + // well-spelled words, it is easier to compare the given word with misspelled + // ones than to compare with well-spelled ones. + static const char* misspelledWords[] = { + // These words are known misspelled words in webkit tests. + // If there are other misspelled words in webkit tests, please add them in + // this array. + "foo", + "Foo", + "baz", + "fo", + "LibertyF", + "chello", + "xxxtestxxx", + "XXxxx", + "Textx", + "blockquoted", + "asd", + "Lorem", + "Nunc", + "Curabitur", + "eu", + "adlj", + "adaasj", + "sdklj", + "jlkds", + "jsaada", + "jlda", + "zz", + "contentEditable", + // The following words are used by unit tests. + "ifmmp", + "qwertyuiopasd", + "qwertyuiopasdf", + "wellcome" + }; + + m_misspelledWords.clear(); + for (size_t i = 0; i < arraysize(misspelledWords); ++i) + m_misspelledWords.add(WTF::String::fromUTF8(misspelledWords[i]), false); + + // Mark as initialized to prevent this object from being initialized twice + // or more. + m_initialized = true; + + // Since this MockSpellCheck class doesn't download dictionaries, this + // function always returns false. + return false; +} diff --git a/Tools/DumpRenderTree/chromium/MockSpellCheck.h b/Tools/DumpRenderTree/chromium/MockSpellCheck.h new file mode 100644 index 000000000..bce05c772 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MockSpellCheck_h +#define MockSpellCheck_h + +#include <wtf/HashMap.h> +#include <wtf/text/StringHash.h> +#include <wtf/text/WTFString.h> + +namespace WebKit { +class WebString; +} + +// A mock implementation of a spell-checker used for WebKit tests. +// This class only implements the minimal functionarities required by WebKit +// tests, i.e. this class just compares the given string with known misspelled +// words in webkit tests and mark them as missspelled. +// Even though this is sufficent for webkit tests, this class is not suitable +// for any other usages. +class MockSpellCheck { +public: + MockSpellCheck(); + ~MockSpellCheck(); + + // Checks the spellings of the specified text. + // This function returns true if the text consists of valid words, and + // returns false if it includes invalid words. + // When the given text includes invalid words, this function sets the + // position of the first invalid word to misspelledOffset, and the length of + // the first invalid word to misspelledLength, respectively. + // For example, when the given text is " zz zz", this function sets 3 to + // misspelledOffset and 2 to misspelledLength, respectively. + bool spellCheckWord(const WebKit::WebString& text, + int* misspelledOffset, + int* misspelledLength); + + void fillSuggestionList(const WebKit::WebString& word, Vector<WebKit::WebString>* suggestions); + +private: + // Initialize the internal resources if we need to initialize it. + // Initializing this object may take long time. To prevent from hurting + // the performance of test_shell, we initialize this object when + // SpellCheckWord() is called for the first time. + // To be compliant with SpellCheck:InitializeIfNeeded(), this function + // returns true if this object is downloading a dictionary, otherwise + // it returns false. + bool initializeIfNeeded(); + + // A table that consists of misspelled words. + HashMap<WTF::String, bool> m_misspelledWords; + + // A flag representing whether or not this object is initialized. + bool m_initialized; +}; + +#endif // MockSpellCheck_h diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp new file mode 100644 index 000000000..7809821aa --- /dev/null +++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "NotificationPresenter.h" + +#if ENABLE(NOTIFICATIONS) + +#include "WebKit.h" +#include "platform/WebKitPlatformSupport.h" +#include "WebNotification.h" +#include "WebNotificationPermissionCallback.h" +#include "WebSecurityOrigin.h" +#include "platform/WebString.h" +#include "platform/WebURL.h" +#include "googleurl/src/gurl.h" +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +using namespace WebKit; + +static WebString identifierForNotification(const WebNotification& notification) +{ + if (notification.isHTML()) + return notification.url().spec().utf16(); + return notification.title(); +} + +static void deferredDisplayDispatch(void* context) +{ + WebNotification* notification = static_cast<WebNotification*>(context); + notification->dispatchDisplayEvent(); + delete notification; +} + +NotificationPresenter::~NotificationPresenter() +{ +} + +void NotificationPresenter::grantPermission(const WebString& origin) +{ + m_allowedOrigins.add(WTF::String(origin.data(), origin.length())); +} + +bool NotificationPresenter::simulateClick(const WebString& title) +{ + WTF::String id(title.data(), title.length()); + if (m_activeNotifications.find(id) == m_activeNotifications.end()) + return false; + + const WebNotification& notification = m_activeNotifications.find(id)->second; + WebNotification eventTarget(notification); + eventTarget.dispatchClickEvent(); + return true; +} + +// The output from all these methods matches what DumpRenderTree produces. +bool NotificationPresenter::show(const WebNotification& notification) +{ + WebString identifier = identifierForNotification(notification); + if (!notification.replaceId().isEmpty()) { + WTF::String replaceId(notification.replaceId().data(), notification.replaceId().length()); + if (m_replacements.find(replaceId) != m_replacements.end()) + printf("REPLACING NOTIFICATION %s\n", + m_replacements.find(replaceId)->second.utf8().data()); + + m_replacements.set(replaceId, WTF::String(identifier.data(), identifier.length())); + } + + if (notification.isHTML()) { + printf("DESKTOP NOTIFICATION: contents at %s\n", + notification.url().spec().data()); + } else { + printf("DESKTOP NOTIFICATION:%s icon %s, title %s, text %s\n", + notification.direction() == WebTextDirectionRightToLeft ? "(RTL)" : "", + notification.iconURL().isEmpty() ? "" : + notification.iconURL().spec().data(), + notification.title().isEmpty() ? "" : + notification.title().utf8().data(), + notification.body().isEmpty() ? "" : + notification.body().utf8().data()); + } + + WTF::String id(identifier.data(), identifier.length()); + m_activeNotifications.set(id, notification); + + webKitPlatformSupport()->callOnMainThread(deferredDisplayDispatch, new WebNotification(notification)); + return true; +} + +void NotificationPresenter::cancel(const WebNotification& notification) +{ + WebString identifier = identifierForNotification(notification); + printf("DESKTOP NOTIFICATION CLOSED: %s\n", identifier.utf8().data()); + WebNotification eventTarget(notification); + eventTarget.dispatchCloseEvent(false); + + WTF::String id(identifier.data(), identifier.length()); + m_activeNotifications.remove(id); +} + +void NotificationPresenter::objectDestroyed(const WebKit::WebNotification& notification) +{ + WebString identifier = identifierForNotification(notification); + WTF::String id(identifier.data(), identifier.length()); + m_activeNotifications.remove(id); +} + +WebNotificationPresenter::Permission NotificationPresenter::checkPermission(const WebSecurityOrigin& origin) +{ + // Check with the layout test controller + WebString originString = origin.toString(); + bool allowed = m_allowedOrigins.find(WTF::String(originString.data(), originString.length())) != m_allowedOrigins.end(); + return allowed ? WebNotificationPresenter::PermissionAllowed + : WebNotificationPresenter::PermissionDenied; +} + +void NotificationPresenter::requestPermission( + const WebSecurityOrigin& origin, + WebNotificationPermissionCallback* callback) +{ + printf("DESKTOP NOTIFICATION PERMISSION REQUESTED: %s\n", + origin.toString().utf8().data()); + callback->permissionRequestComplete(); +} + +#endif // ENABLE(NOTIFICATIONS) diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.h b/Tools/DumpRenderTree/chromium/NotificationPresenter.h new file mode 100644 index 000000000..b33df9138 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NotificationPresenter_h +#define NotificationPresenter_h + +#include "WebNotification.h" +#include "WebNotificationPresenter.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/text/StringHash.h> +#include <wtf/text/WTFString.h> + +class TestShell; + +// A class that implements WebNotificationPresenter for DRT. +class NotificationPresenter : public WebKit::WebNotificationPresenter { +public: + explicit NotificationPresenter(TestShell* shell) : m_shell(shell) { } + virtual ~NotificationPresenter(); + + // Called by the LayoutTestController to simulate a user granting permission. + void grantPermission(const WebKit::WebString& origin); + + // Called by the LayoutTestController to simulate a user clicking on a notification. + bool simulateClick(const WebKit::WebString& notificationIdentifier); + + // WebKit::WebNotificationPresenter interface + virtual bool show(const WebKit::WebNotification&); + virtual void cancel(const WebKit::WebNotification&); + virtual void objectDestroyed(const WebKit::WebNotification&); + virtual Permission checkPermission(const WebKit::WebSecurityOrigin&); + virtual void requestPermission(const WebKit::WebSecurityOrigin&, WebKit::WebNotificationPermissionCallback*); + + void reset() { m_allowedOrigins.clear(); } + +private: + // Non-owned pointer. The NotificationPresenter is owned by the test shell. + TestShell* m_shell; + + // Set of allowed origins. + HashSet<WTF::String> m_allowedOrigins; + + // Map of active notifications. + HashMap<WTF::String, WebKit::WebNotification> m_activeNotifications; + + // Map of active replacement IDs to the titles of those notifications + HashMap<WTF::String, WTF::String> m_replacements; +}; + +#endif // NotificationPresenter_h diff --git a/Tools/DumpRenderTree/chromium/PlainTextController.cpp b/Tools/DumpRenderTree/chromium/PlainTextController.cpp new file mode 100644 index 000000000..7287c2c83 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/PlainTextController.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlainTextController.h" + +#include "TestShell.h" +#include "WebBindings.h" +#include "WebRange.h" +#include "platform/WebString.h" + +using namespace WebKit; + +PlainTextController::PlainTextController() +{ + // Initialize the map that associates methods of this class with the names + // they will use when called by JavaScript. The actual binding of those + // names to their methods will be done by calling bindToJavaScript() (defined + // by CppBoundClass, the parent to PlainTextController). + bindMethod("plainText", &PlainTextController::plainText); + + // The fallback method is called when an unknown method is invoked. + bindFallbackMethod(&PlainTextController::fallbackMethod); +} + +void PlainTextController::plainText(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() < 1 || !arguments[0].isObject()) + return; + + // Check that passed-in object is, in fact, a range. + NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]); + if (!npobject) + return; + WebRange range; + if (!WebBindings::getRange(npobject, &range)) + return; + + // Extract the text using the Range's text() method + WebString text = range.toPlainText(); + result->set(text.utf8()); +} + +void PlainTextController::fallbackMethod(const CppArgumentList&, CppVariant* result) +{ + printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on PlainTextController\n"); + result->setNull(); +} + diff --git a/Tools/DumpRenderTree/chromium/PlainTextController.h b/Tools/DumpRenderTree/chromium/PlainTextController.h new file mode 100644 index 000000000..3d3a04c61 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/PlainTextController.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PlainTextController_h +#define PlainTextController_h + +#include "CppBoundClass.h" + +class TestShell; + +class PlainTextController : public CppBoundClass { +public: + // Builds the property and method lists needed to bind this class to a JS + // object. + explicit PlainTextController(); + + // JS callback methods. + void plainText(const CppArgumentList&, CppVariant*); + + // Fall-back method: called if an unknown method is invoked. + void fallbackMethod(const CppArgumentList&, CppVariant*); +}; + +#endif // PlainTextController_h + diff --git a/Tools/DumpRenderTree/chromium/Task.cpp b/Tools/DumpRenderTree/chromium/Task.cpp new file mode 100644 index 000000000..d80beef34 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/Task.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Task.h" + +#include "WebKit.h" +#include "platform/WebKitPlatformSupport.h" + +WebTask::WebTask(TaskList* list) + : m_taskList(list) +{ + m_taskList->registerTask(this); +} + +WebTask::~WebTask() +{ + if (m_taskList) + m_taskList->unregisterTask(this); +} + +void TaskList::unregisterTask(WebTask* task) +{ + size_t index = m_tasks.find(task); + if (index != notFound) + m_tasks.remove(index); +} + +void TaskList::revokeAll() +{ + while (!m_tasks.isEmpty()) + m_tasks[0]->cancel(); +} + +static void invokeTask(void* context) +{ + WebTask* task = static_cast<WebTask*>(context); + task->run(); + delete task; +} + +void postTask(WebTask* task) +{ + WebKit::webKitPlatformSupport()->callOnMainThread(invokeTask, static_cast<void*>(task)); +} + +void postDelayedTask(WebTask* task, int64_t ms) +{ + webkit_support::PostDelayedTask(task, ms); +} + + diff --git a/Tools/DumpRenderTree/chromium/Task.h b/Tools/DumpRenderTree/chromium/Task.h new file mode 100644 index 000000000..0b32c472b --- /dev/null +++ b/Tools/DumpRenderTree/chromium/Task.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Task_h +#define Task_h + +#include "webkit/support/webkit_support.h" +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> + +class TaskList; + +// WebTask represents a task which can run by postTask() or postDelayedTask(). +// it is named "WebTask", not "Task", to avoid conflist with base/task.h. +class WebTask : public webkit_support::TaskAdaptor { +public: + WebTask(TaskList*); + // The main code of this task. + // An implementation of run() should return immediately if cancel() was called. + virtual void run() = 0; + virtual void cancel() = 0; + virtual ~WebTask(); + +private: + virtual void Run() { run(); } + +protected: + TaskList* m_taskList; +}; + +class TaskList { +public: + TaskList() { } + ~TaskList() { revokeAll(); } + void registerTask(WebTask* task) { m_tasks.append(task); } + void unregisterTask(WebTask*); + void revokeAll(); + +private: + Vector<WebTask*> m_tasks; +}; + +// A task containing an object pointer of class T. Is is supposed that +// runifValid() calls a member function of the object pointer. +// Class T must have "TaskList* taskList()". +template<class T> class MethodTask: public WebTask { +public: + MethodTask(T* object): WebTask(object->taskList()), m_object(object) { } + virtual void run() + { + if (m_object) + runIfValid(); + } + virtual void cancel() + { + m_object = 0; + m_taskList->unregisterTask(this); + m_taskList = 0; + } + virtual void runIfValid() = 0; + +protected: + T* m_object; +}; + +void postTask(WebTask*); +void postDelayedTask(WebTask*, int64_t ms); + +#endif // Task_h diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp new file mode 100644 index 000000000..8246c09be --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TestEventPrinter.h" + +#include <stdio.h> +#include <stdlib.h> +#include <wtf/Assertions.h> + +class DRTPrinter : public TestEventPrinter { +public: + DRTPrinter() { } + void handleTestHeader(const char* url) const; + void handleTimedOut() const; + void handleTextHeader() const; + void handleTextFooter() const; + void handleAudioHeader() const; + void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const; + void handleImageFooter() const; + void handleTestFooter(bool dumpedAnything) const; +}; + +class TestShellPrinter : public TestEventPrinter { +public: + TestShellPrinter() { } + void handleTestHeader(const char* url) const; + void handleTimedOut() const; + void handleTextHeader() const; + void handleTextFooter() const; + void handleAudioHeader() const; + void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const; + void handleImageFooter() const; + void handleTestFooter(bool dumpedAnything) const; +}; + +TestEventPrinter::~TestEventPrinter() +{ +} + +PassOwnPtr<TestEventPrinter> TestEventPrinter::createDRTPrinter() +{ + return adoptPtr(new DRTPrinter); +} + +PassOwnPtr<TestEventPrinter> TestEventPrinter::createTestShellPrinter() +{ + return adoptPtr(new TestShellPrinter); +} + +// ---------------------------------------------------------------- + +void DRTPrinter::handleTestHeader(const char*) const +{ +} + +void DRTPrinter::handleTimedOut() const +{ + fprintf(stderr, "FAIL: Timed out waiting for notifyDone to be called\n"); + fprintf(stdout, "FAIL: Timed out waiting for notifyDone to be called\n"); +} + +void DRTPrinter::handleTextHeader() const +{ + printf("Content-Type: text/plain\n"); +} + +void DRTPrinter::handleTextFooter() const +{ + printf("#EOF\n"); +} + +void DRTPrinter::handleAudioHeader() const +{ + printf("Content-Type: audio/wav\n"); +} + +void DRTPrinter::handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char*) const +{ + ASSERT(actualHash); + printf("\nActualHash: %s\n", actualHash); + if (expectedHash && expectedHash[0]) + printf("\nExpectedHash: %s\n", expectedHash); + if (imageData && imageSize) { + printf("Content-Type: image/png\n"); + // Printf formatting for size_t on 32-bit, 64-bit, and on Windows is hard so just cast to an int. + printf("Content-Length: %d\n", static_cast<int>(imageSize)); + if (fwrite(imageData, 1, imageSize, stdout) != imageSize) { + fprintf(stderr, "Short write to stdout.\n"); + exit(1); + } + } +} + +void DRTPrinter::handleImageFooter() const +{ + printf("#EOF\n"); +} + +void DRTPrinter::handleTestFooter(bool) const +{ +} + +// ---------------------------------------------------------------- + +void TestShellPrinter::handleTestHeader(const char* url) const +{ + printf("#URL:%s\n", url); +} + +void TestShellPrinter::handleTimedOut() const +{ + puts("#TEST_TIMED_OUT\n"); +} + +void TestShellPrinter::handleTextHeader() const +{ +} + +void TestShellPrinter::handleTextFooter() const +{ +} + +void TestShellPrinter::handleAudioHeader() const +{ + printf("Content-Type: audio/wav\n"); +} + +void TestShellPrinter::handleImage(const char* actualHash, const char*, const unsigned char* imageData, size_t imageSize, const char* fileName) const +{ + ASSERT(actualHash); + if (imageData && imageSize) { + ASSERT(fileName); + FILE* fp = fopen(fileName, "wb"); + if (!fp) { + perror(fileName); + exit(EXIT_FAILURE); + } + if (fwrite(imageData, 1, imageSize, fp) != imageSize) { + perror(fileName); + fclose(fp); + exit(EXIT_FAILURE); + } + fclose(fp); + } + printf("#MD5:%s\n", actualHash); +} + +void TestShellPrinter::handleImageFooter() const +{ +} + +void TestShellPrinter::handleTestFooter(bool dumpedAnything) const +{ + if (dumpedAnything) + printf("#EOF\n"); +} diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.h b/Tools/DumpRenderTree/chromium/TestEventPrinter.h new file mode 100644 index 000000000..f69523c34 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.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 TestEventPrinter_h +#define TestEventPrinter_h + +#include <wtf/PassOwnPtr.h> + +class TestEventPrinter { +public: + static PassOwnPtr<TestEventPrinter> createDRTPrinter(); + static PassOwnPtr<TestEventPrinter> createTestShellPrinter(); + + virtual ~TestEventPrinter(); + virtual void handleTestHeader(const char* url) const = 0; + virtual void handleTimedOut() const = 0; + virtual void handleTextHeader() const = 0; + virtual void handleTextFooter() const = 0; + virtual void handleAudioHeader() const = 0; + virtual void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const = 0; + virtual void handleImageFooter() const = 0; + virtual void handleTestFooter(bool dumpedAnything) const = 0; +}; + +#endif // TestEventPrinter_h diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.cpp b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp new file mode 100644 index 000000000..ad6fcfff4 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TestNavigationController.h" + +#include "TestShell.h" +#include <wtf/Assertions.h> + +using namespace WebKit; +using namespace std; + +// ---------------------------------------------------------------------------- +// TestNavigationEntry + +PassRefPtr<TestNavigationEntry> TestNavigationEntry::create() +{ + return adoptRef(new TestNavigationEntry); +} + +PassRefPtr<TestNavigationEntry> TestNavigationEntry::create( + int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame) +{ + return adoptRef(new TestNavigationEntry(pageID, url, title, targetFrame)); +} + +TestNavigationEntry::TestNavigationEntry() + : m_pageID(-1) { } + +TestNavigationEntry::TestNavigationEntry( + int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame) + : m_pageID(pageID) + , m_url(url) + , m_title(title) + , m_targetFrame(targetFrame) { } + +TestNavigationEntry::~TestNavigationEntry() { } + +void TestNavigationEntry::setContentState(const WebHistoryItem& state) +{ + m_state = state; +} + +// ---------------------------------------------------------------------------- +// TestNavigationController + +TestNavigationController::TestNavigationController(NavigationHost* host) + : m_pendingEntry(0) + , m_lastCommittedEntryIndex(-1) + , m_pendingEntryIndex(-1) + , m_host(host) + , m_maxPageID(-1) { } + +TestNavigationController::~TestNavigationController() +{ + discardPendingEntry(); +} + +void TestNavigationController::reset() +{ + m_entries.clear(); + discardPendingEntry(); + + m_lastCommittedEntryIndex = -1; +} + +void TestNavigationController::reload() +{ + // Base the navigation on where we are now... + int currentIndex = currentEntryIndex(); + + // If we are no where, then we can't reload. + // FIXME: We should add a CanReload method. + if (currentIndex == -1) + return; + + discardPendingEntry(); + + m_pendingEntryIndex = currentIndex; + navigateToPendingEntry(true); +} + +void TestNavigationController::goToOffset(int offset) +{ + int index = m_lastCommittedEntryIndex + offset; + if (index < 0 || index >= entryCount()) + return; + + goToIndex(index); +} + +void TestNavigationController::goToIndex(int index) +{ + ASSERT(index >= 0); + ASSERT(index < static_cast<int>(m_entries.size())); + + discardPendingEntry(); + + m_pendingEntryIndex = index; + navigateToPendingEntry(false); +} + +void TestNavigationController::loadEntry(TestNavigationEntry* entry) +{ + // When navigating to a new page, we don't know for sure if we will actually + // end up leaving the current page. The new page load could for example + // result in a download or a 'no content' response (e.g., a mailto: URL). + discardPendingEntry(); + m_pendingEntry = entry; + navigateToPendingEntry(false); +} + + +TestNavigationEntry* TestNavigationController::lastCommittedEntry() const +{ + if (m_lastCommittedEntryIndex == -1) + return 0; + return m_entries[m_lastCommittedEntryIndex].get(); +} + +TestNavigationEntry* TestNavigationController::activeEntry() const +{ + TestNavigationEntry* entry = m_pendingEntry.get(); + if (!entry) + entry = lastCommittedEntry(); + return entry; +} + +int TestNavigationController::currentEntryIndex() const +{ + if (m_pendingEntryIndex != -1) + return m_pendingEntryIndex; + return m_lastCommittedEntryIndex; +} + + +TestNavigationEntry* TestNavigationController::entryAtIndex(int index) const +{ + if (index < 0 || index >= entryCount()) + return 0; + return m_entries[index].get(); +} + +TestNavigationEntry* TestNavigationController::entryWithPageID(int32_t pageID) const +{ + int index = entryIndexWithPageID(pageID); + return (index != -1) ? m_entries[index].get() : 0; +} + +void TestNavigationController::didNavigateToEntry(TestNavigationEntry* entry) +{ + // If the entry is that of a page with PageID larger than any this Tab has + // seen before, then consider it a new navigation. + if (entry->pageID() > maxPageID()) { + insertEntry(entry); + return; + } + + // Otherwise, we just need to update an existing entry with matching PageID. + // If the existing entry corresponds to the entry which is pending, then we + // must update the current entry index accordingly. When navigating to the + // same URL, a new PageID is not created. + + int existingEntryIndex = entryIndexWithPageID(entry->pageID()); + TestNavigationEntry* existingEntry = (existingEntryIndex != -1) ? + m_entries[existingEntryIndex].get() : 0; + if (!existingEntry) { + // No existing entry, then simply ignore this navigation! + } else if (existingEntry == m_pendingEntry.get()) { + // The given entry might provide a new URL... e.g., navigating back to a + // page in session history could have resulted in a new client redirect. + existingEntry->setURL(entry->URL()); + existingEntry->setContentState(entry->contentState()); + m_lastCommittedEntryIndex = m_pendingEntryIndex; + m_pendingEntryIndex = -1; + m_pendingEntry.clear(); + } else if (m_pendingEntry && m_pendingEntry->pageID() == -1 + && GURL(m_pendingEntry->URL()) == GURL(existingEntry->URL().spec())) { + // Not a new navigation + discardPendingEntry(); + } else { + // The given entry might provide a new URL... e.g., navigating to a page + // might result in a client redirect, which should override the URL of the + // existing entry. + existingEntry->setURL(entry->URL()); + existingEntry->setContentState(entry->contentState()); + + // The navigation could have been issued by the renderer, so be sure that + // we update our current index. + m_lastCommittedEntryIndex = existingEntryIndex; + } + + updateMaxPageID(); +} + +void TestNavigationController::discardPendingEntry() +{ + m_pendingEntry.clear(); + m_pendingEntryIndex = -1; +} + +void TestNavigationController::insertEntry(TestNavigationEntry* entry) +{ + discardPendingEntry(); + + // Prune any entry which are in front of the current entry + int currentSize = static_cast<int>(m_entries.size()); + if (currentSize > 0) { + while (m_lastCommittedEntryIndex < (currentSize - 1)) { + m_entries.removeLast(); + currentSize--; + } + } + + m_entries.append(RefPtr<TestNavigationEntry>(entry)); + m_lastCommittedEntryIndex = static_cast<int>(m_entries.size()) - 1; + updateMaxPageID(); +} + +int TestNavigationController::entryIndexWithPageID(int32 pageID) const +{ + for (int i = static_cast<int>(m_entries.size()) - 1; i >= 0; --i) { + if (m_entries[i]->pageID() == pageID) + return i; + } + return -1; +} + +void TestNavigationController::navigateToPendingEntry(bool reload) +{ + // For session history navigations only the pending_entry_index_ is set. + if (!m_pendingEntry) { + ASSERT(m_pendingEntryIndex != -1); + m_pendingEntry = m_entries[m_pendingEntryIndex]; + } + + if (m_host->navigate(*m_pendingEntry.get(), reload)) { + // Note: this is redundant if navigation completed synchronously because + // DidNavigateToEntry call this as well. + updateMaxPageID(); + } else + discardPendingEntry(); +} + +void TestNavigationController::updateMaxPageID() +{ + TestNavigationEntry* entry = activeEntry(); + if (entry) + m_maxPageID = max(m_maxPageID, entry->pageID()); +} diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.h b/Tools/DumpRenderTree/chromium/TestNavigationController.h new file mode 100644 index 000000000..f23a2ae92 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestNavigationController.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TestNavigationController_h +#define TestNavigationController_h + +#include "WebDataSource.h" +#include "WebHistoryItem.h" +#include "platform/WebString.h" +#include "platform/WebURL.h" +#include "webkit/support/webkit_support.h" +#include <string> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +// Associated with browser-initated navigations to hold tracking data. +class TestShellExtraData : public WebKit::WebDataSource::ExtraData { +public: + TestShellExtraData(int32_t pendingPageID) + : pendingPageID(pendingPageID) + , requestCommitted(false) { } + + // Contains the page_id for this navigation or -1 if there is none yet. + int32_t pendingPageID; + + // True if we have already processed the "DidCommitLoad" event for this + // request. Used by session history. + bool requestCommitted; +}; + +// Stores one back/forward navigation state for the test shell. +class TestNavigationEntry: public RefCounted<TestNavigationEntry> { +public: + static PassRefPtr<TestNavigationEntry> create(); + static PassRefPtr<TestNavigationEntry> create( + int pageID, + const WebKit::WebURL&, + const WebKit::WebString& title, + const WebKit::WebString& targetFrame); + + // Virtual to allow test_shell to extend the class. + virtual ~TestNavigationEntry(); + + // Set / Get the URI + void setURL(const WebKit::WebURL& url) { m_url = url; } + const WebKit::WebURL& URL() const { return m_url; } + + // Set / Get the title + void setTitle(const WebKit::WebString& title) { m_title = title; } + const WebKit::WebString& title() const { return m_title; } + + // Set / Get a state. + void setContentState(const WebKit::WebHistoryItem&); + const WebKit::WebHistoryItem& contentState() const { return m_state; } + + // Get the page id corresponding to the tab's state. + void setPageID(int pageID) { m_pageID = pageID; } + int32_t pageID() const { return m_pageID; } + + const WebKit::WebString& targetFrame() const { return m_targetFrame; } + +private: + TestNavigationEntry(); + TestNavigationEntry(int pageID, + const WebKit::WebURL&, + const WebKit::WebString& title, + const WebKit::WebString& targetFrame); + + // Describes the current page that the tab represents. This is not relevant + // for all tab contents types. + int32_t m_pageID; + + WebKit::WebURL m_url; + WebKit::WebString m_title; + WebKit::WebHistoryItem m_state; + WebKit::WebString m_targetFrame; +}; + +class NavigationHost { +public: + virtual bool navigate(const TestNavigationEntry&, bool reload) = 0; +}; + +// Test shell's NavigationController. The goal is to be as close to the Chrome +// version as possible. +class TestNavigationController { + WTF_MAKE_NONCOPYABLE(TestNavigationController); +public: + TestNavigationController(NavigationHost*); + ~TestNavigationController(); + + void reset(); + + // Causes the controller to reload the current (or pending) entry. + void reload(); + + // Causes the controller to go to the specified offset from current. Does + // nothing if out of bounds. + void goToOffset(int); + + // Causes the controller to go to the specified index. + void goToIndex(int); + + // Causes the controller to load the specified entry. + // NOTE: Do not pass an entry that the controller already owns! + void loadEntry(TestNavigationEntry*); + + // Returns the last committed entry, which may be null if there are no + // committed entries. + TestNavigationEntry* lastCommittedEntry() const; + + // Returns the number of entries in the NavigationControllerBase, excluding + // the pending entry if there is one. + int entryCount() const { return static_cast<int>(m_entries.size()); } + + // Returns the active entry, which is the pending entry if a navigation is in + // progress or the last committed entry otherwise. NOTE: This can be 0!! + // + // If you are trying to get the current state of the NavigationControllerBase, + // this is the method you will typically want to call. + TestNavigationEntry* activeEntry() const; + + // Returns the index from which we would go back/forward or reload. This is + // the m_lastCommittedEntryIndex if m_pendingEntryIndex is -1. Otherwise, + // it is the m_pendingEntryIndex. + int currentEntryIndex() const; + + // Returns the entry at the specified index. Returns 0 if out of bounds. + TestNavigationEntry* entryAtIndex(int) const; + + // Return the entry with the corresponding type and page ID, or 0 if + // not found. + TestNavigationEntry* entryWithPageID(int32_t) const; + + // Returns the index of the last committed entry. + int lastCommittedEntryIndex() const { return m_lastCommittedEntryIndex; } + + // Used to inform us of a navigation being committed for a tab. Any entry + // located forward to the current entry will be deleted. The new entry + // becomes the current entry. + void didNavigateToEntry(TestNavigationEntry*); + + // Used to inform us to discard its pending entry. + void discardPendingEntry(); + +private: + // Inserts an entry after the current position, removing all entries after it. + // The new entry will become the active one. + void insertEntry(TestNavigationEntry*); + + int maxPageID() const { return m_maxPageID; } + void navigateToPendingEntry(bool reload); + + // Return the index of the entry with the corresponding type and page ID, + // or -1 if not found. + int entryIndexWithPageID(int32_t) const; + + // Updates the max page ID with that of the given entry, if is larger. + void updateMaxPageID(); + + // List of NavigationEntry for this tab + typedef Vector<RefPtr<TestNavigationEntry> > NavigationEntryList; + typedef NavigationEntryList::iterator NavigationEntryListIterator; + NavigationEntryList m_entries; + + // An entry we haven't gotten a response for yet. This will be discarded + // when we navigate again. It's used only so we know what the currently + // displayed tab is. + RefPtr<TestNavigationEntry> m_pendingEntry; + + // currently visible entry + int m_lastCommittedEntryIndex; + + // index of pending entry if it is in entries_, or -1 if pending_entry_ is a + // new entry (created by LoadURL). + int m_pendingEntryIndex; + + NavigationHost* m_host; + int m_maxPageID; +}; + +#endif // TestNavigationController_h + diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h new file mode 100644 index 000000000..9fa3fff3b --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h @@ -0,0 +1,9 @@ +#include "bindings/npapi.h" + +// These are defined in WebCore/brdige/npapi.h and we need them on Linux/Win. +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h new file mode 100644 index 000000000..59ae666b9 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h @@ -0,0 +1,8 @@ +#include "npapi.h" +#include "bindings/npfunctions.h" + +// Non-standard event types can be passed to HandleEvent. +// npapi.h that comes with WebKit.framework adds these events. +#define getFocusEvent (osEvt + 16) +#define loseFocusEvent (osEvt + 17) +#define adjustCursorEvent (osEvt + 18) diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h new file mode 100644 index 000000000..597d4ad7c --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h @@ -0,0 +1 @@ +#include "bindings/npruntime.h" diff --git a/Tools/DumpRenderTree/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp new file mode 100644 index 000000000..f15cb444a --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShell.cpp @@ -0,0 +1,768 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TestShell.h" + +#include "DRTDevToolsAgent.h" +#include "DRTDevToolsClient.h" +#include "LayoutTestController.h" +#include "platform/WebArrayBufferView.h" +#include "WebCompositor.h" +#include "WebDataSource.h" +#include "WebDocument.h" +#include "WebElement.h" +#include "WebFrame.h" +#include "WebHistoryItem.h" +#include "WebIDBFactory.h" +#include "WebTestingSupport.h" +#include "platform/WebThread.h" +#include "WebKit.h" +#include "platform/WebKitPlatformSupport.h" +#include "WebPermissions.h" +#include "platform/WebPoint.h" +#include "WebRuntimeFeatures.h" +#include "WebScriptController.h" +#include "WebSettings.h" +#include "platform/WebSize.h" +#include "WebSpeechInputControllerMock.h" +#include "platform/WebString.h" +#include "platform/WebURLRequest.h" +#include "platform/WebURLResponse.h" +#include "WebView.h" +#include "WebViewHost.h" +#include "skia/ext/platform_canvas.h" +#include "webkit/support/webkit_support.h" +#include "webkit/support/webkit_support_gfx.h" +#include <algorithm> +#include <cctype> +#include <vector> +#include <wtf/MD5.h> + +using namespace WebKit; +using namespace std; + +// Content area size for newly created windows. +static const int testWindowWidth = 800; +static const int testWindowHeight = 600; + +// The W3C SVG layout tests use a different size than the other layout tests. +static const int SVGTestWindowWidth = 480; +static const int SVGTestWindowHeight = 360; + +static const char layoutTestsPattern[] = "/LayoutTests/"; +static const string::size_type layoutTestsPatternSize = sizeof(layoutTestsPattern) - 1; +static const char fileUrlPattern[] = "file:/"; +static const char fileTestPrefix[] = "(file test):"; +static const char dataUrlPattern[] = "data:"; +static const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1; + +// FIXME: Move this to a common place so that it can be shared with +// WebCore::TransparencyWin::makeLayerOpaque(). +static void makeCanvasOpaque(SkCanvas* canvas) +{ + const SkBitmap& bitmap = canvas->getTopDevice()->accessBitmap(true); + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); + + SkAutoLockPixels lock(bitmap); + for (int y = 0; y < bitmap.height(); y++) { + uint32_t* row = bitmap.getAddr32(0, y); + for (int x = 0; x < bitmap.width(); x++) + row[x] |= 0xFF000000; // Set alpha bits to 1. + } +} + +TestShell::TestShell(bool testShellMode) + : m_testIsPending(false) + , m_testIsPreparing(false) + , m_focusedWidget(0) + , m_testShellMode(testShellMode) + , m_devTools(0) + , m_allowExternalPages(false) + , m_acceleratedCompositingForVideoEnabled(false) + , m_threadedCompositingEnabled(false) + , m_compositeToTexture(false) + , m_forceCompositingMode(false) + , m_accelerated2dCanvasEnabled(false) + , m_legacyAccelerated2dCanvasEnabled(false) + , m_acceleratedPaintingEnabled(false) + , m_perTilePaintingEnabled(false) + , m_stressOpt(false) + , m_stressDeopt(false) + , m_dumpWhenFinished(true) +{ + WebRuntimeFeatures::enableDataTransferItems(true); + WebRuntimeFeatures::enableGeolocation(true); + WebRuntimeFeatures::enablePointerLock(true); + WebRuntimeFeatures::enableIndexedDatabase(true); + WebRuntimeFeatures::enableFileSystem(true); + WebRuntimeFeatures::enableJavaScriptI18NAPI(true); + WebRuntimeFeatures::enableMediaStream(true); + WebRuntimeFeatures::enableWebAudio(true); + WebRuntimeFeatures::enableVideoTrack(true); + WebRuntimeFeatures::enableGamepad(true); + + m_webPermissions = adoptPtr(new WebPermissions(this)); + m_accessibilityController = adoptPtr(new AccessibilityController(this)); + m_gamepadController = adoptPtr(new GamepadController(this)); + m_layoutTestController = adoptPtr(new LayoutTestController(this)); + m_eventSender = adoptPtr(new EventSender(this)); + m_plainTextController = adoptPtr(new PlainTextController()); + m_textInputController = adoptPtr(new TextInputController(this)); +#if ENABLE(NOTIFICATIONS) + m_notificationPresenter = adoptPtr(new NotificationPresenter(this)); +#endif + m_printer = m_testShellMode ? TestEventPrinter::createTestShellPrinter() : TestEventPrinter::createDRTPrinter(); + + WTF::initializeThreading(); + + if (m_threadedCompositingEnabled) { + m_webCompositorThread = adoptPtr(WebKit::webKitPlatformSupport()->createThread("Compositor")); + WebCompositor::initialize(m_webCompositorThread.get()); + } else + WebCompositor::initialize(0); + + + // 30 second is the same as the value in Mac DRT. + // If we use a value smaller than the timeout value of + // (new-)run-webkit-tests, (new-)run-webkit-tests misunderstands that a + // timed-out DRT process was crashed. + m_timeout = 30 * 1000; + + createMainWindow(); +} + +void TestShell::createMainWindow() +{ + m_drtDevToolsAgent = adoptPtr(new DRTDevToolsAgent); + m_webViewHost = adoptPtr(createNewWindow(WebURL(), m_drtDevToolsAgent.get())); + m_webView = m_webViewHost->webView(); + m_drtDevToolsAgent->setWebView(m_webView); +} + +TestShell::~TestShell() +{ + // Note: DevTools are closed together with all the other windows in the + // windows list. + + // Destroy the WebView before its WebViewHost. + m_drtDevToolsAgent->setWebView(0); + + WebCompositor::shutdown(); +} + +void TestShell::createDRTDevToolsClient(DRTDevToolsAgent* agent) +{ + m_drtDevToolsClient = adoptPtr(new DRTDevToolsClient(agent, m_devTools->webView())); +} + +void TestShell::showDevTools() +{ + if (!m_devTools) { + WebURL url = webkit_support::GetDevToolsPathAsURL(); + if (!url.isValid()) { + ASSERT(false); + return; + } + m_devTools = createNewWindow(url); + m_devTools->webView()->settings()->setMemoryInfoEnabled(true); + m_devTools->setLogConsoleOutput(false); + ASSERT(m_devTools); + createDRTDevToolsClient(m_drtDevToolsAgent.get()); + } + m_devTools->show(WebKit::WebNavigationPolicyNewWindow); +} + +void TestShell::closeDevTools() +{ + if (m_devTools) { + m_devTools->webView()->settings()->setMemoryInfoEnabled(false); + m_drtDevToolsAgent->reset(); + m_drtDevToolsClient.clear(); + closeWindow(m_devTools); + m_devTools = 0; + } +} + +void TestShell::resetWebSettings(WebView& webView) +{ + m_prefs.reset(); + m_prefs.acceleratedCompositingEnabled = true; + m_prefs.acceleratedCompositingForVideoEnabled = m_acceleratedCompositingForVideoEnabled; + m_prefs.compositeToTexture = m_compositeToTexture; + m_prefs.forceCompositingMode = m_forceCompositingMode; + m_prefs.accelerated2dCanvasEnabled = m_accelerated2dCanvasEnabled; + m_prefs.legacyAccelerated2dCanvasEnabled = m_legacyAccelerated2dCanvasEnabled; + m_prefs.acceleratedPaintingEnabled = m_acceleratedPaintingEnabled; + m_prefs.perTilePaintingEnabled = m_perTilePaintingEnabled; + m_prefs.applyTo(&webView); +} + +void TestShell::runFileTest(const TestParams& params) +{ + ASSERT(params.testUrl.isValid()); + m_testIsPreparing = true; + m_params = params; + string testUrl = m_params.testUrl.spec(); + + if (testUrl.find("loading/") != string::npos + || testUrl.find("loading\\") != string::npos) + m_layoutTestController->setShouldDumpFrameLoadCallbacks(true); + + if (testUrl.find("compositing/") != string::npos || testUrl.find("compositing\\") != string::npos) { + m_prefs.acceleratedCompositingForVideoEnabled = true; + m_prefs.accelerated2dCanvasEnabled = true; + m_prefs.applyTo(m_webView); + } + + if (testUrl.find("/dumpAsText/") != string::npos + || testUrl.find("\\dumpAsText\\") != string::npos) { + m_layoutTestController->setShouldDumpAsText(true); + m_layoutTestController->setShouldGeneratePixelResults(false); + } + + if (testUrl.find("/inspector/") != string::npos + || testUrl.find("\\inspector\\") != string::npos) + showDevTools(); + + if (m_params.debugLayerTree) + m_layoutTestController->setShowDebugLayerTree(true); + + if (m_dumpWhenFinished) + m_printer->handleTestHeader(testUrl.c_str()); + loadURL(m_params.testUrl); + + m_testIsPreparing = false; + waitTestFinished(); +} + +static inline bool isSVGTestURL(const WebURL& url) +{ + return url.isValid() && string(url.spec()).find("W3C-SVG-1.1") != string::npos; +} + +void TestShell::resizeWindowForTest(WebViewHost* window, const WebURL& url) +{ + int width, height; + if (isSVGTestURL(url)) { + width = SVGTestWindowWidth; + height = SVGTestWindowHeight; + } else { + width = testWindowWidth; + height = testWindowHeight; + } + window->setWindowRect(WebRect(0, 0, width + virtualWindowBorder * 2, height + virtualWindowBorder * 2)); +} + +void TestShell::resetTestController() +{ + resetWebSettings(*webView()); + m_webPermissions->reset(); + m_accessibilityController->reset(); + m_gamepadController->reset(); + m_layoutTestController->reset(); + m_eventSender->reset(); + m_webViewHost->reset(); +#if ENABLE(NOTIFICATIONS) + m_notificationPresenter->reset(); +#endif + m_drtDevToolsAgent->reset(); + if (m_drtDevToolsClient) + m_drtDevToolsClient->reset(); + webView()->setPageScaleFactor(1, WebPoint(0, 0)); + webView()->enableFixedLayoutMode(false); + webView()->setFixedLayoutSize(WebSize(0, 0)); + webView()->mainFrame()->clearOpener(); + WebTestingSupport::resetInternalsObject(webView()->mainFrame()); +} + +void TestShell::loadURL(const WebURL& url) +{ + m_webViewHost->loadURLForFrame(url, WebString()); +} + +void TestShell::reload() +{ + m_webViewHost->navigationController()->reload(); +} + +void TestShell::goToOffset(int offset) +{ + m_webViewHost->navigationController()->goToOffset(offset); +} + +int TestShell::navigationEntryCount() const +{ + return m_webViewHost->navigationController()->entryCount(); +} + +void TestShell::callJSGC() +{ + m_webView->mainFrame()->collectGarbage(); +} + +void TestShell::setFocus(WebWidget* widget, bool enable) +{ + // Simulate the effects of InteractiveSetFocus(), which includes calling + // both setFocus() and setIsActive(). + if (enable) { + if (m_focusedWidget != widget) { + if (m_focusedWidget) + m_focusedWidget->setFocus(false); + webView()->setIsActive(enable); + widget->setFocus(enable); + m_focusedWidget = widget; + } + } else { + if (m_focusedWidget == widget) { + widget->setFocus(enable); + webView()->setIsActive(enable); + m_focusedWidget = 0; + } + } +} + +void TestShell::testFinished() +{ + if (!m_testIsPending) + return; + m_testIsPending = false; + if (m_dumpWhenFinished) + dump(); + webkit_support::QuitMessageLoop(); +} + +void TestShell::testTimedOut() +{ + m_printer->handleTimedOut(); + testFinished(); +} + +static string dumpDocumentText(WebFrame* frame) +{ + // We use the document element's text instead of the body text here because + // not all documents have a body, such as XML documents. + WebElement documentElement = frame->document().documentElement(); + if (documentElement.isNull()) + return string(); + return documentElement.innerText().utf8(); +} + +static string dumpFramesAsText(WebFrame* frame, bool recursive) +{ + string result; + + // Add header for all but the main frame. Skip empty frames. + if (frame->parent() && !frame->document().documentElement().isNull()) { + result.append("\n--------\nFrame: '"); + result.append(frame->name().utf8().data()); + result.append("'\n--------\n"); + } + + result.append(dumpDocumentText(frame)); + result.append("\n"); + + if (recursive) { + for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) + result.append(dumpFramesAsText(child, recursive)); + } + + return result; +} + +static string dumpFramesAsPrintedText(WebFrame* frame, bool recursive) +{ + string result; + + // Cannot do printed format for anything other than HTML + if (!frame->document().isHTMLDocument()) + return string(); + + // Add header for all but the main frame. Skip empty frames. + if (frame->parent() && !frame->document().documentElement().isNull()) { + result.append("\n--------\nFrame: '"); + result.append(frame->name().utf8().data()); + result.append("'\n--------\n"); + } + + result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8()); + result.append("\n"); + + if (recursive) { + for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) + result.append(dumpFramesAsPrintedText(child, recursive)); + } + + return result; +} + +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 normalizeLayoutTestURLInternal(const string& url) +{ + string result = url; + size_t pos; + if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) { + // adjust file URLs to match upstream results. + result.replace(0, pos + layoutTestsPatternSize, fileTestPrefix); + } else if (!url.find(dataUrlPattern)) { + // URL-escape data URLs to match results upstream. + string path = url.substr(dataUrlPatternSize); + result.replace(dataUrlPatternSize, url.length(), path); + } + return result; +} + +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 = normalizeLayoutTestURLInternal(item.urlString().utf8()); + 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 shouldDumpAsAudio = m_layoutTestController->shouldDumpAsAudio(); + bool shouldGeneratePixelResults = m_layoutTestController->shouldGeneratePixelResults(); + bool shouldDumpAsPrinted = m_layoutTestController->isPrinting(); + bool dumpedAnything = false; + + if (shouldDumpAsAudio) { + m_printer->handleAudioHeader(); + + const WebKit::WebArrayBufferView& webArrayBufferView = m_layoutTestController->audioData(); + printf("Content-Length: %d\n", webArrayBufferView.byteLength()); + + if (fwrite(webArrayBufferView.baseAddress(), 1, webArrayBufferView.byteLength(), stdout) != webArrayBufferView.byteLength()) + FATAL("Short write to stdout, disk full?\n"); + printf("\n"); + + m_printer->handleTestFooter(true); + + fflush(stdout); + fflush(stderr); + return; + } + + if (m_params.dumpTree) { + dumpedAnything = true; + m_printer->handleTextHeader(); + // Text output: the test page can request different types of output + // which we handle here. + if (!shouldDumpAsText) { + // Plain text pages should be dumped as text + string mimeType = frame->dataSource()->response().mimeType().utf8(); + if (mimeType == "text/plain") { + shouldDumpAsText = true; + shouldGeneratePixelResults = false; + } + } + if (shouldDumpAsText) { + bool recursive = m_layoutTestController->shouldDumpChildFramesAsText(); + string dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive); + if (fwrite(dataUtf8.c_str(), 1, dataUtf8.size(), stdout) != dataUtf8.size()) + FATAL("Short write to stdout, disk full?\n"); + } else { + WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal; + if (shouldDumpAsPrinted) + renderTextBehavior |= WebFrame::RenderAsTextPrinting; + if (m_params.debugRenderTree) + renderTextBehavior |= WebFrame::RenderAsTextDebug; + printf("%s", frame->renderTreeAsText(renderTextBehavior).utf8().data()); + bool recursive = m_layoutTestController->shouldDumpChildFrameScrollPositions(); + dumpFrameScrollPosition(frame, recursive); + } + if (m_layoutTestController->shouldDumpBackForwardList()) + printf("%s", dumpAllBackForwardLists().c_str()); + } + if (dumpedAnything && m_params.printSeparators) + m_printer->handleTextFooter(); + + if (m_params.dumpPixels && shouldGeneratePixelResults) { + // Image output: we write the image data to the file given on the + // command line (for the dump pixels argument), and the MD5 sum to + // stdout. + dumpedAnything = true; + m_webView->layout(); + if (m_layoutTestController->testRepaint()) { + WebSize viewSize = m_webView->size(); + int width = viewSize.width; + int height = viewSize.height; + if (m_layoutTestController->sweepHorizontally()) { + for (WebRect column(0, 0, 1, height); column.x < width; column.x++) + m_webViewHost->paintRect(column); + } else { + for (WebRect line(0, 0, width, 1); line.y < height; line.y++) + m_webViewHost->paintRect(line); + } + } else if (m_layoutTestController->isPrinting()) + m_webViewHost->paintPagesWithBoundaries(); + else + m_webViewHost->paintInvalidatedRegion(); + + // See if we need to draw the selection bounds rect. Selection bounds + // rect is the rect enclosing the (possibly transformed) selection. + // The rect should be drawn after everything is laid out and painted. + if (m_layoutTestController->shouldDumpSelectionRect()) { + // If there is a selection rect - draw a red 1px border enclosing rect + WebRect wr = frame->selectionBoundsRect(); + if (!wr.isEmpty()) { + // Render a red rectangle bounding selection rect + SkPaint paint; + paint.setColor(0xFFFF0000); // Fully opaque red + paint.setStyle(SkPaint::kStroke_Style); + paint.setFlags(SkPaint::kAntiAlias_Flag); + paint.setStrokeWidth(1.0f); + SkIRect rect; // Bounding rect + rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height); + m_webViewHost->canvas()->drawIRect(rect, paint); + } + } + + dumpImage(m_webViewHost->canvas()); + } + m_printer->handleImageFooter(); + m_printer->handleTestFooter(dumpedAnything); + fflush(stdout); + fflush(stderr); +} + +void TestShell::dumpImage(SkCanvas* canvas) const +{ + // Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want + // to keep it. On Windows, the alpha channel is wrong since text/form control + // drawing may have erased it in a few places. So on Windows we force it to + // opaque and also don't write the alpha channel for the reference. Linux + // doesn't have the wrong alpha like Windows, but we match Windows. +#if OS(MAC_OS_X) + bool discardTransparency = false; +#else + bool discardTransparency = true; + makeCanvasOpaque(canvas); +#endif + + const SkBitmap& sourceBitmap = canvas->getTopDevice()->accessBitmap(false); + SkAutoLockPixels sourceBitmapLock(sourceBitmap); + + // Compute MD5 sum. + MD5 digester; + Vector<uint8_t, 16> digestValue; + digester.addBytes(reinterpret_cast<const uint8_t*>(sourceBitmap.getPixels()), sourceBitmap.getSize()); + digester.checksum(digestValue); + string md5hash; + md5hash.reserve(16 * 2); + for (unsigned i = 0; i < 16; ++i) { + char hex[3]; + // Use "x", not "X". The string must be lowercased. + sprintf(hex, "%02x", digestValue[i]); + md5hash.append(hex); + } + + // Only encode and dump the png if the hashes don't match. Encoding the + // image is really expensive. + if (md5hash.compare(m_params.pixelHash)) { + std::vector<unsigned char> png; + webkit_support::EncodeBGRAPNGWithChecksum(reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()), sourceBitmap.width(), + sourceBitmap.height(), static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, md5hash, &png); + + m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), &png[0], png.size(), m_params.pixelFileName.c_str()); + } else + m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), 0, 0, m_params.pixelFileName.c_str()); +} + +void TestShell::bindJSObjectsToWindow(WebFrame* frame) +{ + WebTestingSupport::injectInternalsObject(frame); + m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController")); + m_gamepadController->bindToJavascript(frame, WebString::fromUTF8("gamepadController")); + m_layoutTestController->bindToJavascript(frame, WebString::fromUTF8("layoutTestController")); + m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender")); + m_plainTextController->bindToJavascript(frame, WebString::fromUTF8("plainText")); + m_textInputController->bindToJavascript(frame, WebString::fromUTF8("textInputController")); +} + +WebViewHost* TestShell::createNewWindow(const WebKit::WebURL& url) +{ + return createNewWindow(url, 0); +} + +WebViewHost* TestShell::createNewWindow(const WebKit::WebURL& url, DRTDevToolsAgent* devToolsAgent) +{ + WebViewHost* host = new WebViewHost(this); + WebView* view = WebView::create(host); + view->setPermissionClient(webPermissions()); + view->setDevToolsAgentClient(devToolsAgent); + host->setWebWidget(view); + m_prefs.applyTo(view); + view->initializeMainFrame(host); + m_windowList.append(host); + host->loadURLForFrame(url, WebString()); + return host; +} + +void TestShell::closeWindow(WebViewHost* window) +{ + size_t i = m_windowList.find(window); + if (i == notFound) { + ASSERT_NOT_REACHED(); + return; + } + m_windowList.remove(i); + WebWidget* focusedWidget = m_focusedWidget; + if (window->webWidget() == m_focusedWidget) + focusedWidget = 0; + + delete window; + // We set the focused widget after deleting the web view host because it + // can change the focus. + m_focusedWidget = focusedWidget; + if (m_focusedWidget) { + webView()->setIsActive(true); + m_focusedWidget->setFocus(true); + } +} + +void TestShell::closeRemainingWindows() +{ + // Just close devTools window manually because we have custom deinitialization code for it. + closeDevTools(); + + // Iterate through the window list and close everything except the main + // window. We don't want to delete elements as we're iterating, so we copy + // to a temp vector first. + Vector<WebViewHost*> windowsToDelete; + for (unsigned i = 0; i < m_windowList.size(); ++i) { + if (m_windowList[i] != webViewHost()) + windowsToDelete.append(m_windowList[i]); + } + ASSERT(windowsToDelete.size() + 1 == m_windowList.size()); + for (unsigned i = 0; i < windowsToDelete.size(); ++i) + closeWindow(windowsToDelete[i]); + ASSERT(m_windowList.size() == 1); +} + +int TestShell::windowCount() +{ + return m_windowList.size(); +} + +string TestShell::normalizeLayoutTestURL(const string& url) +{ + return normalizeLayoutTestURLInternal(url); +} diff --git a/Tools/DumpRenderTree/chromium/TestShell.h b/Tools/DumpRenderTree/chromium/TestShell.h new file mode 100644 index 000000000..a095ef2d0 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShell.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TestShell_h +#define TestShell_h + +#include "AccessibilityController.h" +#include "EventSender.h" +#include "GamepadController.h" +#include "LayoutTestController.h" +#include "NotificationPresenter.h" +#include "PlainTextController.h" +#include "TestEventPrinter.h" +#include "TextInputController.h" +#include "WebPreferences.h" +#include "WebViewHost.h" +#include <string> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> + +// TestShell is a container of global variables and has bridge functions between +// various objects. Only one instance is created in one DRT process. + +namespace WebKit { +class WebDevToolsAgentClient; +class WebFrame; +class WebNotificationPresenter; +class WebThread; +class WebView; +class WebURL; +} + +class DRTDevToolsAgent; +class DRTDevToolsCallArgs; +class DRTDevToolsClient; +class WebPermissions; + +struct TestParams { + bool dumpTree; + bool dumpPixels; + bool debugRenderTree; + bool debugLayerTree; + bool printSeparators; + WebKit::WebURL testUrl; + // Resultant image file name. Required only if the test_shell mode. + std::string pixelFileName; + std::string pixelHash; + + TestParams() + : dumpTree(true) + , dumpPixels(false) + , debugRenderTree(false) + , debugLayerTree(false) + , printSeparators(false) { } +}; + +class TestShell { +public: + TestShell(bool testShellMode); + ~TestShell(); + + // The main WebView. + WebKit::WebView* webView() const { return m_webView; } + // Returns the host for the main WebView. + WebViewHost* webViewHost() const { return m_webViewHost.get(); } + LayoutTestController* layoutTestController() const { return m_layoutTestController.get(); } + EventSender* eventSender() const { return m_eventSender.get(); } + AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); } + GamepadController* gamepadController() const { return m_gamepadController.get(); } + NotificationPresenter* notificationPresenter() const { return m_notificationPresenter.get(); } + TestEventPrinter* printer() const { return m_printer.get(); } + + WebPreferences* preferences() { return &m_prefs; } + void applyPreferences() { m_prefs.applyTo(m_webView); } + + WebPermissions* webPermissions() { return m_webPermissions.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&); + void reload(); + void goToOffset(int offset); + int navigationEntryCount() const; + + void setFocus(WebKit::WebWidget*, bool enable); + bool shouldDumpFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpFrameLoadCallbacks(); } + bool shouldDumpUserGestureInFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpUserGestureInFrameLoadCallbacks(); } + bool shouldDumpResourceLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceLoadCallbacks(); } + bool shouldDumpResourceResponseMIMETypes() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceResponseMIMETypes(); } + void setIsLoading(bool flag) { m_isLoading = flag; } + + // Called by the LayoutTestController to signal test completion. + void testFinished(); + // Called by LayoutTestController when a test hits the timeout, but does not + // cause a hang. We can avoid killing TestShell in this case and still dump + // the test results. + void testTimedOut(); + + bool allowExternalPages() const { return m_allowExternalPages; } + void setAllowExternalPages(bool allowExternalPages) { m_allowExternalPages = allowExternalPages; } + + void setAcceleratedCompositingForVideoEnabled(bool enabled) { m_acceleratedCompositingForVideoEnabled = enabled; } + void setThreadedCompositingEnabled(bool enabled) { m_threadedCompositingEnabled = enabled; } + void setCompositeToTexture(bool enabled) { m_compositeToTexture = enabled; } + void setForceCompositingMode(bool enabled) { m_forceCompositingMode = enabled; } + void setAccelerated2dCanvasEnabled(bool enabled) { m_accelerated2dCanvasEnabled = enabled; } + void setLegacyAccelerated2dCanvasEnabled(bool enabled) { m_legacyAccelerated2dCanvasEnabled = enabled; } + void setAcceleratedPaintingEnabled(bool enabled) { m_acceleratedPaintingEnabled = enabled; } + void setPerTilePaintingEnabled(bool enabled) { m_perTilePaintingEnabled = enabled; } +#if defined(OS_WIN) + // Access to the finished event. Used by the static WatchDog thread. + HANDLE finishedEvent() { return m_finishedEvent; } +#endif + + // Get the timeout for running a test in milliseconds. + int layoutTestTimeout() { return m_timeout; } + int layoutTestTimeoutForWatchDog() { return layoutTestTimeout() + 1000; } + void setLayoutTestTimeout(int timeout) { m_timeout = timeout; } + + // V8 JavaScript stress test options. + int stressOpt() { return m_stressOpt; } + void setStressOpt(bool stressOpt) { m_stressOpt = stressOpt; } + int stressDeopt() { return m_stressDeopt; } + void setStressDeopt(int stressDeopt) { m_stressDeopt = stressDeopt; } + + // The JavaScript flags specified as a strings. + std::string javaScriptFlags() { return m_javaScriptFlags; } + void setJavaScriptFlags(std::string javaScriptFlags) { m_javaScriptFlags = javaScriptFlags; } + + // Set whether to dump when the loaded page has finished processing. This is used with multiple load + // testing where we only want to have the output from the last load. + void setDumpWhenFinished(bool dumpWhenFinished) { m_dumpWhenFinished = dumpWhenFinished; } + + WebViewHost* createNewWindow(const WebKit::WebURL&); + void closeWindow(WebViewHost*); + void closeRemainingWindows(); + int windowCount(); + static void resizeWindowForTest(WebViewHost*, const WebKit::WebURL&); + + void showDevTools(); + void closeDevTools(); + + DRTDevToolsAgent* drtDevToolsAgent() { return m_drtDevToolsAgent.get(); } + DRTDevToolsClient* drtDevToolsClient() { return m_drtDevToolsClient.get(); } + WebViewHost* devToolsWebView() { return m_devTools; } + + static const int virtualWindowBorder = 3; + + typedef Vector<WebViewHost*> WindowList; + WindowList windowList() const { return m_windowList; } + + // Returns a string representation of an URL's spec that does not depend on + // the location of the layout test in the file system. + std::string normalizeLayoutTestURL(const std::string&); + +private: + WebViewHost* createNewWindow(const WebKit::WebURL&, DRTDevToolsAgent*); + void createMainWindow(); + void createDRTDevToolsClient(DRTDevToolsAgent*); + + void resetWebSettings(WebKit::WebView&); + void dump(); + std::string dumpAllBackForwardLists(); + void dumpImage(SkCanvas*) const; + + bool m_testIsPending; + bool m_testIsPreparing; + bool m_isLoading; + WebKit::WebView* m_webView; + WebKit::WebWidget* m_focusedWidget; + bool m_testShellMode; + WebViewHost* m_devTools; + + // Be careful of the destruction order of the following objects. + OwnPtr<TestEventPrinter> m_printer; + OwnPtr<WebPermissions> m_webPermissions; + OwnPtr<DRTDevToolsAgent> m_drtDevToolsAgent; + OwnPtr<DRTDevToolsClient> m_drtDevToolsClient; + OwnPtr<AccessibilityController> m_accessibilityController; + OwnPtr<GamepadController> m_gamepadController; + OwnPtr<EventSender> m_eventSender; + OwnPtr<LayoutTestController> m_layoutTestController; + OwnPtr<PlainTextController> m_plainTextController; + OwnPtr<TextInputController> m_textInputController; + OwnPtr<NotificationPresenter> m_notificationPresenter; + OwnPtr<WebViewHost> m_webViewHost; + OwnPtr<WebKit::WebThread> m_webCompositorThread; + + TestParams m_params; + int m_timeout; // timeout value in millisecond + bool m_allowExternalPages; + bool m_acceleratedCompositingForVideoEnabled; + bool m_threadedCompositingEnabled; + bool m_compositeToTexture; + bool m_forceCompositingMode; + bool m_accelerated2dCanvasEnabled; + bool m_legacyAccelerated2dCanvasEnabled; + bool m_acceleratedPaintingEnabled; + bool m_perTilePaintingEnabled; + WebPreferences m_prefs; + bool m_stressOpt; + bool m_stressDeopt; + std::string m_javaScriptFlags; + bool m_dumpWhenFinished; + + + // List of all windows in this process. + // The main window should be put into windowList[0]. + WindowList m_windowList; + +#if defined(OS_WIN) + // Used by the watchdog to know when it's finished. + HANDLE m_finishedEvent; +#endif +}; + +void platformInit(int*, char***); +void openStartupDialog(); +bool checkLayoutTestSystemDependencies(); + +#endif // TestShell_h diff --git a/Tools/DumpRenderTree/chromium/TestShellGtk.cpp b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp new file mode 100644 index 000000000..4228f2afd --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp @@ -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. + */ + +#include "config.h" +#include "TestShell.h" + +#include "webkit/support/webkit_support.h" +#include <fontconfig/fontconfig.h> +#include <gtk/gtk.h> +#include <signal.h> + + +void openStartupDialog() +{ + GtkWidget* dialog = gtk_message_dialog_new( + 0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Attach to me?"); + gtk_window_set_title(GTK_WINDOW(dialog), "DumpRenderTree"); + gtk_dialog_run(GTK_DIALOG(dialog)); // Runs a nested message loop. + gtk_widget_destroy(dialog); +} + +bool checkLayoutTestSystemDependencies() +{ + return true; +} diff --git a/Tools/DumpRenderTree/chromium/TestShellLinux.cpp b/Tools/DumpRenderTree/chromium/TestShellLinux.cpp new file mode 100644 index 000000000..82db69a2f --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShellLinux.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2011 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 "SkTypeface.h" +#include "WebView.h" +#include "webkit/support/webkit_support.h" + +#if !OS(ANDROID) +#include <fontconfig/fontconfig.h> +#endif + +#if USE(GTK) +#include <gtk/gtk.h> +#endif +#include <signal.h> +#include <unistd.h> + +static void AlarmHandler(int) +{ + // 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. + struct sigaction alarmAction; + alarmAction.sa_handler = AlarmHandler; + sigemptyset(&alarmAction.sa_mask); + alarmAction.sa_flags = 0; + + struct sigaction oldAction; + sigaction(SIGALRM, &alarmAction, &oldAction); + 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); + sigaction(SIGALRM, &oldAction, 0); +} + +#if !OS(ANDROID) +static void setupFontconfig() +{ + // We wish to make the layout tests reproducable with respect to fonts. Skia + // uses fontconfig to resolve font family names from WebKit into actual font + // files found on the current system. This means that fonts vary based on the + // system and also on the fontconfig configuration. + // + // To avoid this we initialise fontconfig here and install a configuration + // which only knows about a few, select, fonts. + + // We have fontconfig parse a config file from our resources file. This + // sets a number of aliases ("sans"->"Arial" etc), but doesn't include any + // font directories. + FcInit(); + + char drtPath[PATH_MAX + 1]; + int drtPathSize = readlink("/proc/self/exe", drtPath, PATH_MAX); + if (drtPathSize < 0 || drtPathSize > PATH_MAX) { + fputs("Unable to resolve /proc/self/exe.", stderr); + exit(1); + } + drtPath[drtPathSize] = 0; + std::string drtDirPath(drtPath); + size_t lastPathPos = drtDirPath.rfind("/"); + ASSERT(lastPathPos != std::string::npos); + drtDirPath.erase(lastPathPos + 1); + + FcConfig* fontcfg = FcConfigCreate(); + std::string fontconfigPath = drtDirPath + "fonts.conf"; + if (!FcConfigParseAndLoad(fontcfg, reinterpret_cast<const FcChar8*>(fontconfigPath.c_str()), true)) { + fputs("Failed to parse fontconfig config file\n", stderr); + exit(1); + } + + // This is the list of fonts that fontconfig will know about. It + // will try its best to match based only on the fonts here in. The + // paths are where these fonts are found on our Ubuntu boxes. + static const char *const fonts[] = { + "/usr/share/fonts/truetype/kochi/kochi-gothic.ttf", + "/usr/share/fonts/truetype/kochi/kochi-mincho.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Arial_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Courier_New.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Georgia_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Impact.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Verdana.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold_Italic.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Verdana_Italic.ttf", + "/usr/share/fonts/truetype/thai/Garuda.ttf", + // The DejaVuSans font is used by the css2.1 tests. + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_hi.ttf", + "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_ta.ttf", + "/usr/share/fonts/truetype/ttf-indic-fonts-core/MuktiNarrow.ttf", + }; + for (size_t i = 0; i < arraysize(fonts); ++i) { + if (access(fonts[i], R_OK)) { + fprintf(stderr, "You are missing %s. Try re-running build/install-build-deps.sh. Also see " + "http://code.google.com/p/chromium/wiki/LayoutTestsLinux", + fonts[i]); + exit(1); + } + if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) fonts[i])) { + fprintf(stderr, "Failed to load font %s\n", fonts[i]); + exit(1); + } + } + + // We special case these fonts because they're only needed in a + // few layout tests. + static const char* const optionalFonts[] = { + "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf", + }; + for (size_t i = 0; i < arraysize(optionalFonts); ++i) { + const char* font = optionalFonts[i]; + + // This font changed paths across Ubuntu releases, so try checking in both locations. + if (!strcmp(font, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf") + && access(font, R_OK) < 0) + font = "/usr/share/fonts/truetype/ttf-punjabi-fonts/lohit_pa.ttf"; + + if (access(font, R_OK) < 0) { + fprintf(stderr, "You are missing %s. Without this, some layout tests may fail. " + "See http://code.google.com/p/chromium/wiki/LayoutTestsLinux " + "for more.\n", font); + } else if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) font)) { + fprintf(stderr, "Failed to load font %s\n", font); + exit(1); + } + } + + // Also load the layout-test-specific "Ahem" font. + std::string ahemPath = drtDirPath + "AHEM____.TTF"; + if (!FcConfigAppFontAddFile(fontcfg, reinterpret_cast<const FcChar8*>(ahemPath.c_str()))) { + fprintf(stderr, "Failed to load font %s\n", ahemPath.c_str()); + exit(1); + } + + if (!FcConfigSetCurrent(fontcfg)) { + fputs("Failed to set the default font configuration\n", stderr); + exit(1); + } +} +#endif // !OS(ANDROID) + +void platformInit(int* argc, char*** argv) +{ + // FIXME: It's better call gtk_init() only when we run plugin tests. + // See http://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/633ea167cde196ca# +#if USE(GTK) + gtk_init(argc, argv); +#endif + +#if !OS(ANDROID) + setupFontconfig(); +#endif +} + diff --git a/Tools/DumpRenderTree/chromium/TestShellMac.mm b/Tools/DumpRenderTree/chromium/TestShellMac.mm new file mode 100644 index 000000000..d79a8c835 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShellMac.mm @@ -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 "TestShell.h" +#include "WebThemeEngineDRTMac.h" +#include "webkit/support/webkit_support.h" +#import <AppKit/AppKit.h> + +static WebThemeEngineDRTMac themeEngine; + +// A class to be the target/selector of the "watchdog" thread that ensures +// pages timeout if they take too long and tells the test harness via stdout. +@interface WatchDogTarget : NSObject { +@private + NSTimeInterval _timeout; +} +// |timeout| is in seconds +- (id)initWithTimeout:(NSTimeInterval)timeout; +// serves as the "run" method of a NSThread. +- (void)run:(id)sender; +@end + +@implementation WatchDogTarget + +- (id)initWithTimeout:(NSTimeInterval)timeout +{ + if ((self = [super init])) + _timeout = timeout; + return self; +} + +- (void)run:(id)ignore +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + // check for debugger, just bail if so. We don't want the timeouts hitting + // when we're trying to track down an issue. + if (webkit_support::BeingDebugged()) + return; + + NSThread* currentThread = [NSThread currentThread]; + + // Wait to be cancelled. If we are that means the test finished. If it hasn't, + // then we need to tell the layout script we timed out and start again. + NSDate* limitDate = [NSDate dateWithTimeIntervalSinceNow:_timeout]; + while ([(NSDate*)[NSDate date] compare:limitDate] == NSOrderedAscending && + ![currentThread isCancelled]) { + // sleep for a small increment then check again + NSDate* incrementDate = [NSDate dateWithTimeIntervalSinceNow:1.0]; + [NSThread sleepUntilDate:incrementDate]; + } + if (![currentThread isCancelled]) { + // Print a warning to be caught by the layout-test script. + // Note: the layout test driver may or may not recognize + // this as a timeout. + puts("#TEST_TIMED_OUT\n"); + puts("#EOF\n"); + fflush(stdout); + exit(0); + } + + [pool release]; +} + +@end + +void TestShell::waitTestFinished() +{ + ASSERT(!m_testIsPending); + + m_testIsPending = true; + + // Create a watchdog thread which just sets a timer and + // kills the process if it times out. This catches really + // bad hangs where the shell isn't coming back to the + // message loop. If the watchdog is what catches a + // timeout, it can't do anything except terminate the test + // shell, which is unfortunate. + // Windows multiplies by 2.5, but that causes us to run for far, far too + // long. We use the passed value and let the scripts flag override + // the value as needed. + NSTimeInterval timeoutSeconds = layoutTestTimeoutForWatchDog() / 1000; + WatchDogTarget* watchdog = [[[WatchDogTarget alloc] + initWithTimeout:timeoutSeconds] autorelease]; + NSThread* thread = [[NSThread alloc] initWithTarget:watchdog + selector:@selector(run:) + object:nil]; + [thread start]; + + // TestFinished() will post a quit message to break this loop when the page + // finishes loading. + while (m_testIsPending) + webkit_support::RunMessageLoop(); + + // Tell the watchdog that we're finished. No point waiting to re-join, it'll + // die on its own. + [thread cancel]; + [thread release]; +} + +void platformInit(int*, char***) +{ + webkit_support::SetThemeEngine(&themeEngine); +} + +void openStartupDialog() +{ + // FIXME: This code doesn't work. Need NSApplication event loop? + NSAlert* alert = [[[NSAlert alloc] init] autorelease]; + alert.messageText = @"Attach to me?"; + alert.informativeText = @"This would probably be a good time to attach your debugger."; + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; +} + +bool checkLayoutTestSystemDependencies() +{ + return true; +} + diff --git a/Tools/DumpRenderTree/chromium/TestShellStub.cpp b/Tools/DumpRenderTree/chromium/TestShellStub.cpp new file mode 100644 index 000000000..6c34f84b3 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShellStub.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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" + +bool checkLayoutTestSystemDependencies() +{ + return true; +} + +void openStartupDialog() +{ + // FIXME: Not implemented. +} + diff --git a/Tools/DumpRenderTree/chromium/TestShellWin.cpp b/Tools/DumpRenderTree/chromium/TestShellWin.cpp new file mode 100644 index 000000000..850e5de81 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestShellWin.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TestShell.h" + +#include "WebThemeEngineDRTWin.h" +#include "webkit/support/webkit_support.h" +#include <fcntl.h> +#include <io.h> +#include <list> +#include <process.h> +#include <shlwapi.h> +#include <string> +#include <sys/stat.h> +#include <windows.h> + +#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ + offsetof(structName, member) + \ + (sizeof static_cast<structName*>(0)->member) +#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ + SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) + +// Theme engine +static WebThemeEngineDRTWin themeEngine; + +// Thread main to run for the thread which just tests for timeout. +unsigned int __stdcall watchDogThread(void* arg) +{ + // If we're debugging a layout test, don't timeout. + if (::IsDebuggerPresent()) + return 0; + + TestShell* shell = static_cast<TestShell*>(arg); + // FIXME: Do we need user-specified time settings as with the original + // Chromium implementation? + DWORD timeout = static_cast<DWORD>(shell->layoutTestTimeoutForWatchDog()); + DWORD rv = WaitForSingleObject(shell->finishedEvent(), timeout); + if (rv == WAIT_TIMEOUT) { + // Print a warning to be caught by the layout-test script. + // Note: the layout test driver may or may not recognize + // this as a timeout. + puts("\n#TEST_TIMED_OUT\n"); + puts("#EOF\n"); + fflush(stdout); + TerminateProcess(GetCurrentProcess(), 0); + } + // Finished normally. + return 0; +} + +void TestShell::waitTestFinished() +{ + DCHECK(!m_testIsPending) << "cannot be used recursively"; + + m_testIsPending = true; + + // Create a watchdog thread which just sets a timer and + // kills the process if it times out. This catches really + // bad hangs where the shell isn't coming back to the + // message loop. If the watchdog is what catches a + // timeout, it can't do anything except terminate the test + // shell, which is unfortunate. + m_finishedEvent = CreateEvent(0, TRUE, FALSE, 0); + DCHECK(m_finishedEvent); + + HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex( + 0, + 0, + &watchDogThread, + this, + 0, + 0)); + DCHECK(threadHandle); + + // TestFinished() will post a quit message to break this loop when the page + // finishes loading. + while (m_testIsPending) + webkit_support::RunMessageLoop(); + + // Tell the watchdog that we are finished. + SetEvent(m_finishedEvent); + + // Wait to join the watchdog thread. (up to 1s, then quit) + WaitForSingleObject(threadHandle, 1000); +} + +void platformInit(int*, char***) +{ + // Set stdout/stderr binary mode. + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); + + // Set theme engine. + webkit_support::SetThemeEngine(&themeEngine); + + // Load Ahem font. + // AHEM____.TTF is copied to the directory of DumpRenderTree.exe by WebKit.gyp. + WCHAR path[_MAX_PATH]; + if (!::GetModuleFileName(0, path, _MAX_PATH)) { + fprintf(stderr, "Can't get the module path.\n"); + exit(1); + } + ::PathRemoveFileSpec(path); + wcscat_s(path, _MAX_PATH, L"/AHEM____.TTF"); + struct _stat ahemStat; + if (_wstat(path, &ahemStat) == -1) { + fprintf(stderr, "Can't access: '%S'\n", path); + exit(1); + } + + FILE* fp = _wfopen(path, L"rb"); + if (!fp) { + _wperror(path); + exit(1); + } + size_t size = ahemStat.st_size; + char* fontBuffer = new char[size]; + if (fread(fontBuffer, 1, size, fp) != size) { + fprintf(stderr, "Can't read the font: '%S'\n", path); + fclose(fp); + exit(1); + } + fclose(fp); + DWORD numFonts = 1; + HANDLE fontHandle = ::AddFontMemResourceEx(fontBuffer, size, 0, &numFonts); + delete[] fontBuffer; // OS owns a copy of the buffer. + if (!fontHandle) { + fprintf(stderr, "Failed to register Ahem font: '%S'\n", path); + exit(1); + } + // We don't need to release the font explicitly. +} + +void openStartupDialog() +{ + ::MessageBox(0, L"Attach to me?", L"DumpRenderTree", MB_OK); +} + +bool checkLayoutTestSystemDependencies() +{ + // This metric will be 17 when font size is "Normal". + // The size of drop-down menus depends on it. + int verticalScrollSize = ::GetSystemMetrics(SM_CXVSCROLL); + int requiredVScrollSize = 17; + std::list<std::string> errors; + if (verticalScrollSize != requiredVScrollSize) + errors.push_back("Must use normal size fonts (96 dpi)."); + + // ClearType must be disabled, because the rendering is unpredictable. + BOOL fontSmoothingEnabled; + ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); + int fontSmoothingType; + ::SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fontSmoothingType, 0); + if (fontSmoothingEnabled && (fontSmoothingType == FE_FONTSMOOTHINGCLEARTYPE)) + errors.push_back("ClearType must be disabled."); + + // Check that we're using the default system fonts. + OSVERSIONINFO versionInfo = {0}; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + ::GetVersionEx(&versionInfo); + const bool isVistaOrLater = (versionInfo.dwMajorVersion >= 6); + NONCLIENTMETRICS metrics = {0}; + metrics.cbSize = isVistaOrLater ? (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; + const bool success = !!::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); + ASSERT(success); + LOGFONTW* systemFonts[] = + {&metrics.lfStatusFont, &metrics.lfMenuFont, &metrics.lfSmCaptionFont}; + const wchar_t* const requiredFont = isVistaOrLater ? L"Segoe UI" : L"Tahoma"; + const int requiredFontSize = isVistaOrLater ? -12 : -11; + for (size_t i = 0; i < arraysize(systemFonts); ++i) { + if (systemFonts[i]->lfHeight != requiredFontSize || wcscmp(requiredFont, systemFonts[i]->lfFaceName)) { + errors.push_back(isVistaOrLater ? "Must use either the Aero or Basic theme." : "Must use the default XP theme (Luna)."); + break; + } + } + + if (!errors.empty()) { + fprintf(stderr, "%s", + "##################################################################\n" + "## Layout test system dependencies check failed.\n" + "##\n"); + for (std::list<std::string>::iterator it = errors.begin(); it != errors.end(); ++it) + fprintf(stderr, "## %s\n", it->c_str()); + fprintf(stderr, "%s", + "##\n" + "##################################################################\n"); + } + return errors.empty(); +} diff --git a/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp b/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp new file mode 100644 index 000000000..ac2336664 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2011 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "TestWebPlugin.h" + +#include "WebFrame.h" +#include "platform/WebGraphicsContext3D.h" +#include "WebKit.h" +#include "platform/WebKitPlatformSupport.h" +#include "WebPluginContainer.h" +#include "WebPluginParams.h" +#include <wtf/Assertions.h> +#include <wtf/text/CString.h> + +using namespace WebKit; + +// GLenum values copied from gl2.h. +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_ONE 1 +#define GL_TRIANGLES 0x0004 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_BLEND 0x0BE2 +#define GL_FLOAT 0x1406 +#define GL_COLOR_BUFFER_BIT 0x4000 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_STATIC_DRAW 0x88E4 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 + +static void premultiplyAlpha(const unsigned colorIn[3], float alpha, float colorOut[4]) +{ + for (int i = 0; i < 3; ++i) + colorOut[i] = (colorIn[i] / 255.0f) * alpha; + + colorOut[3] = alpha; +} + +TestWebPlugin::TestWebPlugin(WebKit::WebFrame* frame, + const WebKit::WebPluginParams& params) + : m_frame(frame) + , m_container(0) + , m_context(0) +{ + static const WebString kAttributePrimitive = WebString::fromUTF8("primitive"); + static const WebString kAttributeBackgroundColor = WebString::fromUTF8("background-color"); + static const WebString kAttributePrimitiveColor = WebString::fromUTF8("primitive-color"); + static const WebString kAttributeOpacity = WebString::fromUTF8("opacity"); + + ASSERT(params.attributeNames.size() == params.attributeValues.size()); + size_t size = params.attributeNames.size(); + for (size_t i = 0; i < size; ++i) { + const WebString& attributeName = params.attributeNames[i]; + const WebString& attributeValue = params.attributeValues[i]; + + if (attributeName == kAttributePrimitive) + m_scene.primitive = parsePrimitive(attributeValue); + else if (attributeName == kAttributeBackgroundColor) + parseColor(attributeValue, m_scene.backgroundColor); + else if (attributeName == kAttributePrimitiveColor) + parseColor(attributeValue, m_scene.primitiveColor); + else if (attributeName == kAttributeOpacity) + m_scene.opacity = parseOpacity(attributeValue); + } +} + +TestWebPlugin::~TestWebPlugin() +{ +} + +const WebString& TestWebPlugin::mimeType() +{ + static const WebString kMimeType = WebString::fromUTF8("application/x-webkit-test-webplugin"); + return kMimeType; +} + +bool TestWebPlugin::initialize(WebPluginContainer* container) +{ + m_context = webKitPlatformSupport()->createGraphicsContext3D(); + if (!m_context) + return false; + + WebGraphicsContext3D::Attributes attrs; + if (!m_context->initialize(attrs, m_frame->view(), false)) + return false; + + if (!m_context->makeContextCurrent()) + return false; + + if (!initScene()) + return false; + + m_container = container; + m_container->setBackingTextureId(m_context->getPlatformTextureId()); + return true; +} + +void TestWebPlugin::destroy() +{ + destroyScene(); + + delete m_context; + m_context = 0; + + m_container = 0; + m_frame = 0; +} + +void TestWebPlugin::updateGeometry(const WebRect& frameRect, + const WebRect& clipRect, + const WebVector<WebRect>& cutOutsRects, + bool isVisible) +{ + if (clipRect == m_rect) + return; + m_rect = clipRect; + + m_context->reshape(m_rect.width, m_rect.height); + drawScene(); + m_context->prepareTexture(); + + m_container->commitBackingTexture(); +} + +TestWebPlugin::Primitive TestWebPlugin::parsePrimitive(const WebString& string) +{ + static const WebString kPrimitiveNone = WebString::fromUTF8("none"); + static const WebString kPrimitiveTriangle = WebString::fromUTF8("triangle"); + + Primitive primitive = PrimitiveNone; + if (string == kPrimitiveNone) + primitive = PrimitiveNone; + else if (string == kPrimitiveTriangle) + primitive = PrimitiveTriangle; + else + ASSERT_NOT_REACHED(); + return primitive; +} + +// FIXME: This method should already exist. Use it. +// For now just parse primary colors. +void TestWebPlugin::parseColor(const WebString& string, unsigned color[3]) +{ + color[0] = color[1] = color[2] = 0; + if (string == "black") + return; + + if (string == "red") + color[0] = 255; + else if (string == "green") + color[1] = 255; + else if (string == "blue") + color[2] = 255; + else + ASSERT_NOT_REACHED(); +} + +float TestWebPlugin::parseOpacity(const WebString& string) +{ + return static_cast<float>(atof(string.utf8().data())); +} + +bool TestWebPlugin::initScene() +{ + float color[4]; + premultiplyAlpha(m_scene.backgroundColor, m_scene.opacity, color); + m_context->clearColor(color[0], color[1], color[2], color[3]); + + m_context->enable(GL_BLEND); + m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + return m_scene.primitive != PrimitiveNone ? initProgram() && initPrimitive() : true; +} + +void TestWebPlugin::drawScene() +{ + m_context->viewport(0, 0, m_rect.width, m_rect.height); + m_context->clear(GL_COLOR_BUFFER_BIT); + + if (m_scene.primitive != PrimitiveNone) + drawPrimitive(); +} + +void TestWebPlugin::destroyScene() +{ + if (m_scene.program) { + m_context->deleteProgram(m_scene.program); + m_scene.program = 0; + } + if (m_scene.vbo) { + m_context->deleteBuffer(m_scene.vbo); + m_scene.vbo = 0; + } +} + +bool TestWebPlugin::initProgram() +{ + const CString vertexSource( + "attribute vec4 position; \n" + "void main() { \n" + " gl_Position = position; \n" + "} \n" + ); + + const CString fragmentSource( + "precision mediump float; \n" + "uniform vec4 color; \n" + "void main() { \n" + " gl_FragColor = color; \n" + "} \n" + ); + + m_scene.program = loadProgram(vertexSource, fragmentSource); + if (!m_scene.program) + return false; + + m_scene.colorLocation = m_context->getUniformLocation(m_scene.program, "color"); + m_scene.positionLocation = m_context->getAttribLocation(m_scene.program, "position"); + return true; +} + +bool TestWebPlugin::initPrimitive() +{ + ASSERT(m_scene.primitive == PrimitiveTriangle); + + m_scene.vbo = m_context->createBuffer(); + if (!m_scene.vbo) + return false; + + const float vertices[] = { 0.0f, 0.8f, 0.0f, + -0.8f, -0.8f, 0.0f, + 0.8f, -0.8f, 0.0f }; + m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo); + m_context->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), 0, GL_STATIC_DRAW); + m_context->bufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); + return true; +} + +void TestWebPlugin::drawPrimitive() +{ + ASSERT(m_scene.primitive == PrimitiveTriangle); + ASSERT(m_scene.vbo); + ASSERT(m_scene.program); + + m_context->useProgram(m_scene.program); + + // Bind primitive color. + float color[4]; + premultiplyAlpha(m_scene.primitiveColor, m_scene.opacity, color); + m_context->uniform4f(m_scene.colorLocation, color[0], color[1], color[2], color[3]); + + // Bind primitive vertices. + m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo); + m_context->enableVertexAttribArray(m_scene.positionLocation); + m_context->vertexAttribPointer(m_scene.positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); + m_context->drawArrays(GL_TRIANGLES, 0, 3); +} + +unsigned TestWebPlugin::loadShader(unsigned type, const CString& source) +{ + unsigned shader = m_context->createShader(type); + if (shader) { + m_context->shaderSource(shader, source.data()); + m_context->compileShader(shader); + + int compiled = 0; + m_context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + m_context->deleteShader(shader); + shader = 0; + } + } + return shader; +} + +unsigned TestWebPlugin::loadProgram(const CString& vertexSource, + const CString& fragmentSource) +{ + unsigned vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource); + unsigned fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource); + unsigned program = m_context->createProgram(); + if (vertexShader && fragmentShader && program) { + m_context->attachShader(program, vertexShader); + m_context->attachShader(program, fragmentShader); + m_context->linkProgram(program); + + int linked = 0; + m_context->getProgramiv(program, GL_LINK_STATUS, &linked); + if (!linked) { + m_context->deleteProgram(program); + program = 0; + } + } + if (vertexShader) + m_context->deleteShader(vertexShader); + if (fragmentShader) + m_context->deleteShader(fragmentShader); + + return program; +} + diff --git a/Tools/DumpRenderTree/chromium/TestWebPlugin.h b/Tools/DumpRenderTree/chromium/TestWebPlugin.h new file mode 100644 index 000000000..cef472884 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestWebPlugin.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 TestWebPlugin_h +#define TestWebPlugin_h + +#include "WebPlugin.h" +#include "platform/WebRect.h" + +namespace WebKit { +class WebGraphicsContext3D; +} + +// A fake implemention of WebKit::WebPlugin for testing purposes. +// +// It uses WebGraphicsContext3D to paint a scene consisiting of a primitive +// over a background. The primitive and background can be customized using +// the following plugin parameters: +// primitive: none (default), triangle. +// background-color: black (default), red, green, blue. +// primitive-color: black (default), red, green, blue. +// opacity: [0.0 - 1.0]. Default is 1.0. +class TestWebPlugin : public WebKit::WebPlugin { +public: + TestWebPlugin(WebKit::WebFrame*, const WebKit::WebPluginParams&); + virtual ~TestWebPlugin(); + + static const WebKit::WebString& mimeType(); + + // WebPlugin methods: + virtual bool initialize(WebKit::WebPluginContainer*); + virtual void destroy(); + virtual NPObject* scriptableObject() { return 0; } + virtual void paint(WebKit::WebCanvas*, const WebKit::WebRect&) { } + virtual void updateGeometry(const WebKit::WebRect& frameRect, + const WebKit::WebRect& clipRect, + const WebKit::WebVector<WebKit::WebRect>& cutOutsRects, + bool isVisible); + virtual void updateFocus(bool) { } + virtual void updateVisibility(bool) { } + virtual bool acceptsInputEvents() { return false; } + virtual bool handleInputEvent(const WebKit::WebInputEvent&, WebKit::WebCursorInfo&) { return false; } + virtual void didReceiveResponse(const WebKit::WebURLResponse&) { } + virtual void didReceiveData(const char* data, int dataLength) { } + virtual void didFinishLoading() { } + virtual void didFailLoading(const WebKit::WebURLError&) { } + virtual void didFinishLoadingFrameRequest(const WebKit::WebURL&, void* notifyData) { } + virtual void didFailLoadingFrameRequest(const WebKit::WebURL&, void* notifyData, const WebKit::WebURLError&) { } + +private: + enum Primitive { + PrimitiveNone, + PrimitiveTriangle + }; + + struct Scene { + Primitive primitive; + unsigned backgroundColor[3]; + unsigned primitiveColor[3]; + float opacity; + + unsigned vbo; + unsigned program; + int colorLocation; + int positionLocation; + + Scene() + : primitive(PrimitiveNone) + , opacity(1.0f) // Fully opaque. + , vbo(0) + , program(0) + , colorLocation(-1) + , positionLocation(-1) + { + backgroundColor[0] = backgroundColor[1] = backgroundColor[2] = 0; + primitiveColor[0] = primitiveColor[1] = primitiveColor[2] = 0; + } + }; + + // Functions for parsing plugin parameters. + Primitive parsePrimitive(const WebKit::WebString&); + void parseColor(const WebKit::WebString&, unsigned color[3]); + float parseOpacity(const WebKit::WebString&); + + // Functions for loading and drawing scene. + bool initScene(); + void drawScene(); + void destroyScene(); + bool initProgram(); + bool initPrimitive(); + void drawPrimitive(); + unsigned loadShader(unsigned type, const WTF::CString& source); + unsigned loadProgram(const WTF::CString& vertexSource, + const WTF::CString& fragmentSource); + + WebKit::WebFrame* m_frame; + WebKit::WebPluginContainer* m_container; + + WebKit::WebRect m_rect; + WebKit::WebGraphicsContext3D* m_context; + Scene m_scene; +}; + +#endif // TestPepperPlugin_h diff --git a/Tools/DumpRenderTree/chromium/TestWebWorker.h b/Tools/DumpRenderTree/chromium/TestWebWorker.h new file mode 100644 index 000000000..ad82a87e9 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TestWebWorker.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TestWebWorker_h +#define TestWebWorker_h + +#include "WebMessagePortChannel.h" +#include "WebSharedWorkerClient.h" +#include "WebWorker.h" +#include <wtf/RefCounted.h> + +namespace WebKit { +class WebNotificationPresenter; +class WebString; +class WebURL; +} + +class TestWebWorker : public WebKit::WebWorker, + public WebKit::WebSharedWorkerClient, + public WTF::RefCounted<TestWebWorker> { +public: + TestWebWorker() + { + // This class expects refcounting semantics like those found in + // Chromium's base::RefCounted, so it's OK to call ref() directly. + relaxAdoptionRequirement(); + ref(); + // The initial counter value should be 2. One for a worker object, + // another for a worker context object. We need to call ref() just once + // because the default counter value of RefCounted is 1. + } + + // WebWorker methods: + virtual void startWorkerContext(const WebKit::WebURL&, const WebKit::WebString&, const WebKit::WebString&) { } + virtual void terminateWorkerContext() { } + virtual void postMessageToWorkerContext(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) { } + virtual void workerObjectDestroyed() + { + // Releases the reference held for worker object. + deref(); + } + virtual void clientDestroyed() { } + + // WebWorkerClient methods: + virtual void postMessageToWorkerObject(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) { } + virtual void postExceptionToWorkerObject(const WebKit::WebString&, int, const WebKit::WebString&) { } + virtual void postConsoleMessageToWorkerObject(int, int, int, int, const WebKit::WebString&, int, const WebKit::WebString&) { } + virtual void confirmMessageFromWorkerObject(bool) { } + virtual void reportPendingActivity(bool) { } + virtual void workerContextClosed() { } + virtual void workerContextDestroyed() + { + // Releases the reference held for worker context object. + deref(); + } + virtual WebKit::WebWorker* createWorker(WebKit::WebSharedWorkerClient*) { return 0; } + virtual WebKit::WebNotificationPresenter* notificationPresenter() { return 0; } + virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebApplicationCacheHostClient*) { return 0; } + virtual bool allowDatabase(WebKit::WebFrame*, const WebKit::WebString&, const WebKit::WebString&, unsigned long) { return true; } + +private: + ~TestWebWorker() { } + friend class WTF::RefCounted<TestWebWorker>; +}; + +#endif // TestWebWorker_h diff --git a/Tools/DumpRenderTree/chromium/TextInputController.cpp b/Tools/DumpRenderTree/chromium/TextInputController.cpp new file mode 100644 index 000000000..a3637067a --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TextInputController.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TextInputController.h" + +#include "TestShell.h" +#include "WebBindings.h" +#include "WebCompositionUnderline.h" +#include "WebFrame.h" +#include "WebRange.h" +#include "platform/WebString.h" +#include "platform/WebVector.h" +#include "WebView.h" +#include <string> +#include <wtf/StringExtras.h> + +using namespace WebKit; + +TestShell* TextInputController::testShell = 0; + +TextInputController::TextInputController(TestShell* shell) +{ + // Set static testShell variable. Be careful not to assign testShell to new + // windows which are temporary. + if (!testShell) + testShell = shell; + + bindMethod("attributedSubstringFromRange", &TextInputController::attributedSubstringFromRange); + bindMethod("characterIndexForPoint", &TextInputController::characterIndexForPoint); + bindMethod("conversationIdentifier", &TextInputController::conversationIdentifier); + bindMethod("doCommand", &TextInputController::doCommand); + bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange); + bindMethod("hasMarkedText", &TextInputController::hasMarkedText); + bindMethod("insertText", &TextInputController::insertText); + bindMethod("makeAttributedString", &TextInputController::makeAttributedString); + bindMethod("markedRange", &TextInputController::markedRange); + bindMethod("selectedRange", &TextInputController::selectedRange); + bindMethod("setMarkedText", &TextInputController::setMarkedText); + bindMethod("substringFromRange", &TextInputController::substringFromRange); + bindMethod("unmarkText", &TextInputController::unmarkText); + bindMethod("validAttributesForMarkedText", &TextInputController::validAttributesForMarkedText); + bindMethod("setComposition", &TextInputController::setComposition); +} + +WebFrame* TextInputController::getMainFrame() +{ + return testShell->webView()->mainFrame(); +} + +void TextInputController::insertText(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + if (arguments.size() < 1 || !arguments[0].isString()) + return; + + testShell->webView()->confirmComposition(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(); + + if (arguments.size() >= 3 && arguments[0].isString() + && arguments[1].isNumber() && arguments[2].isNumber()) { + WebVector<WebCompositionUnderline> underlines; + testShell->webView()->setComposition(WebString::fromUTF8(arguments[0].toString()), + underlines, + arguments[1].toInt32(), + arguments[1].toInt32() + arguments[2].toInt32()); + } +} + +void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + + testShell->webView()->confirmComposition(); +} + +void TextInputController::hasMarkedText(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + + WebFrame* mainFrame = getMainFrame(); + if (!mainFrame) + return; + + result->set(mainFrame->hasMarkedText()); +} + +void TextInputController::conversationIdentifier(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void TextInputController::substringFromRange(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void TextInputController::attributedSubstringFromRange(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void TextInputController::markedRange(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + + WebFrame* mainFrame = getMainFrame(); + if (!mainFrame) + return; + + WebRange range = mainFrame->markedRange(); + Vector<int> intArray(2); + intArray[0] = range.startOffset(); + intArray[1] = range.endOffset(); + result->set(WebBindings::makeIntArray(intArray)); +} + +void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + + WebFrame* mainFrame = getMainFrame(); + if (!mainFrame) + return; + + WebRange range = mainFrame->selectionRange(); + Vector<int> intArray(2); + intArray[0] = range.startOffset(); + intArray[1] = range.endOffset(); + result->set(WebBindings::makeIntArray(intArray)); +} + +void TextInputController::firstRectForCharacterRange(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + WebFrame* frame = testShell->webView()->focusedFrame(); + if (!frame) + return; + + if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) + return; + + WebRect rect; + if (!frame->firstRectForCharacterRange(arguments[0].toInt32(), arguments[1].toInt32(), rect)) + return; + + Vector<int> intArray(4); + intArray[0] = rect.x; + intArray[1] = rect.y; + intArray[2] = rect.width; + intArray[3] = rect.height; + result->set(WebBindings::makeIntArray(intArray)); +} + +void TextInputController::characterIndexForPoint(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void TextInputController::validAttributesForMarkedText(const CppArgumentList&, CppVariant* result) +{ + result->setNull(); + + WebFrame* mainFrame = getMainFrame(); + if (!mainFrame) + return; + + result->set("NSUnderline,NSUnderlineColor,NSMarkedClauseSegment," + "NSTextInputReplacementRangeAttributeName"); +} + +void TextInputController::makeAttributedString(const CppArgumentList&, CppVariant* result) +{ + // FIXME: Implement this. + result->setNull(); +} + +void TextInputController::setComposition(const CppArgumentList& arguments, CppVariant* result) +{ + result->setNull(); + + WebView* view = getMainFrame() ? getMainFrame()->view() : 0; + if (!view) + return; + + if (arguments.size() < 1) + return; + + // Sends a keydown event with key code = 0xE5 to emulate input method behavior. + WebKeyboardEvent keyDown; + keyDown.type = WebInputEvent::RawKeyDown; + keyDown.modifiers = 0; + keyDown.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY + keyDown.setKeyIdentifierFromWindowsKeyCode(); + view->handleInputEvent(keyDown); + + WebVector<WebCompositionUnderline> underlines; + WebString text(WebString::fromUTF8(arguments[0].toString())); + view->setComposition(text, underlines, 0, text.length()); +} diff --git a/Tools/DumpRenderTree/chromium/TextInputController.h b/Tools/DumpRenderTree/chromium/TextInputController.h new file mode 100644 index 000000000..3a3907fda --- /dev/null +++ b/Tools/DumpRenderTree/chromium/TextInputController.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// TextInputController is bound to window.textInputController in Javascript +// when DRT is running. Layout tests use it to exercise various corners of +// text input. + +#ifndef TextInputController_h +#define TextInputController_h + +#include "CppBoundClass.h" + +class TestShell; + +namespace WebKit { +class WebFrame; +} + +class TextInputController : public CppBoundClass { +public: + TextInputController(TestShell*); + + void insertText(const CppArgumentList&, CppVariant*); + void doCommand(const CppArgumentList&, CppVariant*); + void setMarkedText(const CppArgumentList&, CppVariant*); + void unmarkText(const CppArgumentList&, CppVariant*); + void hasMarkedText(const CppArgumentList&, CppVariant*); + void conversationIdentifier(const CppArgumentList&, CppVariant*); + void substringFromRange(const CppArgumentList&, CppVariant*); + void attributedSubstringFromRange(const CppArgumentList&, CppVariant*); + void markedRange(const CppArgumentList&, CppVariant*); + void selectedRange(const CppArgumentList&, CppVariant*); + void firstRectForCharacterRange(const CppArgumentList&, CppVariant*); + void characterIndexForPoint(const CppArgumentList&, CppVariant*); + void validAttributesForMarkedText(const CppArgumentList&, CppVariant*); + void makeAttributedString(const CppArgumentList&, CppVariant*); + void setComposition(const CppArgumentList&, CppVariant*); + +private: + // Returns the test shell's main WebFrame. + static WebKit::WebFrame* getMainFrame(); + + // Non-owning pointer. The TextInputController is owned by the TestShell. + static TestShell* testShell; +}; + +#endif // TextInputController_h diff --git a/Tools/DumpRenderTree/chromium/WebPermissions.cpp b/Tools/DumpRenderTree/chromium/WebPermissions.cpp new file mode 100644 index 000000000..ee90a7b2c --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebPermissions.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2011 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 "WebPermissions.h" + +#include "LayoutTestController.h" +#include "TestShell.h" +#include "platform/WebCString.h" +#include "platform/WebURL.h" + +WebPermissions::WebPermissions(TestShell* shell) + : m_shell(shell) +{ + reset(); +} + +WebPermissions::~WebPermissions() +{ +} + +bool WebPermissions::allowImage(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& imageURL) +{ + bool allowed = enabledPerSettings && m_imagesAllowed; + if (layoutTestController()->shouldDumpPermissionClientCallbacks()) + fprintf(stdout, "PERMISSION CLIENT: allowImage(%s): %s\n", m_shell->normalizeLayoutTestURL(imageURL.spec()).c_str(), allowed ? "true" : "false"); + return allowed; +} + +bool WebPermissions::allowScriptFromSource(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& scriptURL) +{ + bool allowed = enabledPerSettings && m_scriptsAllowed; + if (layoutTestController()->shouldDumpPermissionClientCallbacks()) + fprintf(stdout, "PERMISSION CLIENT: allowScriptFromSource(%s): %s\n", m_shell->normalizeLayoutTestURL(scriptURL.spec()).c_str(), allowed ? "true" : "false"); + return allowed; +} + +bool WebPermissions::allowStorage(WebKit::WebFrame*, bool) +{ + return m_storageAllowed; +} + +bool WebPermissions::allowPlugins(WebKit::WebFrame*, bool enabledPerSettings) +{ + return enabledPerSettings && m_pluginsAllowed; +} + +bool WebPermissions::allowDisplayingInsecureContent(WebKit::WebFrame*, bool enabledPerSettings, + const WebKit::WebSecurityOrigin&, const WebKit::WebURL&) +{ + return enabledPerSettings || m_displayingInsecureContentAllowed; +} + +bool WebPermissions::allowRunningInsecureContent(WebKit::WebFrame*, bool enabledPerSettings, + const WebKit::WebSecurityOrigin&, const WebKit::WebURL&) +{ + return enabledPerSettings || m_runningInsecureContentAllowed; +} + +void WebPermissions::setImagesAllowed(bool imagesAllowed) +{ + m_imagesAllowed = imagesAllowed; +} + +void WebPermissions::setScriptsAllowed(bool scriptsAllowed) +{ + m_scriptsAllowed = scriptsAllowed; +} + +void WebPermissions::setStorageAllowed(bool storageAllowed) +{ + m_storageAllowed = storageAllowed; +} + +void WebPermissions::setPluginsAllowed(bool pluginsAllowed) +{ + m_pluginsAllowed = pluginsAllowed; +} + +void WebPermissions::setDisplayingInsecureContentAllowed(bool allowed) +{ + m_displayingInsecureContentAllowed = allowed; +} + +void WebPermissions::setRunningInsecureContentAllowed(bool allowed) +{ + m_runningInsecureContentAllowed = allowed; +} + +void WebPermissions::reset() +{ + m_imagesAllowed = true; + m_scriptsAllowed = true; + m_storageAllowed = true; + m_pluginsAllowed = true; + m_displayingInsecureContentAllowed = false; + m_runningInsecureContentAllowed = false; +} + +// Private functions ---------------------------------------------------------- + +LayoutTestController* WebPermissions::layoutTestController() const +{ + return m_shell->layoutTestController(); +} diff --git a/Tools/DumpRenderTree/chromium/WebPermissions.h b/Tools/DumpRenderTree/chromium/WebPermissions.h new file mode 100644 index 000000000..184046a0a --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebPermissions.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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 WebPermissions_h +#define WebPermissions_h + +#include "WebPermissionClient.h" + +class LayoutTestController; +class TestShell; + +class WebPermissions : public WebKit::WebPermissionClient { +public: + WebPermissions(TestShell*); + virtual ~WebPermissions(); + + // Override WebPermissionClient methods. + virtual bool allowImage(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& imageURL); + virtual bool allowScriptFromSource(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& scriptURL); + virtual bool allowStorage(WebKit::WebFrame*, bool local); + virtual bool allowPlugins(WebKit::WebFrame*, bool enabledPerSettings); + virtual bool allowDisplayingInsecureContent(WebKit::WebFrame*, bool enabledPerSettings, + const WebKit::WebSecurityOrigin&, const WebKit::WebURL&); + virtual bool allowRunningInsecureContent(WebKit::WebFrame*, bool enabledPerSettings, + const WebKit::WebSecurityOrigin&, const WebKit::WebURL&); + + // Hooks to set the different policies. + void setImagesAllowed(bool); + void setScriptsAllowed(bool); + void setStorageAllowed(bool); + void setPluginsAllowed(bool); + void setDisplayingInsecureContentAllowed(bool); + void setRunningInsecureContentAllowed(bool); + + // Resets the policy to allow everything, except for running insecure content. + void reset(); + +private: + LayoutTestController* layoutTestController() const; + + // Non-owning pointer. The WebPermissions instance is owned by this TestShell instance. + TestShell* m_shell; + + bool m_imagesAllowed; + bool m_scriptsAllowed; + bool m_storageAllowed; + bool m_pluginsAllowed; + bool m_displayingInsecureContentAllowed; + bool m_runningInsecureContentAllowed; +}; + +#endif diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.cpp b/Tools/DumpRenderTree/chromium/WebPreferences.cpp new file mode 100644 index 000000000..01e4fcc4e --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebPreferences.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPreferences.h" + +#include "WebView.h" + +using namespace WebKit; + +void WebPreferences::reset() +{ +#if OS(MAC_OS_X) + cursiveFontFamily = WebString::fromUTF8("Apple Chancery"); + fantasyFontFamily = WebString::fromUTF8("Papyrus"); + WebString serif = WebString::fromUTF8("Times"); +#else + // These two fonts are picked from the intersection of + // Win XP font list and Vista font list : + // http://www.microsoft.com/typography/fonts/winxp.htm + // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx + // Some of them are installed only with CJK and complex script + // support enabled on Windows XP and are out of consideration here. + // (although we enabled both on our buildbots.) + // They (especially Impact for fantasy) are not typical cursive + // and fantasy fonts, but it should not matter for layout tests + // as long as they're available. + cursiveFontFamily = WebString::fromUTF8("Comic Sans MS"); + fantasyFontFamily = WebString::fromUTF8("Impact"); + // NOTE: case matters here, this must be 'times new roman', else + // some layout tests fail. + WebString serif = WebString::fromUTF8("times new roman"); +#endif + serifFontFamily = serif; + standardFontFamily = serif; + fixedFontFamily = WebString::fromUTF8("Courier"); + sansSerifFontFamily = WebString::fromUTF8("Helvetica"); + + defaultFontSize = 16; + defaultFixedFontSize = 13; + minimumFontSize = 0; + minimumLogicalFontSize = 9; + // Do not disable acceleration for 2d canvas based on size. + // This makes having test expectations consistent. + minimumAccelerated2dCanvasSize = 0; + + DOMPasteAllowed = true; + XSSAuditorEnabled = false; + allowDisplayOfInsecureContent = true; + allowFileAccessFromFileURLs = true; + allowRunningOfInsecureContent = true; + authorAndUserStylesEnabled = true; + defaultTextEncodingName = WebString::fromUTF8("ISO-8859-1"); + developerExtrasEnabled = true; + experimentalWebGLEnabled = false; + javaEnabled = false; + javaScriptCanAccessClipboard = true; + javaScriptCanOpenWindowsAutomatically = true; + javaScriptEnabled = true; + loadsImagesAutomatically = true; + localStorageEnabled = true; + offlineWebApplicationCacheEnabled = true; + pluginsEnabled = true; + shrinksStandaloneImagesToFit = false; + textAreasAreResizable = false; + userStyleSheetLocation = WebURL(); + usesPageCache = false; + pageCacheSupportsPlugins = false; + webSecurityEnabled = true; + caretBrowsingEnabled = false; + + // Allow those layout tests running as local files, i.e. under + // LayoutTests/http/tests/local, to access http server. + allowUniversalAccessFromFileURLs = true; + +#if OS(DARWIN) + editingBehavior = WebSettings::EditingBehaviorMac; +#else + editingBehavior = WebSettings::EditingBehaviorWin; +#endif + + tabsToLinks = false; + hyperlinkAuditingEnabled = false; + acceleratedCompositingForVideoEnabled = false; + acceleratedCompositingEnabled = false; + compositeToTexture = false; + accelerated2dCanvasEnabled = false; + legacyAccelerated2dCanvasEnabled = false; + acceleratedPaintingEnabled = false; + forceCompositingMode = false; + hixie76WebSocketProtocolEnabled = true; + perTilePaintingEnabled = false; +} + +static void setStandardFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setStandardFontFamily(font, script); +} + +static void setFixedFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setFixedFontFamily(font, script); +} + +static void setSerifFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setSerifFontFamily(font, script); +} + +static void setSansSerifFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setSansSerifFontFamily(font, script); +} + +static void setCursiveFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setCursiveFontFamily(font, script); +} + +static void setFantasyFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script) +{ + settings->setFantasyFontFamily(font, script); +} + +typedef void (*SetFontFamilyWrapper)(WebSettings*, const WebString&, UScriptCode); + +static void applyFontMap(WebSettings* settings, const WebPreferences::ScriptFontFamilyMap& map, SetFontFamilyWrapper setter) +{ + for (WebPreferences::ScriptFontFamilyMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) { + const WebString& font = iter->second; + if (!font.isNull() && !font.isEmpty()) + (*setter)(settings, font, static_cast<UScriptCode>(iter->first)); + } +} + +void WebPreferences::applyTo(WebView* webView) +{ + WebSettings* settings = webView->settings(); + settings->setStandardFontFamily(standardFontFamily); + settings->setFixedFontFamily(fixedFontFamily); + settings->setSerifFontFamily(serifFontFamily); + settings->setSansSerifFontFamily(sansSerifFontFamily); + settings->setCursiveFontFamily(cursiveFontFamily); + settings->setFantasyFontFamily(fantasyFontFamily); + + applyFontMap(settings, standardFontMap, setStandardFontFamilyWrapper); + applyFontMap(settings, fixedFontMap, setFixedFontFamilyWrapper); + applyFontMap(settings, serifFontMap, setSerifFontFamilyWrapper); + applyFontMap(settings, sansSerifFontMap, setSansSerifFontFamilyWrapper); + applyFontMap(settings, cursiveFontMap, setCursiveFontFamilyWrapper); + applyFontMap(settings, fantasyFontMap, setFantasyFontFamilyWrapper); + + settings->setDefaultFontSize(defaultFontSize); + settings->setDefaultFixedFontSize(defaultFixedFontSize); + settings->setMinimumFontSize(minimumFontSize); + settings->setMinimumLogicalFontSize(minimumLogicalFontSize); + settings->setMinimumAccelerated2dCanvasSize(minimumAccelerated2dCanvasSize); + + settings->setDOMPasteAllowed(DOMPasteAllowed); + settings->setXSSAuditorEnabled(XSSAuditorEnabled); + settings->setAllowDisplayOfInsecureContent(allowDisplayOfInsecureContent); + settings->setAllowFileAccessFromFileURLs(allowFileAccessFromFileURLs); + settings->setAllowRunningOfInsecureContent(allowRunningOfInsecureContent); + settings->setAuthorAndUserStylesEnabled(authorAndUserStylesEnabled); + settings->setDefaultTextEncodingName(defaultTextEncodingName); + settings->setDeveloperExtrasEnabled(developerExtrasEnabled); + settings->setExperimentalWebGLEnabled(experimentalWebGLEnabled); + settings->setJavaEnabled(javaEnabled); + settings->setJavaScriptCanAccessClipboard(javaScriptCanAccessClipboard); + settings->setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically); + settings->setJavaScriptEnabled(javaScriptEnabled); + settings->setLoadsImagesAutomatically(loadsImagesAutomatically); + settings->setLocalStorageEnabled(localStorageEnabled); + settings->setOfflineWebApplicationCacheEnabled(offlineWebApplicationCacheEnabled); + settings->setPluginsEnabled(pluginsEnabled); + settings->setShrinksStandaloneImagesToFit(shrinksStandaloneImagesToFit); + settings->setTextAreasAreResizable(textAreasAreResizable); + settings->setUserStyleSheetLocation(userStyleSheetLocation); + settings->setUsesPageCache(usesPageCache); + settings->setPageCacheSupportsPlugins(pageCacheSupportsPlugins); + settings->setWebSecurityEnabled(webSecurityEnabled); + settings->setAllowUniversalAccessFromFileURLs(allowUniversalAccessFromFileURLs); + settings->setEditingBehavior(editingBehavior); + settings->setHyperlinkAuditingEnabled(hyperlinkAuditingEnabled); + // LayoutTests were written with Safari Mac in mind which does not allow + // tabbing to links by default. + webView->setTabsToLinks(tabsToLinks); + settings->setCaretBrowsingEnabled(caretBrowsingEnabled); + settings->setAcceleratedCompositingEnabled(acceleratedCompositingEnabled); + settings->setAcceleratedCompositingForVideoEnabled(acceleratedCompositingForVideoEnabled); + settings->setCompositeToTextureEnabled(compositeToTexture); + settings->setForceCompositingMode(forceCompositingMode); + settings->setAccelerated2dCanvasEnabled(accelerated2dCanvasEnabled); + settings->setLegacyAccelerated2dCanvasEnabled(legacyAccelerated2dCanvasEnabled); + settings->setAcceleratedPaintingEnabled(acceleratedPaintingEnabled); + settings->setHixie76WebSocketProtocolEnabled(hixie76WebSocketProtocolEnabled); + settings->setPerTilePaintingEnabled(perTilePaintingEnabled); + + // Fixed values. + settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded(); + settings->setDownloadableBinaryFontsEnabled(true); + settings->setAllowScriptsToCloseWindows(false); + settings->setNeedsSiteSpecificQuirks(true); + settings->setEditableLinkBehaviorNeverLive(); + settings->setEnableScrollAnimator(false); + settings->setFontRenderingModeNormal(); + settings->setMockScrollbarsEnabled(false); + settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded(); + settings->setUsesEncodingDetector(false); + settings->setImagesEnabled(true); + settings->setInteractiveFormValidationEnabled(true); + // Enable fullscreen so the fullscreen layout tests can run. + settings->setFullScreenEnabled(true); + settings->setValidationMessageTimerMagnification(-1); + settings->setVisualWordMovementEnabled(false); +} diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.h b/Tools/DumpRenderTree/chromium/WebPreferences.h new file mode 100644 index 000000000..2e2135ab7 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebPreferences.h @@ -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. + */ + +#ifndef WebPreferences_h +#define WebPreferences_h + +#include "WebSettings.h" +#include "platform/WebString.h" +#include "platform/WebURL.h" +#include <wtf/HashMap.h> + +namespace WebKit { +class WebView; +} + +struct WebPreferences { + WebKit::WebString standardFontFamily; + WebKit::WebString fixedFontFamily; + WebKit::WebString serifFontFamily; + WebKit::WebString sansSerifFontFamily; + WebKit::WebString cursiveFontFamily; + WebKit::WebString fantasyFontFamily; + + // UScriptCode uses -1 and 0 for UScriptInvalidCode and UScriptCommon. + // We need to use -2 and -3 for empty value and deleted value. + // (See WebCore::ScriptFontFamilyMap) + struct UScriptCodeHashTraits : WTF::GenericHashTraits<int> { + static const bool emptyValueIsZero = false; + static int emptyValue() { return -2; } + static void constructDeletedValue(int& slot) { slot = -3; } + static bool isDeletedValue(int value) { return value == -3; } + }; + + // Map of UScriptCode to font such as USCRIPT_ARABIC to "My Arabic Font". + typedef HashMap<int, WebKit::WebString, DefaultHash<int>::Hash, UScriptCodeHashTraits> ScriptFontFamilyMap; + ScriptFontFamilyMap standardFontMap; + ScriptFontFamilyMap fixedFontMap; + ScriptFontFamilyMap serifFontMap; + ScriptFontFamilyMap sansSerifFontMap; + ScriptFontFamilyMap cursiveFontMap; + ScriptFontFamilyMap fantasyFontMap; + + int defaultFontSize; + int defaultFixedFontSize; + int minimumFontSize; + int minimumLogicalFontSize; + int minimumAccelerated2dCanvasSize; + + bool DOMPasteAllowed; + bool XSSAuditorEnabled; + bool allowDisplayOfInsecureContent; + bool allowFileAccessFromFileURLs; + bool allowRunningOfInsecureContent; + bool authorAndUserStylesEnabled; + WebKit::WebString defaultTextEncodingName; + bool developerExtrasEnabled; + bool experimentalWebGLEnabled; + bool javaEnabled; + bool javaScriptCanAccessClipboard; + bool javaScriptCanOpenWindowsAutomatically; + bool javaScriptEnabled; + bool loadsImagesAutomatically; + bool localStorageEnabled; + bool offlineWebApplicationCacheEnabled; + bool pluginsEnabled; + bool shrinksStandaloneImagesToFit; + bool textAreasAreResizable; + WebKit::WebURL userStyleSheetLocation; + bool usesPageCache; + bool pageCacheSupportsPlugins; + bool webSecurityEnabled; + bool allowUniversalAccessFromFileURLs; + WebKit::WebSettings::EditingBehavior editingBehavior; + bool tabsToLinks; + bool hyperlinkAuditingEnabled; + bool caretBrowsingEnabled; + bool acceleratedCompositingForVideoEnabled; + bool acceleratedCompositingEnabled; + bool compositeToTexture; + bool forceCompositingMode; + bool accelerated2dCanvasEnabled; + bool legacyAccelerated2dCanvasEnabled; + bool acceleratedPaintingEnabled; + bool hixie76WebSocketProtocolEnabled; + bool perTilePaintingEnabled; + + WebPreferences() { reset(); } + void reset(); + void applyTo(WebKit::WebView*); +}; + +#endif // WebPreferences_h diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp new file mode 100755 index 000000000..13b798284 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file implements a simple generic version of the WebThemeEngine, +// which is used to draw all the native controls on a web page. We use this +// file when running in layout test mode in order to remove any +// platform-specific rendering differences due to themes, colors, etc. +// + +#include "config.h" +#include "WebThemeControlDRTWin.h" + +#include "skia/ext/skia_utils_win.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkRect.h" + +#include <wtf/Assertions.h> + +using namespace std; + +static const SkColor edgeColor = SK_ColorBLACK; +static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6); +static const SkColor fgColor = SK_ColorBLACK; +static const SkColor bgColors[] = { + SK_ColorBLACK, // Unknown + SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled + SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly + SkColorSetRGB(0x89, 0xc4, 0xff), // Normal + SkColorSetRGB(0x43, 0xf9, 0xff), // Hot + SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused + SkColorSetRGB(0x00, 0xf3, 0xac), // Hover + SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed + SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate +}; + +static SkIRect validate(const SkIRect& rect, WebThemeControlDRTWin::Type ctype) +{ + switch (ctype) { + case WebThemeControlDRTWin::UncheckedBoxType: + case WebThemeControlDRTWin::CheckedBoxType: + case WebThemeControlDRTWin::UncheckedRadioType: + case WebThemeControlDRTWin::CheckedRadioType: { + SkIRect retval = rect; + + // The maximum width and height is 13. + // Center the square in the passed rectangle. + const int maxControlSize = 13; + int controlSize = min(rect.width(), rect.height()); + controlSize = min(controlSize, maxControlSize); + + retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2); + retval.fRight = retval.fLeft + controlSize - 1; + retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2); + retval.fBottom = retval.fTop + controlSize - 1; + + return retval; + } + + default: + return rect; + } +} + +// WebThemeControlDRTWin + +WebThemeControlDRTWin::WebThemeControlDRTWin(SkCanvas* canvas, + const SkIRect& irect, + Type ctype, + State cstate) + : m_canvas(canvas) + , m_irect(validate(irect, ctype)) + , m_type(ctype) + , m_state(cstate) + , m_left(m_irect.fLeft) + , m_right(m_irect.fRight) + , m_top(m_irect.fTop) + , m_bottom(m_irect.fBottom) + , m_height(m_irect.height()) + , m_width(m_irect.width()) + , m_edgeColor(edgeColor) + , m_bgColor(bgColors[cstate]) + , m_fgColor(fgColor) +{ +} + +WebThemeControlDRTWin::~WebThemeControlDRTWin() +{ +} + +void WebThemeControlDRTWin::box(const SkIRect& rect, SkColor fillColor) +{ + SkPaint paint; + + paint.setStyle(SkPaint::kFill_Style); + paint.setColor(fillColor); + m_canvas->drawIRect(rect, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawIRect(rect, paint); +} + +void WebThemeControlDRTWin::line(int x0, int y0, int x1, int y1, SkColor color) +{ + SkPaint paint; + paint.setColor(color); + m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0), + SkIntToScalar(x1), SkIntToScalar(y1), + paint); +} + +void WebThemeControlDRTWin::triangle(int x0, int y0, + int x1, int y1, + int x2, int y2, + SkColor color) +{ + SkPath path; + SkPaint paint; + + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + path.incReserve(4); + path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0)); + path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1)); + path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2)); + path.close(); + m_canvas->drawPath(path, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawPath(path, paint); +} + +void WebThemeControlDRTWin::roundRect(SkColor color) +{ + SkRect rect; + SkScalar radius = SkIntToScalar(5); + SkPaint paint; + + rect.set(m_irect); + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawRoundRect(rect, radius, radius, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawRoundRect(rect, radius, radius, paint); +} + +void WebThemeControlDRTWin::oval(SkColor color) +{ + SkRect rect; + SkPaint paint; + + rect.set(m_irect); + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawOval(rect, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawOval(rect, paint); +} + +void WebThemeControlDRTWin::circle(SkScalar radius, SkColor color) +{ + SkScalar cy = SkIntToScalar(m_top + m_height / 2); + SkScalar cx = SkIntToScalar(m_left + m_width / 2); + SkPaint paint; + + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawCircle(cx, cy, radius, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawCircle(cx, cy, radius, paint); +} + +void WebThemeControlDRTWin::nestedBoxes(int indentLeft, + int indentTop, + int indentRight, + int indentBottom, + SkColor outerColor, + SkColor innerColor) +{ + SkIRect lirect; + box(m_irect, outerColor); + lirect.set(m_irect.fLeft + indentLeft, + m_irect.fTop + indentTop, + m_irect.fRight - indentRight, + m_irect.fBottom - indentBottom); + box(lirect, innerColor); +} + +void WebThemeControlDRTWin::markState() +{ + // The horizontal lines in a read only control are spaced by this amount. + const int readOnlyLineOffset = 5; + + // The length of a triangle side for the corner marks. + const int triangleSize = 5; + + switch (m_state) { + case UnknownState: + case DisabledState: + case NormalState: + // Don't visually mark these states (color is enough). + break; + case ReadOnlyState: + // Drawing lines across the control. + for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset) + line(m_left + 1, i, m_right - 1, i, readOnlyColor); + break; + + case HotState: + // Draw a triangle in the upper left corner of the control. + triangle(m_left, m_top, + m_left + triangleSize, m_top, + m_left, m_top + triangleSize, m_edgeColor); + break; + + case HoverState: + // Draw a triangle in the upper right corner of the control. + triangle(m_right, m_top, + m_right, m_top + triangleSize, + m_right - triangleSize, m_top, m_edgeColor); + break; + + case FocusedState: + // Draw a triangle in the bottom right corner of the control. + triangle(m_right, m_bottom, + m_right - triangleSize, m_bottom, + m_right, m_bottom - triangleSize, m_edgeColor); + break; + + case PressedState: + // Draw a triangle in the bottom left corner of the control. + triangle(m_left, m_bottom, + m_left, m_bottom - triangleSize, + m_left + triangleSize, m_bottom, m_edgeColor); + break; + + default: + ASSERT_NOT_REACHED(); + CRASH(); + break; + } +} + +void WebThemeControlDRTWin::draw() +{ + int halfWidth = m_width / 2; + int halfHeight = m_height / 2; + int quarterWidth = m_width / 4; + int quarterHeight = m_height / 4; + + // Indent amounts for the check in a checkbox or radio button. + const int checkIndent = 3; + + // Indent amounts for short and long sides of the scrollbar notches. + const int notchLongOffset = 1; + const int notchShortOffset = 4; + const int noOffset = 0; + + // Indent amounts for the short and long sides of a scroll thumb box. + const int thumbLongIndent = 0; + const int thumbShortIndent = 2; + + // Indents for the crosshatch on a scroll grip. + const int gripLongIndent = 3; + const int gripShortIndent = 5; + + // Indents for the the slider track. + const int sliderIndent = 2; + + switch (m_type) { + case UnknownType: + ASSERT_NOT_REACHED(); + CRASH(); + break; + + case TextFieldType: + // We render this by hand outside of this function. + ASSERT_NOT_REACHED(); + CRASH(); + break; + + case PushButtonType: + // push buttons render as a rounded rectangle + roundRect(m_bgColor); + break; + + case UncheckedBoxType: + // Unchecked boxes are simply plain boxes. + box(m_irect, m_bgColor); + break; + + case CheckedBoxType: + nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor); + break; + + case IndeterminateCheckboxType: + // Indeterminate checkbox is a box containing '-'. + nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor); + break; + + case UncheckedRadioType: + circle(SkIntToScalar(halfHeight), m_bgColor); + break; + + case CheckedRadioType: + circle(SkIntToScalar(halfHeight), m_bgColor); + circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor); + break; + + case HorizontalScrollTrackBackType: { + // Draw a box with a notch at the left. + int longOffset = halfHeight - notchLongOffset; + int shortOffset = m_width - notchShortOffset; + nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor); + break; + } + + case HorizontalScrollTrackForwardType: { + // Draw a box with a notch at the right. + int longOffset = halfHeight - notchLongOffset; + int shortOffset = m_width - notchShortOffset; + nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor); + break; + } + + case VerticalScrollTrackBackType: { + // Draw a box with a notch at the top. + int longOffset = halfWidth - notchLongOffset; + int shortOffset = m_height - notchShortOffset; + nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor); + break; + } + + case VerticalScrollTrackForwardType: { + // Draw a box with a notch at the bottom. + int longOffset = halfWidth - notchLongOffset; + int shortOffset = m_height - notchShortOffset; + nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor); + break; + } + + case HorizontalScrollThumbType: + // Draw a narrower box on top of the outside box. + nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor); + break; + + case VerticalScrollThumbType: + // Draw a shorter box on top of the outside box. + nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor); + break; + + case HorizontalSliderThumbType: + case VerticalSliderThumbType: + // Slider thumbs are ovals. + oval(m_bgColor); + break; + + case HorizontalScrollGripType: { + // Draw a horizontal crosshatch for the grip. + int longOffset = halfWidth - gripLongIndent; + line(m_left + gripLongIndent, m_top + halfHeight, + m_right - gripLongIndent, m_top + halfHeight, m_fgColor); + line(m_left + longOffset, m_top + gripShortIndent, + m_left + longOffset, m_bottom - gripShortIndent, m_fgColor); + line(m_right - longOffset, m_top + gripShortIndent, + m_right - longOffset, m_bottom - gripShortIndent, m_fgColor); + break; + } + + case VerticalScrollGripType: { + // Draw a vertical crosshatch for the grip. + int longOffset = halfHeight - gripLongIndent; + line(m_left + halfWidth, m_top + gripLongIndent, + m_left + halfWidth, m_bottom - gripLongIndent, m_fgColor); + line(m_left + gripShortIndent, m_top + longOffset, + m_right - gripShortIndent, m_top + longOffset, m_fgColor); + line(m_left + gripShortIndent, m_bottom - longOffset, + m_right - gripShortIndent, m_bottom - longOffset, m_fgColor); + break; + } + + case LeftArrowType: + // Draw a left arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_right - quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_bottom - quarterHeight, + m_left + quarterWidth, m_top + halfHeight, m_fgColor); + break; + + case RightArrowType: + // Draw a left arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_top + halfHeight, + m_left + quarterWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case UpArrowType: + // Draw an up arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_bottom - quarterHeight, + m_left + halfWidth, m_top + quarterHeight, + m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case DownArrowType: + // Draw a down arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_top + quarterHeight, + m_left + halfWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case HorizontalSliderTrackType: { + // Draw a narrow rect for the track plus box hatches on the ends. + SkIRect lirect; + lirect = m_irect; + lirect.inset(noOffset, halfHeight - sliderIndent); + box(lirect, m_bgColor); + line(m_left, m_top, m_left, m_bottom, m_edgeColor); + line(m_right, m_top, m_right, m_bottom, m_edgeColor); + break; + } + + case VerticalSliderTrackType: { + // Draw a narrow rect for the track plus box hatches on the ends. + SkIRect lirect; + lirect = m_irect; + lirect.inset(halfWidth - sliderIndent, noOffset); + box(lirect, m_bgColor); + line(m_left, m_top, m_right, m_top, m_edgeColor); + line(m_left, m_bottom, m_right, m_bottom, m_edgeColor); + break; + } + + case DropDownButtonType: + // Draw a box with a big down arrow on top. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top, + m_right - quarterWidth, m_top, + m_left + halfWidth, m_bottom, m_fgColor); + break; + + default: + ASSERT_NOT_REACHED(); + CRASH(); + break; + } + + markState(); +} + +// Because rendering a text field is dependent on input +// parameters the other controls don't have, we render it directly +// rather than trying to overcomplicate draw() further. +void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, SkColor color) +{ + SkPaint paint; + + if (fillContentArea) { + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(m_irect, paint); + } + if (drawEdges) { + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawIRect(m_irect, paint); + } + + markState(); +} + +void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect) +{ + SkPaint paint; + + paint.setColor(m_bgColor); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(m_irect, paint); + + // Emulate clipping + SkIRect tofill; + tofill.intersect(m_irect, fillRect); + paint.setColor(m_fgColor); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(tofill, paint); + + markState(); +} + diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h new file mode 100644 index 000000000..ef731ab39 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// WebThemeControlDRTWin implements the generic rendering of controls +// needed by WebThemeEngineDRTWin. See the comments in that class +// header file for why this class is needed and used. +// +// This class implements a generic set of widgets using Skia. The widgets +// are optimized for testability, not a pleasing appearance. +// + +#ifndef WebThemeControlDRTWin_h +#define WebThemeControlDRTWin_h + +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkRect.h" +#include <wtf/Noncopyable.h> + +// Skia forward declarations +class SkCanvas; + +class WebThemeControlDRTWin { + WTF_MAKE_NONCOPYABLE(WebThemeControlDRTWin); +public: + // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h + // but is maintained separately since that isn't public and also to minimize + // dependencies. + // Note that the WebKit ThemeTypes seem to imply that a control can be + // in multiple states simultaneously but WebThemeEngine only allows for + // a single state at a time. + // + // Some definitions for the various states: + // Disabled - indicates that a control can't be modified or selected + // (corresponds to HTML 'disabled' attribute) + // ReadOnly - indicates that a control can't be modified but can be + // selected + // Normal - the normal state of control on the page when it isn't + // focused or otherwise active + // Hot - when the mouse is hovering over a part of the control, + // all the other parts are considered "hot" + // Hover - when the mouse is directly over a control (the CSS + // :hover pseudo-class) + // Focused - when the control has the keyboard focus + // Pressed - when the control is being triggered (by a mousedown or + // a key event). + // Indeterminate - when set to indeterminate (only for progress bar) + enum State { + UnknownState = 0, + DisabledState, + ReadOnlyState, + NormalState, + HotState, + HoverState, + FocusedState, + PressedState, + IndeterminateState + }; + + // This list of types mostly mirrors the list in + // WebCore/platform/ThemeTypes.h but is maintained + // separately since that isn't public and also to minimize dependencies. + // + // Note that what the user might think of as a single control can be + // made up of multiple parts. For example, a single scroll bar contains + // six clickable parts - two arrows, the "thumb" indicating the current + // position on the bar, the other two parts of the bar (before and after + // the thumb) and the "gripper" on the thumb itself. + // + enum Type { + UnknownType = 0, + TextFieldType, + PushButtonType, + UncheckedBoxType, + CheckedBoxType, + IndeterminateCheckboxType, + UncheckedRadioType, + CheckedRadioType, + HorizontalScrollTrackBackType, + HorizontalScrollTrackForwardType, + HorizontalScrollThumbType, + HorizontalScrollGripType, + VerticalScrollTrackBackType, + VerticalScrollTrackForwardType, + VerticalScrollThumbType, + VerticalScrollGripType, + LeftArrowType, + RightArrowType, + UpArrowType, + DownArrowType, + HorizontalSliderTrackType, + HorizontalSliderThumbType, + VerticalSliderTrackType, + VerticalSliderThumbType, + DropDownButtonType, + ProgressBarType + }; + + // Constructs a control of the given size, type and state to draw + // on to the given canvas. + WebThemeControlDRTWin(SkCanvas*, const SkIRect&, Type, State); + ~WebThemeControlDRTWin(); + + // Draws the control. + void draw(); + + // Use this for TextField controls instead, because the logic + // for drawing them is dependent on what WebKit tells us to do. + // If drawEdges is true, draw an edge around the control. If + // fillContentArea is true, fill the content area with the given color. + void drawTextField(bool drawEdges, bool fillContentArea, SkColor); + + // Use this for drawing ProgressBar controls instead, since we + // need to know the rect to fill inside the bar. + void drawProgressBar(const SkIRect& fillRect); + +private: + // Draws a box of size specified by irect, filled with the given color. + // The box will have a border drawn in the default edge color. + void box(const SkIRect& irect, SkColor); + + + // Draws a triangle of size specified by the three pairs of coordinates, + // filled with the given color. The box will have an edge drawn in the + // default edge color. + void triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor); + + // Draws a rectangle the size of the control with rounded corners, filled + // with the specified color (and with a border in the default edge color). + void roundRect(SkColor); + + // Draws an oval the size of the control, filled with the specified color + // and with a border in the default edge color. + void oval(SkColor); + + // Draws a circle centered in the control with the specified radius, + // filled with the specified color, and with a border draw in the + // default edge color. + void circle(SkScalar radius, SkColor); + + // Draws a box the size of the control, filled with the outerColor and + // with a border in the default edge color, and then draws another box + // indented on all four sides by the specified amounts, filled with the + // inner color and with a border in the default edge color. + void nestedBoxes(int indentLeft, + int indentTop, + int indentRight, + int indentBottom, + SkColor outerColor, + SkColor innerColor); + + // Draws a line between the two points in the given color. + void line(int x0, int y0, int x1, int y1, SkColor); + + // Draws a distinctive mark on the control for each state, so that the + // state of the control can be determined without needing to know which + // color is which. + void markState(); + + SkCanvas* m_canvas; + const SkIRect m_irect; + const Type m_type; + const State m_state; + const SkColor m_edgeColor; + const SkColor m_bgColor; + const SkColor m_fgColor; + + // The following are convenience accessors for m_irect. + const int m_left; + const int m_right; + const int m_top; + const int m_bottom; + const int m_width; + const int m_height; +}; + +#endif // WebThemeControlDRTWin_h diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h new file mode 100644 index 000000000..2398be3ae --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h @@ -0,0 +1,59 @@ +/* + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This implements the WebThemeEngine API in such a way that we match the Mac +// port rendering more than usual Chromium path, thus allowing us to share +// more pixel baselines. + +#ifndef WebThemeEngineDRTMac_h +#define WebThemeEngineDRTMac_h + +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/mac/WebThemeEngine.h" + +class WebThemeEngineDRTMac : public WebKit::WebThemeEngine { +public: + virtual void paintScrollbarThumb( + WebKit::WebCanvas*, + WebKit::WebThemeEngine::State, + WebKit::WebThemeEngine::Size, + const WebKit::WebRect&, + const WebKit::WebThemeEngine::ScrollbarInfo&); + +private: + virtual void paintHIThemeScrollbarThumb( + WebKit::WebCanvas*, + WebKit::WebThemeEngine::State, + WebKit::WebThemeEngine::Size, + const WebKit::WebRect&, + const WebKit::WebThemeEngine::ScrollbarInfo&); + virtual void paintNSScrollerScrollbarThumb( + WebKit::WebCanvas*, + WebKit::WebThemeEngine::State, + WebKit::WebThemeEngine::Size, + const WebKit::WebRect&, + const WebKit::WebThemeEngine::ScrollbarInfo&); +}; + +#endif // WebThemeEngineDRTMac_h diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm new file mode 100644 index 000000000..9a1c30857 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm @@ -0,0 +1,202 @@ +/* + * 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 "WebThemeEngineDRTMac.h" + +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCanvas.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" +#import <AppKit/NSAffineTransform.h> +#import <AppKit/NSGraphicsContext.h> +#import <AppKit/NSScroller.h> +#import <AppKit/NSWindow.h> +#include <Carbon/Carbon.h> + +#if WEBKIT_USING_SKIA +#include "skia/ext/skia_utils_mac.h" +#endif + +using WebKit::WebCanvas; +using WebKit::WebRect; +using WebKit::WebThemeEngine; + +// We can't directly tell the NSScroller to draw itself as active or inactive, +// instead we have to make it a child of an (in)active window. This class lets +// us fake that parent window. +@interface FakeActiveWindow : NSWindow { +@private + BOOL hasActiveControls; +} ++ (NSWindow*)alwaysActiveWindow; ++ (NSWindow*)alwaysInactiveWindow; +- (id)initWithActiveControls:(BOOL)_hasActiveControls; +- (BOOL)_hasActiveControls; +@end + +@implementation FakeActiveWindow + +static NSWindow* alwaysActiveWindow = nil; +static NSWindow* alwaysInactiveWindow = nil; + ++ (NSWindow*)alwaysActiveWindow +{ + if (alwaysActiveWindow == nil) + alwaysActiveWindow = [[self alloc] initWithActiveControls:YES]; + return alwaysActiveWindow; +} + ++ (NSWindow*)alwaysInactiveWindow +{ + if (alwaysInactiveWindow == nil) + alwaysInactiveWindow = [[self alloc] initWithActiveControls:NO]; + return alwaysInactiveWindow; +} + +- (id)initWithActiveControls:(BOOL)_hasActiveControls +{ + self = [super init]; + hasActiveControls = _hasActiveControls; + return self; +} + +- (BOOL)_hasActiveControls +{ + return hasActiveControls; +} + +@end + +void WebThemeEngineDRTMac::paintScrollbarThumb( + WebCanvas* canvas, + WebThemeEngine::State state, + WebThemeEngine::Size size, + const WebRect& rect, + const WebThemeEngine::ScrollbarInfo& scrollbarInfo) +{ + // To match the Mac port, we still use HITheme for inner scrollbars. + if (scrollbarInfo.parent == WebThemeEngine::ScrollbarParentRenderLayer) + paintHIThemeScrollbarThumb(canvas, state, size, rect, scrollbarInfo); + else + paintNSScrollerScrollbarThumb(canvas, state, size, rect, scrollbarInfo); +} + +static ThemeTrackEnableState stateToHIEnableState(WebThemeEngine::State state) +{ + switch (state) { + case WebThemeEngine::StateDisabled: + return kThemeTrackDisabled; + case WebThemeEngine::StateInactive: + return kThemeTrackInactive; + default: + return kThemeTrackActive; + } +} + +// Duplicated from webkit/glue/webthemeengine_impl_mac.cc in the downstream +// Chromium WebThemeEngine implementation. +void WebThemeEngineDRTMac::paintHIThemeScrollbarThumb( + WebCanvas* canvas, + WebThemeEngine::State state, + WebThemeEngine::Size size, + const WebRect& rect, + const WebThemeEngine::ScrollbarInfo& scrollbarInfo) +{ + HIThemeTrackDrawInfo trackInfo; + trackInfo.version = 0; + trackInfo.kind = size == WebThemeEngine::SizeRegular ? kThemeMediumScrollBar : kThemeSmallScrollBar; + trackInfo.bounds = CGRectMake(rect.x, rect.y, rect.width, rect.height); + trackInfo.min = 0; + trackInfo.max = scrollbarInfo.maxValue; + trackInfo.value = scrollbarInfo.currentValue; + trackInfo.trackInfo.scrollbar.viewsize = scrollbarInfo.visibleSize; + trackInfo.attributes = 0; + if (scrollbarInfo.orientation == WebThemeEngine::ScrollbarOrientationHorizontal) + trackInfo.attributes |= kThemeTrackHorizontal; + + trackInfo.enableState = stateToHIEnableState(state); + + trackInfo.trackInfo.scrollbar.pressState = + state == WebThemeEngine::StatePressed ? kThemeThumbPressed : 0; + trackInfo.attributes |= (kThemeTrackShowThumb | kThemeTrackHideTrack); +#if WEBKIT_USING_SKIA + gfx::SkiaBitLocker bitLocker(canvas); + CGContextRef cgContext = bitLocker.cgContext(); +#else + CGContextRef cgContext = canvas; +#endif + HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal); +} + +void WebThemeEngineDRTMac::paintNSScrollerScrollbarThumb( + WebCanvas* canvas, + WebThemeEngine::State state, + WebThemeEngine::Size size, + const WebRect& rect, + const WebThemeEngine::ScrollbarInfo& scrollbarInfo) +{ + [NSGraphicsContext saveGraphicsState]; + NSScroller* scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(rect.x, rect.y, rect.width, rect.height)]; + [scroller setEnabled:state != WebThemeEngine::StateDisabled]; + if (state == WebThemeEngine::StateInactive) + [[[FakeActiveWindow alwaysInactiveWindow] contentView] addSubview:scroller]; + else + [[[FakeActiveWindow alwaysActiveWindow] contentView] addSubview:scroller]; + + [scroller setControlSize:size == WebThemeEngine::SizeRegular ? NSRegularControlSize : NSSmallControlSize]; + + double value = double(scrollbarInfo.currentValue) / double(scrollbarInfo.maxValue); + [scroller setDoubleValue: value]; + + float knobProportion = float(scrollbarInfo.visibleSize) / float(scrollbarInfo.totalSize); + [scroller setKnobProportion: knobProportion]; + +#if WEBKIT_USING_SKIA + gfx::SkiaBitLocker bitLocker(canvas); + CGContextRef cgContext = bitLocker.cgContext(); +#else + CGContextRef cgContext = canvas; +#endif + NSGraphicsContext* nsGraphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]; + [NSGraphicsContext setCurrentContext:nsGraphicsContext]; + + // Despite passing in frameRect() to the scroller, it always draws at (0, 0). + // Force it to draw in the right location by translating the whole graphics + // context. + CGContextSaveGState(cgContext); + NSAffineTransform *transform = [NSAffineTransform transform]; + [transform translateXBy:rect.x yBy:rect.y]; + [transform concat]; + + [scroller drawKnob]; + CGContextRestoreGState(cgContext); + + [scroller release]; + + [NSGraphicsContext restoreGraphicsState]; +} diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp new file mode 100755 index 000000000..789b1c816 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebThemeEngineDRTWin.h" + +#include "platform/WebRect.h" +#include "WebThemeControlDRTWin.h" +#include "third_party/skia/include/core/SkRect.h" + +// Although all this code is generic, we include these headers +// to pull in the Windows #defines for the parts and states of +// the controls. +#include <vsstyle.h> +#include <windows.h> + +#include <wtf/Assertions.h> + +using namespace WebKit; + +// We define this for clarity, although there really should be a DFCS_NORMAL in winuser.h. +static const int dfcsNormal = 0x0000; + +static SkIRect webRectToSkIRect(const WebRect& webRect) +{ + SkIRect irect; + irect.set(webRect.x, webRect.y, webRect.x + webRect.width, webRect.y + webRect.height); + return irect; +} + +static void drawControl(WebCanvas* canvas, + const WebRect& rect, + WebThemeControlDRTWin::Type ctype, + WebThemeControlDRTWin::State cstate) +{ + WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate); + control.draw(); +} + +static void drawTextField(WebCanvas* canvas, + const WebRect& rect, + WebThemeControlDRTWin::Type ctype, + WebThemeControlDRTWin::State cstate, + bool drawEdges, + bool fillContentArea, + WebColor color) +{ + WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate); + control.drawTextField(drawEdges, fillContentArea, color); +} + +static void drawProgressBar(WebCanvas* canvas, + WebThemeControlDRTWin::Type ctype, + WebThemeControlDRTWin::State cstate, + const WebRect& barRect, + const WebRect& fillRect) +{ + WebThemeControlDRTWin control(canvas, webRectToSkIRect(barRect), ctype, cstate); + control.drawProgressBar(webRectToSkIRect(fillRect)); +} + +// WebThemeEngineDRTWin + +void WebThemeEngineDRTWin::paintButton(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + if (part == BP_CHECKBOX) { + switch (state) { + case CBS_UNCHECKEDNORMAL: + ASSERT(classicState == dfcsNormal); + ctype = WebThemeControlDRTWin::UncheckedBoxType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case CBS_UNCHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT)); + ctype = WebThemeControlDRTWin::UncheckedBoxType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case CBS_UNCHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::UncheckedBoxType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case CBS_UNCHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::UncheckedBoxType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case CBS_CHECKEDNORMAL: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED)); + ctype = WebThemeControlDRTWin::CheckedBoxType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case CBS_CHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT)); + ctype = WebThemeControlDRTWin::CheckedBoxType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case CBS_CHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::CheckedBoxType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case CBS_CHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::CheckedBoxType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case CBS_MIXEDNORMAL: + // Classic theme can't represent mixed state checkbox. We assume + // it's equivalent to unchecked. + ASSERT(classicState == DFCS_BUTTONCHECK); + ctype = WebThemeControlDRTWin::IndeterminateCheckboxType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case CBS_MIXEDHOT: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT)); + ctype = WebThemeControlDRTWin::IndeterminateCheckboxType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case CBS_MIXEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::IndeterminateCheckboxType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case CBS_MIXEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::IndeterminateCheckboxType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (BP_RADIOBUTTON == part) { + switch (state) { + case RBS_UNCHECKEDNORMAL: + ASSERT(classicState == DFCS_BUTTONRADIO); + ctype = WebThemeControlDRTWin::UncheckedRadioType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case RBS_UNCHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_HOT)); + ctype = WebThemeControlDRTWin::UncheckedRadioType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case RBS_UNCHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::UncheckedRadioType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case RBS_UNCHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::UncheckedRadioType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case RBS_CHECKEDNORMAL: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED)); + ctype = WebThemeControlDRTWin::CheckedRadioType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case RBS_CHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT)); + ctype = WebThemeControlDRTWin::CheckedRadioType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case RBS_CHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::CheckedRadioType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case RBS_CHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::CheckedRadioType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (BP_PUSHBUTTON == part) { + switch (state) { + case PBS_NORMAL: + ASSERT(classicState == DFCS_BUTTONPUSH); + ctype = WebThemeControlDRTWin::PushButtonType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case PBS_HOT: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_HOT)); + ctype = WebThemeControlDRTWin::PushButtonType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case PBS_PRESSED: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_PUSHED)); + ctype = WebThemeControlDRTWin::PushButtonType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case PBS_DISABLED: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::PushButtonType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case PBS_DEFAULTED: + ASSERT(classicState == DFCS_BUTTONPUSH); + ctype = WebThemeControlDRTWin::PushButtonType; + cstate = WebThemeControlDRTWin::FocusedState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else + ASSERT_NOT_REACHED(); + + drawControl(canvas, rect, ctype, cstate); +} + + +void WebThemeEngineDRTWin::paintMenuList(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + if (CP_DROPDOWNBUTTON == part) { + ctype = WebThemeControlDRTWin::DropDownButtonType; + switch (state) { + case CBXS_NORMAL: + ASSERT(classicState == DFCS_MENUARROW); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case CBXS_HOT: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_HOT)); + cstate = WebThemeControlDRTWin::HoverState; + break; + + case CBXS_PRESSED: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_PUSHED)); + cstate = WebThemeControlDRTWin::PressedState; + break; + + case CBXS_DISABLED: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_INACTIVE)); + cstate = WebThemeControlDRTWin::DisabledState; + break; + + default: + CRASH(); + break; + } + } else + CRASH(); + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRTWin::paintScrollbarArrow(WebCanvas* canvas, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + switch (state) { + case ABS_UPNORMAL: + ASSERT(classicState == DFCS_SCROLLUP); + ctype = WebThemeControlDRTWin::UpArrowType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case ABS_DOWNNORMAL: + ASSERT(classicState == DFCS_SCROLLDOWN); + ctype = WebThemeControlDRTWin::DownArrowType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case ABS_LEFTNORMAL: + ASSERT(classicState == DFCS_SCROLLLEFT); + ctype = WebThemeControlDRTWin::LeftArrowType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case ABS_RIGHTNORMAL: + ASSERT(classicState == DFCS_SCROLLRIGHT); + ctype = WebThemeControlDRTWin::RightArrowType; + cstate = WebThemeControlDRTWin::NormalState; + break; + + case ABS_UPHOT: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT)); + ctype = WebThemeControlDRTWin::UpArrowType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case ABS_DOWNHOT: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT)); + ctype = WebThemeControlDRTWin::DownArrowType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case ABS_LEFTHOT: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_HOT)); + ctype = WebThemeControlDRTWin::LeftArrowType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case ABS_RIGHTHOT: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_HOT)); + ctype = WebThemeControlDRTWin::RightArrowType; + cstate = WebThemeControlDRTWin::HotState; + break; + + case ABS_UPHOVER: + ASSERT(classicState == DFCS_SCROLLUP); + ctype = WebThemeControlDRTWin::UpArrowType; + cstate = WebThemeControlDRTWin::HoverState; + break; + + case ABS_DOWNHOVER: + ASSERT(classicState == DFCS_SCROLLDOWN); + ctype = WebThemeControlDRTWin::DownArrowType; + cstate = WebThemeControlDRTWin::HoverState; + break; + + case ABS_LEFTHOVER: + ASSERT(classicState == DFCS_SCROLLLEFT); + ctype = WebThemeControlDRTWin::LeftArrowType; + cstate = WebThemeControlDRTWin::HoverState; + break; + + case ABS_RIGHTHOVER: + ASSERT(classicState == DFCS_SCROLLRIGHT); + ctype = WebThemeControlDRTWin::RightArrowType; + cstate = WebThemeControlDRTWin::HoverState; + break; + + case ABS_UPPRESSED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRTWin::UpArrowType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case ABS_DOWNPRESSED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRTWin::DownArrowType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case ABS_LEFTPRESSED: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRTWin::LeftArrowType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case ABS_RIGHTPRESSED: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRTWin::RightArrowType; + cstate = WebThemeControlDRTWin::PressedState; + break; + + case ABS_UPDISABLED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::UpArrowType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case ABS_DOWNDISABLED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::DownArrowType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case ABS_LEFTDISABLED: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::LeftArrowType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case ABS_RIGHTDISABLED: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_INACTIVE)); + ctype = WebThemeControlDRTWin::RightArrowType; + cstate = WebThemeControlDRTWin::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRTWin::paintScrollbarThumb(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + switch (part) { + case SBP_THUMBBTNHORZ: + ctype = WebThemeControlDRTWin::HorizontalScrollThumbType; + break; + + case SBP_THUMBBTNVERT: + ctype = WebThemeControlDRTWin::VerticalScrollThumbType; + break; + + case SBP_GRIPPERHORZ: + ctype = WebThemeControlDRTWin::HorizontalScrollGripType; + break; + + case SBP_GRIPPERVERT: + ctype = WebThemeControlDRTWin::VerticalScrollGripType; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + switch (state) { + case SCRBS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case SCRBS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRTWin::HotState; + break; + + case SCRBS_HOVER: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::HoverState; + break; + + case SCRBS_PRESSED: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::PressedState; + break; + + case SCRBS_DISABLED: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRTWin::paintScrollbarTrack(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect, + const WebRect& alignRect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + switch (part) { + case SBP_UPPERTRACKHORZ: + ctype = WebThemeControlDRTWin::HorizontalScrollTrackBackType; + break; + + case SBP_LOWERTRACKHORZ: + ctype = WebThemeControlDRTWin::HorizontalScrollTrackForwardType; + break; + + case SBP_UPPERTRACKVERT: + ctype = WebThemeControlDRTWin::VerticalScrollTrackBackType; + break; + + case SBP_LOWERTRACKVERT: + ctype = WebThemeControlDRTWin::VerticalScrollTrackForwardType; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + switch (state) { + case SCRBS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case SCRBS_HOT: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + case SCRBS_HOVER: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::HoverState; + break; + + case SCRBS_PRESSED: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + case SCRBS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRTWin::DisabledState; + break; + + default: + CRASH(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRTWin::paintSpinButton(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + if (part == SPNP_UP) { + ctype = WebThemeControlDRTWin::UpArrowType; + switch (state) { + case UPS_NORMAL: + ASSERT(classicState == DFCS_SCROLLUP); + cstate = WebThemeControlDRTWin::NormalState; + break; + case UPS_DISABLED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE)); + cstate = WebThemeControlDRTWin::DisabledState; + break; + case UPS_PRESSED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED)); + cstate = WebThemeControlDRTWin::PressedState; + break; + case UPS_HOT: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT)); + cstate = WebThemeControlDRTWin::HoverState; + break; + default: + ASSERT_NOT_REACHED(); + } + } else if (part == SPNP_DOWN) { + ctype = WebThemeControlDRTWin::DownArrowType; + switch (state) { + case DNS_NORMAL: + ASSERT(classicState == DFCS_SCROLLDOWN); + cstate = WebThemeControlDRTWin::NormalState; + break; + case DNS_DISABLED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE)); + cstate = WebThemeControlDRTWin::DisabledState; + break; + case DNS_PRESSED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED)); + cstate = WebThemeControlDRTWin::PressedState; + break; + case DNS_HOT: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT)); + cstate = WebThemeControlDRTWin::HoverState; + break; + default: + ASSERT_NOT_REACHED(); + } + } else + ASSERT_NOT_REACHED(); + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRTWin::paintTextField(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect, + WebColor color, + bool fillContentArea, + bool drawEdges) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + ASSERT(EP_EDITTEXT == part); + ctype = WebThemeControlDRTWin::TextFieldType; + + switch (state) { + case ETS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case ETS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRTWin::HotState; + break; + + case ETS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case ETS_SELECTED: + ASSERT(classicState == DFCS_PUSHED); + cstate = WebThemeControlDRTWin::PressedState; + break; + + case ETS_FOCUSED: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::FocusedState; + break; + + case ETS_READONLY: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::ReadOnlyState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawTextField(canvas, rect, ctype, cstate, drawEdges, fillContentArea, color); +} + +void WebThemeEngineDRTWin::paintTrackbar(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType; + WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState; + + if (TKP_THUMBBOTTOM == part) { + ctype = WebThemeControlDRTWin::HorizontalSliderThumbType; + switch (state) { + case TUS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case TUS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRTWin::HotState; + break; + + case TUS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case TUS_PRESSED: + ASSERT(classicState == DFCS_PUSHED); + cstate = WebThemeControlDRTWin::PressedState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (TKP_THUMBVERT == part) { + ctype = WebThemeControlDRTWin::VerticalSliderThumbType; + switch (state) { + case TUS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + break; + + case TUS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRTWin::HotState; + break; + + case TUS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRTWin::DisabledState; + break; + + case TUS_PRESSED: + ASSERT(classicState == DFCS_PUSHED); + cstate = WebThemeControlDRTWin::PressedState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (TKP_TRACK == part) { + ctype = WebThemeControlDRTWin::HorizontalSliderTrackType; + ASSERT(state == TRS_NORMAL); + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + } else if (TKP_TRACKVERT == part) { + ctype = WebThemeControlDRTWin::VerticalSliderTrackType; + ASSERT(state == TRVS_NORMAL); + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRTWin::NormalState; + } else + ASSERT_NOT_REACHED(); + + drawControl(canvas, rect, ctype, cstate); +} + + +void WebThemeEngineDRTWin::paintProgressBar(WebKit::WebCanvas* canvas, + const WebKit::WebRect& barRect, + const WebKit::WebRect& valueRect, + bool determinate, + double) +{ + WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::ProgressBarType; + WebThemeControlDRTWin::State cstate = determinate ? WebThemeControlDRTWin::NormalState + : WebThemeControlDRTWin::IndeterminateState; + drawProgressBar(canvas, ctype, cstate, barRect, valueRect); +} + diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h new file mode 100644 index 000000000..daa911166 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This implements the WebThemeEngine API used by the Windows version of +// Chromium to render native form controls like checkboxes, radio buttons, +// and scroll bars. +// The normal implementation (native_theme) renders the controls using either +// the UXTheme theming engine present in XP, Vista, and Win 7, or the "classic" +// theme used if that theme is selected in the Desktop settings. +// Unfortunately, both of these themes render controls differently on the +// different versions of Windows. +// +// In order to ensure maximum consistency of baselines across the different +// Windows versions, we provide a simple implementation for DRT here +// instead. These controls are actually platform-independent (they're rendered +// using Skia) and could be used on Linux and the Mac as well, should we +// choose to do so at some point. +// + +#ifndef WebThemeEngineDRTWin_h +#define WebThemeEngineDRTWin_h + +#include "platform/win/WebThemeEngine.h" +#include <wtf/Noncopyable.h> + +class WebThemeEngineDRTWin : public WebKit::WebThemeEngine { + WTF_MAKE_NONCOPYABLE(WebThemeEngineDRTWin); +public: + WebThemeEngineDRTWin() { } + + // WebThemeEngine methods: + virtual void paintButton( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintMenuList( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarArrow( + WebKit::WebCanvas*, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarThumb( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarTrack( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&, const WebKit::WebRect& alignRect); + + virtual void paintSpinButton( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintTextField( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&, WebKit::WebColor, bool fillContentArea, + bool drawEdges); + + virtual void paintTrackbar( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintProgressBar( + WebKit::WebCanvas*, const WebKit::WebRect& barRect, + const WebKit::WebRect& valueRect, + bool determinate, double time); +}; + +#endif // WebThemeEngineDRTWin_h diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp new file mode 100644 index 000000000..1b0687dd0 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp @@ -0,0 +1,1687 @@ +/* + * Copyright (C) 2010, 2011 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 "TestWebPlugin.h" +#include "TestWebWorker.h" +#include "platform/WebCString.h" +#include "WebConsoleMessage.h" +#include "WebContextMenuData.h" +#include "WebDOMMessageEvent.h" +#include "WebDataSource.h" +#include "WebDeviceOrientationClientMock.h" +#include "platform/WebDragData.h" +#include "WebElement.h" +#include "WebFrame.h" +#include "WebGeolocationClientMock.h" +#include "WebHistoryItem.h" +#include "WebKit.h" +#include "WebNode.h" +#include "WebPluginParams.h" +#include "WebPopupMenu.h" +#include "WebPopupType.h" +#include "WebRange.h" +#include "platform/WebRect.h" +#include "WebScreenInfo.h" +#include "platform/WebSize.h" +#include "WebSpeechInputControllerMock.h" +#include "WebStorageNamespace.h" +#include "WebTextCheckingCompletion.h" +#include "WebTextCheckingResult.h" +#include "platform/WebThread.h" +#include "platform/WebURLRequest.h" +#include "platform/WebURLResponse.h" +#include "WebView.h" +#include "WebWindowFeatures.h" +#include "skia/ext/platform_canvas.h" +#include "webkit/support/webkit_support.h" + +#include <wtf/Assertions.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +using namespace WebCore; +using namespace WebKit; +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 dragData (CF_HDROP). Use to fake +// dragging a file. +static void addDRTFakeFileToDataObject(WebDragData* dragData) +{ + dragData->appendToFilenames(WebString::fromUTF8("DRTFakeFile")); +} + +// Get a debugging string from a WebNavigationType. +static const char* webNavigationTypeToString(WebNavigationType type) +{ + switch (type) { + case WebKit::WebNavigationTypeLinkClicked: + return linkClickedString; + case WebKit::WebNavigationTypeFormSubmitted: + return formSubmittedString; + case WebKit::WebNavigationTypeBackForward: + return backForwardString; + case WebKit::WebNavigationTypeReload: + return reloadString; + case WebKit::WebNavigationTypeFormResubmitted: + return formResubmittedString; + case WebKit::WebNavigationTypeOther: + return otherString; + } + return illegalString; +} + +static string URLDescription(const GURL& url) +{ + if (url.SchemeIs("file")) + return url.ExtractFileName(); + return url.possibly_invalid_spec(); +} + +static void printResponseDescription(const WebURLResponse& response) +{ + if (response.isNull()) { + fputs("(null)", stdout); + return; + } + string url = response.url().spec(); + printf("<NSURLResponse %s, http status code %d>", + descriptionSuitableForTestResult(url).c_str(), + response.httpStatusCode()); +} + +static void printNodeDescription(const WebNode& node, int exception) +{ + if (exception) { + fputs("ERROR", stdout); + return; + } + if (node.isNull()) { + fputs("(null)", stdout); + return; + } + fputs(node.nodeName().utf8().data(), stdout); + const WebNode& parent = node.parentNode(); + if (!parent.isNull()) { + fputs(" > ", stdout); + printNodeDescription(parent, 0); + } +} + +static void printRangeDescription(const WebRange& range) +{ + if (range.isNull()) { + fputs("(null)", stdout); + return; + } + printf("range from %d of ", range.startOffset()); + int exception = 0; + WebNode startNode = range.startContainer(exception); + printNodeDescription(startNode, exception); + printf(" to %d of ", range.endOffset()); + WebNode endNode = range.endContainer(exception); + printNodeDescription(endNode, exception); +} + +static string editingActionDescription(WebEditingAction action) +{ + switch (action) { + case WebKit::WebEditingActionTyped: + return "WebViewInsertActionTyped"; + case WebKit::WebEditingActionPasted: + return "WebViewInsertActionPasted"; + case WebKit::WebEditingActionDropped: + return "WebViewInsertActionDropped"; + } + return "(UNKNOWN ACTION)"; +} + +static string textAffinityDescription(WebTextAffinity affinity) +{ + switch (affinity) { + case WebKit::WebTextAffinityUpstream: + return "NSSelectionAffinityUpstream"; + case WebKit::WebTextAffinityDownstream: + return "NSSelectionAffinityDownstream"; + } + return "(UNKNOWN AFFINITY)"; +} + +// WebViewClient ------------------------------------------------------------- + +WebView* WebViewHost::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&) +{ + if (!layoutTestController()->canOpenWindows()) + return 0; + if (layoutTestController()->shouldDumpCreateView()) + fprintf(stdout, "createView(%s)\n", URLDescription(request.url()).c_str()); + return m_shell->createNewWindow(WebURL())->webView(); +} + +WebWidget* WebViewHost::createPopupMenu(WebPopupType type) +{ + switch (type) { + case WebKit::WebPopupTypeNone: + break; + case WebKit::WebPopupTypeSelect: + case WebKit::WebPopupTypeSuggestion: + m_popupmenus.append(WebPopupMenu::create(0)); + return m_popupmenus.last(); + } + return 0; +} + +WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&) +{ + // Do not use this method. It's been replaced by createExternalPopupMenu. + ASSERT_NOT_REACHED(); + return 0; +} + +WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota) +{ + return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota); +} + +void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine) +{ + // This matches win DumpRenderTree's UIDelegate.cpp. + if (!m_logConsoleOutput) + return; + 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() +{ + if (layoutTestController()->shouldDumpProgressFinishedCallback()) + fputs("postProgressFinishedNotification\n", stdout); + 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, WebVector<WebString>* optionalSuggestions) +{ + // Check the spelling of the given text. + m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength); +} + +void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion) +{ + if (text.isEmpty()) { + if (completion) + completion->didFinishCheckingText(Vector<WebTextCheckingResult>()); + return; + } + + m_lastRequestedTextCheckingCompletion = completion; + m_lastRequestedTextCheckString = text; + postDelayedTask(new HostMethodTask(this, &WebViewHost::finishLastTextCheck), 0); +} + +void WebViewHost::finishLastTextCheck() +{ + Vector<WebTextCheckingResult> results; + // FIXME: Do the grammar check. + int offset = 0; + String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length()); + while (text.length()) { + int misspelledPosition = 0; + int misspelledLength = 0; + m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength); + if (!misspelledLength) + break; + results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength)); + text = text.substring(misspelledPosition + misspelledLength); + offset += misspelledPosition + misspelledLength; + } + + m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results); + m_lastRequestedTextCheckingCompletion = 0; +} + + +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& message) +{ + printf("CONFIRM NAVIGATION: %s\n", message.utf8().data()); + return !layoutTestController()->shouldStayOnPageAfterHandlingBeforeUnload(); +} + +void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData) +{ + m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData)); +} + +void WebViewHost::clearContextMenuData() +{ + m_lastContextMenuData.clear(); +} + +WebContextMenuData* WebViewHost::lastContextMenuData() const +{ + return m_lastContextMenuData.get(); +} + +void WebViewHost::setStatusText(const WebString& text) +{ + if (!layoutTestController()->shouldDumpStatusCallbacks()) + return; + // When running tests, write to stdout. + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data()); +} + +void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&) +{ + WebDragData mutableDragData = data; + if (layoutTestController()->shouldAddFileToPasteboard()) { + // Add a file called DRTFakeFile to the drag&drop clipboard. + addDRTFakeFileToDataObject(&mutableDragData); + } + + // When running a test, we need to fake a drag drop operation otherwise + // Windows waits for real mouse events to know when the drag is over. + m_shell->eventSender()->doDragDrop(mutableDragData, mask); +} + +void WebViewHost::didUpdateLayout() +{ +#if OS(MAC_OS_X) + static bool queryingPreferredSize = false; + if (queryingPreferredSize) + return; + + queryingPreferredSize = true; + // Query preferred width to emulate the same functionality in Chromium: + // see RenderView::CheckPreferredSize (src/content/renderer/render_view.cc) + // and TabContentsViewMac::RenderViewCreated (src/chrome/browser/tab_contents/tab_contents_view_mac.mm) + webView()->mainFrame()->contentsPreferredWidth(); + webView()->mainFrame()->documentElementScrollHeight(); + queryingPreferredSize = false; +#endif +} + +void WebViewHost::navigateBackForwardSoon(int offset) +{ + navigationController()->goToOffset(offset); +} + +int WebViewHost::historyBackListCount() +{ + return navigationController()->lastCommittedEntryIndex(); +} + +int WebViewHost::historyForwardListCount() +{ + int currentIndex =navigationController()->lastCommittedEntryIndex(); + return navigationController()->entryCount() - currentIndex - 1; +} + +void WebViewHost::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification) +{ + if (notification == WebAccessibilityNotificationFocusedUIElementChanged) + m_shell->accessibilityController()->setFocusedElement(obj); + + const char* notificationName; + switch (notification) { + case WebAccessibilityNotificationActiveDescendantChanged: + notificationName = "ActiveDescendantChanged"; + break; + case WebAccessibilityNotificationAutocorrectionOccured: + notificationName = "AutocorrectionOccured"; + break; + case WebAccessibilityNotificationCheckedStateChanged: + notificationName = "CheckedStateChanged"; + break; + case WebAccessibilityNotificationChildrenChanged: + notificationName = "ChildrenChanged"; + break; + case WebAccessibilityNotificationFocusedUIElementChanged: + notificationName = "FocusedUIElementChanged"; + break; + case WebAccessibilityNotificationLayoutComplete: + notificationName = "LayoutComplete"; + break; + case WebAccessibilityNotificationLoadComplete: + notificationName = "LoadComplete"; + break; + case WebAccessibilityNotificationSelectedChildrenChanged: + notificationName = "SelectedChildrenChanged"; + break; + case WebAccessibilityNotificationSelectedTextChanged: + notificationName = "SelectedTextChanged"; + break; + case WebAccessibilityNotificationValueChanged: + notificationName = "ValueChanged"; + break; + case WebAccessibilityNotificationScrolledToAnchor: + notificationName = "ScrolledToAnchor"; + break; + case WebAccessibilityNotificationLiveRegionChanged: + notificationName = "LiveRegionChanged"; + break; + case WebAccessibilityNotificationMenuListItemSelected: + notificationName = "MenuListItemSelected"; + break; + case WebAccessibilityNotificationMenuListValueChanged: + notificationName = "MenuListValueChanged"; + break; + case WebAccessibilityNotificationRowCountChanged: + notificationName = "RowCountChanged"; + break; + case WebAccessibilityNotificationRowCollapsed: + notificationName = "RowCollapsed"; + break; + case WebAccessibilityNotificationRowExpanded: + notificationName = "RowExpanded"; + break; + case WebAccessibilityNotificationInvalidStatusChanged: + notificationName = "InvalidStatusChanged"; + break; + default: + notificationName = "UnknownNotification"; + break; + } + + m_shell->accessibilityController()->notificationReceived(obj, notificationName); + + if (m_shell->accessibilityController()->shouldLogAccessibilityEvents()) { + printf("AccessibilityNotification - %s", notificationName); + + WebKit::WebNode node = obj.node(); + if (!node.isNull() && node.isElementNode()) { + WebKit::WebElement element = node.to<WebKit::WebElement>(); + if (element.hasAttribute("id")) + printf(" - id:%s", element.getAttribute("id").utf8().data()); + } + + printf("\n"); + } +} + +WebNotificationPresenter* WebViewHost::notificationPresenter() +{ + return m_shell->notificationPresenter(); +} + +WebKit::WebGeolocationClient* WebViewHost::geolocationClient() +{ + return geolocationClientMock(); +} + +WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock() +{ + if (!m_geolocationClientMock) + m_geolocationClientMock = adoptPtr(WebGeolocationClientMock::create()); + return m_geolocationClientMock.get(); +} + +WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener) +{ + if (!m_speechInputControllerMock) + m_speechInputControllerMock = adoptPtr(WebSpeechInputControllerMock::create(listener)); + return m_speechInputControllerMock.get(); +} + +WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock() +{ + if (!m_deviceOrientationClientMock.get()) + m_deviceOrientationClientMock = adoptPtr(WebDeviceOrientationClientMock::create()); + return m_deviceOrientationClientMock.get(); +} + +MockSpellCheck* WebViewHost::mockSpellCheck() +{ + return &m_spellcheck; +} + +WebDeviceOrientationClient* WebViewHost::deviceOrientationClient() +{ + return deviceOrientationClientMock(); +} + +// WebWidgetClient ----------------------------------------------------------- + +void WebViewHost::didInvalidateRect(const WebRect& rect) +{ + updatePaintRect(rect); +} + +void WebViewHost::didScrollRect(int, int, const WebRect& clipRect) +{ + // This is used for optimizing painting when the renderer is scrolled. We're + // currently not doing any optimizations so just invalidate the region. + didInvalidateRect(clipRect); +} + +void WebViewHost::scheduleComposite() +{ + WebSize widgetSize = webWidget()->size(); + WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); + didInvalidateRect(clientRect); +} + +#if ENABLE(REQUEST_ANIMATION_FRAME) +void WebViewHost::scheduleAnimation() +{ + postDelayedTask(new HostMethodTask(this, &WebViewHost::scheduleComposite), 0); +} +#endif + +void WebViewHost::didFocus() +{ + m_shell->setFocus(webWidget(), true); +} + +void WebViewHost::didBlur() +{ + m_shell->setFocus(webWidget(), false); +} + +WebScreenInfo WebViewHost::screenInfo() +{ + // We don't need to set actual values. + WebScreenInfo info; + info.depth = 24; + info.depthPerComponent = 8; + info.isMonochrome = false; + info.rect = WebRect(0, 0, screenWidth, screenHeight); + // Use values different from info.rect for testing. + info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder, + screenWidth - screenUnavailableBorder * 2, + screenHeight - screenUnavailableBorder * 2); + return info; +} + +void WebViewHost::show(WebNavigationPolicy) +{ + m_hasWindow = true; + WebSize size = webWidget()->size(); + updatePaintRect(WebRect(0, 0, size.width, size.height)); +} + + + +void WebViewHost::closeWidget() +{ + m_hasWindow = false; + m_shell->closeWindow(this); + // No more code here, we should be deleted at this point. +} + +void WebViewHost::closeWidgetSoon() +{ + postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0); +} + +void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo) +{ + if (!hasWindow()) + return; + m_currentCursor = cursorInfo; +} + +WebRect WebViewHost::windowRect() +{ + return m_windowRect; +} + +void WebViewHost::setWindowRect(const WebRect& rect) +{ + m_windowRect = rect; + const int border2 = TestShell::virtualWindowBorder * 2; + if (m_windowRect.width <= border2) + m_windowRect.width = 1 + border2; + if (m_windowRect.height <= border2) + m_windowRect.height = 1 + border2; + int width = m_windowRect.width - border2; + int height = m_windowRect.height - border2; + discardBackingStore(); + webWidget()->resize(WebSize(width, height)); + updatePaintRect(WebRect(0, 0, width, height)); +} + +WebRect WebViewHost::rootWindowRect() +{ + return windowRect(); +} + +WebRect WebViewHost::windowResizerRect() +{ + // Not necessary. + return WebRect(); +} + +void WebViewHost::runModal() +{ + bool oldState = webkit_support::MessageLoopNestableTasksAllowed(); + webkit_support::MessageLoopSetNestableTasksAllowed(true); + m_inModalLoop = true; + webkit_support::RunMessageLoop(); + webkit_support::MessageLoopSetNestableTasksAllowed(oldState); +} + +bool WebViewHost::enterFullScreen() +{ + postDelayedTask(new HostMethodTask(this, &WebViewHost::enterFullScreenNow), 0); + return true; +} + +void WebViewHost::exitFullScreen() +{ + postDelayedTask(new HostMethodTask(this, &WebViewHost::exitFullScreenNow), 0); +} + +// WebFrameClient ------------------------------------------------------------ + +WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params) +{ + if (params.mimeType == TestWebPlugin::mimeType()) + return new TestWebPlugin(frame, params); + + return webkit_support::CreateWebPlugin(frame, params); +} + +WebWorker* WebViewHost::createWorker(WebFrame*, WebSharedWorkerClient*) +{ + return new TestWebWorker(); +} + +WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client) +{ + return webkit_support::CreateMediaPlayer(frame, client); +} + +WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client) +{ + return webkit_support::CreateApplicationCacheHost(frame, client); +} + +void WebViewHost::loadURLExternally(WebFrame* frame, const WebURLRequest& request, WebNavigationPolicy policy) +{ + loadURLExternally(frame, request, policy, WebString()); +} + +void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy, const WebString& downloadName) +{ + ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab); + WebViewHost* another = m_shell->createNewWindow(request.url()); + if (another) + another->show(policy); +} + +WebNavigationPolicy WebViewHost::decidePolicyForNavigation( + WebFrame*, const WebURLRequest& request, + WebNavigationType type, const WebNode& originatingNode, + WebNavigationPolicy defaultPolicy, bool isRedirect) +{ + WebNavigationPolicy result; + if (!m_policyDelegateEnabled) + return defaultPolicy; + + printf("Policy delegate: attempt to load %s with navigation type '%s'", + URLDescription(request.url()).c_str(), webNavigationTypeToString(type)); + if (!originatingNode.isNull()) { + fputs(" originating from ", stdout); + printNodeDescription(originatingNode, 0); + } + fputs("\n", stdout); + if (m_policyDelegateIsPermissive) + result = WebKit::WebNavigationPolicyCurrentTab; + else + result = WebKit::WebNavigationPolicyIgnore; + + if (m_policyDelegateShouldNotifyDone) + layoutTestController()->policyDelegateDone(); + return result; +} + +bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request) +{ + GURL url = request.url(); + // Just reject the scheme used in + // LayoutTests/http/tests/misc/redirect-to-external-url.html + return !url.SchemeIs("spaceballs"); +} + +WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request) +{ + WebURLError error; + // A WebKit layout test expects the following values. + // unableToImplementPolicyWithError() below prints them. + error.domain = WebString::fromUTF8("WebKitErrorDomain"); + error.reason = 101; + error.unreachableURL = request.url(); + return error; +} + +WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request) +{ + return webkit_support::CreateCancelledError(request); +} + +void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error) +{ + printf("Policy delegate: unable to implement policy with error domain '%s', " + "error code %d, in frame '%s'\n", + error.domain.utf8().data(), error.reason, frame->name().utf8().data()); +} + +void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to, + double interval, double fire_time) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data()); + } + + if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks()) + printFrameUserGestureStatus(frame, " - in willPerformClientRedirect\n"); +} + +void WebViewHost::didCancelClientRedirect(WebFrame* frame) +{ + if (!m_shell->shouldDumpFrameLoadCallbacks()) + return; + printFrameDescription(frame); + fputs(" - didCancelClientRedirectForFrame\n", stdout); +} + +void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds) +{ + ds->setExtraData(m_pendingExtraData.leakPtr()); + if (!layoutTestController()->deferMainResourceDataLoad()) + ds->setDeferMainResourceDataLoad(false); +} + +void WebViewHost::didStartProvisionalLoad(WebFrame* frame) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didStartProvisionalLoadForFrame\n", stdout); + } + + if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks()) + printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n"); + + 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, WebTextDirection direction) +{ + 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); + layoutTestController()->setTitleTextDirection(direction); +} + +void WebViewHost::didFinishDocumentLoad(WebFrame* frame) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didFinishDocumentLoadForFrame\n", stdout); + } else { + unsigned pendingUnloadEvents = frame->unloadListenerCount(); + if (pendingUnloadEvents) { + printFrameDescription(frame); + printf(" - has %u onunload handler(s)\n", pendingUnloadEvents); + } + } +} + +void WebViewHost::didHandleOnloadEvents(WebFrame* frame) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didHandleOnloadEventsForFrame\n", stdout); + } +} + +void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didFailLoadWithError\n", stdout); + } + locationChangeDone(frame); +} + +void WebViewHost::didFinishLoad(WebFrame* frame) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didFinishLoadForFrame\n", stdout); + } + updateAddressBar(frame->view()); + locationChangeDone(frame); +} + +void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation) +{ + frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr()); + + updateForCommittedLoad(frame, isNewNavigation); +} + +void WebViewHost::didChangeLocationWithinPage(WebFrame* frame) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) { + printFrameDescription(frame); + fputs(" - didChangeLocationWithinPageForFrame\n", stdout); + } +} + +void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request) +{ + if (!m_shell->shouldDumpResourceLoadCallbacks()) + return; + ASSERT(!m_resourceIdentifierMap.contains(identifier)); + m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec())); +} + +void WebViewHost::removeIdentifierForRequest(unsigned identifier) +{ + m_resourceIdentifierMap.remove(identifier); +} + +void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse) +{ + // Need to use GURL for host() and SchemeIs() + GURL url = request.url(); + string requestURL = url.possibly_invalid_spec(); + + if (layoutTestController()->shouldDumpResourceLoadCallbacks()) { + GURL mainDocumentURL = request.firstPartyForCookies(); + printResourceDescription(identifier); + printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s," + " http method %s> redirectResponse ", + descriptionSuitableForTestResult(requestURL).c_str(), + URLDescription(mainDocumentURL).c_str(), + request.httpMethod().utf8().data()); + printResponseDescription(redirectResponse); + fputs("\n", stdout); + } + + if (!redirectResponse.isNull() && m_blocksRedirects) { + fputs("Returning null for this redirect\n", stdout); + // To block the request, we set its URL to an empty one. + request.setURL(WebURL()); + return; + } + + if (m_requestReturnNull) { + // To block the request, we set its URL to an empty one. + request.setURL(WebURL()); + return; + } + + string host = url.host(); + // 255.255.255.255 is used in some tests that expect to get back an error. + if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https")) + && host != "127.0.0.1" + && host != "255.255.255.255" + && host != "localhost" + && !m_shell->allowExternalPages()) { + printf("Blocked access to external URL %s\n", requestURL.c_str()); + + // To block the request, we set its URL to an empty one. + request.setURL(WebURL()); + return; + } + + HashSet<String>::const_iterator end = m_clearHeaders.end(); + for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header) + request.clearHTTPHeaderField(WebString(header->characters(), header->length())); + + // Set the new substituted URL. + request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec())); +} + +void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response) +{ + if (m_shell->shouldDumpResourceLoadCallbacks()) { + printResourceDescription(identifier); + fputs(" - didReceiveResponse ", stdout); + printResponseDescription(response); + fputs("\n", stdout); + } + if (m_shell->shouldDumpResourceResponseMIMETypes()) { + GURL url = response.url(); + WebString mimeType = response.mimeType(); + printf("%s has MIME type %s\n", + url.ExtractFileName().c_str(), + // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream + mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data()); + } +} + +void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier) +{ + if (m_shell->shouldDumpResourceLoadCallbacks()) { + printResourceDescription(identifier); + fputs(" - didFinishLoading\n", stdout); + } + removeIdentifierForRequest(identifier); +} + +void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error) +{ + if (m_shell->shouldDumpResourceLoadCallbacks()) { + printResourceDescription(identifier); + fputs(" - didFailLoadingWithError: ", stdout); + fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout); + fputs("\n", stdout); + } + removeIdentifierForRequest(identifier); +} + +void WebViewHost::didDisplayInsecureContent(WebFrame*) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) + fputs("didDisplayInsecureContent\n", stdout); +} + +void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) + fputs("didRunInsecureContent\n", stdout); +} + +void WebViewHost::didDetectXSS(WebFrame*, const WebURL&, bool) +{ + if (m_shell->shouldDumpFrameLoadCallbacks()) + fputs("didDetectXSS\n", stdout); +} + +void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks) +{ + webkit_support::OpenFileSystem(frame, type, size, create, callbacks); +} + +bool WebViewHost::willCheckAndDispatchMessageEvent(WebFrame* source, WebSecurityOrigin target, WebDOMMessageEvent event) +{ + if (m_shell->layoutTestController()->shouldInterceptPostMessage()) { + fputs("intercepted postMessage\n", stdout); + return true; + } + + return false; +} + +// Public functions ----------------------------------------------------------- + +WebViewHost::WebViewHost(TestShell* shell) + : m_shell(shell) + , m_webWidget(0) + , m_lastRequestedTextCheckingCompletion(0) +{ + reset(); +} + +WebViewHost::~WebViewHost() +{ + // DevTools frontend page is supposed to be navigated only once and + // loading another URL in that Page is an error. + if (m_shell->devToolsWebView() != this) { + // Navigate to an empty page to fire all the destruction logic for the + // current page. + loadURLForFrame(GURL("about:blank"), WebString()); + } + + for (Vector<WebKit::WebWidget*>::iterator it = m_popupmenus.begin(); + it < m_popupmenus.end(); ++it) + (*it)->close(); + + webWidget()->close(); + if (m_inModalLoop) + webkit_support::QuitMessageLoop(); +} + +void WebViewHost::setWebWidget(WebKit::WebWidget* widget) +{ + m_webWidget = widget; + webView()->setSpellCheckClient(this); +} + +WebView* WebViewHost::webView() const +{ + ASSERT(m_webWidget); + // DRT does not support popup widgets. So m_webWidget is always a WebView. + return static_cast<WebView*>(m_webWidget); +} + +WebWidget* WebViewHost::webWidget() const +{ + ASSERT(m_webWidget); + return m_webWidget; +} + +void WebViewHost::reset() +{ + m_policyDelegateEnabled = false; + m_policyDelegateIsPermissive = false; + m_policyDelegateShouldNotifyDone = false; + m_topLoadingFrame = 0; + m_pageId = -1; + m_lastPageIdUpdated = -1; + m_hasWindow = false; + m_inModalLoop = false; + m_smartInsertDeleteEnabled = true; + m_logConsoleOutput = true; +#if OS(WINDOWS) + m_selectTrailingWhitespaceEnabled = true; +#else + m_selectTrailingWhitespaceEnabled = false; +#endif + m_blocksRedirects = false; + m_requestReturnNull = false; + m_isPainting = false; + m_canvas.clear(); + + m_navigationController = adoptPtr(new TestNavigationController(this)); + + m_pendingExtraData.clear(); + m_resourceIdentifierMap.clear(); + m_clearHeaders.clear(); + m_editCommandName.clear(); + m_editCommandValue.clear(); + + if (m_geolocationClientMock.get()) + m_geolocationClientMock->resetMock(); + + if (m_speechInputControllerMock.get()) + m_speechInputControllerMock->clearResults(); + + m_currentCursor = WebCursorInfo(); + m_windowRect = WebRect(); + m_paintRect = WebRect(); + + if (m_webWidget) { + webView()->mainFrame()->setName(WebString()); + webView()->settings()->setMinimumTimerInterval(webkit_support::GetForegroundTabTimerInterval()); + } +} + +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::setLogConsoleOutput(bool enabled) +{ + m_logConsoleOutput = enabled; +} + +void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive) +{ + m_policyDelegateEnabled = isCustom; + m_policyDelegateIsPermissive = isPermissive; +} + +void WebViewHost::waitForPolicyDelegate() +{ + m_policyDelegateEnabled = true; + m_policyDelegateShouldNotifyDone = true; +} + +void WebViewHost::setEditCommand(const string& name, const string& value) +{ + m_editCommandName = name; + m_editCommandValue = value; +} + +void WebViewHost::clearEditCommand() +{ + m_editCommandName.clear(); + m_editCommandValue.clear(); +} + +void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName) +{ + if (!url.isValid()) + return; + TestShell::resizeWindowForTest(this, url); + navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), frameName).get()); +} + +bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload) +{ + // Get the right target frame for the entry. + WebFrame* frame = webView()->mainFrame(); + if (!entry.targetFrame().isEmpty()) + frame = webView()->findFrameByName(entry.targetFrame()); + + // TODO(mpcomplete): should we clear the target frame, or should + // back/forward navigations maintain the target frame? + + // A navigation resulting from loading a javascript URL should not be + // treated as a browser initiated event. Instead, we want it to look as if + // the page initiated any load resulting from JS execution. + if (!GURL(entry.URL()).SchemeIs("javascript")) + setPendingExtraData(adoptPtr(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(nullptr); + + // Restore focus to the main frame prior to loading new request. + // This makes sure that we don't have a focused iframe. Otherwise, that + // iframe would keep focus when the SetFocus called immediately after + // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 + // for more details). + webView()->setFocusedFrame(frame); + m_shell->setFocus(webView(), true); + + return true; +} + +// Private functions ---------------------------------------------------------- + +LayoutTestController* WebViewHost::layoutTestController() const +{ + return m_shell->layoutTestController(); +} + +void WebViewHost::updateAddressBar(WebView* webView) +{ + WebFrame* mainFrame = webView->mainFrame(); + WebDataSource* dataSource = mainFrame->dataSource(); + if (!dataSource) + dataSource = mainFrame->provisionalDataSource(); + if (!dataSource) + return; + + setAddressBarURL(dataSource->request().url()); +} + +void WebViewHost::locationChangeDone(WebFrame* frame) +{ + if (frame != m_topLoadingFrame) + return; + m_topLoadingFrame = 0; + layoutTestController()->locationChangeDone(); +} + +void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation) +{ + // Code duplicated from RenderView::DidCommitLoadForFrame. + TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData()); + + if (isNewNavigation) { + // New navigation. + updateSessionHistory(frame); + m_pageId = nextPageID++; + } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) { + // This is a successful session history navigation! + updateSessionHistory(frame); + m_pageId = extraData->pendingPageID; + } + + // Don't update session history multiple times. + if (extraData) + extraData->requestCommitted = true; + + updateURL(frame); +} + +void WebViewHost::updateURL(WebFrame* frame) +{ + WebDataSource* ds = frame->dataSource(); + ASSERT(ds); + const WebURLRequest& request = ds->request(); + RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create()); + + // The referrer will be empty on https->http transitions. It + // would be nice if we could get the real referrer from somewhere. + entry->setPageID(m_pageId); + if (ds->hasUnreachableURL()) + entry->setURL(ds->unreachableURL()); + else + entry->setURL(request.url()); + + const WebHistoryItem& historyItem = frame->currentHistoryItem(); + if (!historyItem.isNull()) + entry->setContentState(historyItem); + + navigationController()->didNavigateToEntry(entry.get()); + updateAddressBar(frame->view()); + m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId); +} + +void WebViewHost::updateSessionHistory(WebFrame* frame) +{ + // If we have a valid page ID at this point, then it corresponds to the page + // we are navigating away from. Otherwise, this is the first navigation, so + // there is no past session history to record. + if (m_pageId == -1) + return; + + TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId); + if (!entry) + return; + + const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem(); + if (historyItem.isNull()) + return; + + entry->setContentState(historyItem); +} + +void WebViewHost::printFrameDescription(WebFrame* webframe) +{ + string name8 = webframe->name().utf8(); + if (webframe == webView()->mainFrame()) { + if (!name8.length()) { + fputs("main frame", stdout); + return; + } + printf("main frame \"%s\"", name8.c_str()); + return; + } + if (!name8.length()) { + fputs("frame (anonymous)", stdout); + return; + } + printf("frame \"%s\"", name8.c_str()); +} + +void WebViewHost::printFrameUserGestureStatus(WebFrame* webframe, const char* msg) +{ + bool isUserGesture = webframe->isProcessingUserGesture(); + printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg); +} + +void WebViewHost::printResourceDescription(unsigned identifier) +{ + ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier); + printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>"); +} + +void WebViewHost::setPendingExtraData(PassOwnPtr<TestShellExtraData> extraData) +{ + m_pendingExtraData = extraData; +} + +void WebViewHost::setPageTitle(const WebString&) +{ + // Nothing to do in layout test. +} + +void WebViewHost::setAddressBarURL(const WebURL&) +{ + // Nothing to do in layout test. +} + +void WebViewHost::enterFullScreenNow() +{ + webView()->willEnterFullScreen(); + webView()->didEnterFullScreen(); +} + +void WebViewHost::exitFullScreenNow() +{ + webView()->willExitFullScreen(); + webView()->didExitFullScreen(); +} + +// 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 USE(CG) + webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect); + skia::EndPlatformPaint(canvas()); +#else + webWidget()->paint(canvas(), rect); +#endif + m_isPainting = false; +} + +void WebViewHost::paintInvalidatedRegion() +{ +#if ENABLE(REQUEST_ANIMATION_FRAME) + webWidget()->animate(0.0); +#endif + webWidget()->layout(); + WebSize widgetSize = webWidget()->size(); + WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); + + // Paint the canvas if necessary. Allow painting to generate extra rects + // for the first two calls. This is necessary because some WebCore rendering + // objects update their layout only when painted. + // Store the total area painted in total_paint. Then tell the gdk window + // to update that area after we're done painting it. + for (int i = 0; i < 3; ++i) { + // m_paintRect = intersect(m_paintRect , clientRect) + int left = max(m_paintRect.x, clientRect.x); + int top = max(m_paintRect.y, clientRect.y); + int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width); + int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height); + if (left >= right || top >= bottom) + m_paintRect = WebRect(); + else + m_paintRect = WebRect(left, top, right - left, bottom - top); + + if (m_paintRect.isEmpty()) + continue; + WebRect rect(m_paintRect); + m_paintRect = WebRect(); + paintRect(rect); + } + ASSERT(m_paintRect.isEmpty()); +} + +void WebViewHost::paintPagesWithBoundaries() +{ + ASSERT(!m_isPainting); + ASSERT(canvas()); + m_isPainting = true; + + WebSize pageSizeInPixels = webWidget()->size(); + WebFrame* webFrame = webView()->mainFrame(); + + int pageCount = webFrame->printBegin(pageSizeInPixels); + int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1; + + SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true); + if (testCanvas) { + discardBackingStore(); + m_canvas = adoptPtr(testCanvas); + } else { + webFrame->printEnd(); + return; + } + +#if WEBKIT_USING_SKIA + WebCanvas* webCanvas = canvas(); +#elif WEBKIT_USING_CG + const SkBitmap& canvasBitmap = canvas()->getDevice()->accessBitmap(false); + WebCanvas* webCanvas = CGBitmapContextCreate(canvasBitmap.getPixels(), + pageSizeInPixels.width, totalHeight, + 8, pageSizeInPixels.width * 4, + CGColorSpaceCreateDeviceRGB(), + kCGImageAlphaPremultipliedFirst | + kCGBitmapByteOrder32Host); + CGContextTranslateCTM(webCanvas, 0.0, totalHeight); + CGContextScaleCTM(webCanvas, 1.0, -1.0f); +#endif + + webFrame->printPagesWithBoundaries(webCanvas, pageSizeInPixels); + webFrame->printEnd(); + + m_isPainting = false; +} + +SkCanvas* WebViewHost::canvas() +{ + if (m_canvas) + return m_canvas.get(); + WebSize widgetSize = webWidget()->size(); + resetScrollRect(); + m_canvas = adoptPtr(skia::CreateBitmapCanvas(widgetSize.width, widgetSize.height, true)); + return m_canvas.get(); +} + +void WebViewHost::resetScrollRect() +{ +} + +void WebViewHost::discardBackingStore() +{ + m_canvas.clear(); +} + +// Paints the entire canvas a semi-transparent black (grayish). This is used +// by the layout tests in fast/repaint. The alpha value matches upstream. +void WebViewHost::displayRepaintMask() +{ + canvas()->drawARGB(167, 0, 0, 0); +} diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h new file mode 100644 index 000000000..0bc4c38e6 --- /dev/null +++ b/Tools/DumpRenderTree/chromium/WebViewHost.h @@ -0,0 +1,368 @@ +/* + * 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 "Task.h" +#include "TestNavigationController.h" +#include "WebAccessibilityNotification.h" +#include "WebCursorInfo.h" +#include "WebFrameClient.h" +#include "WebSpellCheckClient.h" +#include "WebViewClient.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +class LayoutTestController; +class SkCanvas; +class TestShell; + +namespace WebKit { +class WebFrame; +class WebDeviceOrientationClient; +class WebDeviceOrientationClientMock; +class WebGeolocationClient; +class WebGeolocationClientMock; +class WebGeolocationServiceMock; +class WebSharedWorkerClient; +class WebSpeechInputController; +class WebSpeechInputControllerMock; +class WebSpeechInputListener; +class WebURL; +struct WebRect; +struct WebURLError; +struct WebWindowFeatures; +} + +class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost { + public: + WebViewHost(TestShell*); + virtual ~WebViewHost(); + void setWebWidget(WebKit::WebWidget*); + WebKit::WebView* webView() const; + WebKit::WebWidget* webWidget() const; + void reset(); + void setSelectTrailingWhitespaceEnabled(bool); + void setSmartInsertDeleteEnabled(bool); + void setLogConsoleOutput(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(PassOwnPtr<TestShellExtraData>); + + void paintRect(const WebKit::WebRect&); + void updatePaintRect(const WebKit::WebRect&); + void paintInvalidatedRegion(); + void paintPagesWithBoundaries(); + SkCanvas* canvas(); + void displayRepaintMask(); + + void loadURLForFrame(const WebKit::WebURL&, const WebKit::WebString& frameName); + TestNavigationController* navigationController() { return m_navigationController.get(); } + + void addClearHeader(const WTF::String& header) { m_clearHeaders.add(header); } + const HashSet<WTF::String>& clearHeaders() const { return m_clearHeaders; } + void closeWidget(); + + WebKit::WebContextMenuData* lastContextMenuData() const; + void clearContextMenuData(); + + WebKit::WebSpeechInputControllerMock* speechInputControllerMock() { return m_speechInputControllerMock.get(); } + + // NavigationHost + virtual bool navigate(const TestNavigationEntry&, bool reload); + + // WebKit::WebSpellCheckClient + virtual void spellCheck(const WebKit::WebString&, int& offset, int& length, WebKit::WebVector<WebKit::WebString>* optionalSuggestions); + virtual void requestCheckingOfText(const WebKit::WebString&, WebKit::WebTextCheckingCompletion*); + virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&); + + // WebKit::WebViewClient + virtual WebKit::WebView* createView(WebKit::WebFrame*, const WebKit::WebURLRequest&, const WebKit::WebWindowFeatures&, const WebKit::WebString&); + virtual WebKit::WebWidget* createPopupMenu(WebKit::WebPopupType); + virtual WebKit::WebWidget* createPopupMenu(const WebKit::WebPopupMenuInfo&); + virtual WebKit::WebStorageNamespace* createSessionStorageNamespace(unsigned quota); + virtual void didAddMessageToConsole(const WebKit::WebConsoleMessage&, const WebKit::WebString& sourceName, unsigned sourceLine); + virtual void didStartLoading(); + virtual void didStopLoading(); + virtual bool shouldBeginEditing(const WebKit::WebRange&); + virtual bool shouldEndEditing(const WebKit::WebRange&); + virtual bool shouldInsertNode(const WebKit::WebNode&, const WebKit::WebRange&, WebKit::WebEditingAction); + virtual bool shouldInsertText(const WebKit::WebString&, const WebKit::WebRange&, WebKit::WebEditingAction); + virtual bool shouldChangeSelectedRange(const WebKit::WebRange& from, const WebKit::WebRange& to, WebKit::WebTextAffinity, bool stillSelecting); + virtual bool shouldDeleteRange(const WebKit::WebRange&); + virtual bool shouldApplyStyle(const WebKit::WebString& style, const WebKit::WebRange&); + virtual bool isSmartInsertDeleteEnabled(); + virtual bool isSelectTrailingWhitespaceEnabled(); + virtual void didBeginEditing(); + virtual void didChangeSelection(bool isSelectionEmpty); + virtual void didChangeContents(); + virtual void didEndEditing(); + virtual bool handleCurrentKeyboardEvent(); + virtual void runModalAlertDialog(WebKit::WebFrame*, const WebKit::WebString&); + virtual bool runModalConfirmDialog(WebKit::WebFrame*, const WebKit::WebString&); + virtual bool runModalPromptDialog(WebKit::WebFrame*, const WebKit::WebString& message, const WebKit::WebString& defaultValue, WebKit::WebString* actualValue); + virtual bool runModalBeforeUnloadDialog(WebKit::WebFrame*, const WebKit::WebString&); + virtual void showContextMenu(WebKit::WebFrame*, const WebKit::WebContextMenuData&); + virtual void setStatusText(const WebKit::WebString&); + virtual void startDragging(const WebKit::WebDragData&, WebKit::WebDragOperationsMask, const WebKit::WebImage&, const WebKit::WebPoint&); + virtual void didUpdateLayout(); + virtual void navigateBackForwardSoon(int offset); + virtual int historyBackListCount(); + virtual int historyForwardListCount(); + virtual void postAccessibilityNotification(const WebKit::WebAccessibilityObject&, WebKit::WebAccessibilityNotification); + virtual WebKit::WebNotificationPresenter* notificationPresenter(); + virtual WebKit::WebGeolocationClient* geolocationClient(); + virtual WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*); + virtual WebKit::WebDeviceOrientationClient* deviceOrientationClient(); + + // WebKit::WebWidgetClient + virtual void didInvalidateRect(const WebKit::WebRect&); + virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&); + virtual void scheduleComposite(); +#if ENABLE(REQUEST_ANIMATION_FRAME) + virtual void scheduleAnimation(); +#endif + virtual void didFocus(); + virtual void didBlur(); + virtual void didChangeCursor(const WebKit::WebCursorInfo&); + virtual void closeWidgetSoon(); + virtual void show(WebKit::WebNavigationPolicy); + virtual void runModal(); + virtual bool enterFullScreen(); + virtual void exitFullScreen(); + 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::WebSharedWorkerClient*); + virtual WebKit::WebMediaPlayer* createMediaPlayer(WebKit::WebFrame*, WebKit::WebMediaPlayerClient*); + virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebFrame*, WebKit::WebApplicationCacheHostClient*); + virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy); + virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy, const WebKit::WebString& downloadName); + 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&, WebKit::WebTextDirection); + virtual void didFinishDocumentLoad(WebKit::WebFrame*); + virtual void didHandleOnloadEvents(WebKit::WebFrame*); + virtual void didFailLoad(WebKit::WebFrame*, const WebKit::WebURLError&); + virtual void didFinishLoad(WebKit::WebFrame*); + virtual void didNavigateWithinPage(WebKit::WebFrame*, bool isNewNavigation); + virtual void didChangeLocationWithinPage(WebKit::WebFrame*); + virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&); + virtual void removeIdentifierForRequest(unsigned identifier); + virtual void willSendRequest(WebKit::WebFrame*, unsigned identifier, WebKit::WebURLRequest&, const WebKit::WebURLResponse&); + virtual void didReceiveResponse(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLResponse&); + virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier); + virtual void didFailResourceLoad(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLError&); + virtual void didDisplayInsecureContent(WebKit::WebFrame*); + virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&, const WebKit::WebURL&); + virtual void didDetectXSS(WebKit::WebFrame*, const WebKit::WebURL&, bool didBlockEntirePage); + virtual void openFileSystem(WebKit::WebFrame*, WebKit::WebFileSystem::Type, long long size, bool create, WebKit::WebFileSystemCallbacks*); + virtual bool willCheckAndDispatchMessageEvent(WebKit::WebFrame* source, WebKit::WebSecurityOrigin target, WebKit::WebDOMMessageEvent); + + WebKit::WebDeviceOrientationClientMock* deviceOrientationClientMock(); + + // Spellcheck related helper APIs + MockSpellCheck* mockSpellCheck(); + void finishLastTextCheck(); + + // Geolocation client mocks for LayoutTestController + WebKit::WebGeolocationClientMock* geolocationClientMock(); + + // Pending task list, Note taht the method is referred from MethodTask class. + TaskList* taskList() { return &m_taskList; } + +private: + + class HostMethodTask : public MethodTask<WebViewHost> { + public: + typedef void (WebViewHost::*CallbackMethodType)(); + HostMethodTask(WebViewHost* object, CallbackMethodType callback) + : MethodTask<WebViewHost>(object) + , m_callback(callback) + { } + + virtual void runIfValid() { (m_object->*m_callback)(); } + + private: + CallbackMethodType m_callback; + }; + + 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&); + + void enterFullScreenNow(); + void exitFullScreenNow(); + + // In the Mac code, this is called to trigger the end of a test after the + // page has finished loading. From here, we can generate the dump for the + // test. + void locationChangeDone(WebKit::WebFrame*); + + void updateForCommittedLoad(WebKit::WebFrame*, bool isNewNavigation); + void updateURL(WebKit::WebFrame*); + void updateSessionHistory(WebKit::WebFrame*); + + // Dumping a frame to the console. + void printFrameDescription(WebKit::WebFrame*); + + // Dumping the user gesture status to the console. + void printFrameUserGestureStatus(WebKit::WebFrame*, const char*); + + bool hasWindow() const { return m_hasWindow; } + void resetScrollRect(); + void discardBackingStore(); + + // Causes navigation actions just printout the intended navigation instead + // of taking you to the page. This is used for cases like mailto, where you + // don't actually want to open the mail program. + bool m_policyDelegateEnabled; + + // Toggles the behavior of the policy delegate. If true, then navigations + // will be allowed. Otherwise, they will be ignored (dropped). + bool m_policyDelegateIsPermissive; + + // If true, the policy delegate will signal layout test completion. + bool m_policyDelegateShouldNotifyDone; + + // Non-owning pointer. The WebViewHost instance is owned by this TestShell instance. + TestShell* m_shell; + + // This delegate works for the following widget. + WebKit::WebWidget* m_webWidget; + + // This is non-0 IFF a load is in progress. + WebKit::WebFrame* m_topLoadingFrame; + + // For tracking session history. See RenderView. + int m_pageId; + int m_lastPageIdUpdated; + + OwnPtr<TestShellExtraData> m_pendingExtraData; + + // Maps resource identifiers to a descriptive string. + typedef HashMap<unsigned, std::string> ResourceMap; + ResourceMap m_resourceIdentifierMap; + void printResourceDescription(unsigned identifier); + + WebKit::WebCursorInfo m_currentCursor; + + bool m_hasWindow; + bool m_inModalLoop; + WebKit::WebRect m_windowRect; + + // true if we want to enable smart insert/delete. + bool m_smartInsertDeleteEnabled; + + // true if we want to enable selection of trailing whitespaces + bool m_selectTrailingWhitespaceEnabled; + + // true if whatever is sent to the console should be logged to stdout. + bool m_logConsoleOutput; + + // Set of headers to clear in willSendRequest. + HashSet<WTF::String> m_clearHeaders; + + // true if we should block any redirects + bool m_blocksRedirects; + + // true if we should block (set an empty request for) any requests + bool m_requestReturnNull; + + // Edit command associated to the current keyboard event. + std::string m_editCommandName; + std::string m_editCommandValue; + + // The mock spellchecker used in spellCheck(). + MockSpellCheck m_spellcheck; + + // Painting. + OwnPtr<SkCanvas> m_canvas; + WebKit::WebRect m_paintRect; + bool m_isPainting; + + OwnPtr<WebKit::WebContextMenuData> m_lastContextMenuData; + + // Geolocation + OwnPtr<WebKit::WebGeolocationClientMock> m_geolocationClientMock; + + OwnPtr<WebKit::WebDeviceOrientationClientMock> m_deviceOrientationClientMock; + OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock; + + OwnPtr<TestNavigationController> m_navigationController; + + WebKit::WebString m_lastRequestedTextCheckString; + WebKit::WebTextCheckingCompletion* m_lastRequestedTextCheckingCompletion; + + TaskList m_taskList; + Vector<WebKit::WebWidget*> m_popupmenus; +}; + +#endif // WebViewHost_h diff --git a/Tools/DumpRenderTree/chromium/config.h b/Tools/DumpRenderTree/chromium/config.h new file mode 100644 index 000000000..57b3a54fc --- /dev/null +++ b/Tools/DumpRenderTree/chromium/config.h @@ -0,0 +1,53 @@ +/* + * 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> +#include <wtf/ExportMacros.h> + +#if OS(WINDOWS) && !COMPILER(GCC) +// Allow 'this' to be used in base member initializer list. +#pragma warning(disable : 4355) +#endif + +#endif // config_h diff --git a/Tools/DumpRenderTree/chromium/fonts.conf b/Tools/DumpRenderTree/chromium/fonts.conf new file mode 100644 index 000000000..b75a9322e --- /dev/null +++ b/Tools/DumpRenderTree/chromium/fonts.conf @@ -0,0 +1,229 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<!-- /etc/fonts/fonts.conf file to configure system font access --> +<fontconfig> + <match target="font"> + <edit name="embeddedbitmap" mode="assign"><bool>false</bool></edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>Times</string> + </test> + <edit name="family" mode="assign"> + <string>Times New Roman</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>sans</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>sans serif</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + </match> + + <!-- Some layout tests specify Helvetica as a family and we need to make sure + that we don't fallback to Times New Roman for them --> + <match target="pattern"> + <test qual="any" name="family"> + <string>Helvetica</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>sans-serif</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>serif</string> + </test> + <edit name="family" mode="assign"> + <string>Times New Roman</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>mono</string> + </test> + <edit name="family" mode="assign"> + <string>Courier New</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>monospace</string> + </test> + <edit name="family" mode="assign"> + <string>Courier New</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>Courier</string> + </test> + <edit name="family" mode="assign"> + <string>Courier New</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>cursive</string> + </test> + <edit name="family" mode="assign"> + <string>Comic Sans MS</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>fantasy</string> + </test> + <edit name="family" mode="assign"> + <string>Impact</string> + </edit> + </match> + + <match target="pattern"> + <test qual="any" name="family"> + <string>Monaco</string> + </test> + <edit name="family" mode="assign"> + <string>Times New Roman</string> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonAntiAliasedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="antialias" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SlightHintedGeorgia</string> + </test> + <edit name="family" mode="assign"> + <string>Georgia</string> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintslight</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonHintedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Verdana</string> + </edit> + <!-- These deliberately contradict each other. The 'hinting' preference + should take priority --> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>AutohintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>HintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="autohint" mode="assign"> + <bool>false</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>FullAndAutoHintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelEnabledArial</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="rgba" mode="assign"> + <const>rgb</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelDisabledArial</string> + </test> + <edit name="family" mode="assign"> + <string>Arial</string> + </edit> + <edit name="rgba" mode="assign"> + <const>none</const> + </edit> + </match> + +</fontconfig> diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h new file mode 100644 index 000000000..d52cd84de --- /dev/null +++ b/Tools/DumpRenderTree/config.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 Nuanti Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#define Config_H + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#if defined(BUILDING_WITH_CMAKE) +#include "cmakeconfig.h" +#else +#include "autotoolsconfig.h" +#endif +#endif + +#include <wtf/Platform.h> +#include <wtf/ExportMacros.h> +#if USE(JSC) +#include <runtime/JSExportMacros.h> +#endif + +// On MSW, wx headers need to be included before windows.h is. +// The only way we can always ensure this is if we include wx here. +#if PLATFORM(WX) +#include <wx/defs.h> +#endif + + +#ifdef __cplusplus +#undef new +#undef delete +#include <wtf/FastMalloc.h> +#endif + +#if PLATFORM(MAC) +#define WTF_USE_CF 1 + +#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 +#define BUILDING_ON_LEOPARD 1 +#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 +#define BUILDING_ON_SNOW_LEOPARD 1 +#endif +#endif // PLATFORM(MAC) + +#if OS(WINDOWS) +// If we don't define these, they get defined in windef.h. +// We want to use std::min and std::max +#undef max +#define max max +#undef min +#define min min +#endif + +#if PLATFORM(WIN) +#define WTF_USE_CF 1 +#if PLATFORM(WIN_CAIRO) +#define WTF_USE_CAIRO 1 +#define WTF_USE_CURL 1 +#else +#define WTF_USE_CG 1 +#define WTF_USE_CFNETWORK 1 +#endif + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 + +#undef WINVER +#define WINVER 0x0500 + +#undef _WINSOCKAPI_ +#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h +#endif // PLATFORM(WIN) diff --git a/Tools/DumpRenderTree/efl/CMakeLists.txt b/Tools/DumpRenderTree/efl/CMakeLists.txt new file mode 100644 index 000000000..c929191b2 --- /dev/null +++ b/Tools/DumpRenderTree/efl/CMakeLists.txt @@ -0,0 +1,132 @@ +SET(DumpRenderTree_SOURCES + ${TOOLS_DIR}/DumpRenderTree/CyclicRedundancyCheck.cpp + ${TOOLS_DIR}/DumpRenderTree/GCController.cpp + ${TOOLS_DIR}/DumpRenderTree/LayoutTestController.cpp + ${TOOLS_DIR}/DumpRenderTree/PixelDumpSupport.cpp + ${TOOLS_DIR}/DumpRenderTree/WorkQueue.cpp + ${TOOLS_DIR}/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpHistoryItem.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTree.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeChrome.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeView.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/EventSender.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/FontManagement.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/GCControllerEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/JSStringUtils.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/LayoutTestControllerEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/PixelDumpSupportEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/WorkQueueItemEfl.cpp +) + +SET(ImageDiff_SOURCES + ${TOOLS_DIR}/DumpRenderTree/efl/ImageDiff.cpp +) + +SET(DumpRenderTree_LIBRARIES + ${JavaScriptCore_LIBRARY_NAME} + ${WebCore_LIBRARY_NAME} + ${WebKit_LIBRARY_NAME} + ${Cairo_LIBRARIES} + ${ECORE_X_LIBRARIES} + ${EDJE_LIBRARIES} + ${EFLDEPS_LIBRARIES} + ${EVAS_LIBRARIES} + ${LIBXML2_LIBRARIES} + ${LIBXSLT_LIBRARIES} + ${SQLITE_LIBRARIES} +) + +SET(DumpRenderTree_LIBRARIES ${DumpRenderTree_LIBRARIES}) +SET(DumpRenderTree_INCLUDE_DIRECTORIES + "${WEBKIT_DIR}/efl/ewk" + ${WEBKIT_DIR}/efl + ${WEBCORE_DIR} + ${WEBCORE_DIR}/bridge + ${WEBCORE_DIR}/bridge/jsc + ${WEBCORE_DIR}/bindings + ${WEBCORE_DIR}/dom + ${WEBCORE_DIR}/editing + ${WEBCORE_DIR}/css + ${WEBCORE_DIR}/html + ${WEBCORE_DIR}/page + ${WEBCORE_DIR}/page/animation + ${WEBCORE_DIR}/platform + ${WEBCORE_DIR}/platform/animation + ${WEBCORE_DIR}/platform/text + ${WEBCORE_DIR}/platform/graphics + ${WEBCORE_DIR}/platform/graphics/cairo + ${WEBCORE_DIR}/platform/network + ${WEBCORE_DIR}/plugins + ${WEBCORE_DIR}/rendering + ${WEBCORE_DIR}/rendering/style + ${WEBCORE_DIR}/history + ${WEBCORE_DIR}/loader + ${WEBCORE_DIR}/loader/cache + ${WEBCORE_DIR}/loader/icon + ${JAVASCRIPTCORE_DIR} + ${JAVASCRIPTCORE_DIR}/API + ${JAVASCRIPTCORE_DIR}/assembler + ${JAVASCRIPTCORE_DIR}/dfg + ${JAVASCRIPTCORE_DIR}/heap + ${JAVASCRIPTCORE_DIR}/interpreter + ${JAVASCRIPTCORE_DIR}/jit + ${JAVASCRIPTCORE_DIR}/runtime + ${JAVASCRIPTCORE_DIR}/ForwardingHeaders + ${JAVASCRIPTCORE_DIR}/wtf + ${JAVASCRIPTCORE_DIR}/wtf/efl + ${TOOLS_DIR}/DumpRenderTree + ${TOOLS_DIR}/DumpRenderTree/cairo + ${TOOLS_DIR}/DumpRenderTree/efl + ${CMAKE_SOURCE_DIR}/Source + ${CMAKE_BINARY_DIR} + ${DERIVED_SOURCES_WEBCORE_DIR} + ${WEBCORE_DIR}/bindings/js + ${Cairo_INCLUDE_DIRS} + ${EDJE_INCLUDE_DIRS} + ${EFLDEPS_INCLUDE_DIRS} + ${EVAS_INCLUDE_DIRS} +) + +SET(DumpRenderTree_LINK_FLAGS + ${ECORE_X_LDFLAGS} + ${EDJE_LDFLAGS} + ${EFLDEPS_LDFLAGS} + ${EVAS_LDFLAGS} +) + +IF (ENABLE_GLIB_SUPPORT) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/wtf/gobject") + + LIST(APPEND DumpRenderTree_LIBRARIES + ${Gdk_LIBRARIES} + ${Glib_LIBRARIES} + ${Gthread_LIBRARIES} + ) +ENDIF () + +IF (WTF_USE_SOUP) + LIST(APPEND DumpRenderTree_LIBRARIES ${LIBSOUP24_LIBRARIES}) + LIST(APPEND DumpRenderTree_LINK_FLAGS ${LIBSOUP24_LDFLAGS}) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${LIBSOUP24_INCLUDE_DIRS} ${WEBCORE_DIR}/platform/network/soup) +ENDIF () + +IF (WTF_USE_CURL) + LIST(APPEND DumpRenderTree_LIBRARIES ${CURL_LIBRARIES}) + LIST(APPEND DumpRenderTree_LINK_FLAGS ${CURL_LDFLAGS}) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${WEBCORE_DIR}/platform/network/curl) +ENDIF () + +ADD_DEFINITIONS(-DFONTS_CONF_DIR="${TOOLS_DIR}/DumpRenderTree/gtk/fonts" + -DDATA_DIR="${THEME_BINARY_DIR}") + +INCLUDE_DIRECTORIES(${DumpRenderTree_INCLUDE_DIRECTORIES}) + +ADD_EXECUTABLE(Programs/DumpRenderTree ${DumpRenderTree_SOURCES}) +TARGET_LINK_LIBRARIES(Programs/DumpRenderTree ${DumpRenderTree_LIBRARIES}) +ADD_TARGET_PROPERTIES(Programs/DumpRenderTree LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}") +SET_TARGET_PROPERTIES(Programs/DumpRenderTree PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") + +ADD_EXECUTABLE(Programs/ImageDiff ${ImageDiff_SOURCES}) +TARGET_LINK_LIBRARIES(Programs/ImageDiff ${DumpRenderTree_LIBRARIES}) +ADD_TARGET_PROPERTIES(Programs/ImageDiff LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}") +SET_TARGET_PROPERTIES(Programs/ImageDiff PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp new file mode 100644 index 000000000..125b12847 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpHistoryItem.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <algorithm> +#include <cstdio> +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +Ewk_History_Item* prevTestBFItem = 0; +const unsigned historyItemIndent = 8; + +static bool compareHistoryItemsByTarget(const Ewk_History_Item* item1, const Ewk_History_Item* item2) +{ + return WTF::codePointCompare(DumpRenderTreeSupportEfl::historyItemTarget(item1), + DumpRenderTreeSupportEfl::historyItemTarget(item2)) < 1; +} + +static void dumpHistoryItem(const Ewk_History_Item* item, int indent, bool current) +{ + ASSERT(item); + int start = 0; + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + // normalize file URLs. + const char* uri = ewk_history_item_uri_get(item); + if (!strncasecmp(uri, "file://", sizeof("file://") - 1)) { + const char* pos = strstr(uri, "/LayoutTests/"); + if (!pos) + return; + + printf("(file test):%s", pos + sizeof("/LayoutTests/") - 1); + } else + printf("%s", uri); + + const String target = DumpRenderTreeSupportEfl::historyItemTarget(item); + if (!target.isEmpty()) + printf(" (in frame \"%s\")", target.utf8().data()); + if (DumpRenderTreeSupportEfl::isTargetItem(item)) + printf(" **nav target**"); + putchar('\n'); + + HistoryItemChildrenVector children = DumpRenderTreeSupportEfl::childHistoryItems(item); + + // Must sort to eliminate arbitrary result ordering which defeats reproducible testing. + std::stable_sort(children.begin(), children.end(), compareHistoryItemsByTarget); + + const size_t size = children.size(); + for (size_t i = 0; i < size; ++i) + dumpHistoryItem(children[i], indent + 4, false); +} + +static void dumpBackForwardListForWebView(Evas_Object* view) +{ + printf("\n============== Back Forward List ==============\n"); + + const Ewk_History* history = ewk_view_history_get(view); + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + Eina_List* itemsToPrint = 0; + void* historyItem; + Eina_List* backwardList = ewk_history_back_list_get(history); + EINA_LIST_FREE(backwardList, historyItem) { + if (historyItem == prevTestBFItem) { + eina_list_free(backwardList); + break; + } + itemsToPrint = eina_list_append(itemsToPrint, historyItem); + } + + const Ewk_History_Item* currentItem = ewk_history_history_item_current_get(history); + if (currentItem) + itemsToPrint = eina_list_append(itemsToPrint, currentItem); + + Eina_List* forwardList = ewk_history_forward_list_get(history); + EINA_LIST_FREE(forwardList, historyItem) { + ASSERT(historyItem != prevTestBFItem); + itemsToPrint = eina_list_append(itemsToPrint, historyItem); + } + + EINA_LIST_FREE(itemsToPrint, historyItem) { + dumpHistoryItem(static_cast<Ewk_History_Item*>(historyItem), historyItemIndent, historyItem == currentItem); + ewk_history_item_free(static_cast<Ewk_History_Item*>(historyItem)); + } + + printf("===============================================\n"); +} + +void dumpBackForwardListForWebViews() +{ + // Dump the back forward list of the main WebView first + dumpBackForwardListForWebView(browser->mainView()); + + Vector<Evas_Object*>::const_iterator it = browser->extraViews().begin(); + for (; it != browser->extraViews().end(); ++it) + dumpBackForwardListForWebView(*it); +} diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.h b/Tools/DumpRenderTree/efl/DumpHistoryItem.h new file mode 100644 index 000000000..ea8afeaaf --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 DumpHistoryItem_h +#define DumpHistoryItem_h + +#include <Evas.h> + +void dumpBackForwardListForWebViews(); + +#endif // DumpHistoryItem_h diff --git a/Tools/DumpRenderTree/efl/DumpRenderTree.cpp b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp new file mode 100644 index 000000000..bb8f7d2d7 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpRenderTree.h" + +#include "DumpHistoryItem.h" +#include "DumpRenderTreeChrome.h" +#include "DumpRenderTreeView.h" +#include "EventSender.h" +#include "FontManagement.h" +#include "LayoutTestController.h" +#include "NotImplemented.h" +#include "PixelDumpSupport.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "WorkQueue.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <Ecore.h> +#include <Ecore_Evas.h> +#include <Ecore_File.h> +#include <Edje.h> +#include <Evas.h> +#include <fontconfig/fontconfig.h> +#include <getopt.h> +#include <stdlib.h> +#include <text/CString.h> +#include <unistd.h> +#include <wtf/OwnPtr.h> + +OwnPtr<DumpRenderTreeChrome> browser; +Evas_Object* topLoadingFrame = 0; +bool waitForPolicy = false; +Ecore_Timer* waitToDumpWatchdog = 0; +extern Ewk_History_Item* prevTestBFItem; + +// From the top-level DumpRenderTree.h +RefPtr<LayoutTestController> gLayoutTestController; +volatile bool done = false; + +static int dumpPixels = false; +static int dumpTree = true; +static int printSeparators = true; +static int useX11Window = false; + +static String dumpFramesAsText(Evas_Object* frame) +{ + String result; + + if (browser->mainFrame() != frame) { + result.append("\n--------\nFrame: '"); + result.append(String::fromUTF8(ewk_frame_name_get(frame))); + result.append("'\n--------\n"); + } + + char* frameContents = ewk_frame_plain_text_get(frame); + result.append(String::fromUTF8(frameContents)); + result.append("\n"); + free(frameContents); + + if (gLayoutTestController->dumpChildFramesAsText()) { + Eina_List* children = DumpRenderTreeSupportEfl::frameChildren(frame); + void* iterator; + + EINA_LIST_FREE(children, iterator) { + Evas_Object* currentFrame = static_cast<Evas_Object*>(iterator); + String tempText(dumpFramesAsText(currentFrame)); + + if (tempText.isEmpty()) + continue; + + result.append(tempText); + } + } + + return result; +} + +static void dumpFrameScrollPosition(Evas_Object*) +{ + notImplemented(); +} + +static bool shouldLogFrameLoadDelegates(const String& pathOrURL) +{ + return pathOrURL.contains("loading/"); +} + +static bool shouldDumpAsText(const String& pathOrURL) +{ + return pathOrURL.contains("dumpAsText/"); +} + +static void sendPixelResultsEOF() +{ + puts("#EOF"); + fflush(stdout); + fflush(stderr); +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + ecore_timer_del(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } + waitForPolicy = false; +} + +static void onEcoreEvasResize(Ecore_Evas* ecoreEvas) +{ + int width, height; + + ecore_evas_geometry_get(ecoreEvas, 0, 0, &width, &height); + evas_object_move(browser->mainView(), 0, 0); + evas_object_resize(browser->mainView(), width, height); +} + +static void onCloseWindow(Ecore_Evas*) +{ + notImplemented(); +} + +static Eina_Bool useLongRunningServerMode(int argc, char** argv) +{ + return (argc == optind + 1 && !strcmp(argv[optind], "-")); +} + +static bool parseCommandLineOptions(int argc, char** argv) +{ + static const option options[] = { + {"notree", no_argument, &dumpTree, false}, + {"pixel-tests", no_argument, &dumpPixels, true}, + {"tree", no_argument, &dumpTree, true}, + {"gui", no_argument, &useX11Window, true}, + {0, 0, 0, 0} + }; + + int option; + while ((option = getopt_long(argc, (char* const*)argv, "", options, 0)) != -1) { + switch (option) { + case '?': + case ':': + return false; + } + } + + return true; +} + +static String getFinalTestURL(const String& testURL) +{ + const size_t hashSeparatorPos = testURL.find("'"); + if (hashSeparatorPos != notFound) + return getFinalTestURL(testURL.left(hashSeparatorPos)); + + // Convert the path into a full file URL if it does not look + // like an HTTP/S URL (doesn't start with http:// or https://). + if (!testURL.startsWith("http://") && !testURL.startsWith("https://")) { + char* cFilePath = ecore_file_realpath(testURL.utf8().data()); + const String filePath = String::fromUTF8(cFilePath); + free(cFilePath); + + if (ecore_file_exists(filePath.utf8().data())) + return String("file://") + filePath; + } + + return testURL; +} + +static String getExpectedPixelHash(const String& testURL) +{ + const size_t hashSeparatorPos = testURL.find("'"); + return (hashSeparatorPos != notFound) ? testURL.substring(hashSeparatorPos + 1) : String(); +} + +static void createLayoutTestController(const String& testURL, const String& expectedPixelHash) +{ + gLayoutTestController = + LayoutTestController::create(std::string(testURL.utf8().data()), + std::string(expectedPixelHash.utf8().data())); + + topLoadingFrame = 0; + done = false; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (shouldLogFrameLoadDelegates(testURL)) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + gLayoutTestController->setDeveloperExtrasEnabled(true); + + if (shouldDumpAsText(testURL)) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } +} + +static void runTest(const char* cTestPathOrURL) +{ + const String testPathOrURL = String::fromUTF8(cTestPathOrURL); + ASSERT(!testPathOrURL.isEmpty()); + + const String testURL = getFinalTestURL(testPathOrURL); + const String expectedPixelHash = getExpectedPixelHash(testPathOrURL); + + browser->resetDefaultsToConsistentValues(); + createLayoutTestController(testURL, expectedPixelHash); + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + const bool isSVGW3CTest = testURL.contains("svg/W3C-SVG-1.1"); + const int width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth; + const int height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight; + evas_object_resize(browser->mainView(), width, height); + + if (prevTestBFItem) + ewk_history_item_free(prevTestBFItem); + const Ewk_History* history = ewk_view_history_get(browser->mainView()); + prevTestBFItem = ewk_history_history_item_current_get(history); + + evas_object_focus_set(browser->mainView(), EINA_TRUE); + ewk_view_uri_set(browser->mainView(), testURL.utf8().data()); + + ecore_main_loop_begin(); + + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + + ewk_view_uri_set(browser->mainView(), "about:blank"); + + gLayoutTestController.clear(); + sendPixelResultsEOF(); +} + +static void runTestingServerLoop() +{ + char filename[PATH_MAX]; + + while (fgets(filename, sizeof(filename), stdin)) { + char* newLine = strrchr(filename, '\n'); + if (newLine) + *newLine = '\0'; + + if (filename[0] != '\0') + runTest(filename); + } +} + +static void adjustOutputTypeByMimeType(const Evas_Object* frame) +{ + const String responseMimeType(DumpRenderTreeSupportEfl::responseMimeType(frame)); + if (responseMimeType == "text/plain") { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } +} + +static void dumpFrameContentsAsText(Evas_Object* frame) +{ + String result; + if (gLayoutTestController->dumpAsText()) + result = dumpFramesAsText(frame); + else + result = DumpRenderTreeSupportEfl::renderTreeDump(frame); + + printf("%s", result.utf8().data()); +} + +static bool shouldDumpFrameScrollPosition() +{ + return gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive(); +} + +static bool shouldDumpPixelsAndCompareWithExpected() +{ + return dumpPixels && gLayoutTestController->generatePixelResults() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive(); +} + +static bool shouldDumpBackForwardList() +{ + return gLayoutTestController->dumpBackForwardList(); +} + +static bool initEfl() +{ + if (!ecore_evas_init()) + return false; + if (!ecore_file_init()) { + ecore_evas_shutdown(); + return false; + } + if (!edje_init()) { + ecore_file_shutdown(); + ecore_evas_shutdown(); + return false; + } + if (!ewk_init()) { + edje_shutdown(); + ecore_file_shutdown(); + ecore_evas_shutdown(); + return false; + } + + return true; +} + +static void shutdownEfl() +{ + ewk_shutdown(); + edje_shutdown(); + ecore_file_shutdown(); + ecore_evas_shutdown(); +} + +void displayWebView() +{ + notImplemented(); +} + +void dump() +{ + Evas_Object* frame = browser->mainFrame(); + + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (dumpTree) { + adjustOutputTypeByMimeType(frame); + dumpFrameContentsAsText(frame); + + if (shouldDumpFrameScrollPosition()) + dumpFrameScrollPosition(frame); + + if (shouldDumpBackForwardList()) + dumpBackForwardListForWebViews(); + + if (printSeparators) { + puts("#EOF"); + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (shouldDumpPixelsAndCompareWithExpected()) + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + done = true; + ecore_main_loop_quit(); +} + +static Ecore_Evas* initEcoreEvas() +{ + Ecore_Evas* ecoreEvas = useX11Window ? ecore_evas_new(0, 0, 0, 800, 600, 0) : ecore_evas_buffer_new(800, 600); + if (!ecoreEvas) { + shutdownEfl(); + exit(EXIT_FAILURE); + } + + ecore_evas_title_set(ecoreEvas, "EFL DumpRenderTree"); + ecore_evas_callback_resize_set(ecoreEvas, onEcoreEvasResize); + ecore_evas_callback_delete_request_set(ecoreEvas, onCloseWindow); + ecore_evas_show(ecoreEvas); + + return ecoreEvas; +} + +int main(int argc, char** argv) +{ + if (!parseCommandLineOptions(argc, argv)) + return EXIT_FAILURE; + + if (!initEfl()) + return EXIT_FAILURE; + + OwnPtr<Ecore_Evas> ecoreEvas = adoptPtr(initEcoreEvas()); + browser = DumpRenderTreeChrome::create(ecore_evas_get(ecoreEvas.get())); + addFontsToEnvironment(); + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = true; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc - 1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + ecoreEvas.clear(); + + shutdownEfl(); + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp new file mode 100644 index 000000000..ce7a00d9f --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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 + * HOLDERS OR ITS 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 "DumpRenderTreeChrome.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeView.h" +#include "EventSender.h" +#include "GCController.h" +#include "LayoutTestController.h" +#include "NotImplemented.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "WorkQueue.h" +#include "ewk_private.h" // FIXME: create some WebCoreSupport/DumpRenderTree.cpp instead + +#include <EWebKit.h> +#include <Ecore.h> +#include <Eina.h> +#include <Evas.h> +#include <cstdio> +#include <wtf/NotFound.h> + +PassOwnPtr<DumpRenderTreeChrome> DumpRenderTreeChrome::create(Evas* evas) +{ + OwnPtr<DumpRenderTreeChrome> chrome = adoptPtr(new DumpRenderTreeChrome(evas)); + + if (!chrome->initialize()) + return nullptr; + + return chrome.release(); +} + +DumpRenderTreeChrome::DumpRenderTreeChrome(Evas* evas) + : m_mainView(0) + , m_mainFrame(0) + , m_evas(evas) + , m_gcController(adoptPtr(new GCController)) +{ +} + +DumpRenderTreeChrome::~DumpRenderTreeChrome() +{ +} + +Evas_Object* DumpRenderTreeChrome::createNewWindow() +{ + Evas_Object* newView = createView(); + + ewk_view_setting_scripts_can_open_windows_set(newView, EINA_TRUE); + ewk_view_setting_scripts_can_close_windows_set(newView, EINA_TRUE); + + m_extraViews.append(newView); + + return newView; +} + +Evas_Object* DumpRenderTreeChrome::createView() const +{ + Evas_Object* view = drtViewAdd(m_evas); + if (!view) + return 0; + + ewk_view_theme_set(view, DATA_DIR"/default.edj"); + + evas_object_smart_callback_add(view, "load,started", onLoadStarted, 0); + evas_object_smart_callback_add(view, "load,finished", onLoadFinished, 0); + evas_object_smart_callback_add(view, "title,changed", onTitleChanged, 0); + evas_object_smart_callback_add(view, "window,object,cleared", onWindowObjectCleared, m_gcController.get()); + evas_object_smart_callback_add(view, "statusbar,text,set", onStatusbarTextSet, 0); + evas_object_smart_callback_add(view, "load,document,finished", onDocumentLoadFinished, 0); + + return view; +} + +void DumpRenderTreeChrome::removeWindow(Evas_Object* view) +{ + const size_t pos = m_extraViews.find(view); + + if (pos == notFound) + return; + + m_extraViews.remove(pos); + evas_object_del(view); +} + +bool DumpRenderTreeChrome::initialize() +{ + DumpRenderTreeSupportEfl::setMockScrollbarsEnabled(true); + + m_mainView = createView(); + if (!m_mainView) + return false; + + ewk_view_theme_set(m_mainView, DATA_DIR"/default.edj"); + + evas_object_name_set(m_mainView, "m_mainView"); + evas_object_move(m_mainView, 0, 0); + evas_object_resize(m_mainView, 800, 600); + evas_object_layer_set(m_mainView, EVAS_LAYER_MAX); + evas_object_show(m_mainView); + evas_object_focus_set(m_mainView, EINA_TRUE); + + m_mainFrame = ewk_view_frame_main_get(m_mainView); + + return true; +} + +Vector<Evas_Object*> DumpRenderTreeChrome::extraViews() const +{ + return m_extraViews; +} + +Evas_Object* DumpRenderTreeChrome::mainFrame() const +{ + return m_mainFrame; +} + +Evas_Object* DumpRenderTreeChrome::mainView() const +{ + return m_mainView; +} + +void DumpRenderTreeChrome::resetDefaultsToConsistentValues() +{ + Vector<Evas_Object*>::iterator it = m_extraViews.begin(); + for (; it != m_extraViews.end(); ++it) + evas_object_del(*it); + m_extraViews.clear(); + + ewk_settings_icon_database_clear(); + ewk_settings_icon_database_path_set(0); + + ewk_view_setting_private_browsing_set(mainView(), EINA_FALSE); + ewk_view_setting_spatial_navigation_set(mainView(), EINA_FALSE); + ewk_view_setting_enable_frame_flattening_set(mainView(), EINA_FALSE); + ewk_view_setting_application_cache_set(mainView(), EINA_TRUE); + ewk_view_setting_enable_scripts_set(mainView(), EINA_TRUE); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_STANDARD, "Times"); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_MONOSPACE, "Courier"); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SERIF, "Times"); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SANS_SERIF, "Helvetica"); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_CURSIVE, "cursive"); + ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_FANTASY, "fantasy"); + ewk_view_setting_font_default_size_set(mainView(), 16); + ewk_view_setting_font_monospace_size_set(mainView(), 13); + ewk_view_setting_font_minimum_size_set(mainView(), 0); + ewk_view_setting_caret_browsing_set(mainView(), EINA_FALSE); + ewk_view_setting_page_cache_set(mainView(), EINA_FALSE); + ewk_view_setting_enable_auto_resize_window_set(mainView(), EINA_TRUE); + ewk_view_setting_enable_plugins_set(mainView(), EINA_TRUE); + ewk_view_setting_scripts_can_open_windows_set(mainView(), EINA_TRUE); + ewk_view_setting_scripts_can_close_windows_set(mainView(), EINA_TRUE); + + ewk_view_zoom_set(mainView(), 1.0, 0, 0); + ewk_view_scale_set(mainView(), 1.0, 0, 0); + + ewk_history_clear(ewk_view_history_get(mainView())); + + ewk_cookies_clear(); + ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY); + + DumpRenderTreeSupportEfl::clearFrameName(mainFrame()); + DumpRenderTreeSupportEfl::clearOpener(mainFrame()); +} + +// Smart Callbacks +// --------------- + +void DumpRenderTreeChrome::onWindowObjectCleared(void* userData, Evas_Object*, void* eventInfo) +{ + Ewk_Window_Object_Cleared_Event* objectClearedInfo = static_cast<Ewk_Window_Object_Cleared_Event*>(eventInfo); + JSValueRef exception = 0; + ASSERT(gLayoutTestController); + + GCController* gcController = static_cast<GCController*>(userData); + ASSERT(gcController); + + gLayoutTestController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); + ASSERT(!exception); + + JSRetainPtr<JSStringRef> controllerName(JSStringCreateWithUTF8CString("eventSender")); + JSObjectSetProperty(objectClearedInfo->context, objectClearedInfo->windowObject, + controllerName.get(), + makeEventSender(objectClearedInfo->context, !DumpRenderTreeSupportEfl::frameParent(objectClearedInfo->frame)), + kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); +} + +void DumpRenderTreeChrome::onLoadStarted(void*, Evas_Object* view, void*) +{ + // FIXME: we actually need the frame related to this event + Evas_Object* frame = ewk_view_frame_main_get(view); + + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; +} + +Eina_Bool DumpRenderTreeChrome::processWork(void* data) +{ + Evas_Object* frame = static_cast<Evas_Object*>(data); + + if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) + dump(); + + return ECORE_CALLBACK_CANCEL; +} + +void DumpRenderTreeChrome::onLoadFinished(void*, Evas_Object* view, void*) +{ + // FIXME: we actually need the frame related to this event + Evas_Object* frame = ewk_view_frame_main_get(view); + + if (topLoadingFrame != frame) + return; + + topLoadingFrame = 0; + + WorkQueue::shared()->setFrozen(true); + if (gLayoutTestController->waitToDump()) + return; + + if (WorkQueue::shared()->count()) + ecore_idler_add(processWork, frame); + else + dump(); +} + +void DumpRenderTreeChrome::onStatusbarTextSet(void*, Evas_Object*, void* eventInfo) +{ + if (!gLayoutTestController->dumpStatusCallbacks()) + return; + + const char* statusbarText = static_cast<const char*>(eventInfo); + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", statusbarText); +} + +void DumpRenderTreeChrome::onTitleChanged(void*, Evas_Object*, void*) +{ + notImplemented(); +} + +void DumpRenderTreeChrome::onDocumentLoadFinished(void*, Evas_Object*, void* eventInfo) +{ + const Evas_Object* frame = static_cast<Evas_Object*>(eventInfo); + const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); + + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didFinishDocumentLoadForFrame\n", frameName.utf8().data()); + else if (!done) { + const unsigned pendingFrameUnloadEvents = DumpRenderTreeSupportEfl::pendingUnloadEventCount(frame); + if (pendingFrameUnloadEvents) + printf("%s - has %u onunload handler(s)\n", frameName.utf8().data(), pendingFrameUnloadEvents); + } +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h new file mode 100644 index 000000000..4ea991806 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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 + * HOLDERS OR ITS 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 DumpRenderTreeChrome_h +#define DumpRenderTreeChrome_h + +#include "GCController.h" + +#include <Eina.h> +#include <Evas.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +class DumpRenderTreeChrome { +public: + ~DumpRenderTreeChrome(); + + static PassOwnPtr<DumpRenderTreeChrome> create(Evas*); + + Evas_Object* createNewWindow(); + void removeWindow(Evas_Object*); + + Vector<Evas_Object*> extraViews() const; + Evas_Object* mainFrame() const; + Evas_Object* mainView() const; + + void resetDefaultsToConsistentValues(); + +private: + DumpRenderTreeChrome(Evas*); + + Evas_Object* createView() const; + bool initialize(); + + Evas_Object* m_mainFrame; + Evas_Object* m_mainView; + Evas* m_evas; + OwnPtr<GCController> m_gcController; + Vector<Evas_Object*> m_extraViews; + + // Smart callbacks + static void onWindowObjectCleared(void*, Evas_Object*, void*); + static void onLoadStarted(void*, Evas_Object*, void*); + + static Eina_Bool processWork(void*); + + static void onLoadFinished(void*, Evas_Object*, void*); + + static void onStatusbarTextSet(void*, Evas_Object*, void*); + + static void onTitleChanged(void*, Evas_Object*, void*); + + static void onDocumentLoadFinished(void*, Evas_Object*, void*); +}; + +#endif // DumpRenderTreeChrome_h diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h new file mode 100644 index 000000000..43812b19b --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Red istributions 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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 + * HOLDERS OR ITS 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 DumpRenderTreeEfl_h +#define DumpRenderTreeEfl_h + +#include <Ecore.h> +#include <Evas.h> +#include <wtf/OwnPtr.h> + +class DumpRenderTreeChrome; + +extern OwnPtr<DumpRenderTreeChrome> browser; +extern Evas_Object* topLoadingFrame; +extern bool waitForPolicy; +extern Ecore_Timer* waitToDumpWatchdog; + +#endif /* DumpRenderTreeEfl_h */ diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp new file mode 100644 index 000000000..938c3fbdb --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Red istributions 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpRenderTreeView.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "LayoutTestController.h" +#include <EWebKit.h> +#include <Ecore.h> +#include <Eina.h> +#include <Evas.h> +#include <cstdio> +#include <cstdlib> + +using namespace std; + +static Ewk_View_Smart_Class gParentSmartClass = EWK_VIEW_SMART_CLASS_INIT_NULL; + +static void onConsoleMessage(Ewk_View_Smart_Data*, const char* message, unsigned int lineNumber, const char*) +{ + printf("CONSOLE MESSAGE: line %u: %s\n", lineNumber, message); +} + +static void onJavaScriptAlert(Ewk_View_Smart_Data*, Evas_Object*, const char* message) +{ + printf("ALERT: %s\n", message); +} + +static Eina_Bool onJavaScriptConfirm(Ewk_View_Smart_Data*, Evas_Object*, const char* message) +{ + printf("CONFIRM: %s\n", message); + return EINA_TRUE; +} + +static Eina_Bool onJavaScriptPrompt(Ewk_View_Smart_Data*, Evas_Object*, const char* message, const char* defaultValue, char** value) +{ + printf("PROMPT: %s, default text: %s\n", message, defaultValue); + *value = strdup(defaultValue); + return EINA_TRUE; +} + +static Evas_Object* onWindowCreate(Ewk_View_Smart_Data*, Eina_Bool, const Ewk_Window_Features*) +{ + return gLayoutTestController->canOpenWindows() ? browser->createNewWindow() : 0; +} + +static Eina_Bool onWindowCloseDelayed(void* data) +{ + Evas_Object* view = static_cast<Evas_Object*>(data); + browser->removeWindow(view); + return EINA_FALSE; +} + +static void onWindowClose(Ewk_View_Smart_Data* smartData) +{ + Evas_Object* view = smartData->self; + ecore_idler_add(onWindowCloseDelayed, view); +} + +static bool shouldUseSingleBackingStore() +{ + const char* useSingleBackingStore = getenv("DRT_USE_SINGLE_BACKING_STORE"); + return useSingleBackingStore && *useSingleBackingStore == '1'; +} + +static bool chooseAndInitializeAppropriateSmartClass(Ewk_View_Smart_Class* api) +{ + return shouldUseSingleBackingStore() ? ewk_view_single_smart_set(api) : ewk_view_tiled_smart_set(api); +} + +Evas_Object* drtViewAdd(Evas* evas) +{ + static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("DRT_View"); + + if (!chooseAndInitializeAppropriateSmartClass(&api)) + return 0; + + if (EINA_UNLIKELY(!gParentSmartClass.sc.add)) + ewk_view_base_smart_set(&gParentSmartClass); + + api.add_console_message = onConsoleMessage; + api.run_javascript_alert = onJavaScriptAlert; + api.run_javascript_confirm = onJavaScriptConfirm; + api.run_javascript_prompt = onJavaScriptPrompt; + api.window_create = onWindowCreate; + api.window_close = onWindowClose; + + return evas_object_smart_add(evas, evas_smart_class_new(&api.sc)); +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.h b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h new file mode 100644 index 000000000..72ddab56d --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Red istributions 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 DumpRenderTreeView_h +#define DumpRenderTreeView_h + +#include <Evas.h> + +Evas_Object* drtViewAdd(Evas*); + +#endif // DumpRenderTreeView_h diff --git a/Tools/DumpRenderTree/efl/EventSender.cpp b/Tools/DumpRenderTree/efl/EventSender.cpp new file mode 100644 index 000000000..89130f00a --- /dev/null +++ b/Tools/DumpRenderTree/efl/EventSender.cpp @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2010 Igalia S.L. + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "JSStringUtils.h" +#include "NotImplemented.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <wtf/ASCIICType.h> +#include <wtf/Platform.h> +#include <wtf/text/CString.h> + +static bool gDragMode; +static int gTimeOffset = 0; + +static int gLastMousePositionX; +static int gLastMousePositionY; +static int gLastClickPositionX; +static int gLastClickPositionY; +static int gLastClickTimeOffset; +static int gLastClickButton; +static int gButtonCurrentlyDown; +static int gClickCount; + +static const float zoomMultiplierRatio = 1.2f; + +// Key event location code defined in DOM Level 3. +enum KeyLocationCode { + DomKeyLocationStandard, + DomKeyLocationLeft, + DomKeyLocationRight, + DomKeyLocationNumpad +}; + +enum EvasKeyModifier { + EvasKeyModifierNone = 0, + EvasKeyModifierControl = 1 << 0, + EvasKeyModifierShift = 1 << 1, + EvasKeyModifierAlt = 1 << 2, + EvasKeyModifierMeta = 1 << 3 +}; + +enum EvasMouseButton { + EvasMouseButtonNone, + EvasMouseButtonLeft, + EvasMouseButtonMiddle, + EvasMouseButtonRight +}; + +enum EvasMouseEvent { + EvasMouseEventNone = 0, + EvasMouseEventDown = 1 << 0, + EvasMouseEventUp = 1 << 1, + EvasMouseEventMove = 1 << 2, + EvasMouseEventScrollUp = 1 << 3, + EvasMouseEventScrollDown = 1 << 4, + EvasMouseEventScrollLeft = 1 << 5, + EvasMouseEventScrollRight = 1 << 6, + EvasMouseEventClick = EvasMouseEventMove | EvasMouseEventDown | EvasMouseEventUp, +}; + +static void setEvasModifiers(Evas* evas, EvasKeyModifier modifiers) +{ + static const char* modifierNames[] = { "Control", "Shift", "Alt", "Super" }; + for (unsigned modifier = 0; modifier < 4; ++modifier) { + if (modifiers & (1 << modifier)) + evas_key_modifier_on(evas, modifierNames[modifier]); + else + evas_key_modifier_off(evas, modifierNames[modifier]); + } +} + +static EvasMouseButton translateMouseButtonNumber(int eventSenderButtonNumber) +{ + static const EvasMouseButton translationTable[] = { + EvasMouseButtonLeft, + EvasMouseButtonMiddle, + EvasMouseButtonRight, + EvasMouseButtonMiddle // fast/events/mouse-click-events expects the 4th button to be treated as the middle button + }; + static const unsigned translationTableSize = sizeof(translationTable) / sizeof(translationTable[0]); + + if (eventSenderButtonNumber < translationTableSize) + return translationTable[eventSenderButtonNumber]; + + return EvasMouseButtonLeft; +} + +static bool sendMouseEvent(Evas* evas, EvasMouseEvent event, int buttonNumber, EvasKeyModifier modifiers) +{ + unsigned timeStamp = 0; + + DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame()); + + setEvasModifiers(evas, modifiers); + if (event & EvasMouseEventMove) + evas_event_feed_mouse_move(evas, gLastMousePositionX, gLastMousePositionY, timeStamp++, 0); + if (event & EvasMouseEventDown) + evas_event_feed_mouse_down(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0); + if (event & EvasMouseEventUp) + evas_event_feed_mouse_up(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0); + + const bool horizontal = !!(event & EvasMouseEventScrollLeft | event & EvasMouseEventScrollRight); + const bool vertical = !!(event & EvasMouseEventScrollUp | event & EvasMouseEventScrollDown); + if (vertical && horizontal) { + evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0); + evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0); + } else if (vertical) + evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0); + else if (horizontal) + evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0); + + setEvasModifiers(evas, EvasKeyModifierNone); + + return true; +} + +static Eina_Bool sendClick(void*) +{ + return !!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventClick, EvasMouseButtonLeft, EvasKeyModifierNone); +} + +static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + ecore_idler_add(sendClick, 0); + return JSValueMakeUndefined(context); +} + +static void updateClickCount(int button) +{ + if (gLastClickPositionX != gLastMousePositionX + || gLastClickPositionY != gLastMousePositionY + || gLastClickButton != button + || gTimeOffset - gLastClickTimeOffset >= 1) + gClickCount = 1; + else + gClickCount++; +} + +static EvasKeyModifier modifierFromJSValue(JSContextRef context, const JSValueRef value) +{ + JSRetainPtr<JSStringRef> jsKeyValue(Adopt, JSValueToStringCopy(context, value, 0)); + + if (equals(jsKeyValue, "ctrlKey") || equals(jsKeyValue, "addSelectionKey")) + return EvasKeyModifierControl; + if (equals(jsKeyValue, "shiftKey") || equals(jsKeyValue, "rangeSelectionKey")) + return EvasKeyModifierShift; + if (equals(jsKeyValue, "altKey")) + return EvasKeyModifierAlt; + if (equals(jsKeyValue, "metaKey")) + return EvasKeyModifierMeta; + + return EvasKeyModifierNone; +} + +static EvasKeyModifier modifiersFromJSValue(JSContextRef context, const JSValueRef modifiers) +{ + // The value may either be a string with a single modifier or an array of modifiers. + if (JSValueIsString(context, modifiers)) + return modifierFromJSValue(context, modifiers); + + JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0); + if (!modifiersArray) + return EvasKeyModifierNone; + + unsigned modifier = 0; + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0); + for (int i = 0; i < modifiersCount; ++i) + modifier |= static_cast<unsigned>(modifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0))); + return static_cast<EvasKeyModifier>(modifier); +} + +static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + + if (exception && *exception) + return JSValueMakeUndefined(context); + } + + button = translateMouseButtonNumber(button); + // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb. + if (gButtonCurrentlyDown == button) + return JSValueMakeUndefined(context); + + updateClickCount(button); + + EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone; + if (!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventDown, button, modifiers)) + return JSValueMakeUndefined(context); + + gButtonCurrentlyDown = button; + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + } + + gLastClickPositionX = gLastMousePositionX; + gLastClickPositionY = gLastMousePositionY; + gLastClickButton = gButtonCurrentlyDown; + gLastClickTimeOffset = gTimeOffset; + gButtonCurrentlyDown = 0; + + EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone; + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventUp, translateMouseButtonNumber(button), modifiers); + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + gLastMousePositionX = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + gLastMousePositionY = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventMove, EvasMouseButtonNone, EvasKeyModifierNone); + return JSValueMakeUndefined(context); +} + +static EvasMouseEvent evasMouseEventFromHorizontalAndVerticalOffsets(int horizontalOffset, int verticalOffset) +{ + unsigned mouseEvent = 0; + + if (verticalOffset > 0) + mouseEvent |= EvasMouseEventScrollUp; + else if (verticalOffset < 0) + mouseEvent |= EvasMouseEventScrollDown; + + if (horizontalOffset > 0) + mouseEvent |= EvasMouseEventScrollRight; + else if (horizontalOffset < 0) + mouseEvent |= EvasMouseEventScrollLeft; + + return static_cast<EvasMouseEvent>(mouseEvent); +} + +static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + const int horizontal = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + const int vertical = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), evasMouseEventFromHorizontalAndVerticalOffsets(horizontal, vertical), EvasMouseButtonNone, EvasKeyModifierNone); + return JSValueMakeUndefined(context); +} + +static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return JSValueMakeUndefined(context); +} + +static const char* keyPadNameFromJSValue(JSStringRef character) +{ + if (equals(character, "leftArrow")) + return "KP_Left"; + if (equals(character, "rightArrow")) + return "KP_Right"; + if (equals(character, "upArrow")) + return "KP_Up"; + if (equals(character, "downArrow")) + return "KP_Down"; + if (equals(character, "pageUp")) + return "KP_Prior"; + if (equals(character, "pageDown")) + return "KP_Next"; + if (equals(character, "home")) + return "KP_Home"; + if (equals(character, "end")) + return "KP_End"; + if (equals(character, "insert")) + return "KP_Insert"; + if (equals(character, "delete")) + return "KP_Delete"; + + return 0; +} + +static const char* keyNameFromJSValue(JSStringRef character) +{ + if (equals(character, "leftArrow")) + return "Left"; + if (equals(character, "rightArrow")) + return "Right"; + if (equals(character, "upArrow")) + return "Up"; + if (equals(character, "downArrow")) + return "Down"; + if (equals(character, "pageUp")) + return "Prior"; + if (equals(character, "pageDown")) + return "Next"; + if (equals(character, "home")) + return "Home"; + if (equals(character, "end")) + return "End"; + if (equals(character, "insert")) + return "Insert"; + if (equals(character, "delete")) + return "Delete"; + if (equals(character, "printScreen")) + return "Print"; + if (equals(character, "menu")) + return "Menu"; + if (equals(character, "F1")) + return "F1"; + if (equals(character, "F2")) + return "F2"; + if (equals(character, "F3")) + return "F3"; + if (equals(character, "F4")) + return "F4"; + if (equals(character, "F5")) + return "F5"; + if (equals(character, "F6")) + return "F6"; + if (equals(character, "F7")) + return "F7"; + if (equals(character, "F8")) + return "F8"; + if (equals(character, "F9")) + return "F9"; + if (equals(character, "F10")) + return "F10"; + if (equals(character, "F11")) + return "F11"; + if (equals(character, "F12")) + return "F12"; + + int charCode = JSStringGetCharactersPtr(character)[0]; + if (charCode == '\n' || charCode == '\r') + return "Return"; + if (charCode == '\t') + return "Tab"; + if (charCode == '\x8') + return "BackSpace"; + + return 0; +} + +static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + Evas_Object* view = ewk_frame_view_get(browser->mainFrame()); + if (!view) + return JSValueMakeUndefined(context); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + // handle location argument. + int location = DomKeyLocationStandard; + if (argumentCount > 2) + location = static_cast<int>(JSValueToNumber(context, arguments[2], exception)); + + JSRetainPtr<JSStringRef> character(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + // send the event + Evas* evas = evas_object_evas_get(view); + if (argumentCount >= 2) + setEvasModifiers(evas, modifiersFromJSValue(context, arguments[1])); + + const CString cCharacter = character.get()->ustring().utf8(); + const char* keyName = (location == DomKeyLocationNumpad) ? keyPadNameFromJSValue(character.get()) : keyNameFromJSValue(character.get()); + + if (!keyName) + keyName = cCharacter.data(); + + DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame()); + evas_event_feed_key_down(evas, keyName, keyName, keyName, 0, 0, 0); + evas_event_feed_key_up(evas, keyName, keyName, keyName, 0, 1, 0); + + setEvasModifiers(evas, EvasKeyModifierNone); + + return JSValueMakeUndefined(context); +} + +static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + Evas_Object* view = ewk_frame_view_get(browser->mainFrame()); + if (!view) + return JSValueMakeUndefined(context); + + float scaleFactor = JSValueToNumber(context, arguments[0], exception); + float x = JSValueToNumber(context, arguments[1], exception); + float y = JSValueToNumber(context, arguments[2], exception); + ewk_view_scale_set(view, scaleFactor, x, y); + + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticFunctions[] = { + { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSStaticValue staticValues[] = { + { 0, 0, 0, 0 } +}; + +static JSClassRef getClass(JSContextRef context) +{ + static JSClassRef eventSenderClass = 0; + + if (!eventSenderClass) { + JSClassDefinition classDefinition = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + classDefinition.staticFunctions = staticFunctions; + classDefinition.staticValues = staticValues; + + eventSenderClass = JSClassCreate(&classDefinition); + } + + return eventSenderClass; +} + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame) +{ + if (isTopFrame) { + gDragMode = true; + + // Fly forward in time one second when the main frame loads. This will + // ensure that when a test begins clicking in the same location as + // a previous test, those clicks won't be interpreted as continuations + // of the previous test's click sequences. + gTimeOffset += 1000; + + gLastMousePositionX = gLastMousePositionY = 0; + gLastClickPositionX = gLastClickPositionY = 0; + gLastClickTimeOffset = 0; + gLastClickButton = 0; + gButtonCurrentlyDown = 0; + gClickCount = 0; + } + + return JSObjectMake(context, getClass(context), 0); +} diff --git a/Tools/DumpRenderTree/efl/EventSender.h b/Tools/DumpRenderTree/efl/EventSender.h new file mode 100644 index 000000000..bded6552d --- /dev/null +++ b/Tools/DumpRenderTree/efl/EventSender.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h +#define EventSender_h + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +// The boolean parameter refers to whether this is being called from a top-level frame. +JSObjectRef makeEventSender(JSContextRef, bool); + +#endif // EventSender_h diff --git a/Tools/DumpRenderTree/efl/FontManagement.cpp b/Tools/DumpRenderTree/efl/FontManagement.cpp new file mode 100644 index 000000000..4cf2fb69b --- /dev/null +++ b/Tools/DumpRenderTree/efl/FontManagement.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "FontManagement.h" + +#include <Ecore_File.h> +#include <cstdio> +#include <fontconfig/fontconfig.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +static Vector<String> getFontDirectories() +{ + Vector<String> fontDirPaths; + + fontDirPaths.append(String("/usr/share/fonts/TTF/")); + fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-liberation/")); + fontDirPaths.append(String("/usr/share/fonts/liberation/")); + fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-dejavu/")); + fontDirPaths.append(String("/usr/share/fonts/dejavu/")); + fontDirPaths.append(String("/usr/share/fonts/OTF/")); // MathML + fontDirPaths.append(String("/usr/share/fonts/opentype/stix/")); // MathML + fontDirPaths.append(String("/usr/share/fonts/stix/")); // MathML + + return fontDirPaths; +} + +static Vector<String> getFontFiles() +{ + Vector<String> fontFilePaths; + + // Ahem is used by many layout tests. + fontFilePaths.append(String(FONTS_CONF_DIR "/AHEM____.TTF")); + // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452 + fontFilePaths.append(String(FONTS_CONF_DIR "/FontWithNoValidEncoding.fon")); + + for (int i = 1; i <= 9; i++) { + char fontPath[PATH_MAX]; + snprintf(fontPath, PATH_MAX - 1, + FONTS_CONF_DIR "/../../fonts/WebKitWeightWatcher%i00.ttf", i); + + fontFilePaths.append(String(fontPath)); + } + + return fontFilePaths; +} + +static size_t addFontDirectories(const Vector<String>& fontDirectories, FcConfig* config) +{ + size_t addedDirectories = 0; + + for (Vector<String>::const_iterator it = fontDirectories.begin(); + it != fontDirectories.end(); ++it) { + const CString currentDirectory = (*it).utf8(); + const char* path = currentDirectory.data(); + + if (ecore_file_is_dir(path)) { + if (!FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8*>(path))) { + fprintf(stderr, "Could not load font at %s!\n", path); + continue; + } + + ++addedDirectories; + } + } + + return addedDirectories; +} + +static void addFontFiles(const Vector<String>& fontFiles, FcConfig* config) +{ + for (Vector<String>::const_iterator it = fontFiles.begin(); it != fontFiles.end(); ++it) { + const CString currentFile = (*it).utf8(); + const char* path = currentFile.data(); + + if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(path))) + fprintf(stderr, "Could not load font at %s!\n", path); + } +} + +void addFontsToEnvironment() +{ + FcInit(); + + // Load our configuration file, which sets up proper aliases for family + // names like sans, serif and monospace. + FcConfig* config = FcConfigCreate(); + const char* fontConfigFilename = FONTS_CONF_DIR "/fonts.conf"; + if (!FcConfigParseAndLoad(config, reinterpret_cast<const FcChar8*>(fontConfigFilename), true)) { + fprintf(stderr, "Couldn't load font configuration file from: %s\n", fontConfigFilename); + exit(1); + } + + if (!addFontDirectories(getFontDirectories(), config)) { + fprintf(stderr, "None of the font directories could be added. Either install them " + "or file a bug at http://bugs.webkit.org if they are installed in " + "another location.\n"); + exit(1); + } + + addFontFiles(getFontFiles(), config); + + if (!FcConfigSetCurrent(config)) { + fprintf(stderr, "Could not set the current font configuration!\n"); + exit(1); + } +} + diff --git a/Tools/DumpRenderTree/efl/FontManagement.h b/Tools/DumpRenderTree/efl/FontManagement.h new file mode 100644 index 000000000..d497513ae --- /dev/null +++ b/Tools/DumpRenderTree/efl/FontManagement.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 FontManagement_h +#define FontManagement_h + +void addFontsToEnvironment(); + +#endif // FontManagement_h diff --git a/Tools/DumpRenderTree/efl/GCControllerEfl.cpp b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp new file mode 100644 index 000000000..1f55a5ce6 --- /dev/null +++ b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h" + +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" + +void GCController::collect() const +{ + DumpRenderTreeSupportEfl::garbageCollectorCollect(); +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + DumpRenderTreeSupportEfl::garbageCollectorCollectOnAlternateThread(waitUntilDone); +} + +size_t GCController::getJSObjectCount() const +{ + return DumpRenderTreeSupportEfl::javaScriptObjectsCount(); +} diff --git a/Tools/DumpRenderTree/efl/ImageDiff.cpp b/Tools/DumpRenderTree/efl/ImageDiff.cpp new file mode 100644 index 000000000..754ecb22a --- /dev/null +++ b/Tools/DumpRenderTree/efl/ImageDiff.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Ecore.h> +#include <Ecore_Evas.h> +#include <Evas.h> +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <getopt.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +enum PixelComponent { + Red, + Green, + Blue, + Alpha +}; + +static OwnPtr<Ecore_Evas> gEcoreEvas; +static double gTolerance = 0; + +static void abortWithErrorMessage(const char* errorMessage); + +static unsigned char* pixelFromImageData(unsigned char* imageData, int rowStride, int x, int y) +{ + return imageData + (y * rowStride) + (x << 2); +} + +static Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned char* buffer, int width, int height) +{ + Evas_Object* image = evas_object_image_filled_add(evas); + if (!image) + abortWithErrorMessage("could not create difference image"); + + evas_object_image_size_set(image, width, height); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + + unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_data_get(image, EINA_TRUE)); + const int rowStride = evas_object_image_stride_get(image); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* diffPixel = pixelFromImageData(diffPixels, rowStride, x, y); + diffPixel[Red] = diffPixel[Green] = diffPixel[Blue] = *buffer++; + diffPixel[Alpha] = 0xff; + } + } + + evas_object_image_data_set(image, diffPixels); + + return image; +} + +static float computeDistanceBetweenPixelComponents(unsigned char actualComponent, unsigned char baseComponent) +{ + return (actualComponent - baseComponent) / std::max<float>(255 - baseComponent, baseComponent); +} + +static float computeDistanceBetweenPixelComponents(unsigned char* actualPixel, unsigned char* basePixel, PixelComponent component) +{ + return computeDistanceBetweenPixelComponents(actualPixel[component], basePixel[component]); +} + +static float calculatePixelDifference(unsigned char* basePixel, unsigned char* actualPixel) +{ + const float red = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Red); + const float green = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Green); + const float blue = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Blue); + const float alpha = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Alpha); + return sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; +} + +static float calculateDifference(Evas_Object* baselineImage, Evas_Object* actualImage, OwnPtr<Evas_Object>& differenceImage) +{ + int width, height, baselineWidth, baselineHeight; + evas_object_image_size_get(actualImage, &width, &height); + evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight); + + if (width != baselineWidth || height != baselineHeight) { + printf("Error, test and reference image have different sizes.\n"); + return 100; // Completely different. + } + + OwnArrayPtr<unsigned char> diffBuffer = adoptArrayPtr(new unsigned char[width * height]); + if (!diffBuffer) + abortWithErrorMessage("could not create difference buffer"); + + const int actualRowStride = evas_object_image_stride_get(actualImage); + const int baseRowStride = evas_object_image_stride_get(baselineImage); + unsigned numberOfDifferentPixels = 0; + float totalDistance = 0; + float maxDistance = 0; + unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_data_get(actualImage, EINA_FALSE)); + unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_data_get(baselineImage, EINA_FALSE)); + unsigned char* currentDiffPixel = diffBuffer.get(); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* actualPixel = pixelFromImageData(actualPixels, actualRowStride, x, y); + unsigned char* basePixel = pixelFromImageData(basePixels, baseRowStride, x, y); + + const float distance = calculatePixelDifference(basePixel, actualPixel); + *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f); + + if (distance >= 1.0f / 255.0f) { + ++numberOfDifferentPixels; + totalDistance += distance; + maxDistance = std::max<float>(maxDistance, distance); + } + } + } + + // When using evas_object_image_data_get(), a complementary evas_object_data_set() must be + // issued to balance the reference count, even if the image hasn't been changed. + evas_object_image_data_set(baselineImage, basePixels); + evas_object_image_data_set(actualImage, actualPixels); + + // Compute the difference as a percentage combining both the number of + // different pixels and their difference amount i.e. the average distance + // over the entire image + float difference = 0; + if (numberOfDifferentPixels) + difference = 100.0f * totalDistance / (height * width); + if (difference <= gTolerance) + difference = 0; + else { + difference = roundf(difference * 100.0f) / 100.0f; + difference = std::max(difference, 0.01f); // round to 2 decimal places + + differenceImage = adoptPtr(differenceImageFromDifferenceBuffer(evas_object_evas_get(baselineImage), diffBuffer.get(), width, height)); + } + + return difference; +} + +static int getTemporaryFile(char *fileName, size_t fileNameLength) +{ + char* tempDirectory = getenv("TMPDIR"); + if (!tempDirectory) + tempDirectory = getenv("TEMP"); + + if (tempDirectory) + snprintf(fileName, fileNameLength, "%s/ImageDiffXXXXXX.png", tempDirectory); + else { +#if __linux__ + strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png"); + const int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1); + if (fileDescriptor >= 0) + return fileDescriptor; +#endif // __linux__ + + strcpy(fileName, "ImageDiffXXXXXX.png"); + } + + return mkstemps(fileName, sizeof(".png") - 1); +} + +static void printImage(Evas_Object* image) +{ + char fileName[PATH_MAX]; + + const int tempImageFd = getTemporaryFile(fileName, PATH_MAX); + if (tempImageFd == -1) + abortWithErrorMessage("could not create temporary file"); + + evas_render(evas_object_evas_get(image)); + + if (evas_object_image_save(image, fileName, 0, 0)) { + struct stat fileInfo; + if (!stat(fileName, &fileInfo)) { + printf("Content-Length: %ld\n", fileInfo.st_size); + fflush(stdout); + + unsigned char buffer[2048]; + ssize_t bytesRead; + while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0) + write(1, buffer, bytesRead); + } + } + close(tempImageFd); + unlink(fileName); +} + +static void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actualImage) +{ + OwnPtr<Evas_Object> differenceImage; + const float difference = calculateDifference(baselineImage, actualImage, differenceImage); + + if (difference > 0.0f) { + if (differenceImage) + printImage(differenceImage.get()); + + printf("diff: %01.2f%% failed\n", difference); + } else + printf("diff: %01.2f%% passed\n", difference); +} + +static void resizeEcoreEvasIfNeeded(Evas_Object* image) +{ + int newWidth, newHeight; + evas_object_image_size_get(image, &newWidth, &newHeight); + + int currentWidth, currentHeight; + ecore_evas_screen_geometry_get(gEcoreEvas.get(), 0, 0, ¤tWidth, ¤tHeight); + + if (newWidth > currentWidth) + currentWidth = newWidth; + if (newHeight > currentHeight) + currentHeight = newHeight; + + ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight); +} + +static PassOwnPtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize) +{ + OwnArrayPtr<unsigned char> imageBuffer = adoptArrayPtr(new unsigned char[imageSize]); + if (!imageBuffer) + abortWithErrorMessage("cannot allocate image"); + + const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin); + if (!bytesRead) + return PassOwnPtr<Evas_Object>(); + + Evas_Object* image = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_memfile_set(image, imageBuffer.get(), bytesRead, 0, 0); + + resizeEcoreEvasIfNeeded(image); + + return adoptPtr(image); +} + +static bool parseCommandLineOptions(int argc, char** argv) +{ + static const option options[] = { + { "tolerance", required_argument, 0, 't' }, + { 0, 0, 0, 0 } + }; + int option; + + while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) { + switch (option) { + case 't': + gTolerance = atof(optarg); + break; + case '?': + case ':': + return false; + } + } + + return true; +} + +static void shutdownEfl() +{ + ecore_evas_shutdown(); + ecore_shutdown(); + evas_shutdown(); +} + +static void abortWithErrorMessage(const char* errorMessage) +{ + shutdownEfl(); + + printf("Error, %s.\n", errorMessage); + exit(EXIT_FAILURE); +} + +static Evas* initEfl() +{ + evas_init(); + ecore_init(); + ecore_evas_init(); + + gEcoreEvas = adoptPtr(ecore_evas_buffer_new(1, 1)); + Evas* evas = ecore_evas_get(gEcoreEvas.get()); + if (!evas) + abortWithErrorMessage("could not create Ecore_Evas buffer"); + + return evas; +} + +int main(int argc, char* argv[]) +{ + if (!parseCommandLineOptions(argc, argv)) + return EXIT_FAILURE; + + Evas* evas = initEfl(); + + OwnPtr<Evas_Object> actualImage; + OwnPtr<Evas_Object> baselineImage; + + char buffer[2048]; + while (fgets(buffer, sizeof(buffer), stdin)) { + char* contentLengthStart = strstr(buffer, "Content-Length: "); + if (!contentLengthStart) + continue; + long imageSize; + if (sscanf(contentLengthStart, "Content-Length: %ld", &imageSize) == 1) { + if (imageSize <= 0) + abortWithErrorMessage("image size must be specified"); + + if (!actualImage) + actualImage = readImageFromStdin(evas, imageSize); + else if (!baselineImage) { + baselineImage = readImageFromStdin(evas, imageSize); + + printImageDifferences(baselineImage.get(), actualImage.get()); + + actualImage.clear(); + baselineImage.clear(); + } + } + + fflush(stdout); + } + + gEcoreEvas.clear(); // Make sure ecore_evas_free is called before the EFL are shut down + + shutdownEfl(); + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.cpp b/Tools/DumpRenderTree/efl/JSStringUtils.cpp new file mode 100644 index 000000000..19ca55736 --- /dev/null +++ b/Tools/DumpRenderTree/efl/JSStringUtils.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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 + * HOLDERS OR ITS 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 "JSStringUtils.h" + +bool equals(JSStringRef jsString, const char* cString) +{ + return JSStringIsEqualToUTF8CString(jsString, cString); +} + +bool equals(JSRetainPtr<JSStringRef> jsString, const char* cString) +{ + return equals(jsString.get(), cString); +} diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.h b/Tools/DumpRenderTree/efl/JSStringUtils.h new file mode 100644 index 000000000..04d7e0812 --- /dev/null +++ b/Tools/DumpRenderTree/efl/JSStringUtils.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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 + * HOLDERS OR ITS 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 JSStringUtils_h +#define JSStringUtils_h + +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> + +bool equals(JSStringRef, const char*); +bool equals(JSRetainPtr<JSStringRef>, const char*); + +#endif // JSStringUtils_h + diff --git a/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp new file mode 100644 index 000000000..8dd0a37ca --- /dev/null +++ b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp @@ -0,0 +1,785 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com> + * Copyright (C) 2009,2011 Collabora Ltd. + * Copyright (C) 2010 Joone Hur <joone@kldp.org> + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "JSStringUtils.h" +#include "NotImplemented.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <Ecore_File.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <JavaScriptCore/wtf/text/WTFString.h> +#include <KURL.h> +#include <editing/FindOptions.h> +#include <stdio.h> + +LayoutTestController::~LayoutTestController() +{ +} + +void LayoutTestController::addDisallowedURL(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::clearBackForwardList() +{ + notImplemented(); +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef) +{ + notImplemented(); + return 0; +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef) +{ + notImplemented(); + return 0; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 + notImplemented(); +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + const Evas_Object* mainFrame = browser->mainFrame(); + const String counterValue(DumpRenderTreeSupportEfl::counterValueByElementId(mainFrame, id->ustring().utf8().data())); + return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(counterValue.utf8().data())); +} + +void LayoutTestController::keepWebHistory() +{ + notImplemented(); +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef, int, int, unsigned, unsigned, unsigned, unsigned, bool) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + notImplemented(); + return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("")); +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight) +{ + return DumpRenderTreeSupportEfl::numberOfPagesForElementId(browser->mainFrame(), id->ustring().utf8().data(), pageWidth, pageHeight); +} + +int LayoutTestController::numberOfPages(float pageWidth, float pageHeight) +{ + return DumpRenderTreeSupportEfl::numberOfPages(browser->mainFrame(), pageWidth, pageHeight); +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char*, int) const +{ + notImplemented(); + return 0; +} + +bool LayoutTestController::isPageBoxVisible(int) const +{ + notImplemented(); + return false; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int, int, int, int, int, int, int) const +{ + notImplemented(); + return 0; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + const Ewk_History* history = ewk_view_history_get(browser->mainView()); + if (!history) + return -1; + + return ewk_history_back_list_length(history) + ewk_history_forward_list_length(history); +} + +unsigned LayoutTestController::workerThreadCount() const +{ + return DumpRenderTreeSupportEfl::workerThreadCount(); +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; + waitForPolicy = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + // Function introduced in r28690. This may need special-casing on Windows. + return JSStringRetain(url); // Do nothing on Unix. +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + WebCore::KURL baseURL(WebCore::KURL(), String::fromUTF8(ewk_frame_uri_get(browser->mainFrame()))); + WebCore::KURL absoluteURL(baseURL, WTF::String(url->characters(), url->length())); + + JSRetainPtr<JSStringRef> jsAbsoluteURL( + Adopt, JSStringCreateWithUTF8CString(absoluteURL.string().utf8().data())); + + WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool acceptsEditing) +{ + ewk_view_editable_set(browser->mainView(), acceptsEditing); +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + ewk_cookies_policy_set(alwaysAcceptCookies ? EWK_COOKIE_JAR_ACCEPT_ALWAYS : EWK_COOKIE_JAR_ACCEPT_NEVER); +} + +void LayoutTestController::setCustomPolicyDelegate(bool, bool) +{ + notImplemented(); +} + +void LayoutTestController::waitForPolicyDelegate() +{ + waitForPolicy = true; + setWaitToDump(true); +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool) +{ + notImplemented(); +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool) +{ + notImplemented(); +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool) +{ + notImplemented(); +} + +static CString gUserStyleSheet; +static bool gUserStyleSheetEnabled = true; + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + gUserStyleSheetEnabled = flag; + ewk_view_setting_user_stylesheet_set(browser->mainView(), flag ? gUserStyleSheet.data() : 0); +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + gUserStyleSheet = path->ustring().utf8(); + + if (gUserStyleSheetEnabled) + setUserStyleSheetEnabled(true); +} + +void LayoutTestController::setValueForUser(JSContextRef, JSValueRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setWindowIsKey(bool) +{ + notImplemented(); +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool) +{ + notImplemented(); +} + +static Eina_Bool waitToDumpWatchdogFired(void*) +{ + waitToDumpWatchdog = 0; + gLayoutTestController->waitToDumpWatchdogTimerFired(); + return ECORE_CALLBACK_CANCEL; +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + static const double timeoutSeconds = 30; + + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) + waitToDumpWatchdog = ecore_timer_add(timeoutSeconds, waitToDumpWatchdogFired, 0); +} + +int LayoutTestController::windowCount() +{ + return browser->extraViews().size() + 1; // + 1 for the main view. +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool flag) +{ + ewk_view_setting_private_browsing_set(browser->mainView(), flag); +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool) +{ + notImplemented(); +} + +void LayoutTestController::setXSSAuditorEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setFrameFlatteningEnabled(bool flag) +{ + ewk_view_setting_enable_frame_flattening_set(browser->mainView(), flag); +} + +void LayoutTestController::setSpatialNavigationEnabled(bool flag) +{ + ewk_view_setting_spatial_navigation_set(browser->mainView(), flag); +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAutofilled(JSContextRef, JSValueRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::disableImageLoading() +{ + // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896 + // Also need to make sure image loading is re-enabled for each new test. + notImplemented(); +} + +void LayoutTestController::setMockDeviceOrientation(bool, double, bool, double, bool, double) +{ + // FIXME: Implement for DeviceOrientation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=30335. + notImplemented(); +} + +void LayoutTestController::setMockGeolocationPosition(double, double, double) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. + notImplemented(); +} + +void LayoutTestController::setMockGeolocationError(int, JSStringRef) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. + notImplemented(); +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + // FIXME: Implement for Geolocation layout tests. + setGeolocationPermissionCommon(allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + // FIXME: Implement for Geolocation layout tests. + return -1; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef, double, JSStringRef) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. + notImplemented(); +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. + notImplemented(); +} + +void LayoutTestController::setIconDatabaseEnabled(bool enabled) +{ + ewk_settings_icon_database_path_set(0); + + if (!enabled) + return; + + String databasePath; + const char* tempDir = getenv("TMPDIR"); + + if (tempDir) + databasePath = String::fromUTF8(tempDir); + else if (tempDir = getenv("TEMP")) + databasePath = String::fromUTF8(tempDir); + else + databasePath = String::fromUTF8("/tmp"); + + databasePath.append("/DumpRenderTree/IconDatabase"); + + if (ecore_file_mkpath(databasePath.utf8().data())) + ewk_settings_icon_database_path_set(databasePath.utf8().data()); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setPopupBlockingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + ewk_view_setting_enable_plugins_set(browser->mainView(), flag); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef) +{ + notImplemented(); + return false; +} + +void LayoutTestController::execCommand(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); + if (!JSValueIsNumber(context, lengthValue)) + return false; + + WebCore::FindOptions options = 0; + + const size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); + for (size_t i = 0; i < length; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); + if (!JSValueIsString(context, value)) + continue; + + JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); + + if (equals(optionName, "CaseInsensitive")) + options |= WebCore::CaseInsensitive; + else if (equals(optionName, "AtWordStarts")) + options |= WebCore::AtWordStarts; + else if (equals(optionName, "TreatMedialCapitalAsWordStart")) + options |= WebCore::TreatMedialCapitalAsWordStart; + else if (equals(optionName, "Backwards")) + options |= WebCore::Backwards; + else if (equals(optionName, "WrapAround")) + options |= WebCore::WrapAround; + else if (equals(optionName, "StartInSelection")) + options |= WebCore::StartInSelection; + } + + return DumpRenderTreeSupportEfl::findString(browser->mainView(), target->ustring().utf8().data(), options); +} + +bool LayoutTestController::isCommandEnabled(JSStringRef name) +{ + return false; +} + +void LayoutTestController::setCacheModel(int) +{ + notImplemented(); +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + notImplemented(); +} + +void LayoutTestController::clearAllApplicationCaches() +{ + ewk_settings_application_cache_clear(); +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long) +{ + // FIXME: Implement to support application cache quotas. + notImplemented(); +} + +void LayoutTestController::clearApplicationCacheForOrigin(OpaqueJSString*) +{ + // FIXME: Implement to support deleting all application caches for an origin. + notImplemented(); +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + notImplemented(); + return 0; +} + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that contain application caches. + notImplemented(); + return JSValueMakeUndefined(context); +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef) +{ + notImplemented(); + return 0; +} + +void LayoutTestController::clearAllDatabases() +{ + ewk_settings_web_database_clear(); +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + ewk_settings_web_database_default_quota_set(quota); +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +void LayoutTestController::deleteAllLocalStorage() +{ + notImplemented(); +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned) +{ + notImplemented(); +} + +void LayoutTestController::syncLocalStorage() +{ + notImplemented(); +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::goBack() +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html + notImplemented(); +} + +void LayoutTestController::setDefersLoading(bool) +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html + notImplemented(); +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + ewk_settings_application_cache_max_quota_set(size); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseAnimation(browser->mainFrame(), animationName->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseTransition(browser->mainFrame(), propertyName->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseSVGAnimation(browser->mainFrame(), animationId->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + return DumpRenderTreeSupportEfl::activeAnimationsCount(browser->mainFrame()); +} + +void LayoutTestController::suspendAnimations() const +{ + DumpRenderTreeSupportEfl::suspendAnimations(browser->mainFrame()); +} + +void LayoutTestController::resumeAnimations() const +{ + DumpRenderTreeSupportEfl::resumeAnimations(browser->mainFrame()); +} + +void LayoutTestController::overridePreference(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::addUserScript(JSStringRef, bool, bool) +{ + notImplemented(); +} + +void LayoutTestController::addUserStyleSheet(JSStringRef, bool) +{ + // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false. + notImplemented(); +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + ewk_view_setting_enable_developer_extras_set(browser->mainView(), enabled); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::showWebInspector() +{ + notImplemented(); +} + +void LayoutTestController::closeWebInspector() +{ + notImplemented(); +} + +void LayoutTestController::evaluateInWebInspector(long, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned, JSObjectRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::removeAllVisitedLinks() +{ + notImplemented(); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + notImplemented(); + return false; +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + notImplemented(); +} + +void LayoutTestController::setWebViewEditable(bool) +{ + ewk_frame_editable_set(browser->mainFrame(), EINA_TRUE); +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef, JSValueRef) const +{ + notImplemented(); + return 0; +} + +void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setEditingBehavior(const char*) +{ + notImplemented(); +} + +void LayoutTestController::abortModal() +{ + notImplemented(); +} + +bool LayoutTestController::hasSpellingMarker(int, int) +{ + notImplemented(); + return false; +} + +bool LayoutTestController::hasGrammarMarker(int, int) +{ + notImplemented(); + return false; +} + +void LayoutTestController::dumpConfigurationForViewport(int, int, int, int, int) +{ + notImplemented(); +} + +void LayoutTestController::setSerializeHTTPLoads(bool) +{ + // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758. + notImplemented(); +} + +void LayoutTestController::setMinimumTimerInterval(double) +{ + notImplemented(); +} + +void LayoutTestController::setTextDirection(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::allowRoundingHacks() +{ + notImplemented(); +} + +void LayoutTestController::addChromeInputField() +{ + notImplemented(); +} + +void LayoutTestController::removeChromeInputField() +{ + notImplemented(); +} + +void LayoutTestController::focusWebView() +{ + notImplemented(); +} + +void LayoutTestController::setBackingScaleFactor(double) +{ + notImplemented(); +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ +} diff --git a/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp new file mode 100644 index 000000000..109374ec9 --- /dev/null +++ b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "IntRect.h" +#include "PixelDumpSupportCairo.h" +#include "RefPtrCairo.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect) +{ + Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(browser->mainView())); + Ewk_View_Private_Data* privateData = static_cast<Ewk_View_Private_Data*>(smartData->_priv); + const Evas_Object* mainFrame = browser->mainFrame(); + + int x, y, width, height; + if (!ewk_frame_visible_content_geometry_get(mainFrame, EINA_TRUE, &x, &y, &width, &height)) + return 0; + + RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); + RefPtr<cairo_t> context = adoptRef(cairo_create(surface.get())); + + const Eina_Rectangle rect = { x, y, width, height }; + if (!ewk_view_paint(privateData, context.get(), &rect)) + return 0; + + if (drawSelectionRect) { + const WebCore::IntRect selectionRect = DumpRenderTreeSupportEfl::selectionRectangle(mainFrame); + + if (!selectionRect.isEmpty()) { + cairo_set_line_width(context.get(), 1.0); + cairo_rectangle(context.get(), selectionRect.x(), selectionRect.y(), selectionRect.width(), selectionRect.height()); + cairo_set_source_rgba(context.get(), 1.0, 0.0, 0.0, 1.0); + cairo_stroke(context.get()); + } + } + + return BitmapContext::createByAdoptingBitmapAndContext(0, context.release().leakRef()); +} diff --git a/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp new file mode 100644 index 000000000..356a6553c --- /dev/null +++ b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WorkQueueItem.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" + +#include <EWebKit.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <JavaScriptCore/runtime/UString.h> +#include <JavaScriptCore/wtf/text/CString.h> + +bool LoadItem::invoke() const +{ + Evas_Object* targetFrame; + + if (!m_target->length()) + targetFrame = browser->mainFrame(); + else + targetFrame = ewk_frame_child_find(browser->mainFrame(), m_target->ustring().utf8().data()); + + ewk_frame_uri_set(targetFrame, m_url->ustring().utf8().data()); + + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + if (!m_unreachableURL->length()) + ewk_frame_contents_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data()); + else + ewk_frame_contents_alternate_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data(), m_unreachableURL->ustring().utf8().data()); + + return true; +} + +bool ReloadItem::invoke() const +{ + ewk_view_reload(browser->mainView()); + return true; +} + +bool ScriptItem::invoke() const +{ + return ewk_frame_script_execute(browser->mainFrame(), m_script->ustring().utf8().data()); +} + +bool BackForwardItem::invoke() const +{ + if (m_howFar == 1) + ewk_view_forward(browser->mainView()); + else if (m_howFar == -1) + ewk_view_back(browser->mainView()); + else + ewk_view_navigate(browser->mainView(), m_howFar); + + return true; +} diff --git a/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf b/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf Binary files differnew file mode 100644 index 000000000..e732fbc42 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf b/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf Binary files differnew file mode 100644 index 000000000..f9f997e63 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf Binary files differnew file mode 100644 index 000000000..22b00dec7 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf Binary files differnew file mode 100644 index 000000000..1ccadbad5 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf Binary files differnew file mode 100644 index 000000000..ab5563dfa --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf Binary files differnew file mode 100644 index 000000000..56d279e0e --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf Binary files differnew file mode 100644 index 000000000..d827d7d85 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf Binary files differnew file mode 100644 index 000000000..914159670 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf Binary files differnew file mode 100644 index 000000000..a2d05059d --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf Binary files differnew file mode 100644 index 000000000..d0f354bf3 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf Binary files differnew file mode 100644 index 000000000..6b895ca71 --- /dev/null +++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp new file mode 100644 index 000000000..f50b033ef --- /dev/null +++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "AccessibilityCallbacks.h" + +#include "AccessibilityController.h" +#include "DumpRenderTree.h" +#include "GOwnPtr.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <gtk/gtk.h> +#include <webkit/webkit.h> + +static guint stateChangeListenerId = 0; +static guint focusEventListenerId = 0; +static guint activeDescendantChangedListenerId = 0; +static guint childrenChangedListenerId = 0; +static guint propertyChangedListenerId = 0; +static guint visibleDataChangedListenerId = 0; + +static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName) +{ + // Sanity check. + if (!accessible || !ATK_IS_OBJECT(accessible) || !signalName) + return; + + const gchar* objectName = atk_object_get_name(accessible); + guint objectRole = atk_object_get_role(accessible); + + // Try to always provide a name to be logged for the object. + if (!objectName || *objectName == '\0') + objectName = "(No name)"; + + printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", + signalName, objectName, objectRole); +} + +static gboolean axObjectEventListener(GSignalInvocationHint *signalHint, + guint numParamValues, + const GValue *paramValues, + gpointer data) +{ + // At least we should receive the instance emitting the signal. + if (numParamValues < 1) + return TRUE; + + AtkObject* accessible = ATK_OBJECT(g_value_get_object(¶mValues[0])); + if (!accessible || !ATK_IS_OBJECT(accessible)) + return TRUE; + + GSignalQuery signal_query; + GOwnPtr<gchar> signalName; + + g_signal_query(signalHint->signal_id, &signal_query); + + if (!g_strcmp0(signal_query.signal_name, "state-change")) { + signalName.set(g_strdup_printf("state-change:%s = %d", + g_value_get_string(¶mValues[1]), + g_value_get_boolean(¶mValues[2]))); + } else if (!g_strcmp0(signal_query.signal_name, "focus-event")) { + signalName.set(g_strdup_printf("focus-event = %d", + g_value_get_boolean(¶mValues[1]))); + } else if (!g_strcmp0(signal_query.signal_name, "children-changed")) { + signalName.set(g_strdup_printf("children-changed = %d", + g_value_get_uint(¶mValues[1]))); + } else if (!g_strcmp0(signal_query.signal_name, "property-change")) { + signalName.set(g_strdup_printf("property-change:%s", + g_quark_to_string(signalHint->detail))); + } else + signalName.set(g_strdup(signal_query.signal_name)); + + printAccessibilityEvent(accessible, signalName.get()); + + return TRUE; +} + +void connectAccessibilityCallbacks() +{ + // Ensure no callbacks are connected before. + disconnectAccessibilityCallbacks(); + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object, which will create the full hierarchy. + DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame); + + // Add global listeners for AtkObject's signals. + stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:state-change"); + focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:focus-event"); + activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:active-descendant-changed"); + childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:children-changed"); + propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:property-change"); + visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:visible-data-changed"); + + // Ensure the Atk interface types are registered, otherwise + // the AtkDocument signal handlers below won't get registered. + GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0)); + AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject); + g_object_unref(G_OBJECT(dummyNoOpAxObject)); + g_object_unref(dummyAxObject); +} + +void disconnectAccessibilityCallbacks() +{ + // AtkObject signals. + if (stateChangeListenerId) { + atk_remove_global_event_listener(stateChangeListenerId); + stateChangeListenerId = 0; + } + if (focusEventListenerId) { + atk_remove_global_event_listener(focusEventListenerId); + focusEventListenerId = 0; + } + if (activeDescendantChangedListenerId) { + atk_remove_global_event_listener(activeDescendantChangedListenerId); + activeDescendantChangedListenerId = 0; + } + if (childrenChangedListenerId) { + atk_remove_global_event_listener(childrenChangedListenerId); + childrenChangedListenerId = 0; + } + if (propertyChangedListenerId) { + atk_remove_global_event_listener(propertyChangedListenerId); + propertyChangedListenerId = 0; + } + if (visibleDataChangedListenerId) { + atk_remove_global_event_listener(visibleDataChangedListenerId); + visibleDataChangedListenerId = 0; + } +} + diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h new file mode 100644 index 000000000..7225757e6 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 AccessibilityCallbacks_h +#define AccessibilityCallbacks_h + +void connectAccessibilityCallbacks(); +void disconnectAccessibilityCallbacks(); + +#endif diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp new file mode 100644 index 000000000..ceeb8dfcb --- /dev/null +++ b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Jan Michael Alonzo + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityCallbacks.h" +#include "AccessibilityUIElement.h" +#include "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" + +#include <atk/atk.h> +#include <gtk/gtk.h> +#include <webkit/webkit.h> + +static bool loggingAccessibilityEvents = false; + +AccessibilityController::AccessibilityController() +{ +} + +AccessibilityController::~AccessibilityController() +{ +} + +AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityController::focusedElement() +{ + AtkObject* accessible = DumpRenderTreeSupportGtk::getFocusedAccessibleElement(mainFrame); + if (!accessible) + return 0; + + return AccessibilityUIElement(accessible); +} + +AccessibilityUIElement AccessibilityController::rootElement() +{ + AtkObject* accessible = DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame); + if (!accessible) + return 0; + + return AccessibilityUIElement(accessible); +} + +void AccessibilityController::setLogFocusEvents(bool) +{ +} + +void AccessibilityController::setLogScrollingStartEvents(bool) +{ +} + +void AccessibilityController::setLogValueChangeEvents(bool) +{ +} + +void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents) +{ + if (logAccessibilityEvents == loggingAccessibilityEvents) + return; + + if (!logAccessibilityEvents) { + disconnectAccessibilityCallbacks(); + loggingAccessibilityEvents = false; + return; + } + + connectAccessibilityCallbacks(); + loggingAccessibilityEvents = true; +} + +bool AccessibilityController::addNotificationListener(JSObjectRef) +{ + return false; +} + +void AccessibilityController::removeNotificationListener() +{ +} diff --git a/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp new file mode 100644 index 000000000..ad5df14c9 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp @@ -0,0 +1,820 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Jan Michael Alonzo + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "GOwnPtr.h" +#include "GRefPtr.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <JavaScriptCore/JSStringRef.h> +#include <atk/atk.h> +#include <gtk/gtk.h> +#include <wtf/Assertions.h> + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) +{ +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) +{ +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements) +{ + // FIXME: implement +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) +{ + // FIXME: implement +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) +{ + int count = childrenCount(); + for (int i = 0; i < count; i++) { + AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i); + children.append(AccessibilityUIElement(child)); + } +} + +void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned start, unsigned end) +{ + for (unsigned i = start; i < end; i++) { + AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i); + elementVector.append(AccessibilityUIElement(child)); + } +} + +int AccessibilityUIElement::rowCount() +{ + if (!m_element) + return 0; + + ASSERT(ATK_IS_TABLE(m_element)); + + return atk_table_get_n_rows(ATK_TABLE(m_element)); +} + +int AccessibilityUIElement::columnCount() +{ + if (!m_element) + return 0; + + ASSERT(ATK_IS_TABLE(m_element)); + + return atk_table_get_n_columns(ATK_TABLE(m_element)); +} + +int AccessibilityUIElement::childrenCount() +{ + if (!m_element) + return 0; + + ASSERT(ATK_IS_OBJECT(m_element)); + + return atk_object_get_n_accessible_children(ATK_OBJECT(m_element)); +} + +AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + Vector<AccessibilityUIElement> children; + getChildrenWithRange(children, index, index + 1); + + if (children.size() == 1) + return children.at(0); + + return 0; +} + +unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) +{ + // FIXME: implement + return 0; +} + +gchar* attributeSetToString(AtkAttributeSet* attributeSet) +{ + GString* str = g_string_new(0); + for (GSList* attributes = attributeSet; attributes; attributes = attributes->next) { + AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data); + g_string_append(str, g_strconcat(attribute->name, ":", attribute->value, NULL)); + if (attributes->next) + g_string_append(str, ", "); + } + + return g_string_free(str, FALSE); +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + if (!m_element) + return JSStringCreateWithCharacters(0, 0); + + ASSERT(ATK_IS_OBJECT(m_element)); + return JSStringCreateWithUTF8CString(attributeSetToString(atk_object_get_attributes(ATK_OBJECT(m_element)))); +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::parentElement() +{ + if (!m_element) + return 0; + + ASSERT(ATK_IS_OBJECT(m_element)); + + AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element)); + return parent ? AccessibilityUIElement(parent) : 0; +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::role() +{ + AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); + + if (!role) + return JSStringCreateWithCharacters(0, 0); + + const gchar* roleName = atk_role_get_name(role); + GOwnPtr<gchar> axRole(g_strdup_printf("AXRole: %s", roleName)); + + return JSStringCreateWithUTF8CString(axRole.get()); +} + +JSStringRef AccessibilityUIElement::subrole() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::roleDescription() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::title() +{ + const gchar* name = atk_object_get_name(ATK_OBJECT(m_element)); + + if (!name) + return JSStringCreateWithCharacters(0, 0); + + GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name)); + + return JSStringCreateWithUTF8CString(axTitle.get()); +} + +JSStringRef AccessibilityUIElement::description() +{ + const gchar* description = atk_object_get_description(ATK_OBJECT(m_element)); + + if (!description) + return JSStringCreateWithCharacters(0, 0); + + GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description)); + + return JSStringCreateWithUTF8CString(axDesc.get()); +} + +JSStringRef AccessibilityUIElement::stringValue() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::language() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::helpText() const +{ + return 0; +} + +double AccessibilityUIElement::x() +{ + int x, y; + + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); + + return x; +} + +double AccessibilityUIElement::y() +{ + int x, y; + + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); + + return y; +} + +double AccessibilityUIElement::width() +{ + int width, height; + + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return width; +} + +double AccessibilityUIElement::height() +{ + int width, height; + + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return height; +} + +double AccessibilityUIElement::clickPointX() +{ + return 0.f; +} + +double AccessibilityUIElement::clickPointY() +{ + return 0.f; +} + +JSStringRef AccessibilityUIElement::orientation() const +{ + return 0; +} + +double AccessibilityUIElement::intValue() const +{ + GValue value = { 0, { { 0 } } }; + + if (!ATK_IS_VALUE(m_element)) + return 0.0f; + + atk_value_get_current_value(ATK_VALUE(m_element), &value); + + if (G_VALUE_HOLDS_DOUBLE(&value)) + return g_value_get_double(&value); + else if (G_VALUE_HOLDS_INT(&value)) + return static_cast<double>(g_value_get_int(&value)); + else + return 0.0f; +} + +double AccessibilityUIElement::minValue() +{ + GValue value = { 0, { { 0 } } }; + + if (!ATK_IS_VALUE(m_element)) + return 0.0f; + + atk_value_get_minimum_value(ATK_VALUE(m_element), &value); + + if (G_VALUE_HOLDS_DOUBLE(&value)) + return g_value_get_double(&value); + else if (G_VALUE_HOLDS_INT(&value)) + return static_cast<double>(g_value_get_int(&value)); + else + return 0.0f; +} + +double AccessibilityUIElement::maxValue() +{ + GValue value = { 0, { { 0 } } }; + + if (!ATK_IS_VALUE(m_element)) + return 0.0f; + + atk_value_get_maximum_value(ATK_VALUE(m_element), &value); + + if (G_VALUE_HOLDS_DOUBLE(&value)) + return g_value_get_double(&value); + else if (G_VALUE_HOLDS_INT(&value)) + return static_cast<double>(g_value_get_int(&value)); + else + return 0.0f; +} + +JSStringRef AccessibilityUIElement::valueDescription() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +static bool checkElementState(PlatformUIElement element, AtkStateType stateType) +{ + if (!ATK_IS_OBJECT(element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element))); + return atk_state_set_contains_state(stateSet.get(), stateType); +} + +bool AccessibilityUIElement::isEnabled() +{ + return checkElementState(m_element, ATK_STATE_ENABLED); +} + +int AccessibilityUIElement::insertionPointLineNumber() +{ + // FIXME: implement + return 0; +} + +bool AccessibilityUIElement::isActionSupported(JSStringRef action) +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isRequired() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isFocused() const +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); + gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED); + + return isFocused; +} + +bool AccessibilityUIElement::isSelected() const +{ + return checkElementState(m_element, ATK_STATE_SELECTED); +} + +int AccessibilityUIElement::hierarchicalLevel() const +{ + // FIXME: implement + return 0; +} + +bool AccessibilityUIElement::ariaIsGrabbed() const +{ + return false; +} + +JSStringRef AccessibilityUIElement::ariaDropEffects() const +{ + return 0; +} + +bool AccessibilityUIElement::isExpanded() const +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); + gboolean isExpanded = atk_state_set_contains_state(stateSet.get(), ATK_STATE_EXPANDED); + + return isExpanded; +} + +bool AccessibilityUIElement::isChecked() const +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); + gboolean isChecked = atk_state_set_contains_state(stateSet.get(), ATK_STATE_CHECKED); + + return isChecked; +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +int AccessibilityUIElement::indexInTable() +{ + // FIXME: implement + return 0; +} + +static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) +{ + GOwnPtr<gchar> rangeString(g_strdup("{0, 0}")); + + if (!element) + return JSStringCreateWithUTF8CString(rangeString.get()); + + ASSERT(ATK_IS_OBJECT(element)); + + AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element)); + if (!axTable || !ATK_IS_TABLE(axTable)) + return JSStringCreateWithUTF8CString(rangeString.get()); + + // Look for the cell in the table. + gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element)); + if (indexInParent == -1) + return JSStringCreateWithUTF8CString(rangeString.get()); + + int row = -1; + int column = -1; + row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent); + column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent); + + // Get the actual values, if row and columns are valid values. + if (row != -1 && column != -1) { + int base = 0; + int length = 0; + if (isRowRange) { + base = row; + length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column); + } else { + base = column; + length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column); + } + rangeString.set(g_strdup_printf("{%d, %d}", base, length)); + } + + return JSStringCreateWithUTF8CString(rangeString.get()); +} + +JSStringRef AccessibilityUIElement::rowIndexRange() +{ + // Range in table for rows. + return indexRangeInTable(m_element, true); +} + +JSStringRef AccessibilityUIElement::columnIndexRange() +{ + // Range in table for columns. + return indexRangeInTable(m_element, false); +} + +int AccessibilityUIElement::lineForIndex(int) +{ + // FIXME: implement + return 0; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) +{ + // FIXME: implement + return false; +} + +AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) +{ + if (!m_element) + return 0; + + ASSERT(ATK_IS_TABLE(m_element)); + + AtkObject* foundCell = atk_table_ref_at(ATK_TABLE(m_element), row, column); + return foundCell ? AccessibilityUIElement(foundCell) : 0; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ + // FIXME: implement +} + +JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return 0.0f; +} + +bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) +{ + return false; +} + +void AccessibilityUIElement::increment() +{ + if (!m_element) + return; + + ASSERT(ATK_IS_OBJECT(m_element)); + DumpRenderTreeSupportGtk::incrementAccessibilityValue(ATK_OBJECT(m_element)); +} + +void AccessibilityUIElement::decrement() +{ + if (!m_element) + return; + + ASSERT(ATK_IS_OBJECT(m_element)); + DumpRenderTreeSupportGtk::decrementAccessibilityValue(ATK_OBJECT(m_element)); +} + +void AccessibilityUIElement::press() +{ + if (!m_element) + return; + + ASSERT(ATK_IS_OBJECT(m_element)); + + if (!ATK_IS_ACTION(m_element)) + return; + + // Only one action per object is supported so far. + atk_action_do_action(ATK_ACTION(m_element), 0); +} + +void AccessibilityUIElement::showMenu() +{ + // FIXME: implement +} + +AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedByRow() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::accessibilityValue() const +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentEncoding() +{ + AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); + if (role != ATK_ROLE_DOCUMENT_FRAME) + return JSStringCreateWithCharacters(0, 0); + + return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding")); +} + +JSStringRef AccessibilityUIElement::documentURI() +{ + AtkRole role = atk_object_get_role(ATK_OBJECT(m_element)); + if (role != ATK_ROLE_DOCUMENT_FRAME) + return JSStringCreateWithCharacters(0, 0); + + return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI")); +} + +JSStringRef AccessibilityUIElement::url() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) +{ + // FIXME: implement + return false; +} + +void AccessibilityUIElement::removeNotificationListener() +{ + // FIXME: implement +} + +bool AccessibilityUIElement::isFocusable() const +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); + gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE); + + return isFocusable; +} + +bool AccessibilityUIElement::isSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isMultiSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelectedOptionActive() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isVisible() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isOffScreen() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isCollapsed() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isIgnored() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::hasPopup() const +{ + // FIXME: implement + return false; +} + +void AccessibilityUIElement::takeFocus() +{ + // FIXME: implement +} + +void AccessibilityUIElement::takeSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::addSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::removeSelection() +{ + // FIXME: implement +} diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp new file mode 100644 index 000000000..d6bb426f2 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -0,0 +1,1208 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Alp Toker <alp@nuanti.com> + * Copyright (C) 2009 Jan Alonzo <jmalonzo@gmail.com> + * Copyright (C) 2010, 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" + +#include "AccessibilityController.h" +#include "EditingCallbacks.h" +#include "EventSender.h" +#include "GCController.h" +#include "GOwnPtr.h" +#include "LayoutTestController.h" +#include "PixelDumpSupport.h" +#include "PlainTextController.h" +#include "SelfScrollingWebKitWebView.h" +#include "TextInputController.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include "WebCoreTestSupport.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include <JavaScriptCore/JavaScript.h> +#include <cassert> +#include <cstdlib> +#include <cstring> +#include <getopt.h> +#include <gtk/gtk.h> +#include <webkit/webkit.h> +#include <wtf/Assertions.h> +#include <wtf/gobject/GlibUtilities.h> + +#if PLATFORM(X11) +#include <fontconfig/fontconfig.h> +#endif + + +using namespace std; + +extern "C" { +// This API is not yet public. +extern gchar* webkit_web_history_item_get_target(WebKitWebHistoryItem*); +extern gboolean webkit_web_history_item_is_target_item(WebKitWebHistoryItem*); +extern GList* webkit_web_history_item_get_children(WebKitWebHistoryItem*); +extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory); +extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame); +} + +volatile bool done; +static bool printSeparators; +static int dumpPixels; +static int dumpTree = 1; + +AccessibilityController* axController = 0; +RefPtr<LayoutTestController> gLayoutTestController; +static GCController* gcController = 0; +static WebKitWebView* webView; +static GtkWidget* window; +static GtkWidget* container; +static GtkWidget* webInspectorWindow; +WebKitWebFrame* mainFrame = 0; +WebKitWebFrame* topLoadingFrame = 0; +guint waitToDumpWatchdog = 0; +bool waitForPolicy = false; + +// This is a list of opened webviews +GSList* webViewList = 0; + +// current b/f item at the end of the previous test +static WebKitWebHistoryItem* prevTestBFItem = NULL; + +const unsigned historyItemIndent = 8; + +static void runTest(const string& testPathOrURL); + +static bool shouldLogFrameLoadDelegates(const string& pathOrURL) +{ + return pathOrURL.find("loading/") != string::npos; +} + +static bool shouldOpenWebInspector(const string& pathOrURL) +{ + return pathOrURL.find("inspector/") != string::npos; +} + +static bool shouldDumpAsText(const string& pathOrURL) +{ + return pathOrURL.find("dumpAsText/") != string::npos; +} + +static bool shouldEnableDeveloperExtras(const string& pathOrURL) +{ + return true; +} + +void dumpFrameScrollPosition(WebKitWebFrame* frame) +{ + +} + +void displayWebView() +{ + gtk_widget_queue_draw(GTK_WIDGET(webView)); +} + +static void appendString(gchar*& target, gchar* string) +{ + gchar* oldString = target; + target = g_strconcat(target, string, NULL); + g_free(oldString); +} + +static void initializeGtkFontSettings(const char* testURL) +{ + GtkSettings* settings = gtk_settings_get_default(); + if (!settings) + return; + g_object_set(settings, + "gtk-xft-dpi", 98304, // This is 96 * 1024 or 96 DPI according to the GTK+ docs. + "gtk-xft-antialias", 1, + "gtk-xft-hinting", 0, + "gtk-font-name", "Liberation Sans 12", + NULL); + gdk_screen_set_resolution(gdk_screen_get_default(), 96.0); + + // One test needs subpixel anti-aliasing turned on, but generally we + // want all text in other tests to use to grayscale anti-aliasing. + if (testURL && strstr(testURL, "xsettings_antialias_settings.html")) + g_object_set(settings, "gtk-xft-rgba", "rgb", NULL); + else + g_object_set(settings, "gtk-xft-rgba", "none", NULL); + + GdkScreen* screen = gdk_screen_get_default(); + ASSERT(screen); + const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen); + ASSERT(screenOptions); + cairo_font_options_t* options = cairo_font_options_copy(screenOptions); + // Turn off text metrics hinting, which quantizes metrics to pixels in device space. + cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF); + gdk_screen_set_font_options(screen, options); + cairo_font_options_destroy(options); +} + +CString getTopLevelPath() +{ + if (const char* topLevelDirectory = g_getenv("WEBKIT_TOP_LEVEL")) + return topLevelDirectory; + + // If the environment variable wasn't provided then assume we were built into + // WebKitBuild/Debug or WebKitBuild/Release. Obviously this will fail if the build + // directory is non-standard, but we can't do much more about this. + GOwnPtr<char> parentPath(g_path_get_dirname(getCurrentExecutablePath().data())); + GOwnPtr<char> layoutTestsPath(g_build_filename(parentPath.get(), "..", "..", "..", NULL)); + GOwnPtr<char> absoluteTopLevelPath(realpath(layoutTestsPath.get(), 0)); + return absoluteTopLevelPath.get(); +} + +static void initializeFonts(const char* testURL = 0) +{ +#if PLATFORM(X11) + initializeGtkFontSettings(testURL); + + FcInit(); + + // If a test resulted a font being added or removed via the @font-face rule, then + // we want to reset the FontConfig configuration to prevent it from affecting other tests. + static int numFonts = 0; + FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication); + if (appFontSet && numFonts && appFontSet->nfont == numFonts) + return; + + // Load our configuration file, which sets up proper aliases for family + // names like sans, serif and monospace. + FcConfig* config = FcConfigCreate(); + GOwnPtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", NULL)); + if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true)) + g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get()); + + CString topLevelPath = getTopLevelPath(); + GOwnPtr<char> fontsPath(g_build_filename(topLevelPath.data(), "WebKitBuild", "Dependencies", + "Root", "webkitgtk-test-fonts", NULL)); + if (!g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + g_error("Could not locate test fonts at %s. Is WEBKIT_TOP_LEVEL set?", fontsPath.get()); + + GOwnPtr<GError> error; + GOwnPtr<GDir> fontsDirectory(g_dir_open(fontsPath.get(), 0, &error.outPtr())); + while (const char* directoryEntry = g_dir_read_name(fontsDirectory.get())) { + if (!g_str_has_suffix(directoryEntry, ".ttf") && !g_str_has_suffix(directoryEntry, ".otf")) + continue; + GOwnPtr<gchar> fontPath(g_build_filename(fontsPath.get(), directoryEntry, NULL)); + if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPath.get()))) + g_error("Could not load font at %s!", fontPath.get()); + + } + + // Ahem is used by many layout tests. + GOwnPtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", NULL)); + if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(ahemFontFilename.get()))) + g_error("Could not load font at %s!", ahemFontFilename.get()); + + for (int i = 1; i <= 9; i++) { + GOwnPtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i)); + GOwnPtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), NULL)); + if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontPath.get()))) + g_error("Could not load font at %s!", fontPath.get()); + } + + // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452 + GOwnPtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", NULL)); + if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontWithNoValidEncodingFilename.get()))) + g_error("Could not load font at %s!", fontWithNoValidEncodingFilename.get()); + + if (!FcConfigSetCurrent(config)) + g_error("Could not set the current font configuration!"); + + numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont; +#endif +} + +static gchar* dumpFramesAsText(WebKitWebFrame* frame) +{ + gchar* result = 0; + + // Add header for all but the main frame. + bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame); + + CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame); + if (isMainFrame) + result = g_strdup_printf("%s\n", innerText.data()); + else { + const gchar* frameName = webkit_web_frame_get_name(frame); + result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText.data()); + } + + if (gLayoutTestController->dumpChildFramesAsText()) { + GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame); + for (GSList* child = children; child; child = g_slist_next(child)) + appendString(result, dumpFramesAsText(static_cast<WebKitWebFrame* >(child->data))); + g_slist_free(children); + } + + return result; +} + +static gint compareHistoryItems(gpointer* item1, gpointer* item2) +{ + GOwnPtr<gchar> firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1))); + GOwnPtr<gchar> secondItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2))); + return g_ascii_strcasecmp(firstItemTarget.get(), secondItemTarget.get()); +} + +static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current) +{ + ASSERT(item != NULL); + int start = 0; + g_object_ref(item); + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + // normalize file URLs. + const gchar* uri = webkit_web_history_item_get_uri(item); + gchar* uriScheme = g_uri_parse_scheme(uri); + if (g_strcmp0(uriScheme, "file") == 0) { + gchar* pos = g_strstr_len(uri, -1, "/LayoutTests/"); + if (!pos) + return; + + GString* result = g_string_sized_new(strlen(uri)); + result = g_string_append(result, "(file test):"); + result = g_string_append(result, pos + strlen("/LayoutTests/")); + printf("%s", result->str); + g_string_free(result, TRUE); + } else + printf("%s", uri); + + g_free(uriScheme); + + const gchar* target = webkit_web_history_item_get_target(item); + if (target && strlen(target) > 0) + printf(" (in frame \"%s\")", target); + if (webkit_web_history_item_is_target_item(item)) + printf(" **nav target**"); + putchar('\n'); + + if (GList* kids = webkit_web_history_item_get_children(item)) { + // must sort to eliminate arbitrary result ordering which defeats reproducible testing + for (GList* kid = g_list_sort(kids, (GCompareFunc) compareHistoryItems); kid; kid = g_list_next(kid)) { + WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(kid->data); + dumpHistoryItem(item, indent + 4, FALSE); + g_object_unref(item); + } + g_list_free(kids); + } + g_object_unref(item); +} + +static void dumpBackForwardListForWebView(WebKitWebView* view) +{ + printf("\n============== Back Forward List ==============\n"); + WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view); + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + GList* itemsToPrint = NULL; + gint forwardListCount = webkit_web_back_forward_list_get_forward_length(bfList); + for (int i = forwardListCount; i > 0; i--) { + WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i); + // something is wrong if the item from the last test is in the forward part of the b/f list + ASSERT(item != prevTestBFItem); + g_object_ref(item); + itemsToPrint = g_list_prepend(itemsToPrint, item); + } + + WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList); + g_object_ref(currentItem); + itemsToPrint = g_list_prepend(itemsToPrint, currentItem); + + gint backListCount = webkit_web_back_forward_list_get_back_length(bfList); + for (int i = -1; i >= -(backListCount); i--) { + WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i); + if (item == prevTestBFItem) + break; + g_object_ref(item); + itemsToPrint = g_list_prepend(itemsToPrint, item); + } + + for (GList* itemToPrint = itemsToPrint; itemToPrint; itemToPrint = g_list_next(itemToPrint)) { + WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(itemToPrint->data); + dumpHistoryItem(item, historyItemIndent, item == currentItem); + g_object_unref(item); + } + + g_list_free(itemsToPrint); + printf("===============================================\n"); +} + +static void dumpBackForwardListForAllWebViews() +{ + // Dump the back forward list of the main WebView first + dumpBackForwardListForWebView(webView); + + // The view list is prepended. Reverse the list so we get the order right. + for (GSList* currentView = g_slist_reverse(webViewList); currentView; currentView = g_slist_next(currentView)) + dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(currentView->data)); +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + g_source_remove(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } + + waitForPolicy = false; +} + +static void resetDefaultsToConsistentValues() +{ + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + GOwnPtr<gchar> localStoragePath(g_build_filename(g_get_user_data_dir(), "DumpRenderTreeGtk", "databases", NULL)); + g_object_set(G_OBJECT(settings), + "enable-private-browsing", FALSE, + "enable-developer-extras", FALSE, + "enable-spell-checking", TRUE, + "enable-html5-database", TRUE, + "enable-html5-local-storage", TRUE, + "html5-local-storage-database-path", localStoragePath.get(), + "enable-xss-auditor", FALSE, + "enable-spatial-navigation", FALSE, + "enable-frame-flattening", FALSE, + "javascript-can-access-clipboard", TRUE, + "javascript-can-open-windows-automatically", TRUE, + "enable-offline-web-application-cache", TRUE, + "enable-universal-access-from-file-uris", TRUE, + "enable-scripts", TRUE, + "enable-dom-paste", TRUE, + "default-font-family", "Times", + "monospace-font-family", "Courier", + "serif-font-family", "Times", + "sans-serif-font-family", "Helvetica", + "cursive-font-family", "cursive", + "fantasy-font-family", "fantasy", + "default-font-size", 12, + "default-monospace-font-size", 10, + "minimum-font-size", 0, + "enable-caret-browsing", FALSE, + "enable-page-cache", FALSE, + "auto-resize-window", TRUE, + "enable-java-applet", FALSE, + "enable-plugins", TRUE, + "enable-hyperlink-auditing", FALSE, + "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, + "enable-fullscreen", TRUE, + NULL); + webkit_web_view_set_settings(webView, settings); + webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER); + + DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame); + DumpRenderTreeSupportGtk::scalePageBy(webView, 1, 0, 0); + + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL); + + webkit_web_view_set_zoom_level(webView, 1.0); + DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, DumpRenderTreeSupportGtk::defaultMinimumTimerInterval()); + + DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists(); + + WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView); + webkit_web_back_forward_list_clear(list); + + SoupSession* session = webkit_get_default_session(); + SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR)); + + // We only create the jar when the soup backend needs to do + // HTTP. Should we initialize it earlier, perhaps? + if (jar) + g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL); + + setlocale(LC_ALL, ""); + + DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true); + webkit_icon_database_set_path(webkit_get_icon_database(), 0); + DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(false); + DumpRenderTreeSupportGtk::setSmartInsertDeleteEnabled(webView, true); + + if (axController) + axController->resetToConsistentState(); + + DumpRenderTreeSupportGtk::clearOpener(mainFrame); + + DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView); + + DumpRenderTreeSupportGtk::setHixie76WebSocketProtocolEnabled(webView, true); +} + +static bool useLongRunningServerMode(int argc, char *argv[]) +{ + // This assumes you've already called getopt_long + return (argc == optind+1 && !strcmp(argv[optind], "-")); +} + +static void runTestingServerLoop() +{ + // When DumpRenderTree runs in server mode, we just wait around for file names + // to be passed to us and read each in turn, passing the results back to the client + char filenameBuffer[2048]; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + char* newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strlen(filenameBuffer)) + continue; + + runTest(filenameBuffer); + } +} + +static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[]) +{ + struct option options[] = { + {"notree", no_argument, &dumpTree, false}, + {"pixel-tests", no_argument, &dumpPixels, true}, + {"tree", no_argument, &dumpTree, true}, + {NULL, 0, NULL, 0} + }; + + int option; + while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) { + switch (option) { + case '?': // unknown or ambiguous option + case ':': // missing argument + exit(1); + break; + } + } +} + + +void dump() +{ + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (dumpTree) { + char* result = 0; + gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame); + + if (g_str_equal(responseMimeType, "text/plain")) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + g_free(responseMimeType); + + if (gLayoutTestController->dumpAsText()) + result = dumpFramesAsText(mainFrame); + else { + // Widget resizing is done asynchronously in GTK+. We pump the main + // loop here, to flush any pending resize requests. This prevents + // timing issues which affect the size of elements in the output. + // We only enable this workaround for tests that print the render tree + // because this seems to break some dumpAsText tests: see bug 39988 + // After fixing that test, we should apply this approach to all dumps. + while (gtk_events_pending()) + gtk_main_iteration(); + + result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data()); + } + + if (!result) { + const char* errorMessage; + if (gLayoutTestController->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (gLayoutTestController->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (gLayoutTestController->dumpSourceAsWebArchive()) + errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + printf("ERROR: nil result from %s", errorMessage); + } else { + printf("%s", result); + g_free(result); + if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + + if (gLayoutTestController->dumpBackForwardList()) + dumpBackForwardListForAllWebViews(); + } + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (dumpPixels + && gLayoutTestController->generatePixelResults() + && !gLayoutTestController->dumpDOMAsWebArchive() + && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + // FIXME: call displayWebView here when we support --paint + + done = true; + gtk_main_quit(); +} + +static void setDefaultsToConsistentStateValuesForTesting() +{ + resetDefaultsToConsistentValues(); + + /* Disable the default auth dialog for testing */ + SoupSession* session = webkit_get_default_session(); + soup_session_remove_feature_by_type(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG); + +#if PLATFORM(X11) + webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR); +#endif + + gchar* databaseDirectory = g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL); + webkit_set_web_database_directory_path(databaseDirectory); + g_free(databaseDirectory); + +#if defined(GTK_API_VERSION_2) + gtk_rc_parse_string("style \"nix_scrollbar_spacing\" " + "{ " + " GtkScrolledWindow::scrollbar-spacing = 0 " + "} " + "class \"GtkWidget\" style \"nix_scrollbar_spacing\""); + +#else + GtkCssProvider* cssProvider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(cssProvider, + " * { " + " -GtkScrolledWindow-scrollbar-spacing: 0;" + "} ", + -1, 0); + gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()), + GTK_STYLE_PROVIDER(cssProvider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref(cssProvider); +#endif +} + +static void sendPixelResultsEOF() +{ + puts("#EOF"); + + fflush(stdout); + fflush(stderr); +} + +static void runTest(const string& testPathOrURL) +{ + ASSERT(!testPathOrURL.empty()); + + // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. + string testURL(testPathOrURL); + string expectedPixelHash; + size_t separatorPos = testURL.find("'"); + if (separatorPos != string::npos) { + testURL = string(testPathOrURL, 0, separatorPos); + expectedPixelHash = string(testPathOrURL, separatorPos + 1); + } + + // Convert the path into a full file URL if it does not look + // like an HTTP/S URL (doesn't start with http:// or https://). + if (testURL.find("http://") && testURL.find("https://")) { + GFile* testFile = g_file_new_for_path(testURL.c_str()); + gchar* testURLCString = g_file_get_uri(testFile); + testURL = testURLCString; + g_free(testURLCString); + g_object_unref(testFile); + } + + resetDefaultsToConsistentValues(); + + gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash); + topLoadingFrame = 0; + done = false; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (shouldLogFrameLoadDelegates(testURL)) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + if (shouldEnableDeveloperExtras(testURL)) { + gLayoutTestController->setDeveloperExtrasEnabled(true); + if (shouldOpenWebInspector(testURL)) + gLayoutTestController->showWebInspector(); + if (shouldDumpAsText(testURL)) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + } + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos); + GtkAllocation size; + size.x = size.y = 0; + size.width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth; + size.height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight; + gtk_window_resize(GTK_WINDOW(window), size.width, size.height); + gtk_widget_size_allocate(container, &size); + + if (prevTestBFItem) + g_object_unref(prevTestBFItem); + WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(webView); + prevTestBFItem = webkit_web_back_forward_list_get_current_item(bfList); + if (prevTestBFItem) + g_object_ref(prevTestBFItem); + + initializeFonts(testURL.c_str()); + + // Focus the web view before loading the test to avoid focusing problems + gtk_widget_grab_focus(GTK_WIDGET(webView)); + webkit_web_view_open(webView, testURL.c_str()); + + gtk_main(); + + // If developer extras enabled Web Inspector may have been open by the test. + if (shouldEnableDeveloperExtras(testURL)) { + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } + + // Also check if we still have opened webViews and free them. + if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) { + while (webViewList) { + g_object_unref(WEBKIT_WEB_VIEW(webViewList->data)); + webViewList = g_slist_next(webViewList); + } + g_slist_free(webViewList); + webViewList = 0; + } + + WebCoreTestSupport::resetInternalsObject(webkit_web_frame_get_global_context(mainFrame)); + + // A blank load seems to be necessary to reset state after certain tests. + webkit_web_view_open(webView, "about:blank"); + + gLayoutTestController.clear(); + + // terminate the (possibly empty) pixels block after all the state reset + sendPixelResultsEOF(); +} + +void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; +} + +static gboolean processWork(void* data) +{ + // if we finish all the commands, we're ready to dump state + if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) + dump(); + + return FALSE; +} + +static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame) +{ + char* frameName = g_strdup(webkit_web_frame_get_name(frame)); + + if (frame == webkit_web_view_get_main_frame(view)) { + // This is a bit strange. Shouldn't web_frame_get_name return NULL? + if (frameName && (frameName[0] != '\0')) { + char* tmp = g_strdup_printf("main frame \"%s\"", frameName); + g_free(frameName); + frameName = tmp; + } else { + g_free(frameName); + frameName = g_strdup("main frame"); + } + } else if (!frameName || (frameName[0] == '\0')) { + g_free(frameName); + frameName = g_strdup("frame (anonymous)"); + } else { + char* tmp = g_strdup_printf("frame \"%s\"", frameName); + g_free(frameName); + frameName = tmp; + } + + return frameName; +} + +static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + // The deprecated "load-finished" signal is triggered by postProgressFinishedNotification(), + // so we can use it here in the DRT to provide the correct dump. + if (frame != topLoadingFrame) + return; + if (gLayoutTestController->dumpProgressFinishedCallback()) + printf("postProgressFinishedNotification\n"); +} + +static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer) +{ + return TRUE; // Return true here to disable the default error page. +} + +static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + char* frameName = getFrameNameSuitableForTestResult(view, frame); + printf("%s - didFinishDocumentLoadForFrame\n", frameName); + g_free(frameName); + } else if (!done) { + guint pendingFrameUnloadEvents = DumpRenderTreeSupportGtk::getPendingUnloadEventCount(frame); + if (pendingFrameUnloadEvents) { + char* frameName = getFrameNameSuitableForTestResult(view, frame); + printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents); + g_free(frameName); + } + } +} + +static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + char* frameName = getFrameNameSuitableForTestResult(view, frame); + printf("%s - didHandleOnloadEventsForFrame\n", frameName); + g_free(frameName); + } +} + +static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller) +{ + JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName); + JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); + JSStringRelease(controllerNameStr); +} + +static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data) +{ + JSValueRef exception = 0; + ASSERT(gLayoutTestController); + + gLayoutTestController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + axController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame))); + addControllerToWindow(context, windowObject, "plainText", makePlainTextController(context)); + addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context)); + WebCoreTestSupport::injectInternalsObject(context); +} + +static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data) +{ + gchar* testMessage = 0; + const gchar* uriScheme; + + // Tests expect only the filename part of local URIs + uriScheme = g_strstr_len(message, -1, "file://"); + if (uriScheme) { + GString* tempString = g_string_sized_new(strlen(message)); + gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S); + + if (filename) { + filename += strlen(G_DIR_SEPARATOR_S); + tempString = g_string_append_len(tempString, message, (uriScheme - message)); + tempString = g_string_append_len(tempString, filename, strlen(filename)); + testMessage = g_string_free(tempString, FALSE); + } + } + + fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, testMessage ? testMessage : message); + g_free(testMessage); + + return TRUE; +} + + +static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data) +{ + fprintf(stdout, "ALERT: %s\n", message); + return TRUE; +} + +static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data) +{ + fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue); + *value = g_strdup(defaultValue); + return TRUE; +} + +static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data) +{ + fprintf(stdout, "CONFIRM: %s\n", message); + *didConfirm = TRUE; + return TRUE; +} + +static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data) +{ + if (gLayoutTestController->dumpTitleChanges() && !done) + printf("TITLE CHANGED: %s\n", title ? title : ""); +} + +static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame, + WebKitNetworkRequest* request, + WebKitWebNavigationAction* navAction, + WebKitWebPolicyDecision* policyDecision) +{ + // Use the default handler if we're not waiting for policy, + // i.e., LayoutTestController::waitForPolicyDelegate + if (!waitForPolicy) + return FALSE; + + gchar* typeDescription; + WebKitWebNavigationReason reason; + g_object_get(G_OBJECT(navAction), "reason", &reason, NULL); + + switch(reason) { + case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED: + typeDescription = g_strdup("link clicked"); + break; + case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED: + typeDescription = g_strdup("form submitted"); + break; + case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD: + typeDescription = g_strdup("back/forward"); + break; + case WEBKIT_WEB_NAVIGATION_REASON_RELOAD: + typeDescription = g_strdup("reload"); + break; + case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED: + typeDescription = g_strdup("form resubmitted"); + break; + case WEBKIT_WEB_NAVIGATION_REASON_OTHER: + typeDescription = g_strdup("other"); + break; + default: + typeDescription = g_strdup("illegal value"); + } + + printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription); + g_free(typeDescription); + + webkit_web_policy_decision_ignore(policyDecision); + gLayoutTestController->notifyDone(); + + return TRUE; +} + +static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data) +{ + // Are we doing anything wrong? One test that does not call + // dumpStatusCallbacks gets true here + if (gLayoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message); +} + +static gboolean webViewClose(WebKitWebView* view) +{ + ASSERT(view); + + webViewList = g_slist_remove(webViewList, view); + g_object_unref(view); + + return TRUE; +} + +static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database) +{ + ASSERT(view); + ASSERT(frame); + ASSERT(database); + + WebKitSecurityOrigin* origin = webkit_web_database_get_security_origin(database); + if (gLayoutTestController->dumpDatabaseCallbacks()) { + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", + webkit_security_origin_get_protocol(origin), + webkit_security_origin_get_host(origin), + webkit_security_origin_get_port(origin), + webkit_web_database_get_name(database)); + } + webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024); +} + +static bool +geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision) +{ + if (!gLayoutTestController->isGeolocationPermissionSet()) + return FALSE; + if (gLayoutTestController->geolocationPermission()) + webkit_geolocation_policy_allow(decision); + else + webkit_geolocation_policy_deny(decision); + + return TRUE; +} + + +static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*); + +static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data) +{ + gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600); + gtk_widget_show_all(webInspectorWindow); + return TRUE; +} + +static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data) +{ + gtk_widget_destroy(webInspectorWindow); + webInspectorWindow = 0; + return TRUE; +} + +static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data) +{ + webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + GtkWidget* webView = self_scrolling_webkit_web_view_new(); + gtk_container_add(GTK_CONTAINER(webInspectorWindow), + webView); + + return WEBKIT_WEB_VIEW(webView); +} + +static void topLoadingFrameLoadFinished() +{ + topLoadingFrame = 0; + WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test + if (gLayoutTestController->waitToDump()) + return; + + if (WorkQueue::shared()->count()) + g_timeout_add(0, processWork, 0); + else + dump(); +} + +static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data) +{ + WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame); + + if (gLayoutTestController->dumpFrameLoadCallbacks()) { + GOwnPtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame)); + + switch (loadStatus) { + case WEBKIT_LOAD_PROVISIONAL: + if (!done) + printf("%s - didStartProvisionalLoadForFrame\n", frameName.get()); + break; + case WEBKIT_LOAD_COMMITTED: + if (!done) + printf("%s - didCommitLoadForFrame\n", frameName.get()); + break; + case WEBKIT_LOAD_FINISHED: + if (!done) + printf("%s - didFinishLoadForFrame\n", frameName.get()); + break; + default: + break; + } + } + + if ((loadStatus == WEBKIT_LOAD_FINISHED || loadStatus == WEBKIT_LOAD_FAILED) + && frame == topLoadingFrame) + topLoadingFrameLoadFinished(); +} + +static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data) +{ + g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL); +} + +static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource*, WebKitNetworkRequest* request, WebKitNetworkResponse*) +{ + if (!done && gLayoutTestController->willSendRequestReturnsNull()) { + // As requested by the LayoutTestController, don't perform the request. + webkit_network_request_set_uri(request, "about:blank"); + return; + } + + SoupMessage* soupMessage = webkit_network_request_get_message(request); + SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request)); + + if (SOUP_URI_VALID_FOR_HTTP(uri) && g_strcmp0(uri->host, "127.0.0.1") + && g_strcmp0(uri->host, "255.255.255.255") + && g_ascii_strncasecmp(uri->host, "localhost", 9)) { + printf("Blocked access to external URL %s\n", soup_uri_to_string(uri, FALSE)); + soup_uri_free(uri); + return; + } + if (uri) + soup_uri_free(uri); + + if (soupMessage) { + const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) + soup_message_headers_remove(soupMessage->request_headers, header->c_str()); + } +} + +static WebKitWebView* createWebView() +{ + // It is important to declare DRT is running early so when creating + // web view mock clients are used instead of proper ones. + DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true); + + WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new()); + + g_object_connect(G_OBJECT(view), + "signal::load-started", webViewLoadStarted, 0, + "signal::load-finished", webViewLoadFinished, 0, + "signal::load-error", webViewLoadError, 0, + "signal::window-object-cleared", webViewWindowObjectCleared, 0, + "signal::console-message", webViewConsoleMessage, 0, + "signal::script-alert", webViewScriptAlert, 0, + "signal::script-prompt", webViewScriptPrompt, 0, + "signal::script-confirm", webViewScriptConfirm, 0, + "signal::title-changed", webViewTitleChanged, 0, + "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0, + "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0, + "signal::create-web-view", webViewCreate, 0, + "signal::close-web-view", webViewClose, 0, + "signal::database-quota-exceeded", databaseQuotaExceeded, 0, + "signal::document-load-finished", webViewDocumentLoadFinished, 0, + "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0, + "signal::onload-event", webViewOnloadEvent, 0, + "signal::drag-begin", dragBeginCallback, 0, + "signal::drag-end", dragEndCallback, 0, + "signal::drag-failed", dragFailedCallback, 0, + "signal::frame-created", frameCreatedCallback, 0, + "signal::resource-request-starting", willSendRequestCallback, 0, + + NULL); + connectEditingCallbacks(view); + + WebKitWebInspector* inspector = webkit_web_view_get_inspector(view); + g_object_connect(G_OBJECT(inspector), + "signal::inspect-web-view", webInspectorInspectWebView, 0, + "signal::show-window", webInspectorShowWindow, 0, + "signal::close-window", webInspectorCloseWindow, 0, + NULL); + + if (webView) { + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + webkit_web_view_set_settings(view, settings); + } + + // frame-created is not issued for main frame. That's why we must do this here + WebKitWebFrame* frame = webkit_web_view_get_main_frame(view); + g_signal_connect(frame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL); + + return view; +} + +static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame) +{ + if (!gLayoutTestController->canOpenWindows()) + return 0; + + // Make sure that waitUntilDone has been called. + ASSERT(gLayoutTestController->waitToDump()); + + WebKitWebView* newWebView = createWebView(); + g_object_ref_sink(G_OBJECT(newWebView)); + webViewList = g_slist_prepend(webViewList, newWebView); + return newWebView; +} + +static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data) +{ + if (level < G_LOG_LEVEL_DEBUG) + fprintf(stderr, "%s\n", message); +} + +int main(int argc, char* argv[]) +{ + gtk_init(&argc, &argv); + + // Some plugins might try to use the GLib logger for printing debug + // messages. This will cause tests to fail because of unexpected output. + // We squelch all debug messages sent to the logger. + g_log_set_default_handler(logHandler, 0); + + initializeGlobalsFromCommandLineOptions(argc, argv); + initializeFonts(); + + window = gtk_window_new(GTK_WINDOW_POPUP); +#ifdef GTK_API_VERSION_2 + container = gtk_hbox_new(TRUE, 0); +#else + container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous(GTK_BOX(container), TRUE); +#endif + gtk_container_add(GTK_CONTAINER(window), container); + gtk_widget_show_all(window); + + webView = createWebView(); + gtk_box_pack_start(GTK_BOX(container), GTK_WIDGET(webView), TRUE, TRUE, 0); + gtk_widget_realize(GTK_WIDGET(webView)); + gtk_widget_show_all(container); + mainFrame = webkit_web_view_get_main_frame(webView); + + setDefaultsToConsistentStateValuesForTesting(); + + gcController = new GCController(); + axController = new AccessibilityController(); + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = true; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + delete gcController; + gcController = 0; + + delete axController; + axController = 0; + + gtk_widget_destroy(window); + + return 0; +} diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h new file mode 100644 index 000000000..dbd1f8a3d --- /dev/null +++ b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeGtk_h +#define DumpRenderTreeGtk_h + +#include <webkit/webkitdefines.h> +#include <JavaScriptCore/JSBase.h> +#include <glib.h> +#include <wtf/text/CString.h> + +extern WebKitWebFrame* mainFrame; +extern WebKitWebFrame* topLoadingFrame; +extern guint waitToDumpWatchdog; +extern bool waitForPolicy; +extern GSList* webViewList; + +gchar* JSStringCopyUTF8CString(JSStringRef jsString); +CString getTopLevelPath(); + +#endif // DumpRenderTreeGtk_h diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp new file mode 100644 index 000000000..2586611aa --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EditingCallbacks.h" + +#include "CString.h" +#include "DumpRenderTree.h" +#include "GOwnPtr.h" +#include "LayoutTestController.h" +#include <gtk/gtk.h> +#include <webkit/webkit.h> + +static CString dumpNodePath(WebKitDOMNode* node) +{ + GOwnPtr<gchar> nodeName(webkit_dom_node_get_node_name(node)); + GString* path = g_string_new(nodeName.get()); + + WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node); + while (parent) { + GOwnPtr<gchar> parentName(webkit_dom_node_get_node_name(parent)); + + g_string_append(path, " > "); + g_string_append(path, parentName.get()); + parent = webkit_dom_node_get_parent_node(parent); + } + + GOwnPtr<gchar> pathBuffer(g_string_free(path, FALSE)); + return pathBuffer.get(); +} + +static CString dumpRange(WebKitDOMRange* range) +{ + if (!range) + return "(null)"; + + GOwnPtr<GError> error1; + GOwnPtr<GError> error2; + GOwnPtr<GError> error3; + GOwnPtr<GError> error4; + GOwnPtr<gchar> dump(g_strdup_printf("range from %li of %s to %li of %s", + webkit_dom_range_get_start_offset(range, &error1.outPtr()), + dumpNodePath(webkit_dom_range_get_start_container(range, &error2.outPtr())).data(), + webkit_dom_range_get_end_offset(range, &error3.outPtr()), + dumpNodePath(webkit_dom_range_get_end_container(range, &error4.outPtr())).data())); + return dump.get(); +} + +static const char* insertActionString(WebKitInsertAction action) +{ + switch (action) { + case WEBKIT_INSERT_ACTION_TYPED: + return "WebViewInsertActionTyped"; + case WEBKIT_INSERT_ACTION_PASTED: + return "WebViewInsertActionPasted"; + case WEBKIT_INSERT_ACTION_DROPPED: + return "WebViewInsertActionDropped"; + } + ASSERT_NOT_REACHED(); + return "WebViewInsertActionTyped"; +} + +static const char* selectionAffinityString(WebKitSelectionAffinity affinity) +{ + switch (affinity) { + case WEBKIT_SELECTION_AFFINITY_UPSTREAM: + return "NSSelectionAffinityUpstream"; + case WEBKIT_SELECTION_AFFINITY_DOWNSTREAM: + return "NSSelectionAffinityDownstream"; + } + ASSERT_NOT_REACHED(); + return "NSSelectionAffinityUpstream"; +} + +gboolean shouldBeginEditing(WebKitWebView* webView, WebKitDOMRange* range) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldEndEditing(WebKitWebView* webView, WebKitDOMRange* range) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldInsertNode(WebKitWebView* webView, WebKitDOMNode* node, WebKitDOMRange* range, WebKitInsertAction action) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) { + printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n", + dumpNodePath(node).data(), dumpRange(range).data(), insertActionString(action)); + } + return TRUE; +} + +gboolean shouldInsertText(WebKitWebView* webView, const gchar* text, WebKitDOMRange* range, WebKitInsertAction action) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) { + printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n", + text, dumpRange(range).data(), insertActionString(action)); + } + return TRUE; +} + +gboolean shouldDeleteRange(WebKitWebView* webView, WebKitDOMRange* range) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldShowDeleteInterfaceForElement(WebKitWebView* webView, WebKitDOMHTMLElement* element) +{ + GOwnPtr<gchar> elementClassName(webkit_dom_html_element_get_class_name(element)); + return g_str_equal(elementClassName.get(), "needsDeletionUI"); +} + +gboolean shouldChangeSelectedRange(WebKitWebView* webView, WebKitDOMRange* fromRange, WebKitDOMRange* toRange, WebKitSelectionAffinity affinity, gboolean stillSelecting) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) { + printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n", + dumpRange(fromRange).data(), dumpRange(toRange).data(), selectionAffinityString(affinity), + stillSelecting ? "TRUE" : "FALSE"); + } + return TRUE; +} + +gboolean shouldApplyStyle(WebKitWebView* webView, WebKitDOMCSSStyleDeclaration* style, WebKitDOMRange* range) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) { + GOwnPtr<gchar> styleText(webkit_dom_css_style_declaration_get_css_text(style)); + printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n", + styleText.get(), dumpRange(range).data()); + } + return TRUE; +} + +void editingBegan(WebKitWebView*) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n"); +} + +void userChangedContents(WebKitWebView*) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n"); +} + +void editingEnded(WebKitWebView*) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n"); +} + +void selectionChanged(WebKitWebView*) +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n"); +} + +void connectEditingCallbacks(WebKitWebView* webView) +{ + g_object_connect(G_OBJECT(webView), + "signal::should-begin-editing", shouldBeginEditing, 0, + "signal::should-end-editing", shouldEndEditing, 0, + "signal::should-insert-node", shouldInsertNode, 0, + "signal::should-insert-text", shouldInsertText, 0, + "signal::should-delete-range", shouldDeleteRange, 0, + "signal::should-show-delete-interface-for-element", shouldShowDeleteInterfaceForElement, 0, + "signal::should-change-selected-range", shouldChangeSelectedRange, 0, + "signal::should-apply-style", shouldApplyStyle, 0, + "signal::editing-began", editingBegan, 0, + "signal::user-changed-contents", userChangedContents, 0, + "signal::editing-ended", editingEnded, 0, + "signal::selection-changed", selectionChanged, 0, + NULL); +} + diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.h b/Tools/DumpRenderTree/gtk/EditingCallbacks.h new file mode 100644 index 000000000..7a9514917 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EditingCallbacks.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EditingCallbacks_h +#define EditingCallbacks_h + +typedef struct _WebKitWebView WebKitWebView; +void connectEditingCallbacks(WebKitWebView*); + +#endif diff --git a/Tools/DumpRenderTree/gtk/EventSender.cpp b/Tools/DumpRenderTree/gtk/EventSender.cpp new file mode 100644 index 000000000..250189090 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EventSender.cpp @@ -0,0 +1,898 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h" + +#include "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <GOwnPtrGtk.h> +#include <GRefPtrGtk.h> +#include <GtkVersioning.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <cstring> +#include <gdk/gdk.h> +#include <gdk/gdkkeysyms.h> +#include <webkit/webkitwebframe.h> +#include <webkit/webkitwebview.h> +#include <wtf/ASCIICType.h> +#include <wtf/Platform.h> +#include <wtf/text/CString.h> + +extern "C" { + extern GtkMenu* webkit_web_view_get_context_menu(WebKitWebView*); +} + +static bool dragMode; +static int timeOffset = 0; + +static int lastMousePositionX; +static int lastMousePositionY; +static int lastClickPositionX; +static int lastClickPositionY; +static int lastClickTimeOffset; +static int lastClickButton; +static unsigned buttonCurrentlyDown; +static int clickCount; +GdkDragContext* currentDragSourceContext; + +struct DelayedMessage { + GdkEvent* event; + gulong delay; +}; + +static DelayedMessage msgQueue[1024]; + +static unsigned endOfQueue; +static unsigned startOfQueue; + +static const float zoomMultiplierRatio = 1.2f; + +// Key event location code defined in DOM Level 3. +enum KeyLocationCode { + DOM_KEY_LOCATION_STANDARD = 0x00, + DOM_KEY_LOCATION_LEFT = 0x01, + DOM_KEY_LOCATION_RIGHT = 0x02, + DOM_KEY_LOCATION_NUMPAD = 0x03 +}; + +static void sendOrQueueEvent(GdkEvent*, bool = true); +static void dispatchEvent(GdkEvent* event); +static guint getStateFlags(); + +static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeBoolean(context, dragMode); +} + +static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + dragMode = JSValueToBoolean(context, value); + return true; +} + +static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount > 0) { + msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception); + timeOffset += msgQueue[endOfQueue].delay; + ASSERT(!exception || !*exception); + } + + return JSValueMakeUndefined(context); +} + +bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber, guint modifiers) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return false; + + // The logic for mapping EventSender button numbers to GDK button + // numbers originates from the Windows EventSender. + int gdkButtonNumber = 3; + if (eventSenderButtonNumber >= 0 && eventSenderButtonNumber <= 2) + gdkButtonNumber = eventSenderButtonNumber + 1; + + // fast/events/mouse-click-events expects the 4th button + // to be event->button = 1, so send a middle-button event. + else if (eventSenderButtonNumber == 3) + gdkButtonNumber = 2; + + event->button.button = gdkButtonNumber; + event->button.x = lastMousePositionX; + event->button.y = lastMousePositionY; + event->button.window = gtk_widget_get_window(GTK_WIDGET(view)); + g_object_ref(event->button.window); + event->button.device = getDefaultGDKPointerDevice(event->button.window); + event->button.state = modifiers | getStateFlags(); + event->button.time = GDK_CURRENT_TIME; + event->button.axes = 0; + + int xRoot, yRoot; + gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); + event->button.x_root = xRoot; + event->button.y_root = yRoot; + + return true; +} + +static JSValueRef getMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + GtkWidget* widget = GTK_WIDGET(JSObjectGetPrivate(object)); + CString label; + if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) + label = "<separator>"; + else + label = gtk_menu_item_get_label(GTK_MENU_ITEM(widget)); + + return JSValueMakeString(context, JSStringCreateWithUTF8CString(label.data())); +} + +static bool setMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + return true; +} + +static JSValueRef menuItemClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GtkMenuItem* item = GTK_MENU_ITEM(JSObjectGetPrivate(thisObject)); + gtk_menu_item_activate(item); + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticMenuItemFunctions[] = { + { "click", menuItemClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSStaticValue staticMenuItemValues[] = { + { "title", getMenuItemTitleCallback, setMenuItemTitleCallback, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static JSClassRef getMenuItemClass() +{ + static JSClassRef menuItemClass = 0; + + if (!menuItemClass) { + JSClassDefinition classDefinition = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + classDefinition.staticFunctions = staticMenuItemFunctions; + classDefinition.staticValues = staticMenuItemValues; + + menuItemClass = JSClassCreate(&classDefinition); + } + + return menuItemClass; +} + + +static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS); + + if (!prepareMouseButtonEvent(pressEvent, 2, 0)) + return JSObjectMakeArray(context, 0, 0, 0); + + GdkEvent* releaseEvent = gdk_event_copy(pressEvent); + sendOrQueueEvent(pressEvent); + + JSValueRef valueRef = JSObjectMakeArray(context, 0, 0, 0); + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + GtkMenu* gtkMenu = webkit_web_view_get_context_menu(view); + if (gtkMenu) { + GList* items = gtk_container_get_children(GTK_CONTAINER(gtkMenu)); + JSValueRef arrayValues[g_list_length(items)]; + int index = 0; + for (GList* item = g_list_first(items); item; item = g_list_next(item)) { + arrayValues[index] = JSObjectMake(context, getMenuItemClass(), item->data); + index++; + } + if (index) + valueRef = JSObjectMakeArray(context, index - 1, arrayValues, 0); + } + + releaseEvent->type = GDK_BUTTON_RELEASE; + sendOrQueueEvent(releaseEvent); + return valueRef; +} + +static gboolean sendClick(gpointer) +{ + GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS); + + if (!prepareMouseButtonEvent(pressEvent, 1, 0)) { + gdk_event_free(pressEvent); + return FALSE; + } + + GdkEvent* releaseEvent = gdk_event_copy(pressEvent); + dispatchEvent(pressEvent); + releaseEvent->type = GDK_BUTTON_RELEASE; + dispatchEvent(releaseEvent); + + return FALSE; +} + +static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + g_idle_add(sendClick, 0); + return JSValueMakeUndefined(context); +} + +static void updateClickCount(int button) +{ + if (lastClickPositionX != lastMousePositionX + || lastClickPositionY != lastMousePositionY + || lastClickButton != button + || timeOffset - lastClickTimeOffset >= 1) + clickCount = 1; + else + clickCount++; +} + +static guint gdkModifierFromJSValue(JSContextRef context, const JSValueRef value) +{ + JSStringRef string = JSValueToStringCopy(context, value, 0); + guint gdkModifier = 0; + if (JSStringIsEqualToUTF8CString(string, "ctrlKey") + || JSStringIsEqualToUTF8CString(string, "addSelectionKey")) + gdkModifier = GDK_CONTROL_MASK; + else if (JSStringIsEqualToUTF8CString(string, "shiftKey") + || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey")) + gdkModifier = GDK_SHIFT_MASK; + else if (JSStringIsEqualToUTF8CString(string, "altKey")) + gdkModifier = GDK_MOD1_MASK; + + // Currently the metaKey as defined in WebCore/platform/gtk/PlatformMouseEventGtk.cpp + // is GDK_META_MASK. This code must be kept in sync with that file. + else if (JSStringIsEqualToUTF8CString(string, "metaKey")) + gdkModifier = GDK_META_MASK; + + JSStringRelease(string); + return gdkModifier; +} + +static guint gdkModifersFromJSValue(JSContextRef context, const JSValueRef modifiers) +{ + // The value may either be a string with a single modifier or an array of modifiers. + if (JSValueIsString(context, modifiers)) + return gdkModifierFromJSValue(context, modifiers); + + JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0); + if (!modifiersArray) + return 0; + + guint gdkModifiers = 0; + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0); + for (int i = 0; i < modifiersCount; ++i) + gdkModifiers |= gdkModifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0)); + return gdkModifiers; +} + +static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + } + guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0; + + GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS); + if (!prepareMouseButtonEvent(event, button, modifiers)) + return JSValueMakeUndefined(context); + + // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb. + if (buttonCurrentlyDown == event->button.button) + return JSValueMakeUndefined(context); + + buttonCurrentlyDown = event->button.button; + + // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for + // the second button press during double-clicks. WebKit GTK+ selectively + // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek. + // Since our events aren't ever going onto the GDK event queue, WebKit won't + // be able to filter out the first GDK_BUTTON_PRESS, so we just don't send + // it here. Eventually this code should probably figure out a way to get all + // appropriate events onto the event queue and this work-around should be + // removed. + updateClickCount(event->button.button); + if (clickCount == 2) + event->type = GDK_2BUTTON_PRESS; + else if (clickCount == 3) + event->type = GDK_3BUTTON_PRESS; + + sendOrQueueEvent(event); + return JSValueMakeUndefined(context); +} + +static guint getStateFlags() +{ + if (buttonCurrentlyDown == 1) + return GDK_BUTTON1_MASK; + if (buttonCurrentlyDown == 2) + return GDK_BUTTON2_MASK; + if (buttonCurrentlyDown == 3) + return GDK_BUTTON3_MASK; + return 0; +} + +static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + } + guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0; + + GdkEvent* event = gdk_event_new(GDK_BUTTON_RELEASE); + if (!prepareMouseButtonEvent(event, button, modifiers)) + return JSValueMakeUndefined(context); + + lastClickPositionX = lastMousePositionX; + lastClickPositionY = lastMousePositionY; + lastClickButton = buttonCurrentlyDown; + lastClickTimeOffset = timeOffset; + buttonCurrentlyDown = 0; + + sendOrQueueEvent(event); + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return JSValueMakeUndefined(context); + + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + lastMousePositionX = (int)JSValueToNumber(context, arguments[0], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + lastMousePositionY = (int)JSValueToNumber(context, arguments[1], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + + GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY); + event->motion.x = lastMousePositionX; + event->motion.y = lastMousePositionY; + + event->motion.time = GDK_CURRENT_TIME; + event->motion.window = gtk_widget_get_window(GTK_WIDGET(view)); + g_object_ref(event->motion.window); + event->button.device = getDefaultGDKPointerDevice(event->motion.window); + + guint modifiers = argumentCount >= 3 ? gdkModifersFromJSValue(context, arguments[2]) : 0; + event->motion.state = modifiers | getStateFlags(); + event->motion.axes = 0; + + int xRoot, yRoot; + gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); + event->motion.x_root = xRoot; + event->motion.y_root = yRoot; + + sendOrQueueEvent(event, false); + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return JSValueMakeUndefined(context); + + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + int horizontal = (int)JSValueToNumber(context, arguments[0], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + int vertical = (int)JSValueToNumber(context, arguments[1], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + + // GTK+ doesn't support multiple direction scrolls in the same event! + g_return_val_if_fail((!vertical || !horizontal), JSValueMakeUndefined(context)); + + GdkEvent* event = gdk_event_new(GDK_SCROLL); + event->scroll.x = lastMousePositionX; + event->scroll.y = lastMousePositionY; + event->scroll.time = GDK_CURRENT_TIME; + event->scroll.window = gtk_widget_get_window(GTK_WIDGET(view)); + g_object_ref(event->scroll.window); + + if (horizontal < 0) + event->scroll.direction = GDK_SCROLL_RIGHT; + else if (horizontal > 0) + event->scroll.direction = GDK_SCROLL_LEFT; + else if (vertical < 0) + event->scroll.direction = GDK_SCROLL_DOWN; + else if (vertical > 0) + event->scroll.direction = GDK_SCROLL_UP; + else + g_assert_not_reached(); + + sendOrQueueEvent(event); + return JSValueMakeUndefined(context); +} + +static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // GTK doesn't support continuous scroll events. + return JSValueMakeUndefined(context); +} + +static void dragWithFilesDragDataGetCallback(GtkWidget*, GdkDragContext*, GtkSelectionData *data, guint, guint, gpointer userData) +{ + gtk_selection_data_set_uris(data, static_cast<gchar**>(userData)); +} + +static void dragWithFilesDragEndCallback(GtkWidget* widget, GdkDragContext*, gpointer userData) +{ + g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragEndCallback), userData); + g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragDataGetCallback), userData); + g_strfreev(static_cast<gchar**>(userData)); +} + +static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSObjectRef filesArray = JSValueToObject(context, arguments[0], exception); + ASSERT(!exception || !*exception); + + const gchar* mainFrameURI = webkit_web_frame_get_uri(mainFrame); + GRefPtr<GFile> testFile(adoptGRef(g_file_new_for_uri(mainFrameURI))); + GRefPtr<GFile> parentDirectory(g_file_get_parent(testFile.get())); + if (!parentDirectory) + return JSValueMakeUndefined(context); + + // If this is an HTTP test, we still need to pass a local file path + // to WebCore. Even though the file doesn't exist, this should be fine + // for most tests. + GOwnPtr<gchar> scheme(g_file_get_uri_scheme(parentDirectory.get())); + if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) { + GOwnPtr<gchar> currentDirectory(g_get_current_dir()); + parentDirectory = g_file_new_for_path(currentDirectory.get()); + } + + JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length"); + int filesArrayLength = JSValueToNumber(context, JSObjectGetProperty(context, filesArray, lengthProperty, 0), 0); + JSStringRelease(lengthProperty); + + gchar** draggedFilesURIList = g_new0(gchar*, filesArrayLength + 1); + for (int i = 0; i < filesArrayLength; ++i) { + JSStringRef filenameString = JSValueToStringCopy(context, + JSObjectGetPropertyAtIndex(context, filesArray, i, 0), 0); + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(filenameString); + GOwnPtr<gchar> filenameBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(filenameString, filenameBuffer.get(), bufferSize); + JSStringRelease(filenameString); + + GRefPtr<GFile> dragFile(g_file_get_child(parentDirectory.get(), filenameBuffer.get())); + draggedFilesURIList[i] = g_file_get_uri(dragFile.get()); + } + + GtkWidget* view = GTK_WIDGET(webkit_web_frame_get_web_view(mainFrame)); + g_object_connect(G_OBJECT(view), + "signal::drag-end", dragWithFilesDragEndCallback, draggedFilesURIList, + "signal::drag-data-get", dragWithFilesDragDataGetCallback, draggedFilesURIList, + NULL); + + GdkEvent event; + GdkWindow* viewGDKWindow = gtk_widget_get_window(view); + memset(&event, 0, sizeof(event)); + event.type = GDK_MOTION_NOTIFY; + event.motion.x = lastMousePositionX; + event.motion.y = lastMousePositionY; + event.motion.time = GDK_CURRENT_TIME; + event.motion.window = viewGDKWindow; + event.motion.device = getDefaultGDKPointerDevice(viewGDKWindow); + event.motion.state = GDK_BUTTON1_MASK; + + int xRoot, yRoot; + gdk_window_get_root_coords(viewGDKWindow, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); + event.motion.x_root = xRoot; + event.motion.y_root = yRoot; + + GtkTargetList* targetList = gtk_target_list_new(0, 0); + gtk_target_list_add_uri_targets(targetList, 0); + gtk_drag_begin(view, targetList, GDK_ACTION_COPY, 1, &event); + gtk_target_list_unref(targetList); + + return JSValueMakeUndefined(context); +} + +static void sendOrQueueEvent(GdkEvent* event, bool shouldReplaySavedEvents) +{ + // Mouse move events are queued if the previous event was queued or if a + // delay was set up by leapForward(). + if ((dragMode && buttonCurrentlyDown) || endOfQueue != startOfQueue || msgQueue[endOfQueue].delay) { + msgQueue[endOfQueue++].event = event; + + if (shouldReplaySavedEvents) + replaySavedEvents(); + + return; + } + + dispatchEvent(event); +} + +static void dispatchEvent(GdkEvent* event) +{ + DumpRenderTreeSupportGtk::layoutFrame(mainFrame); + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) { + gdk_event_free(event); + return; + } + + gtk_main_do_event(event); + + if (!currentDragSourceContext) { + gdk_event_free(event); + return; + } + + if (event->type == GDK_MOTION_NOTIFY) { + // WebKit has called gtk_drag_start(), but because the main loop isn't + // running GDK internals don't know that the drag has started yet. Pump + // the main loop a little bit so that GDK is in the correct state. + while (gtk_events_pending()) + gtk_main_iteration(); + + // Simulate a drag motion on the top-level GDK window. + GtkWidget* parentWidget = gtk_widget_get_parent(GTK_WIDGET(view)); + GdkWindow* parentWidgetWindow = gtk_widget_get_window(parentWidget); + gdk_drag_motion(currentDragSourceContext, parentWidgetWindow, GDK_DRAG_PROTO_XDND, + event->motion.x_root, event->motion.y_root, + gdk_drag_context_get_selected_action(currentDragSourceContext), + gdk_drag_context_get_actions(currentDragSourceContext), + GDK_CURRENT_TIME); + + } else if (currentDragSourceContext && event->type == GDK_BUTTON_RELEASE) { + // We've released the mouse button, we should just be able to spin the + // event loop here and have GTK+ send the appropriate notifications for + // the end of the drag. + while (gtk_events_pending()) + gtk_main_iteration(); + } + + gdk_event_free(event); +} + +void replaySavedEvents() +{ + // First send all the events that are ready to be sent + while (startOfQueue < endOfQueue) { + if (msgQueue[startOfQueue].delay) { + g_usleep(msgQueue[startOfQueue].delay * 1000); + msgQueue[startOfQueue].delay = 0; + } + + dispatchEvent(msgQueue[startOfQueue++].event); + } + + startOfQueue = 0; + endOfQueue = 0; +} + +static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0; + + // handle location argument. + int location = DOM_KEY_LOCATION_STANDARD; + if (argumentCount > 2) + location = (int)JSValueToNumber(context, arguments[2], exception); + + JSStringRef character = JSValueToStringCopy(context, arguments[0], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + int gdkKeySym = GDK_VoidSymbol; + if (location == DOM_KEY_LOCATION_NUMPAD) { + if (JSStringIsEqualToUTF8CString(character, "leftArrow")) + gdkKeySym = GDK_KP_Left; + else if (JSStringIsEqualToUTF8CString(character, "rightArrow")) + gdkKeySym = GDK_KP_Right; + else if (JSStringIsEqualToUTF8CString(character, "upArrow")) + gdkKeySym = GDK_KP_Up; + else if (JSStringIsEqualToUTF8CString(character, "downArrow")) + gdkKeySym = GDK_KP_Down; + else if (JSStringIsEqualToUTF8CString(character, "pageUp")) + gdkKeySym = GDK_KP_Page_Up; + else if (JSStringIsEqualToUTF8CString(character, "pageDown")) + gdkKeySym = GDK_KP_Page_Down; + else if (JSStringIsEqualToUTF8CString(character, "home")) + gdkKeySym = GDK_KP_Home; + else if (JSStringIsEqualToUTF8CString(character, "end")) + gdkKeySym = GDK_KP_End; + else if (JSStringIsEqualToUTF8CString(character, "insert")) + gdkKeySym = GDK_KP_Insert; + else if (JSStringIsEqualToUTF8CString(character, "delete")) + gdkKeySym = GDK_KP_Delete; + else + // If we get some other key specified with the numpad location, + // crash here, so we add it sooner rather than later. + g_assert_not_reached(); + } else { + if (JSStringIsEqualToUTF8CString(character, "leftArrow")) + gdkKeySym = GDK_Left; + else if (JSStringIsEqualToUTF8CString(character, "rightArrow")) + gdkKeySym = GDK_Right; + else if (JSStringIsEqualToUTF8CString(character, "upArrow")) + gdkKeySym = GDK_Up; + else if (JSStringIsEqualToUTF8CString(character, "downArrow")) + gdkKeySym = GDK_Down; + else if (JSStringIsEqualToUTF8CString(character, "pageUp")) + gdkKeySym = GDK_Page_Up; + else if (JSStringIsEqualToUTF8CString(character, "pageDown")) + gdkKeySym = GDK_Page_Down; + else if (JSStringIsEqualToUTF8CString(character, "home")) + gdkKeySym = GDK_Home; + else if (JSStringIsEqualToUTF8CString(character, "end")) + gdkKeySym = GDK_End; + else if (JSStringIsEqualToUTF8CString(character, "insert")) + gdkKeySym = GDK_Insert; + else if (JSStringIsEqualToUTF8CString(character, "delete")) + gdkKeySym = GDK_Delete; + else if (JSStringIsEqualToUTF8CString(character, "printScreen")) + gdkKeySym = GDK_Print; + else if (JSStringIsEqualToUTF8CString(character, "menu")) + gdkKeySym = GDK_Menu; + else if (JSStringIsEqualToUTF8CString(character, "F1")) + gdkKeySym = GDK_F1; + else if (JSStringIsEqualToUTF8CString(character, "F2")) + gdkKeySym = GDK_F2; + else if (JSStringIsEqualToUTF8CString(character, "F3")) + gdkKeySym = GDK_F3; + else if (JSStringIsEqualToUTF8CString(character, "F4")) + gdkKeySym = GDK_F4; + else if (JSStringIsEqualToUTF8CString(character, "F5")) + gdkKeySym = GDK_F5; + else if (JSStringIsEqualToUTF8CString(character, "F6")) + gdkKeySym = GDK_F6; + else if (JSStringIsEqualToUTF8CString(character, "F7")) + gdkKeySym = GDK_F7; + else if (JSStringIsEqualToUTF8CString(character, "F8")) + gdkKeySym = GDK_F8; + else if (JSStringIsEqualToUTF8CString(character, "F9")) + gdkKeySym = GDK_F9; + else if (JSStringIsEqualToUTF8CString(character, "F10")) + gdkKeySym = GDK_F10; + else if (JSStringIsEqualToUTF8CString(character, "F11")) + gdkKeySym = GDK_F11; + else if (JSStringIsEqualToUTF8CString(character, "F12")) + gdkKeySym = GDK_F12; + else { + int charCode = JSStringGetCharactersPtr(character)[0]; + if (charCode == '\n' || charCode == '\r') + gdkKeySym = GDK_Return; + else if (charCode == '\t') + gdkKeySym = GDK_Tab; + else if (charCode == '\x8') + gdkKeySym = GDK_BackSpace; + else { + gdkKeySym = gdk_unicode_to_keyval(charCode); + if (WTF::isASCIIUpper(charCode)) + modifiers |= GDK_SHIFT_MASK; + } + } + } + JSStringRelease(character); + + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return JSValueMakeUndefined(context); + + // create and send the event + GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS); + pressEvent->key.keyval = gdkKeySym; + pressEvent->key.state = modifiers; + pressEvent->key.window = gtk_widget_get_window(GTK_WIDGET(view)); + g_object_ref(pressEvent->key.window); +#ifndef GTK_API_VERSION_2 + gdk_event_set_device(pressEvent, getDefaultGDKPointerDevice(pressEvent->key.window)); +#endif + + // When synthesizing an event, an invalid hardware_keycode value + // can cause it to be badly processed by Gtk+. + GdkKeymapKey* keys; + gint n_keys; + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys, &n_keys)) { + pressEvent->key.hardware_keycode = keys[0].keycode; + g_free(keys); + } + + GdkEvent* releaseEvent = gdk_event_copy(pressEvent); + dispatchEvent(pressEvent); + releaseEvent->key.type = GDK_KEY_RELEASE; + dispatchEvent(releaseEvent); + + return JSValueMakeUndefined(context); +} + +static void zoomIn(gboolean fullContentsZoom) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return; + + webkit_web_view_set_full_content_zoom(view, fullContentsZoom); + gfloat currentZoom = webkit_web_view_get_zoom_level(view); + webkit_web_view_set_zoom_level(view, currentZoom * zoomMultiplierRatio); +} + +static void zoomOut(gboolean fullContentsZoom) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return; + + webkit_web_view_set_full_content_zoom(view, fullContentsZoom); + gfloat currentZoom = webkit_web_view_get_zoom_level(view); + webkit_web_view_set_zoom_level(view, currentZoom / zoomMultiplierRatio); +} + +static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + zoomIn(FALSE); + return JSValueMakeUndefined(context); +} + +static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + zoomOut(FALSE); + return JSValueMakeUndefined(context); +} + +static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + zoomIn(TRUE); + return JSValueMakeUndefined(context); +} + +static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + zoomOut(TRUE); + return JSValueMakeUndefined(context); +} + +static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + float scaleFactor = JSValueToNumber(context, arguments[0], exception); + float x = JSValueToNumber(context, arguments[1], exception); + float y = JSValueToNumber(context, arguments[2], exception); + + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return JSValueMakeUndefined(context); + + DumpRenderTreeSupportGtk::scalePageBy(view, scaleFactor, x, y); + + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticFunctions[] = { + { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "beginDragWithFiles", beginDragWithFilesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + + { 0, 0, 0 } +}; + +static JSStaticValue staticValues[] = { + { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static JSClassRef getClass(JSContextRef context) +{ + static JSClassRef eventSenderClass = 0; + + if (!eventSenderClass) { + JSClassDefinition classDefinition = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + classDefinition.staticFunctions = staticFunctions; + classDefinition.staticValues = staticValues; + + eventSenderClass = JSClassCreate(&classDefinition); + } + + return eventSenderClass; +} + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame) +{ + if (isTopFrame) { + dragMode = true; + + // Fly forward in time one second when the main frame loads. This will + // ensure that when a test begins clicking in the same location as + // a previous test, those clicks won't be interpreted as continuations + // of the previous test's click sequences. + timeOffset += 1000; + + lastMousePositionX = lastMousePositionY = 0; + lastClickPositionX = lastClickPositionY = 0; + lastClickTimeOffset = 0; + lastClickButton = 0; + buttonCurrentlyDown = 0; + clickCount = 0; + + endOfQueue = 0; + startOfQueue = 0; + + currentDragSourceContext = 0; + } + + return JSObjectMake(context, getClass(context), 0); +} + +void dragBeginCallback(GtkWidget*, GdkDragContext* context, gpointer) +{ + currentDragSourceContext = context; +} + +void dragEndCallback(GtkWidget*, GdkDragContext* context, gpointer) +{ + currentDragSourceContext = 0; +} + +gboolean dragFailedCallback(GtkWidget*, GdkDragContext* context, gpointer) +{ + // Return TRUE here to disable the stupid GTK+ drag failed animation, + // which introduces asynchronous behavior into our drags. + return TRUE; +} diff --git a/Tools/DumpRenderTree/gtk/EventSender.h b/Tools/DumpRenderTree/gtk/EventSender.h new file mode 100644 index 000000000..f440f0d3d --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EventSender.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h +#define EventSender_h + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame); +void replaySavedEvents(); +void dragBeginCallback(GtkWidget*, GdkDragContext*, gpointer); +void dragEndCallback(GtkWidget*, GdkDragContext*, gpointer); +gboolean dragFailedCallback(GtkWidget*, GdkDragContext*, gpointer); + +#endif diff --git a/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp b/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp new file mode 100644 index 000000000..4eb5d6ec9 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h" + +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" + +#include <glib.h> +#include <webkit/webkit.h> + +void GCController::collect() const +{ + DumpRenderTreeSupportGtk::gcCollectJavascriptObjects(); +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + DumpRenderTreeSupportGtk::gcCollectJavascriptObjectsOnAlternateThread(waitUntilDone); +} + +size_t GCController::getJSObjectCount() const +{ + return DumpRenderTreeSupportGtk::gcCountJavascriptObjects(); +} diff --git a/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am b/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am new file mode 100644 index 000000000..e7c3aefc0 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am @@ -0,0 +1,28 @@ +noinst_PROGRAMS += \ + Programs/ImageDiff + +Programs_ImageDiff_CPPFLAGS = $(global_cppflags) + +Programs_ImageDiff_SOURCES = \ + Tools/DumpRenderTree/gtk/ImageDiff.cpp + +Programs_ImageDiff_CXXFLAGS = \ + $(global_cxxflags) \ + $(global_cppflags) \ + $(Programs_ImageDiff_CFLAGS) + +Programs_ImageDiff_CFLAGS = \ + -fno-strict-aliasing \ + $(global_cflags) \ + $(GLOBALDEPS_CFLAGS) \ + $(GTK_CFLAGS) + +Programs_ImageDiff_LDADD = \ + $(GTK_LIBS) + +Programs_ImageDiff_LDFLAGS = \ + -no-fast-install \ + -no-install + +CLEANFILES += \ + Programs/ImageDiff diff --git a/Tools/DumpRenderTree/gtk/ImageDiff.cpp b/Tools/DumpRenderTree/gtk/ImageDiff.cpp new file mode 100644 index 000000000..7e2744a05 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/ImageDiff.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <algorithm> +#include <cmath> +#include <cstdio> +#include <cstring> +#include <gdk/gdk.h> + +using namespace std; + +static double tolerance = 0; +static GOptionEntry commandLineOptionEntries[] = +{ + { "tolerance", 0, 0, G_OPTION_ARG_DOUBLE, &tolerance, "Percentage difference between images before considering them different", "T" }, + { 0, 0, 0, G_OPTION_ARG_NONE, 0, 0, 0 }, +}; + +GdkPixbuf* readPixbufFromStdin(long imageSize) +{ + unsigned char imageBuffer[2048]; + GdkPixbufLoader* loader = gdk_pixbuf_loader_new_with_type("png", 0); + GError* error = 0; + + while (imageSize > 0) { + size_t bytesToRead = min<int>(imageSize, 2048); + size_t bytesRead = fread(imageBuffer, 1, bytesToRead, stdin); + + if (!gdk_pixbuf_loader_write(loader, reinterpret_cast<const guchar*>(imageBuffer), bytesRead, &error)) { + g_error_free(error); + gdk_pixbuf_loader_close(loader, 0); + g_object_unref(loader); + return 0; + } + + imageSize -= static_cast<int>(bytesRead); + } + + gdk_pixbuf_loader_close(loader, 0); + GdkPixbuf* decodedImage = gdk_pixbuf_loader_get_pixbuf(loader); + g_object_ref(decodedImage); + return decodedImage; +} + +GdkPixbuf* differenceImageFromDifferenceBuffer(unsigned char* buffer, int width, int height) +{ + GdkPixbuf* image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); + if (!image) + return image; + + int rowStride = gdk_pixbuf_get_rowstride(image); + unsigned char* diffPixels = gdk_pixbuf_get_pixels(image); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* diffPixel = diffPixels + (y * rowStride) + (x * 3); + diffPixel[0] = diffPixel[1] = diffPixel[2] = *buffer++; + } + } + + return image; +} + +float calculateDifference(GdkPixbuf* baselineImage, GdkPixbuf* actualImage, GdkPixbuf** differenceImage) +{ + int width = gdk_pixbuf_get_width(actualImage); + int height = gdk_pixbuf_get_height(actualImage); + int numberOfChannels = gdk_pixbuf_get_n_channels(actualImage); + if ((width != gdk_pixbuf_get_width(baselineImage)) + || (height != gdk_pixbuf_get_height(baselineImage)) + || (numberOfChannels != gdk_pixbuf_get_n_channels(baselineImage)) + || (gdk_pixbuf_get_has_alpha(actualImage) != gdk_pixbuf_get_has_alpha(baselineImage))) { + fprintf(stderr, "Error, test and reference image have different properties.\n"); + return 100; // Completely different. + } + + unsigned char* diffBuffer = static_cast<unsigned char*>(malloc(width * height)); + float count = 0; + float sum = 0; + float maxDistance = 0; + int actualRowStride = gdk_pixbuf_get_rowstride(actualImage); + int baseRowStride = gdk_pixbuf_get_rowstride(baselineImage); + unsigned char* actualPixels = gdk_pixbuf_get_pixels(actualImage); + unsigned char* basePixels = gdk_pixbuf_get_pixels(baselineImage); + unsigned char* currentDiffPixel = diffBuffer; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* actualPixel = actualPixels + (y * actualRowStride) + (x * numberOfChannels); + unsigned char* basePixel = basePixels + (y * baseRowStride) + (x * numberOfChannels); + + float red = (actualPixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]); + float green = (actualPixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]); + float blue = (actualPixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]); + float alpha = (actualPixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]); + float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; + + *currentDiffPixel++ = (unsigned char)(distance * 255.0f); + + if (distance >= 1.0f / 255.0f) { + count += 1.0f; + sum += distance; + maxDistance = max<float>(maxDistance, distance); + } + } + } + + // Compute the difference as a percentage combining both the number of + // different pixels and their difference amount i.e. the average distance + // over the entire image + float difference = 0; + if (count > 0.0f) + difference = 100.0f * sum / (height * width); + if (difference <= tolerance) + difference = 0; + else { + difference = roundf(difference * 100.0f) / 100.0f; + difference = max(difference, 0.01f); // round to 2 decimal places + *differenceImage = differenceImageFromDifferenceBuffer(diffBuffer, width, height); + } + + free(diffBuffer); + return difference; +} + +void printImage(GdkPixbuf* image) +{ + char* buffer; + gsize bufferSize; + GError* error = 0; + if (!gdk_pixbuf_save_to_buffer(image, &buffer, &bufferSize, "png", &error, NULL)) { + g_error_free(error); + return; // Don't bail out, as we can still use the percentage output. + } + + printf("Content-Length: %"G_GSIZE_FORMAT"\n", bufferSize); + fwrite(buffer, 1, bufferSize, stdout); +} + +void printImageDifferences(GdkPixbuf* baselineImage, GdkPixbuf* actualImage) +{ + GdkPixbuf* differenceImage = 0; + float difference = calculateDifference(baselineImage, actualImage, &differenceImage); + if (difference > 0.0f) { + if (differenceImage) { + printImage(differenceImage); + g_object_unref(differenceImage); + } + printf("diff: %01.2f%% failed\n", difference); + } else { + printf("diff: %01.2f%% passed\n", difference); + } +} + +int main(int argc, char* argv[]) +{ + gdk_init(&argc, &argv); + + GError* error = 0; + GOptionContext* context = g_option_context_new("- compare two image files, printing their percentage difference and the difference image to stdout"); + g_option_context_add_main_entries(context, commandLineOptionEntries, 0); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + printf("Option parsing failed: %s\n", error->message); + g_error_free(error); + return 1; + } + + GdkPixbuf* actualImage = 0; + GdkPixbuf* baselineImage = 0; + char buffer[2048]; + while (fgets(buffer, sizeof(buffer), stdin)) { + // Convert the first newline into a NUL character so that strtok doesn't produce it. + char* newLineCharacter = strchr(buffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strncmp("Content-Length: ", buffer, 16)) { + gchar** tokens = g_strsplit(buffer, " ", 0); + if (!tokens[1]) { + g_strfreev(tokens); + printf("Error, image size must be specified..\n"); + return 1; + } + + long imageSize = strtol(tokens[1], 0, 10); + g_strfreev(tokens); + if (imageSize > 0 && !actualImage) { + if (!(actualImage = readPixbufFromStdin(imageSize))) { + printf("Error, could not read actual image.\n"); + return 1; + } + } else if (imageSize > 0 && !baselineImage) { + if (!(baselineImage = readPixbufFromStdin(imageSize))) { + printf("Error, could not read baseline image.\n"); + return 1; + } + } else { + printf("Error, image size must be specified..\n"); + return 1; + } + } + + if (actualImage && baselineImage) { + printImageDifferences(baselineImage, actualImage); + g_object_unref(actualImage); + g_object_unref(baselineImage); + actualImage = 0; + baselineImage = 0; + } + + fflush(stdout); + } + + return 0; +} diff --git a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp new file mode 100644 index 000000000..7c133fd30 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp @@ -0,0 +1,1038 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com> + * Copyright (C) 2009,2011 Collabora Ltd. + * Copyright (C) 2010 Joone Hur <joone@kldp.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <cstring> +#include <iostream> +#include <sstream> +#include <stdio.h> +#include <glib.h> +#include <libsoup/soup.h> +#include <webkit/webkit.h> +#include <wtf/gobject/GOwnPtr.h> + +extern "C" { +void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script); +} + +LayoutTestController::~LayoutTestController() +{ + // FIXME: implement +} + +void LayoutTestController::addDisallowedURL(JSStringRef url) +{ + // FIXME: implement +} + +void LayoutTestController::clearBackForwardList() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView); + WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_current_item(list); + g_object_ref(item); + + // We clear the history by setting the back/forward list's capacity to 0 + // then restoring it back and adding back the current item. + gint limit = webkit_web_back_forward_list_get_limit(list); + webkit_web_back_forward_list_set_limit(list, 0); + webkit_web_back_forward_list_set_limit(list, limit); + webkit_web_back_forward_list_add_item(list, item); + webkit_web_back_forward_list_go_to_item(list, item); + g_object_unref(item); +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + gchar* idGChar = JSStringCopyUTF8CString(id); + CString counterValueGChar = DumpRenderTreeSupportGtk::counterValueForElementById(mainFrame, idGChar); + g_free(idGChar); + if (counterValueGChar.isNull()) + return 0; + JSRetainPtr<JSStringRef> counterValue(Adopt, JSStringCreateWithUTF8CString(counterValueGChar.data())); + return counterValue; +} + +void LayoutTestController::keepWebHistory() +{ + // FIXME: implement +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value) +{ + // FIXME: Implement this. + return JSValueMakeUndefined(context); +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + return DumpRenderTreeSupportGtk::nodesFromRect(context, value, x, y, top, right, bottom, left, ignoreClipping); +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + // FIXME: implement + JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithUTF8CString("")); + return string; +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight) +{ + gchar* idGChar = JSStringCopyUTF8CString(id); + int pageNumber = DumpRenderTreeSupportGtk::pageNumberForElementById(mainFrame, idGChar, pageWidth, pageHeight); + g_free(idGChar); + return pageNumber; +} + +int LayoutTestController::numberOfPages(float pageWidth, float pageHeight) +{ + return DumpRenderTreeSupportGtk::numberOfPagesForFrame(mainFrame, pageWidth, pageHeight); +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithUTF8CString(DumpRenderTreeSupportGtk::pageProperty(mainFrame, propertyName, pageNumber).data())); + return propertyValue; +} + +bool LayoutTestController::isPageBoxVisible(int pageNumber) const +{ + return DumpRenderTreeSupportGtk::isPageBoxVisible(mainFrame, pageNumber); +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithUTF8CString(DumpRenderTreeSupportGtk::pageSizeAndMarginsInPixels(mainFrame, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft).data())); + return propertyValue; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView); + + if (!list) + return -1; + + // We do not add the current page to the total count as it's not + // considered in DRT tests + return webkit_web_back_forward_list_get_back_length(list) + + webkit_web_back_forward_list_get_forward_length(list); +} + +unsigned LayoutTestController::workerThreadCount() const +{ + return DumpRenderTreeSupportGtk::workerThreadCount(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::platformName() const +{ + JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("gtk")); + return platformName; +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; + waitForPolicy = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + GOwnPtr<char> urlCString(JSStringCopyUTF8CString(url)); + if (!g_str_has_prefix(urlCString.get(), "file:///tmp/LayoutTests/")) + return JSStringRetain(url); + + const char* layoutTestsSuffix = urlCString.get() + strlen("file:///tmp/"); + GOwnPtr<char> testPath(g_build_filename(getTopLevelPath().data(), layoutTestsSuffix, NULL)); + GOwnPtr<char> testURI(g_filename_to_uri(testPath.get(), 0, 0)); + return JSStringCreateWithUTF8CString(testURI.get()); +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + gchar* relativeURL = JSStringCopyUTF8CString(url); + SoupURI* baseURI = soup_uri_new(webkit_web_frame_get_uri(mainFrame)); + + SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL); + soup_uri_free(baseURI); + g_free(relativeURL); + + gchar* absoluteCString; + if (absoluteURI) { + absoluteCString = soup_uri_to_string(absoluteURI, FALSE); + soup_uri_free(absoluteURI); + } else + absoluteCString = JSStringCopyUTF8CString(url); + + JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteCString)); + g_free(absoluteCString); + + WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool acceptsEditing) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + webkit_web_view_set_editable(webView, acceptsEditing); +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + SoupSession* session = webkit_get_default_session(); + SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR)); + + /* If the jar was not created - we create it on demand, i.e, just + in case we have HTTP requests - then we must create it here in + order to set the proper accept policy */ + if (!jar) { + jar = soup_cookie_jar_new(); + soup_session_add_feature(session, SOUP_SESSION_FEATURE(jar)); + g_object_unref(jar); + } + + SoupCookieJarAcceptPolicy policy; + + if (alwaysAcceptCookies) + policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS; + else + policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY; + + g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, policy, NULL); +} + +void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive) +{ + // FIXME: implement +} + +void LayoutTestController::waitForPolicyDelegate() +{ + waitForPolicy = true; + setWaitToDump(true); +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains) +{ + gchar* sourceOriginGChar = JSStringCopyUTF8CString(sourceOrigin); + gchar* protocolGChar = JSStringCopyUTF8CString(protocol); + gchar* hostGChar = JSStringCopyUTF8CString(host); + DumpRenderTreeSupportGtk::whiteListAccessFromOrigin(sourceOriginGChar, protocolGChar, hostGChar, includeSubdomains); + g_free(sourceOriginGChar); + g_free(protocolGChar); + g_free(hostGChar); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains) +{ + // FIXME: implement +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + g_object_set(G_OBJECT(settings), "tab-key-cycles-through-elements", cycles, NULL); +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + // FIXME: implement +} + +static gchar* userStyleSheet = NULL; +static gboolean userStyleSheetEnabled = TRUE; + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + userStyleSheetEnabled = flag; + + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + if (flag && userStyleSheet) + g_object_set(G_OBJECT(settings), "user-stylesheet-uri", userStyleSheet, NULL); + else + g_object_set(G_OBJECT(settings), "user-stylesheet-uri", "", NULL); +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + g_free(userStyleSheet); + userStyleSheet = JSStringCopyUTF8CString(path); + if (userStyleSheetEnabled) + setUserStyleSheetEnabled(true); +} + +void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value) +{ + DumpRenderTreeSupportGtk::setValueForUser(context, nodeObject, value); +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef mode) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + char* viewMode = JSStringCopyUTF8CString(mode); + + if (!g_strcmp0(viewMode, "windowed")) + webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_WINDOWED); + else if (!g_strcmp0(viewMode, "floating")) + webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FLOATING); + else if (!g_strcmp0(viewMode, "fullscreen")) + webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FULLSCREEN); + else if (!g_strcmp0(viewMode, "maximized")) + webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MAXIMIZED); + else if (!g_strcmp0(viewMode, "minimized")) + webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MINIMIZED); + + g_free(viewMode); +} + +void LayoutTestController::setWindowIsKey(bool windowIsKey) +{ + // FIXME: implement +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool flag) +{ + DumpRenderTreeSupportGtk::setSmartInsertDeleteEnabled(webkit_web_frame_get_web_view(mainFrame), flag); +} + +static gboolean waitToDumpWatchdogFired(void*) +{ + waitToDumpWatchdog = 0; + gLayoutTestController->waitToDumpWatchdogTimerFired(); + return FALSE; +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + static const int timeoutSeconds = 30; + + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) + waitToDumpWatchdog = g_timeout_add_seconds(timeoutSeconds, waitToDumpWatchdogFired, 0); +} + +int LayoutTestController::windowCount() +{ + // +1 -> including the main view + return g_slist_length(webViewList) + 1; +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-private-browsing", flag, NULL); +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "javascript-can-access-clipboard", flag, NULL); +} + +void LayoutTestController::setXSSAuditorEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-xss-auditor", flag, NULL); +} + +void LayoutTestController::setFrameFlatteningEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-frame-flattening", flag, NULL); +} + +void LayoutTestController::setSpatialNavigationEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-spatial-navigation", flag, NULL); +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-universal-access-from-file-uris", flag, NULL); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-file-access-from-file-uris", flag, NULL); +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool isAutofilled) +{ + DumpRenderTreeSupportGtk::setAutofilled(context, nodeObject, isAutofilled); +} + +void LayoutTestController::disableImageLoading() +{ + // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896 + // Also need to make sure image loading is re-enabled for each new test. +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + // FIXME: Implement for DeviceOrientation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=30335. +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0)); + if (!view) + view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + DumpRenderTreeSupportGtk::setMockGeolocationPosition(view, latitude, longitude, accuracy); +} + +void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) +{ + WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0)); + if (!view) + view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + GOwnPtr<gchar> cMessage(JSStringCopyUTF8CString(message)); + DumpRenderTreeSupportGtk::setMockGeolocationError(view, code, cMessage.get()); +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + setGeolocationPermissionCommon(allow); + WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0)); + if (!view) + view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + DumpRenderTreeSupportGtk::setMockGeolocationPermission(view, allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + return DumpRenderTreeSupportGtk::numberOfPendingGeolocationPermissionRequests(view); +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::setIconDatabaseEnabled(bool enabled) +{ + WebKitIconDatabase* database = webkit_get_icon_database(); + if (enabled) { + GOwnPtr<gchar> iconDatabasePath(g_build_filename(g_get_tmp_dir(), "DumpRenderTree", "icondatabase", NULL)); + webkit_icon_database_set_path(database, iconDatabasePath.get()); + } else + webkit_icon_database_set_path(database, 0); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + setDeveloperExtrasEnabled(flag); + + WebKitWebInspector* inspector = webkit_web_view_get_inspector(view); + g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", flag, NULL); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag) +{ + DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(flag); +} + +void LayoutTestController::setPopupBlockingEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "javascript-can-open-windows-automatically", !flag, NULL); + +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-plugins", flag, NULL); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id) +{ + // FIXME: implement + return false; +} + +void LayoutTestController::execCommand(JSStringRef name, JSStringRef value) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + gchar* cName = JSStringCopyUTF8CString(name); + gchar* cValue = JSStringCopyUTF8CString(value); + DumpRenderTreeSupportGtk::executeCoreCommandByName(view, cName, cValue); + g_free(cName); + g_free(cValue); +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + WebKitFindOptions findOptions = 0; + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + ASSERT(webView); + + JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); + if (!JSValueIsNumber(context, lengthValue)) + return false; + + GOwnPtr<gchar> targetString(JSStringCopyUTF8CString(target)); + + size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); + for (size_t i = 0; i < length; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); + if (!JSValueIsString(context, value)) + continue; + + JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); + + if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive")) + findOptions |= WebKit::WebFindOptionsCaseInsensitive; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts")) + findOptions |= WebKit::WebFindOptionsAtWordStarts; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart")) + findOptions |= WebKit::WebFindOptionsTreatMedialCapitalAsWordStart; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards")) + findOptions |= WebKit::WebFindOptionsBackwards; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround")) + findOptions |= WebKit::WebFindOptionsWrapAround; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) + findOptions |= WebKit::WebFindOptionsStartInSelection; + } + + return DumpRenderTreeSupportGtk::findString(webView, targetString.get(), findOptions); +} + +bool LayoutTestController::isCommandEnabled(JSStringRef name) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + gchar* cName = JSStringCopyUTF8CString(name); + bool result = DumpRenderTreeSupportGtk::isCommandEnabled(view, cName); + g_free(cName); + return result; +} + +void LayoutTestController::setCacheModel(int cacheModel) +{ + // These constants are derived from the Mac cache model enum in Source/WebKit/mac/WebView/WebPreferences.h. + switch (cacheModel) { + case 0: + webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER); + break; + case 1: + webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER); + break; + case 3: + webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + // FIXME: implement +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + // FIXME: implement +} + +void LayoutTestController::clearAllApplicationCaches() +{ + // FIXME: Implement to support application cache quotas. +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + // FIXME: Implement to support application cache quotas. +} + +void LayoutTestController::clearApplicationCacheForOrigin(OpaqueJSString*) +{ + // FIXME: Implement to support deleting all application caches for an origin. +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + return 0; +} + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that contain application caches. + return JSValueMakeUndefined(context); +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::clearAllDatabases() +{ + webkit_remove_all_web_databases(); +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(mainFrame); + webkit_security_origin_set_web_database_quota(origin, quota); +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + // FIXME: implement + return JSValueMakeUndefined(context); +} + +void LayoutTestController::deleteAllLocalStorage() +{ + // FIXME: implement +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: implement +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned number) +{ + // FIXME: implement +} + +void LayoutTestController::syncLocalStorage() +{ + // FIXME: implement +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef) +{ + // FIXME: implement +} + +void LayoutTestController::goBack() +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setDefersLoading(bool) +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + webkit_application_cache_set_maximum_size(size); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + gchar* name = JSStringCopyUTF8CString(animationName); + gchar* element = JSStringCopyUTF8CString(elementId); + bool returnValue = DumpRenderTreeSupportGtk::pauseAnimation(mainFrame, name, time, element); + g_free(name); + g_free(element); + return returnValue; +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + gchar* name = JSStringCopyUTF8CString(propertyName); + gchar* element = JSStringCopyUTF8CString(elementId); + bool returnValue = DumpRenderTreeSupportGtk::pauseTransition(mainFrame, name, time, element); + g_free(name); + g_free(element); + return returnValue; +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + gchar* name = JSStringCopyUTF8CString(animationId); + gchar* element = JSStringCopyUTF8CString(elementId); + bool returnValue = DumpRenderTreeSupportGtk::pauseSVGAnimation(mainFrame, name, time, element); + g_free(name); + g_free(element); + return returnValue; +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + return DumpRenderTreeSupportGtk::numberOfActiveAnimations(mainFrame); +} + +void LayoutTestController::suspendAnimations() const +{ + DumpRenderTreeSupportGtk::suspendAnimations(mainFrame); +} + +void LayoutTestController::resumeAnimations() const +{ + DumpRenderTreeSupportGtk::resumeAnimations(mainFrame); +} + +void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value) +{ + GOwnPtr<gchar> originalName(JSStringCopyUTF8CString(key)); + GOwnPtr<gchar> valueAsString(JSStringCopyUTF8CString(value)); + + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + // This transformation could be handled by a hash table (and it once was), but + // having it prominent, makes it easier for people from other ports to keep the + // list up to date. + const gchar* propertyName = 0; + if (g_str_equal(originalName.get(), "WebKitJavaScriptEnabled")) + propertyName = "enable-scripts"; + else if (g_str_equal(originalName.get(), "WebKitDefaultFontSize")) + propertyName = "default-font-size"; + else if (g_str_equal(originalName.get(), "WebKitEnableCaretBrowsing")) + propertyName = "enable-caret-browsing"; + else if (g_str_equal(originalName.get(), "WebKitUsesPageCachePreferenceKey")) + propertyName = "enable-page-cache"; + else if (g_str_equal(originalName.get(), "WebKitPluginsEnabled")) + propertyName = "enable-plugins"; + else if (g_str_equal(originalName.get(), "WebKitHyperlinkAuditingEnabled")) + propertyName = "enable-hyperlink-auditing"; + else if (g_str_equal(originalName.get(), "WebKitWebGLEnabled")) + propertyName = "enable-webgl"; + else if (g_str_equal(originalName.get(), "WebKitWebAudioEnabled")) + propertyName = "enable-webaudio"; + else if (g_str_equal(originalName.get(), "WebKitTabToLinksPreferenceKey")) { + DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(!g_ascii_strcasecmp(valueAsString.get(), "true") || !g_ascii_strcasecmp(valueAsString.get(), "1")); + return; + } else if (g_str_equal(originalName.get(), "WebKitHixie76WebSocketProtocolEnabled")) { + DumpRenderTreeSupportGtk::setHixie76WebSocketProtocolEnabled(webkit_web_frame_get_web_view(mainFrame), !g_ascii_strcasecmp(valueAsString.get(), "true") || !g_ascii_strcasecmp(valueAsString.get(), "1")); + return; + } else { + fprintf(stderr, "LayoutTestController::overridePreference tried to override " + "unknown preference '%s'.\n", originalName.get()); + return; + } + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + GParamSpec* pspec = g_object_class_find_property(G_OBJECT_CLASS( + WEBKIT_WEB_SETTINGS_GET_CLASS(settings)), propertyName); + GValue currentPropertyValue = { 0, { { 0 } } }; + g_value_init(¤tPropertyValue, pspec->value_type); + + if (G_VALUE_HOLDS_STRING(¤tPropertyValue)) + g_object_set(settings, propertyName, valueAsString.get(), NULL); + else if (G_VALUE_HOLDS_BOOLEAN(¤tPropertyValue)) + g_object_set(G_OBJECT(settings), propertyName, !g_ascii_strcasecmp(valueAsString.get(), "true") + || !g_ascii_strcasecmp(valueAsString.get(), "1"), NULL); + else if (G_VALUE_HOLDS_INT(¤tPropertyValue)) + g_object_set(G_OBJECT(settings), propertyName, atoi(valueAsString.get()), NULL); + else if (G_VALUE_HOLDS_FLOAT(¤tPropertyValue)) { + gfloat newValue = g_ascii_strtod(valueAsString.get(), 0); + g_object_set(G_OBJECT(settings), propertyName, newValue, NULL); + } else + fprintf(stderr, "LayoutTestController::overridePreference failed to override " + "preference '%s'.\n", originalName.get()); +} + +void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + printf("LayoutTestController::addUserScript not implemented.\n"); +} + +void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + GOwnPtr<gchar> sourceCode(JSStringCopyUTF8CString(source)); + DumpRenderTreeSupportGtk::addUserStyleSheet(mainFrame, sourceCode.get(), allFrames); + // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false. + +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebSettings* webSettings = webkit_web_view_get_settings(webView); + + g_object_set(webSettings, "enable-developer-extras", enabled, NULL); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + // FIXME: Implement this. +} + +void LayoutTestController::showWebInspector() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + + webkit_web_inspector_show(inspector); +} + +void LayoutTestController::closeWebInspector() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + + webkit_web_inspector_close(inspector); +} + +void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + char* scriptString = JSStringCopyUTF8CString(script); + + webkit_web_inspector_execute_script(inspector, callId, scriptString); + g_free(scriptString); +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + // FIXME: Implement this. +} + +void LayoutTestController::removeAllVisitedLinks() +{ + // FIXME: Implement this. +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + return DumpRenderTreeSupportGtk::shouldClose(mainFrame); +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + +} + +void LayoutTestController::setWebViewEditable(bool) +{ +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const +{ + CString markerTextGChar = DumpRenderTreeSupportGtk::markerTextForListItem(mainFrame, context, nodeObject); + if (markerTextGChar.isNull()) + return 0; + + JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithUTF8CString(markerTextGChar.data())); + return markerText; +} + +void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ +} + +void LayoutTestController::setEditingBehavior(const char* editingBehavior) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + + if (!strcmp(editingBehavior, "win")) + g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_WINDOWS, NULL); + else if (!strcmp(editingBehavior, "mac")) + g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_MAC, NULL); + else if (!strcmp(editingBehavior, "unix")) + g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, NULL); +} + +void LayoutTestController::abortModal() +{ +} + +bool LayoutTestController::hasSpellingMarker(int from, int length) +{ + return DumpRenderTreeSupportGtk::webkitWebFrameSelectionHasSpellingMarker(mainFrame, from, length); +} + +bool LayoutTestController::hasGrammarMarker(int from, int length) +{ + return false; +} + +void LayoutTestController::dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + ASSERT(webView); + DumpRenderTreeSupportGtk::dumpConfigurationForViewport(webView, deviceDPI, deviceWidth, deviceHeight, availableWidth, availableHeight); +} + +void LayoutTestController::setSerializeHTTPLoads(bool) +{ + // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758. +} + +void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, minimumTimerInterval); +} + +void LayoutTestController::setTextDirection(JSStringRef direction) +{ + // FIXME: Implement. +} + +void LayoutTestController::allowRoundingHacks() +{ +} + +void LayoutTestController::addChromeInputField() +{ +} + +void LayoutTestController::removeChromeInputField() +{ +} + +void LayoutTestController::focusWebView() +{ +} + +void LayoutTestController::setBackingScaleFactor(double) +{ +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ +} diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp new file mode 100644 index 000000000..3eabfd96c --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "GtkVersioning.h" +#include "PixelDumpSupportCairo.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <webkit/webkit.h> + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + GtkWidget* viewContainer = gtk_widget_get_parent(GTK_WIDGET(view)); + gint width, height; +#ifdef GTK_API_VERSION_2 + GdkPixmap* pixmap = gtk_widget_get_snapshot(viewContainer, 0); + gdk_pixmap_get_size(pixmap, &width, &height); +#else + width = gtk_widget_get_allocated_width(viewContainer); + height = gtk_widget_get_allocated_height(viewContainer); +#endif + + cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t* context = cairo_create(imageSurface); + +#ifdef GTK_API_VERSION_2 + gdk_cairo_set_source_pixmap(context, pixmap, 0, 0); + cairo_paint(context); + g_object_unref(pixmap); +#else + gtk_widget_draw(viewContainer, context); +#endif + + if (drawSelectionRect) { + cairo_rectangle_int_t rectangle; + DumpRenderTreeSupportGtk::rectangleForSelection(mainFrame, &rectangle); + + cairo_set_line_width(context, 1.0); + cairo_rectangle(context, rectangle.x, rectangle.y, rectangle.width, rectangle.height); + cairo_set_source_rgba(context, 1.0, 0.0, 0.0, 1.0); + cairo_stroke(context); + } + + return BitmapContext::createByAdoptingBitmapAndContext(0, context); +} diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.cpp b/Tools/DumpRenderTree/gtk/PlainTextController.cpp new file mode 100644 index 000000000..25e251a75 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PlainTextController.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <GOwnPtrGtk.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <webkit/webkit.h> + +static JSValueRef plainTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + g_return_val_if_fail(argumentCount == 1, JSValueMakeUndefined(context)); + WebKitDOMRange* kitRange = DumpRenderTreeSupportGtk::jsValueToDOMRange(context, arguments[0]); + g_return_val_if_fail(kitRange, JSValueMakeUndefined(context)); + + GOwnPtr<gchar> text(webkit_dom_range_get_text(kitRange)); + JSRetainPtr<JSStringRef> jsText(Adopt, JSStringCreateWithUTF8CString(text.get())); + return JSValueMakeString(context, jsText.get()); +} + +JSObjectRef makePlainTextController(JSContextRef context) +{ + static JSStaticFunction staticFunctions[] = { + { "plainText", plainTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassRef plainTextControllerClass = 0; + if (!plainTextControllerClass) { + JSClassDefinition classDefinition = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + classDefinition.staticFunctions = staticFunctions; + plainTextControllerClass = JSClassCreate(&classDefinition); + } + return JSObjectMake(context, plainTextControllerClass, 0); +} diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.h b/Tools/DumpRenderTree/gtk/PlainTextController.h new file mode 100644 index 000000000..dadfc1392 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PlainTextController.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +JSObjectRef makePlainTextController(JSContextRef); + +#endif diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp new file mode 100644 index 000000000..d77cfd5f1 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "SelfScrollingWebKitWebView.h" + +#include <webkit/webkit.h> + +G_BEGIN_DECLS + +#ifdef GTK_API_VERSION_2 +static void sizeRequestMethod(GtkWidget*, GtkRequisition*); +#else +static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural); +#endif + +G_DEFINE_TYPE(SelfScrollingWebKitWebView, self_scrolling_webkit_web_view, WEBKIT_TYPE_WEB_VIEW) + +static void self_scrolling_webkit_web_view_class_init(SelfScrollingWebKitWebViewClass* klass) +{ + GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(klass); +#ifdef GTK_API_VERSION_2 + widgetClass->size_request = sizeRequestMethod; +#else + widgetClass->get_preferred_width = getPreferredSizeMethod; + widgetClass->get_preferred_height = getPreferredSizeMethod; +#endif +} + +static void self_scrolling_webkit_web_view_init(SelfScrollingWebKitWebView* webView) +{ +} + +GtkWidget* self_scrolling_webkit_web_view_new() +{ + return GTK_WIDGET(g_object_new(self_scrolling_webkit_web_view_get_type(), "self-scrolling", TRUE, NULL)); +} + +#ifdef GTK_API_VERSION_2 +static void sizeRequestMethod(GtkWidget*, GtkRequisition* requisition) +{ + requisition->width = 1; + requisition->height = 1; +} +#else +static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural) +{ + *minimum = 1; + *natural = 1; +} +#endif + +G_END_DECLS diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h new file mode 100644 index 000000000..648d38c97 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 SelfScrollingWebKitWebView_h +#define SelfScrollingWebKitWebView_h + +#include <webkit/webkit.h> + +G_BEGIN_DECLS + +typedef struct _SelfScrollingWebKitWebView SelfScrollingWebKitWebView; +typedef struct _SelfScrollingWebKitWebViewClass SelfScrollingWebKitWebViewClass; + +struct _SelfScrollingWebKitWebView { + WebKitWebView web_view; +}; + +struct _SelfScrollingWebKitWebViewClass { + WebKitWebViewClass parent_class; +}; + +GtkWidget* self_scrolling_webkit_web_view_new(); + +G_END_DECLS + +#endif // SelfScrollingWebKitWebView_h diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp new file mode 100644 index 000000000..eed3bbe54 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/TextInputController.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <GOwnPtrGtk.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <cstring> +#include <webkit/webkit.h> + +static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + JSStringRef string = JSValueToStringCopy(context, arguments[0], exception); + ASSERT(!exception || !*exception); + + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string); + GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize); + JSStringRelease(string); + + int start = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + ASSERT(!exception || !*exception); + + int length = static_cast<int>(JSValueToNumber(context, arguments[2], exception)); + ASSERT(!exception || !*exception); + + DumpRenderTreeSupportGtk::setComposition(view, stringBuffer.get(), start, length); + return JSValueMakeUndefined(context); +} + +static JSValueRef hasMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + return JSValueMakeBoolean(context, DumpRenderTreeSupportGtk::hasComposition(view)); +} + +static JSValueRef markedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + int start, length; + if (!DumpRenderTreeSupportGtk::compositionRange(view, &start, &length)) + return JSValueMakeUndefined(context); + + JSValueRef arrayValues[2]; + arrayValues[0] = JSValueMakeNumber(context, start); + arrayValues[1] = JSValueMakeNumber(context, length); + JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception); + ASSERT(!exception || !*exception); + return arrayObject; +} + +static JSValueRef insertTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSStringRef string = JSValueToStringCopy(context, arguments[0], exception); + ASSERT(!exception || !*exception); + + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string); + GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize); + JSStringRelease(string); + + DumpRenderTreeSupportGtk::confirmComposition(view, stringBuffer.get()); + return JSValueMakeUndefined(context); +} + +static JSValueRef unmarkTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + DumpRenderTreeSupportGtk::confirmComposition(view, 0); + return JSValueMakeUndefined(context); +} + +static JSValueRef firstRectForCharacterRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + int location = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + ASSERT(!exception || !*exception); + + int length = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + ASSERT(!exception || !*exception); + + cairo_rectangle_int_t rect; + if (!DumpRenderTreeSupportGtk::firstRectForCharacterRange(view, location, length, &rect)) + return JSValueMakeUndefined(context); + + JSValueRef arrayValues[4]; + arrayValues[0] = JSValueMakeNumber(context, rect.x); + arrayValues[1] = JSValueMakeNumber(context, rect.y); + arrayValues[2] = JSValueMakeNumber(context, rect.width); + arrayValues[3] = JSValueMakeNumber(context, rect.height); + JSObjectRef arrayObject = JSObjectMakeArray(context, 4, arrayValues, exception); + ASSERT(!exception || !*exception); + + return arrayObject; +} + +static JSValueRef selectedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + int start, length; + if (!DumpRenderTreeSupportGtk::selectedRange(view, &start, &length)) + return JSValueMakeUndefined(context); + + JSValueRef arrayValues[2]; + arrayValues[0] = JSValueMakeNumber(context, start); + arrayValues[1] = JSValueMakeNumber(context, length); + JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception); + ASSERT(!exception || !*exception); + + return arrayObject; +} + +static JSValueRef doCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSStringRef string = JSValueToStringCopy(context, arguments[0], exception); + ASSERT(!exception || !*exception); + + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string); + GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize); + JSStringRelease(string); + + DumpRenderTreeSupportGtk::doCommand(view, stringBuffer.get()); + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticFunctions[] = { + { "setMarkedText", setMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hasMarkedText", hasMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "markedRange", markedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "insertText", insertTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "unmarkText", unmarkTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "firstRectForCharacterRange", firstRectForCharacterRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedRange", selectedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "doCommand", doCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSClassRef getClass(JSContextRef context) +{ + static JSClassRef textInputControllerClass = 0; + + if (!textInputControllerClass) { + JSClassDefinition classDefinition = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + classDefinition.staticFunctions = staticFunctions; + + textInputControllerClass = JSClassCreate(&classDefinition); + } + + return textInputControllerClass; +} + +JSObjectRef makeTextInputController(JSContextRef context) +{ + return JSObjectMake(context, getClass(context), 0); +} diff --git a/Tools/DumpRenderTree/gtk/TextInputController.h b/Tools/DumpRenderTree/gtk/TextInputController.h new file mode 100644 index 000000000..53793f637 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/TextInputController.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 TextInputController_h +#define TextInputController_h + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +JSObjectRef makeTextInputController(JSContextRef); + +#endif diff --git a/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp new file mode 100644 index 000000000..d10b19318 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WorkQueueItem.h" + +#include "DumpRenderTree.h" + +#include <GOwnPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <webkit/webkit.h> +#include <string.h> + +// Returns a newly allocated UTF-8 character buffer which must be freed with g_free() +gchar* JSStringCopyUTF8CString(JSStringRef jsString) +{ + size_t dataSize = JSStringGetMaximumUTF8CStringSize(jsString); + gchar* utf8 = (gchar*)g_malloc(dataSize); + JSStringGetUTF8CString(jsString, utf8, dataSize); + + return utf8; +} + +bool LoadItem::invoke() const +{ + gchar* targetString = JSStringCopyUTF8CString(m_target.get()); + + WebKitWebFrame* targetFrame; + if (!strlen(targetString)) + targetFrame = mainFrame; + else + targetFrame = webkit_web_frame_find_frame(mainFrame, targetString); + g_free(targetString); + + gchar* urlString = JSStringCopyUTF8CString(m_url.get()); + WebKitNetworkRequest* request = webkit_network_request_new(urlString); + g_free(urlString); + webkit_web_frame_load_request(targetFrame, request); + g_object_unref(request); + + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + GOwnPtr<gchar> content(JSStringCopyUTF8CString(m_content.get())); + GOwnPtr<gchar> baseURL(JSStringCopyUTF8CString(m_baseURL.get())); + + if (m_unreachableURL) { + GOwnPtr<gchar> unreachableURL(JSStringCopyUTF8CString(m_unreachableURL.get())); + webkit_web_frame_load_alternate_string(mainFrame, content.get(), baseURL.get(), unreachableURL.get()); + return true; + } + webkit_web_frame_load_string(mainFrame, content.get(), 0, 0, baseURL.get()); + return true; +} + +bool ReloadItem::invoke() const +{ + webkit_web_frame_reload(mainFrame); + return true; +} + +bool ScriptItem::invoke() const +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + gchar* scriptString = JSStringCopyUTF8CString(m_script.get()); + webkit_web_view_execute_script(webView, scriptString); + g_free(scriptString); + return true; +} + +bool BackForwardItem::invoke() const +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + if (m_howFar == 1) + webkit_web_view_go_forward(webView); + else if (m_howFar == -1) + webkit_web_view_go_back(webView); + else { + WebKitWebBackForwardList* webBackForwardList = webkit_web_view_get_back_forward_list(webView); + WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(webBackForwardList, m_howFar); + webkit_web_view_go_to_back_forward_item(webView, item); + } + return true; +} diff --git a/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF b/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF Binary files differnew file mode 100644 index 000000000..ac81cb031 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF diff --git a/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon b/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon Binary files differnew file mode 100644 index 000000000..8fff7d9c1 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon diff --git a/Tools/DumpRenderTree/gtk/fonts/fonts.conf b/Tools/DumpRenderTree/gtk/fonts/fonts.conf new file mode 100644 index 000000000..3c55e87f3 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/fonts/fonts.conf @@ -0,0 +1,419 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<fontconfig> + + <!-- Due to patent (http://freetype.sourceforge.net/patents.html) + issues hinting gives different results depending on the + freetype version of the linux distribution, avoiding hinting + gives more consistent results. When all the distributions + release freetype the 2.4, which enables by default the + hinting method that was patented, we could undo this change + and try the hinting again. --> + <match target="font"> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <!-- This system may have turned off selection of bitmap fonts, but + we must turn it on again, because we want to be able to test that + bitmap fonts with no valid encodings are *never* selected regardless + of the Fontconfig settings. So force Fontconfig to select our cruddy + bitmap font --> + <selectfont> + <acceptfont> + <pattern> + <patelt name="family"> + <string>FontWithNoValidEncoding</string> + </patelt> + </pattern> + </acceptfont> + </selectfont> + + <!-- The sans-serif font should be Liberation Serif --> + <match target="pattern"> + <test qual="any" name="family"> + <string>serif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Times</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Times New Roman</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + + <!-- Until we find good fonts to use for cursive and fantasy + just use our serif font. --> + <match target="pattern"> + <test qual="any" name="family"> + <string>cursive</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>fantasy</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + + <!-- The sans-serif font should be Liberation Sans --> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans serif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <!-- We need to ensure that layout tests that use "Helvetica" don't + fall back to the default serif font --> + <match target="pattern"> + <test qual="any" name="family"> + <string>Helvetica</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Arial</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Lucida Grande</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + + <!-- The Monospace font should be Liberation Mono --> + <match target="pattern"> + <test qual="any" name="family"> + <string>monospace</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>mono</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <!-- We need to ensure that layout tests that use "Courier", "Courier New", + and "Monaco" (all monospace fonts) don't fall back to the default + serif font --> + <match target="pattern"> + <test qual="any" name="family"> + <string>Courier</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Courier New</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Monaco</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + + <!-- The following hinting specializations are adapted from those in the + Chromium test_shell. We try to duplicate their incredibly thorough + testing here --> + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonAntiAliasedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="antialias" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SlightHintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintslight</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonHintedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <!-- These deliberately contradict each other. The 'hinting' preference + should take priority --> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>AutohintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>HintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>false</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>FullAndAutoHintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelEnabledSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="rgba" mode="assign"> + <const>rgb</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelDisabledSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="rgba" mode="assign"> + <const>none</const> + </edit> + </match> + + <!-- We need to enable simulated bold to for DejaVu Serif to ensure that we interpret + this property correctly in: platform/gtk/fonts/fontconfig-synthetic-bold.html --> + <match target="font"> + <test qual="any" name="family"> + <string>DejaVu Serif</string> + </test> + <test name="weight" compare="less_eq"> + <const>medium</const> + </test> + <test target="pattern" name="weight" compare="more"> + <const>medium</const> + </test> + <edit name="embolden" mode="assign"> + <bool>true</bool> + </edit> + <edit name="weight" mode="assign"> + <const>bold</const> + </edit> + </match> + + <!-- We need to enable simulated oblique to for DejaVu Serif to ensure that we interpret + this property correctly in: platform/gtk/fonts/fontconfig-synthetic-oblique.html --> + <match target="font"> + <test qual="any" name="family"> + <string>DejaVu Serif</string> + </test> + <test name="slant"> + <const>roman</const> + </test> + <test target="pattern" name="slant" compare="not_eq"> + <const>roman</const> + </test> + <edit name="matrix" mode="assign"> + <times> + <name>matrix</name> + <matrix><double>1</double><double>0.2</double> + <double>0</double><double>1</double> + </matrix> + </times> + </edit> + <edit name="slant" mode="assign"> + <const>oblique</const> + </edit> + <edit name="embeddedbitmap" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <!-- If this font doesn't have a family name we are falling back. The fallback + font will certainly be one of the DejaVu fonts that we have in our + collection since they have a wide range of characters. Fontconfig might + choose DejaVu Sans or DejaVu Serif depending on the system, so we force + the use of DejaVu Sans in these situations to maintain consistency. --> + <match target="pattern"> + <test qual="all" name="family" compare="eq"> + <string></string> + </test> + <edit name="family" mode="append_last"> + <string>DejaVu Sans</string> + </edit> + </match> + + <config> + <!-- These are the default Unicode chars that are expected to be blank + in fonts. All other blank chars are assumed to be broken and won't + appear in the resulting charsets --> + <blank> + <int>0x0020</int> <!-- SPACE --> + <int>0x00A0</int> <!-- NO-BREAK SPACE --> + <int>0x00AD</int> <!-- SOFT HYPHEN --> + <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER --> + <int>0x0600</int> <!-- ARABIC NUMBER SIGN --> + <int>0x0601</int> <!-- ARABIC SIGN SANAH --> + <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER --> + <int>0x0603</int> <!-- ARABIC SIGN SAFHA --> + <int>0x06DD</int> <!-- ARABIC END OF AYAH --> + <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK --> + <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER --> + <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER --> + <int>0x1680</int> <!-- OGHAM SPACE MARK --> + <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ --> + <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA --> + <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR --> + <int>0x2000</int> <!-- EN QUAD --> + <int>0x2001</int> <!-- EM QUAD --> + <int>0x2002</int> <!-- EN SPACE --> + <int>0x2003</int> <!-- EM SPACE --> + <int>0x2004</int> <!-- THREE-PER-EM SPACE --> + <int>0x2005</int> <!-- FOUR-PER-EM SPACE --> + <int>0x2006</int> <!-- SIX-PER-EM SPACE --> + <int>0x2007</int> <!-- FIGURE SPACE --> + <int>0x2008</int> <!-- PUNCTUATION SPACE --> + <int>0x2009</int> <!-- THIN SPACE --> + <int>0x200A</int> <!-- HAIR SPACE --> + <int>0x200B</int> <!-- ZERO WIDTH SPACE --> + <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER --> + <int>0x200D</int> <!-- ZERO WIDTH JOINER --> + <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK --> + <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK --> + <int>0x2028</int> <!-- LINE SEPARATOR --> + <int>0x2029</int> <!-- PARAGRAPH SEPARATOR --> + <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING --> + <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING --> + <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING --> + <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE --> + <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE --> + <int>0x202F</int> <!-- NARROW NO-BREAK SPACE --> + <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE --> + <int>0x2060</int> <!-- WORD JOINER --> + <int>0x2061</int> <!-- FUNCTION APPLICATION --> + <int>0x2062</int> <!-- INVISIBLE TIMES --> + <int>0x2063</int> <!-- INVISIBLE SEPARATOR --> + <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING --> + <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING --> + <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING --> + <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING --> + <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES --> + <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES --> + <int>0x3000</int> <!-- IDEOGRAPHIC SPACE --> + <int>0x3164</int> <!-- HANGUL FILLER --> + <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE --> + <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER --> + <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR --> + <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR --> + <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR --> + </blank> + </config> +</fontconfig> diff --git a/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm new file mode 100644 index 000000000..6fc0dd056 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#import "DumpRenderTree.h" +#import "AccessibilityController.h" + +#import "AccessibilityNotificationHandler.h" +#import "AccessibilityUIElement.h" +#import <AppKit/NSColor.h> +#import <Foundation/Foundation.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLView.h> + +AccessibilityController::AccessibilityController() +{ +} + +AccessibilityController::~AccessibilityController() +{ + // The notification handler should be nil because removeNotificationListener() should have been called in the test. + ASSERT(!m_globalNotificationHandler); +} + +AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y) +{ + id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityHitTest:NSMakePoint(x, y)]; + return AccessibilityUIElement(accessibilityObject); +} + +AccessibilityUIElement AccessibilityController::focusedElement() +{ + id accessibilityObject = [[mainFrame accessibilityRoot] accessibilityFocusedUIElement]; + return AccessibilityUIElement(accessibilityObject); +} + +AccessibilityUIElement AccessibilityController::rootElement() +{ + // FIXME: we could do some caching here. + + // Layout tests expect that the root element will be the scroll area + // containing the web area object. That will be the parent of the accessibilityRoot on WK1. + + id accessibilityObject = [[mainFrame accessibilityRoot] accessibilityAttributeValue:NSAccessibilityParentAttribute]; + return AccessibilityUIElement(accessibilityObject); +} + +void AccessibilityController::setLogFocusEvents(bool) +{ +} + +void AccessibilityController::setLogScrollingStartEvents(bool) +{ +} + +void AccessibilityController::setLogValueChangeEvents(bool) +{ +} + +void AccessibilityController::setLogAccessibilityEvents(bool) +{ +} + +bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + // Mac programmers should not be adding more than one global notification listener. + // Other platforms may be different. + if (m_globalNotificationHandler) + return false; + m_globalNotificationHandler = [[AccessibilityNotificationHandler alloc] init]; + [m_globalNotificationHandler.get() setCallback:functionCallback]; + [m_globalNotificationHandler.get() startObserving]; + + return true; +} + +void AccessibilityController::removeNotificationListener() +{ + // Mac programmers should not be trying to remove a listener that's already removed. + ASSERT(m_globalNotificationHandler); + m_globalNotificationHandler.clear(); +} diff --git a/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h new file mode 100644 index 000000000..19386ceb0 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 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 AccessibilityNotificationHandler_h +#define AccessibilityNotificationHandler_h + +#import <JavaScriptCore/JSObjectRef.h> + +@interface AccessibilityNotificationHandler : NSObject { + id m_platformElement; + JSObjectRef m_notificationFunctionCallback; +} + +- (id)init; +- (void)setPlatformElement:(id)platformElement; +- (void)setCallback:(JSObjectRef)callback; +- (void)startObserving; + +@end + +#endif // AccessibilityNotificationHandler_h diff --git a/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm new file mode 100644 index 000000000..13d08c9f4 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011 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 "config.h" +#import "DumpRenderTree.h" +#import "AccessibilityNotificationHandler.h" +#import "AccessibilityUIElement.h" + +#import <JavaScriptCore/JSRetainPtr.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebTypesInternal.h> +#import <wtf/RetainPtr.h> + +@interface NSObject (WebAccessibilityObjectWrapperAdditions) ++ (void)accessibilitySetShouldRepostNotifications:(BOOL)repost; +@end + +@interface NSString (JSStringRefAdditions) +- (JSStringRef)createJSStringRef; +@end + +@implementation NSString (JSStringRefAdditions) + +- (JSStringRef)createJSStringRef +{ + return JSStringCreateWithCFString((CFStringRef)self); +} + +@end + +@implementation AccessibilityNotificationHandler + +- (id)init +{ + if (!(self = [super init])) + return nil; + + m_platformElement = nil; + return self; +} + +- (void)setPlatformElement:(id)platformElement +{ + m_platformElement = platformElement; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback); + m_notificationFunctionCallback = 0; + + [super dealloc]; +} + +- (void)setCallback:(JSObjectRef)callback +{ + if (!callback) + return; + + if (m_notificationFunctionCallback) + JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback); + + m_notificationFunctionCallback = callback; + JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback); +} + +- (void)startObserving +{ + // Once we start requesting notifications, it's on for the duration of the program. + // This is to avoid any race conditions between tests turning this flag on and off. Instead + // AccessibilityNotificationHandler can ignore events it doesn't care about. + id webAccessibilityObjectWrapperClass = NSClassFromString(@"WebAccessibilityObjectWrapper"); + ASSERT(webAccessibilityObjectWrapperClass); + [webAccessibilityObjectWrapperClass accessibilitySetShouldRepostNotifications:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil]; +} + +- (void)_notificationReceived:(NSNotification *)notification +{ + NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"]; + if (!notificationName) + return; + if (m_platformElement && m_platformElement != [notification object]) + return; + + JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]); + JSValueRef notificationNameArgument = JSValueMakeString([mainFrame globalContext], jsNotification.get()); + if (m_platformElement) { + // Listener for one element just gets one argument, the notification name. + JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, ¬ificationNameArgument, 0); + } else { + // A global listener gets the element and the notification name as arguments. + JSValueRef arguments[2]; + arguments[0] = AccessibilityUIElement::makeJSAccessibilityUIElement([mainFrame globalContext], AccessibilityUIElement([notification object])); + arguments[1] = notificationNameArgument; + JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 2, arguments, 0); + } +} + +@end + diff --git a/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm new file mode 100644 index 000000000..18ddb85c6 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" + +#import "AccessibilityTextMarker.h" +#import "DumpRenderTree.h" + +// MARK: AccessibilityTextMarker + +AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker marker) + : m_textMarker(marker) +{ +} + +AccessibilityTextMarker::AccessibilityTextMarker(const AccessibilityTextMarker& marker) + : m_textMarker(marker.platformTextMarker()) +{ +} + +AccessibilityTextMarker::~AccessibilityTextMarker() +{ +} + +bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker* other) +{ + return [(id)platformTextMarker() isEqual:(id)other->platformTextMarker()]; +} + +PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const +{ + return m_textMarker.get(); +} + +// MARK: AccessibilityTextMarkerRange + +AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange markerRange) + : m_textMarkerRange(markerRange) +{ +} + +AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange& markerRange) + : m_textMarkerRange(markerRange.platformTextMarkerRange()) +{ +} + +AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange() +{ +} + +bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange* other) +{ + return [(id)platformTextMarkerRange() isEqual:(id)other->platformTextMarkerRange()]; +} + +PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const +{ + return m_textMarkerRange.get(); +} diff --git a/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm new file mode 100644 index 000000000..9360ef1e7 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm @@ -0,0 +1,1394 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#import "DumpRenderTree.h" +#import "AccessibilityNotificationHandler.h" +#import "AccessibilityUIElement.h" + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JSRetainPtr.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebHTMLView.h> +#import <WebKit/WebTypesInternal.h> +#import <wtf/RetainPtr.h> +#import <wtf/Vector.h> + + +#ifndef NSAccessibilityOwnsAttribute +#define NSAccessibilityOwnsAttribute @"AXOwns" +#endif + +#ifndef NSAccessibilityGrabbedAttribute +#define NSAccessibilityGrabbedAttribute @"AXGrabbed" +#endif + +#ifndef NSAccessibilityDropEffectsAttribute +#define NSAccessibilityDropEffectsAttribute @"AXDropEffects" +#endif + +// If an unsupported attribute is passed in, it will raise an accessibility exception. These are usually caught by the Accessibility Runtime to inform +// the AX client app of the error. However, DRT is the AX client app, so it must catch these exceptions. +#define BEGIN_AX_OBJC_EXCEPTIONS @try { +#define END_AX_OBJC_EXCEPTIONS } @catch(NSException *e) { if (![[e name] isEqualToString:NSAccessibilityException]) @throw; } + + +typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context); + +@interface NSObject (WebKitAccessibilityAdditions) +- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount; +- (NSUInteger)accessibilityIndexOfChild:(id)child; +- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute; +@end + +@interface NSString (JSStringRefAdditions) ++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef; +- (JSStringRef)createJSStringRef; +@end + +@implementation NSString (JSStringRefAdditions) + ++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef +{ + if (!jsStringRef) + return NULL; + + CFStringRef cfString = JSStringCopyCFString(kCFAllocatorDefault, jsStringRef); + return [(NSString *)cfString autorelease]; +} + +- (JSStringRef)createJSStringRef +{ + return JSStringCreateWithCFString((CFStringRef)self); +} + +@end + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) + , m_notificationHandler(0) +{ + // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac. + [m_element retain]; +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) + , m_notificationHandler(0) +{ + [m_element retain]; +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ + // The notification handler should be nil because removeNotificationListener() should have been called in the test. + ASSERT(!m_notificationHandler); + [m_element release]; +} + +static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject) +{ + if (!valueObject) + return NULL; + + if ([valueObject isKindOfClass:[NSArray class]]) + return [NSString stringWithFormat:@"<array of size %d>", [(NSArray*)valueObject count]]; + + if ([valueObject isKindOfClass:[NSNumber class]]) + return [(NSNumber*)valueObject stringValue]; + + if ([valueObject isKindOfClass:[NSValue class]]) { + NSString* type = [NSString stringWithCString:[valueObject objCType] encoding:NSASCIIStringEncoding]; + NSValue* value = (NSValue*)valueObject; + if ([type rangeOfString:@"NSRect"].length > 0) + return [NSString stringWithFormat:@"NSRect: %@", NSStringFromRect([value rectValue])]; + if ([type rangeOfString:@"NSPoint"].length > 0) + return [NSString stringWithFormat:@"NSPoint: %@", NSStringFromPoint([value pointValue])]; + if ([type rangeOfString:@"NSSize"].length > 0) + return [NSString stringWithFormat:@"NSSize: %@", NSStringFromSize([value sizeValue])]; + if ([type rangeOfString:@"NSRange"].length > 0) + return [NSString stringWithFormat:@"NSRange: %@", NSStringFromRange([value rangeValue])]; + } + + // Strip absolute URL paths + NSString* description = [valueObject description]; + NSRange range = [description rangeOfString:@"LayoutTests"]; + if (range.length) + return [description substringFromIndex:range.location]; + + // Strip pointer locations + if ([description rangeOfString:@"0x"].length) { + NSString* role = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityRoleAttribute]; + NSString* title = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityTitleAttribute]; + if ([title length]) + return [NSString stringWithFormat:@"<%@: '%@'>", role, title]; + return [NSString stringWithFormat:@"<%@>", role]; + } + + return [valueObject description]; +} + +static NSString* attributesOfElement(id accessibilityObject) +{ + NSArray* supportedAttributes = [accessibilityObject accessibilityAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedAttributes count]; ++i) { + NSString* attribute = [supportedAttributes objectAtIndex:i]; + + // Right now, position provides useless and screen-specific information, so we do not + // want to include it for the sake of universally passing tests. + if ([attribute isEqualToString:@"AXPosition"]) + continue; + + // accessibilityAttributeValue: can throw an if an attribute is not returned. + // For DumpRenderTree's purpose, we should ignore those exceptions + BEGIN_AX_OBJC_EXCEPTIONS + id valueObject = [accessibilityObject accessibilityAttributeValue:attribute]; + NSString* value = descriptionOfValue(valueObject, accessibilityObject); + [attributesString appendFormat:@"%@: %@\n", attribute, value]; + END_AX_OBJC_EXCEPTIONS + } + + return attributesString; +} + +static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value) +{ + Vector<UniChar> buffer([attribute length]); + [attribute getCharacters:buffer.data()]; + buffer.append(':'); + buffer.append(' '); + + Vector<UniChar> valueBuffer([value length]); + [value getCharacters:valueBuffer.data()]; + buffer.append(valueBuffer); + + return JSStringCreateWithCharacters(buffer.data(), buffer.size()); +} + +static void convertNSArrayToVector(NSArray* array, Vector<AccessibilityUIElement>& elementVector) +{ + NSUInteger count = [array count]; + for (NSUInteger i = 0; i < count; ++i) + elementVector.append(AccessibilityUIElement([array objectAtIndex:i])); +} + +static JSStringRef descriptionOfElements(Vector<AccessibilityUIElement>& elementVector) +{ + NSMutableString* allElementString = [NSMutableString string]; + size_t size = elementVector.size(); + for (size_t i = 0; i < size; ++i) { + NSString* attributes = attributesOfElement(elementVector[i].platformUIElement()); + [allElementString appendFormat:@"%@\n------------\n", attributes]; + } + + return [allElementString createJSStringRef]; +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* linkedElements = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + convertNSArrayToVector(linkedElements, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* linkElements = [m_element accessibilityAttributeValue:@"AXLinkUIElements"]; + convertNSArrayToVector(linkElements, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* children = [m_element accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; + convertNSArrayToVector(children, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* children = [m_element accessibilityArrayAttributeValues:NSAccessibilityChildrenAttribute index:location maxCount:length]; + convertNSArrayToVector(children, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +int AccessibilityUIElement::childrenCount() +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + + return children.size(); +} + +AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) +{ + id element = [m_element accessibilityHitTest:NSMakePoint(x, y)]; + if (!element) + return nil; + + return AccessibilityUIElement(element); +} + +unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) +{ + return [m_element accessibilityIndexOfChild:element->platformUIElement()]; +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + Vector<AccessibilityUIElement> children; + getChildrenWithRange(children, index, 1); + + if (children.size() == 1) + return children[0]; + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityOwnsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedRowsAttribute]; + if (index < [rows count]) + return [rows objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned index) const +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* array = [m_element accessibilityAttributeValue:NSAccessibilitySelectedChildrenAttribute]; + if (index < [array count]) + return [array objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +unsigned AccessibilityUIElement::selectedChildrenCount() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilitySelectedChildrenAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilitySelectedRowsAttribute]; + if (index < [rows count]) + return [rows objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityTitleUIElementAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::parentElement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityParentAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedByRow() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedByRowAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + Vector<AccessibilityUIElement> linkedElements; + getLinkedUIElements(linkedElements); + return descriptionOfElements(linkedElements); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + Vector<AccessibilityUIElement> linkElements; + getDocumentLinks(linkElements); + return descriptionOfElements(linkElements); +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + return descriptionOfElements(children); +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + NSString* attributes = attributesOfElement(m_element); + return [attributes createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + if ([value isKindOfClass:[NSString class]]) + return [value createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id uiElement = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + return AccessibilityUIElement(uiElement); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + + +double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + if ([value isKindOfClass:[NSNumber class]]) + return [value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [[m_element accessibilityAttributeNames] containsObject:[NSString stringWithJSStringRef:attribute]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedParameterizedAttributes count]; ++i) { + [attributesString appendFormat:@"%@\n", [supportedParameterizedAttributes objectAtIndex:i]]; + } + + return [attributesString createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::role() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString *role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleAttribute], m_element); + return concatenateAttributeAndValue(@"AXRole", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::subrole() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilitySubroleAttribute], m_element); + return concatenateAttributeAndValue(@"AXSubrole", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::roleDescription() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], m_element); + return concatenateAttributeAndValue(@"AXRoleDescription", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::title() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityTitleAttribute], m_element); + return concatenateAttributeAndValue(@"AXTitle", title); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::description() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityDescriptionAttribute], m_element); + return concatenateAttributeAndValue(@"AXDescription", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::orientation() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityOrientationAttribute], m_element); + return concatenateAttributeAndValue(@"AXOrientation", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::stringValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityValueAttribute], m_element); + return concatenateAttributeAndValue(@"AXValue", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::language() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXLanguage"], m_element); + return concatenateAttributeAndValue(@"AXLanguage", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::helpText() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element); + return concatenateAttributeAndValue(@"AXHelp", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +double AccessibilityUIElement::x() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute]; + return static_cast<double>([positionValue pointValue].x); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::y() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute]; + return static_cast<double>([positionValue pointValue].y); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::width() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute]; + return static_cast<double>([sizeValue sizeValue].width); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::height() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute]; + return static_cast<double>([sizeValue sizeValue].height); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::clickPointX() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"]; + return static_cast<double>([positionValue pointValue].x); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::clickPointY() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"]; + return static_cast<double>([positionValue pointValue].y); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::intValue() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::minValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityMinValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::maxValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityMaxValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0; +} + +JSStringRef AccessibilityUIElement::valueDescription() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* valueDescription = [m_element accessibilityAttributeValue:NSAccessibilityValueDescriptionAttribute]; + if ([valueDescription isKindOfClass:[NSString class]]) + return [valueDescription createJSStringRef]; + + END_AX_OBJC_EXCEPTIONS + return 0; +} + +int AccessibilityUIElement::insertionPointLineNumber() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityInsertionPointLineNumberAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +bool AccessibilityUIElement::isActionSupported(JSStringRef action) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* actions = [m_element accessibilityActionNames]; + return [actions containsObject:[NSString stringWithJSStringRef:action]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isEnabled() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityEnabledAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isRequired() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXRequired"]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isFocused() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelected() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilitySelectedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isExpanded() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityExpandedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isChecked() const +{ + // On the Mac, intValue()==1 if a a checkable control is checked. + return intValue() == 1; +} + +int AccessibilityUIElement::hierarchicalLevel() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityDisclosureLevelAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value intValue]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::speak() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXDRTSpeechAttribute"]; + if ([value isKindOfClass:[NSString class]]) + return [value createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::ariaIsGrabbed() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityGrabbedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +JSStringRef AccessibilityUIElement::ariaDropEffects() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityDropEffectsAttribute]; + if (![value isKindOfClass:[NSArray class]]) + return 0; + + NSMutableString* dropEffects = [NSMutableString string]; + NSInteger length = [value count]; + for (NSInteger k = 0; k < length; ++k) { + [dropEffects appendString:[value objectAtIndex:k]]; + if (k < length - 1) + [dropEffects appendString:@","]; + } + + return [dropEffects createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +// parameterized attributes +int AccessibilityUIElement::lineForIndex(int index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:[NSNumber numberWithInt:index]]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +JSStringRef AccessibilityUIElement::rangeForLine(int line) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityRangeForLineParameterizedAttribute forParameter:[NSNumber numberWithInt:line]]; + if ([value isKindOfClass:[NSValue class]]) { + return [NSStringFromRange([value rangeValue]) createJSStringRef]; + } + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityBoundsForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + NSRect rect = NSMakeRect(0,0,0,0); + if ([value isKindOfClass:[NSValue class]]) + rect = [value rectValue]; + + // don't return position information because it is platform dependent + NSMutableString* boundsDescription = [NSMutableString stringWithFormat:@"{{%f, %f}, {%f, %f}}",-1.0f,-1.0f,rect.size.width,rect.size.height]; + return [boundsDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + id string = [m_element accessibilityAttributeValue:NSAccessibilityStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSString class]]) + return 0; + + return [string createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSAttributedString class]]) + return 0; + + NSString* stringWithAttrs = [string description]; + return [stringWithAttrs createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSAttributedString class]]) + return false; + + NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil]; + if([[attrs objectForKey:NSAccessibilityMisspelledTextAttribute] boolValue]) + return true; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSMutableDictionary* parameter = [NSMutableDictionary dictionary]; + [parameter setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"]; + [parameter setObject:[NSNumber numberWithInt:1] forKey:@"AXResultsLimit"]; + if (startElement && startElement->platformUIElement()) + [parameter setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"]; + if (searchKey) + [parameter setObject:[NSString stringWithJSStringRef:searchKey] forKey:@"AXSearchKey"]; + if (searchText) + [parameter setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"]; + + id uiElement = [[m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameter] lastObject]; + return AccessibilityUIElement(uiElement); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + // not yet defined in AppKit... odd + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* columnHeadersArray = [m_element accessibilityAttributeValue:@"AXColumnHeaderUIElements"]; + Vector<AccessibilityUIElement> columnHeadersVector; + convertNSArrayToVector(columnHeadersArray, columnHeadersVector); + return descriptionOfElements(columnHeadersVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rowHeadersArray = [m_element accessibilityAttributeValue:@"AXRowHeaderUIElements"]; + Vector<AccessibilityUIElement> rowHeadersVector; + convertNSArrayToVector(rowHeadersArray, rowHeadersVector); + return descriptionOfElements(rowHeadersVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* columnsArray = [m_element accessibilityAttributeValue:NSAccessibilityColumnsAttribute]; + Vector<AccessibilityUIElement> columnsVector; + convertNSArrayToVector(columnsArray, columnsVector); + return descriptionOfElements(columnsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rowsArray = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute]; + Vector<AccessibilityUIElement> rowsVector; + convertNSArrayToVector(rowsArray, rowsVector); + return descriptionOfElements(rowsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* cellsArray = [m_element accessibilityAttributeValue:@"AXVisibleCells"]; + Vector<AccessibilityUIElement> cellsVector; + convertNSArrayToVector(cellsArray, cellsVector); + return descriptionOfElements(cellsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id headerObject = [m_element accessibilityAttributeValue:NSAccessibilityHeaderAttribute]; + if (!headerObject) + return [@"" createJSStringRef]; + + Vector<AccessibilityUIElement> headerVector; + headerVector.append(headerObject); + return descriptionOfElements(headerVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::rowCount() +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::columnCount() +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::indexInTable() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute]; + if (indexNumber) + return [indexNumber intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +JSStringRef AccessibilityUIElement::rowIndexRange() +{ + NSRange range = NSMakeRange(0,0); + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* indexRange = [m_element accessibilityAttributeValue:@"AXRowIndexRange"]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::columnIndexRange() +{ + NSRange range = NSMakeRange(0,0); + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* indexRange = [m_element accessibilityAttributeValue:@"AXColumnIndexRange"]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) +{ + NSArray *colRowArray = [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:col], [NSNumber numberWithUnsignedInt:row], nil]; + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityAttributeValue:@"AXCellForColumnAndRow" forParameter:colRowArray]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::horizontalScrollbar() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + return AccessibilityUIElement([m_element accessibilityAttributeValue:NSAccessibilityHorizontalScrollBarAttribute]); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + return AccessibilityUIElement([m_element accessibilityAttributeValue:NSAccessibilityVerticalScrollBarAttribute]); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + NSRange range = NSMakeRange(NSNotFound, 0); + BEGIN_AX_OBJC_EXCEPTIONS + NSValue *indexRange = [m_element accessibilityAttributeValue:NSAccessibilitySelectedTextRangeAttribute]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString *rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ + NSRange textRange = NSMakeRange(location, length); + NSValue *textRangeValue = [NSValue valueWithRange:textRange]; + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilitySetValue:textRangeValue forAttribute:NSAccessibilitySelectedTextRangeAttribute]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::increment() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityIncrementAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::decrement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityDecrementAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::showMenu() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityShowMenuAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::press() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityPressAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* array = [NSArray arrayWithObject:element->platformUIElement()]; + [m_element accessibilitySetValue:array forAttribute:NSAccessibilitySelectedChildrenAttribute]; + END_AX_OBJC_EXCEPTIONS +} + +JSStringRef AccessibilityUIElement::accessibilityValue() const +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentEncoding() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentURI() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::url() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSURL *url = [m_element accessibilityAttributeValue:NSAccessibilityURLAttribute]; + return [[url absoluteString] createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return nil; +} + +bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + // Mac programmers should not be adding more than one notification listener per element. + // Other platforms may be different. + if (m_notificationHandler) + return false; + m_notificationHandler = [[AccessibilityNotificationHandler alloc] init]; + [m_notificationHandler setPlatformElement:platformUIElement()]; + [m_notificationHandler setCallback:functionCallback]; + [m_notificationHandler startObserving]; + + return true; +} + +void AccessibilityUIElement::removeNotificationListener() +{ + // Mac programmers should not be trying to remove a listener that's already removed. + ASSERT(m_notificationHandler); + + [m_notificationHandler release]; + m_notificationHandler = nil; +} + +bool AccessibilityUIElement::isFocusable() const +{ + bool result = false; + BEGIN_AX_OBJC_EXCEPTIONS + result = [m_element accessibilityIsAttributeSettable:NSAccessibilityFocusedAttribute]; + END_AX_OBJC_EXCEPTIONS + + return result; +} + +bool AccessibilityUIElement::isSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isMultiSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelectedOptionActive() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isVisible() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isOffScreen() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isCollapsed() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isIgnored() const +{ + BOOL result = NO; + BEGIN_AX_OBJC_EXCEPTIONS + result = [m_element accessibilityIsIgnored]; + END_AX_OBJC_EXCEPTIONS + return result; +} + +bool AccessibilityUIElement::hasPopup() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXHasPopup"]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +void AccessibilityUIElement::takeFocus() +{ + // FIXME: implement +} + +void AccessibilityUIElement::takeSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::addSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::removeSelection() +{ + // FIXME: implement +} + +#if SUPPORTS_AX_TEXTMARKERS + +// Text markers +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUIElement" forParameter:element->platformUIElement()]; + return AccessibilityTextMarkerRange(textMarkerRange); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* lengthValue = [m_element accessibilityAttributeValue:@"AXLengthForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return [lengthValue intValue]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSAttributedString* string = [m_element accessibilityAttributeValue:@"AXAttributedStringForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + if (![string isKindOfClass:[NSAttributedString class]]) + return false; + + NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil]; + if ([attrs objectForKey:[NSString stringWithJSStringRef:attribute]]) + return true; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +AccessibilityTextMarker AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id previousMarker = [m_element accessibilityAttributeValue:@"AXPreviousTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()]; + return AccessibilityTextMarker(previousMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id nextMarker = [m_element accessibilityAttributeValue:@"AXNextTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()]; + return AccessibilityTextMarker(nextMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textString = [m_element accessibilityAttributeValue:@"AXStringForTextMarkerRange" forParameter:(id)markerRange->platformTextMarkerRange()]; + return [textString createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil]; + id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUnorderedTextMarkers" forParameter:textMarkers]; + return AccessibilityTextMarkerRange(textMarkerRange); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXTextMarkerForPosition" forParameter:[NSValue valueWithPoint:NSMakePoint(x, y)]]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id uiElement = [m_element accessibilityAttributeValue:@"AXUIElementForTextMarker" forParameter:(id)marker->platformTextMarker()]; + return AccessibilityUIElement(uiElement); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +#endif // SUPPORTS_AX_TEXTMARKERS diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.h b/Tools/DumpRenderTree/mac/AppleScriptController.h new file mode 100644 index 000000000..c29789c2e --- /dev/null +++ b/Tools/DumpRenderTree/mac/AppleScriptController.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Foundation/Foundation.h> + +@class WebView; + +@interface AppleScriptController : NSObject +{ + WebView *webView; +} +- (id)initWithWebView:(WebView *)view; +@end diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.m b/Tools/DumpRenderTree/mac/AppleScriptController.m new file mode 100644 index 000000000..2eab8271e --- /dev/null +++ b/Tools/DumpRenderTree/mac/AppleScriptController.m @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "AppleScriptController.h" + +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> // for aeDescByEvaluatingJavaScriptFromString, which is pending API review + +@implementation AppleScriptController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(doJavaScript:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(doJavaScript:)) + return @"doJavaScript"; + + return nil; +} + +- (id)initWithWebView:(WebView *)wv +{ + self = [super init]; + webView = wv; + return self; +} + +static id convertAEDescToObject(NSAppleEventDescriptor *aeDesc) +{ + id value = nil; + + DescType descType = [aeDesc descriptorType]; + switch (descType) { + case typeUnicodeText: + value = [NSString stringWithFormat:@"\"%@\"", [aeDesc stringValue]]; + break; + case typeLongDateTime: + if ([[aeDesc data] length] == sizeof(LongDateTime)) { + LongDateTime d; + [[aeDesc data] getBytes:&d]; + value = [NSString stringWithFormat:@"%016llX", (unsigned long long)d]; + } + break; + case typeAEList: + value = [NSMutableString stringWithString:@"("]; + int numItems = [aeDesc numberOfItems]; + for (int i = 0; i < numItems; ++i) { + if (i != 0) + [(NSMutableString*)value appendString:@", "]; + id obj = convertAEDescToObject([aeDesc descriptorAtIndex:(i + 1)]); + [(NSMutableString*)value appendString:[obj description]]; + } + [(NSMutableString*)value appendString:@")"]; + break; + case typeType: { + OSType type = [aeDesc typeCodeValue]; + + char typeStr[5]; + typeStr[0] = type >> 24; + typeStr[1] = type >> 16; + typeStr[2] = type >> 8; + typeStr[3] = type; + typeStr[4] = 0; + + value = [NSString stringWithFormat:@"'%s'", typeStr]; + break; + } + } + + if (!value) + value = [aeDesc stringValue]; + if (!value) + value = [aeDesc data]; + + return value; +} + +- (NSString *)doJavaScript:(NSString *)aString +{ + NSAppleEventDescriptor *aeDesc = [webView aeDescByEvaluatingJavaScriptFromString:aString]; + if (!aeDesc) + return @"(null)"; + + DescType descType = [aeDesc descriptorType]; + char descTypeStr[5]; + descTypeStr[0] = descType >> 24; + descTypeStr[1] = descType >> 16; + descTypeStr[2] = descType >> 8; + descTypeStr[3] = descType; + descTypeStr[4] = 0; + + return [NSString stringWithFormat:@"%@ ('%s')", convertAEDescToObject(aeDesc), descTypeStr]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.cpp b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp new file mode 100644 index 000000000..8bd53e546 --- /dev/null +++ b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "CheckedMalloc.h" + +#import <mach/mach_init.h> +#import <mach/mach_vm.h> +#import <mach/vm_region.h> +#import <malloc/malloc.h> +#import <unistd.h> + +static void* (*savedMalloc)(malloc_zone_t*, size_t); +static void* (*savedRealloc)(malloc_zone_t*, void*, size_t); + +static void* checkedMalloc(malloc_zone_t* zone, size_t size) +{ + if (size >= 0x10000000) + return 0; + return savedMalloc(zone, size); +} + +static void* checkedRealloc(malloc_zone_t* zone, void* ptr, size_t size) +{ + if (size >= 0x10000000) + return 0; + return savedRealloc(zone, ptr, size); +} + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +static vm_prot_t protectionOfRegion(mach_vm_address_t address) +{ + mach_vm_size_t regionSize = 0; + vm_region_basic_info_64 regionInfo; + mach_msg_type_number_t regionInfoCount = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t objectName; + if (mach_vm_region(mach_task_self(), &address, ®ionSize, VM_REGION_BASIC_INFO_64, (vm_region_info_t)®ionInfo, ®ionInfoCount, &objectName)) + CRASH(); + return regionInfo.protection; +} +#endif + +void makeLargeMallocFailSilently() +{ + malloc_zone_t* zone = malloc_default_zone(); + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + mach_vm_address_t pageStart = reinterpret_cast<vm_address_t>(zone) & static_cast<vm_size_t>(~(getpagesize() - 1)); + vm_prot_t initialProtection = protectionOfRegion(pageStart); + + vm_size_t len = reinterpret_cast<vm_address_t>(zone) - pageStart + sizeof(malloc_zone_t); + if (mach_vm_protect(mach_task_self(), pageStart, len, 0, initialProtection | VM_PROT_WRITE)) + CRASH(); +#endif + + savedMalloc = zone->malloc; + savedRealloc = zone->realloc; + zone->malloc = checkedMalloc; + zone->realloc = checkedRealloc; + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + if (mach_vm_protect(mach_task_self(), pageStart, len, 0, initialProtection)) + CRASH(); +#endif +} diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.h b/Tools/DumpRenderTree/mac/CheckedMalloc.h new file mode 100644 index 000000000..c03bd2072 --- /dev/null +++ b/Tools/DumpRenderTree/mac/CheckedMalloc.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +void makeLargeMallocFailSilently(); diff --git a/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig new file mode 100644 index 000000000..11fee7169 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig @@ -0,0 +1,62 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "CompilerVersion.xcconfig" + +HEADER_SEARCH_PATHS = ForwardingHeaders mac/InternalHeaders $(NEXT_ROOT)/usr/local/include/WebCoreTestSupport; +FRAMEWORK_SEARCH_PATHS = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks; +GCC_PREPROCESSOR_DEFINITIONS = ENABLE_DASHBOARD_SUPPORT WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST; +DEBUG_INFORMATION_FORMAT = dwarf +PREBINDING = NO +GCC_C_LANGUAGE_STANDARD = gnu99 +GCC_OBJC_CALL_CXX_CDTORS = YES +GCC_PRECOMPILE_PREFIX_HEADER = YES +GCC_TREAT_WARNINGS_AS_ERRORS = YES +GCC_WARN_UNUSED_FUNCTION = YES +GCC_WARN_UNUSED_VARIABLE = YES +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO +WARNING_CFLAGS = -Wall -W -Wno-unused-parameter +LINKER_DISPLAYS_MANGLED_NAMES = YES; + + +REAL_PLATFORM_NAME = $(REAL_PLATFORM_NAME_$(PLATFORM_NAME)); +REAL_PLATFORM_NAME_ = $(REAL_PLATFORM_NAME_macosx); +REAL_PLATFORM_NAME_iphoneos = iphoneos; +REAL_PLATFORM_NAME_iphonesimulator = iphonesimulator; +REAL_PLATFORM_NAME_macosx = macosx; + +TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR); + + +// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK. +SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +SDKROOT_1060_1050 = macosx10.5; +SDKROOT_1070_1050 = macosx10.5; +SDKROOT_1080_1050 = macosx10.5; +SDKROOT_1090_1050 = macosx10.5; +SDKROOT_1070_1060 = macosx10.6; +SDKROOT_1080_1060 = macosx10.6; +SDKROOT_1090_1060 = macosx10.6; +SDKROOT_1080_1070 = macosx10.7; +SDKROOT_1090_1070 = macosx10.7; +SDKROOT_1090_1080 = macosx10.8; diff --git a/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig b/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig new file mode 100644 index 000000000..a8c7f75a0 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig @@ -0,0 +1,84 @@ +// Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + +IS_XCODE_0400 = $(IS_XCODE_0400_$(XCODE_VERSION_MINOR)); +IS_XCODE_0400_0400 = YES; + +IS_XCODE_0400_OR_0410 = $(IS_XCODE_0400_OR_0410_$(XCODE_VERSION_MINOR)); +IS_XCODE_0400_OR_0410_0400 = YES; +IS_XCODE_0400_OR_0410_0410 = YES; + +// The version of the LLVM Compiler in Xcode 4.0 and earlier have difficulty compiling our code. +LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_$(XCODE_VERSION_MAJOR)); +LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0300 = YES; +LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_$(IS_XCODE_0400)); +LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_YES = YES; + +// The version of the LLVM Compiler in Xcode 4.1 and earlier do not generate fast enough code. +LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_$(XCODE_VERSION_MAJOR)); +LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0300 = YES; +LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_$(IS_XCODE_0400_OR_0410)); +LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_YES = YES; + +LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS)); +LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_ = YES; +LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_YES = NO; + +LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS)); +LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_ = YES; +LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_YES = NO; + + +// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0. +// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version +// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and +// XCODE_VERSION_ACTUAL for the full version number. +TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(REAL_PLATFORM_NAME)); +TARGET_GCC_VERSION_iphoneos = LLVM_GCC_42; +TARGET_GCC_VERSION_iphonesimulator = GCC_42; +TARGET_GCC_VERSION_macosx = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); + +TARGET_GCC_VERSION_macosx_1050 = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_MINOR)); +TARGET_GCC_VERSION_macosx_1050_ = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_ACTUAL)); +TARGET_GCC_VERSION_macosx_1050_0310 = GCC_42; +TARGET_GCC_VERSION_macosx_1050_0320 = GCC_42; + +TARGET_GCC_VERSION_macosx_1060 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION)); +TARGET_GCC_VERSION_macosx_1070 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION)); +TARGET_GCC_VERSION_macosx_1060_AND_1070_Debug = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS)); +TARGET_GCC_VERSION_macosx_1060_AND_1070_Release = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS)); +TARGET_GCC_VERSION_macosx_1060_AND_1070_Production = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS)); +TARGET_GCC_VERSION_macosx_1060_NON_LLVM_FALLBACK = GCC_42; +TARGET_GCC_VERSION_macosx_1070_NON_LLVM_FALLBACK = LLVM_GCC_42; + +TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_YES = LLVM_COMPILER; +TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_NO = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)_NON_LLVM_FALLBACK); + +TARGET_GCC_VERSION_macosx_1080 = LLVM_COMPILER; +TARGET_GCC_VERSION_macosx_1090 = LLVM_COMPILER; + +GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION)); +GCC_VERSION_GCC_40 = 4.0; +GCC_VERSION_GCC_42 = 4.2; +GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42; +GCC_VERSION_LLVM_COMPILER = com.apple.compilers.llvm.clang.1_0; diff --git a/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig new file mode 100644 index 000000000..b61d48485 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig @@ -0,0 +1,40 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "Base.xcconfig" + +ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +ARCHS_1050 = $(NATIVE_ARCH); +ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT); +ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT); +ARCHS_1080 = $(ARCHS_STANDARD_32_64_BIT); +ARCHS_1090 = $(ARCHS_STANDARD_32_64_BIT); + +ONLY_ACTIVE_ARCH = YES; + +MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR)) +MACOSX_DEPLOYMENT_TARGET_1050 = 10.5; +MACOSX_DEPLOYMENT_TARGET_1060 = 10.6; +MACOSX_DEPLOYMENT_TARGET_1070 = 10.7; +MACOSX_DEPLOYMENT_TARGET_1080 = 10.8; +MACOSX_DEPLOYMENT_TARGET_1090 = 10.9; diff --git a/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig new file mode 100644 index 000000000..754bfa962 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig @@ -0,0 +1,28 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + +OTHER_LDFLAGS = -sectcreate __DATA Ahem qt/fonts/AHEM____.TTF -sectcreate __DATA WeightWatcher100 fonts/WebKitWeightWatcher100.ttf -sectcreate __DATA WeightWatcher200 fonts/WebKitWeightWatcher200.ttf -sectcreate __DATA WeightWatcher300 fonts/WebKitWeightWatcher300.ttf -sectcreate __DATA WeightWatcher400 fonts/WebKitWeightWatcher400.ttf -sectcreate __DATA WeightWatcher500 fonts/WebKitWeightWatcher500.ttf -sectcreate __DATA WeightWatcher600 fonts/WebKitWeightWatcher600.ttf -sectcreate __DATA WeightWatcher700 fonts/WebKitWeightWatcher700.ttf -sectcreate __DATA WeightWatcher800 fonts/WebKitWeightWatcher800.ttf -sectcreate __DATA WeightWatcher900 fonts/WebKitWeightWatcher900.ttf +LD_RUNPATH_SEARCH_PATHS = "@loader_path/."; +PRODUCT_NAME = DumpRenderTree +GCC_ENABLE_OBJC_EXCEPTIONS = YES +GCC_PREFIX_HEADER = DumpRenderTreePrefix.h diff --git a/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig new file mode 100644 index 000000000..35968afcf --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig @@ -0,0 +1,24 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + +PRODUCT_NAME = ImageDiff diff --git a/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig new file mode 100644 index 000000000..22ea4c230 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig @@ -0,0 +1,29 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. 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. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + +PRODUCT_NAME = TestNetscapePlugIn +WRAPPER_EXTENSION = plugin +INFOPLIST_FILE = TestNetscapePlugIn.subproj/Info.plist +INSTALL_PATH = "$(USER_LIBRARY_DIR)/Plugins" +WARNING_CFLAGS = -Wmost -Wno-four-char-constants -Wno-unknown-pragmas +LIBRARY_STYLE = BUNDLE diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm new file mode 100644 index 000000000..b25fa2a61 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm @@ -0,0 +1,1353 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTree.h" + +#import "AccessibilityController.h" +#import "CheckedMalloc.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "DumpRenderTreePasteboard.h" +#import "DumpRenderTreeWindow.h" +#import "EditingDelegate.h" +#import "EventSendingController.h" +#import "FrameLoadDelegate.h" +#import "HistoryDelegate.h" +#import "JavaScriptThreading.h" +#import "LayoutTestController.h" +#import "MockGeolocationProvider.h" +#import "NavigationController.h" +#import "ObjCPlugin.h" +#import "ObjCPluginFunction.h" +#import "PixelDumpSupport.h" +#import "PolicyDelegate.h" +#import "ResourceLoadDelegate.h" +#import "StorageTrackerDelegate.h" +#import "UIDelegate.h" +#import "WebArchiveDumpSupport.h" +#import "WebCoreTestSupport.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <Carbon/Carbon.h> +#import <CoreFoundation/CoreFoundation.h> +#import <WebCore/FoundationExtras.h> +#import <WebKit/DOMElement.h> +#import <WebKit/DOMExtensions.h> +#import <WebKit/DOMRange.h> +#import <WebKit/WebArchive.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebCache.h> +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDataSourcePrivate.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebDeviceOrientationProviderMock.h> +#import <WebKit/WebEditingDelegate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebHistoryItemPrivate.h> +#import <WebKit/WebInspector.h> +#import <WebKit/WebKitNSStringExtras.h> +#import <WebKit/WebPluginDatabase.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebPreferenceKeysPrivate.h> +#import <WebKit/WebResourceLoadDelegate.h> +#import <WebKit/WebStorageManagerPrivate.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebViewPrivate.h> +#import <getopt.h> +#import <objc/objc-runtime.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> +#import <wtf/Threading.h> +#import <wtf/OwnPtr.h> + +extern "C" { +#import <mach-o/getsect.h> +} + +using namespace std; + +@interface DumpRenderTreeApplication : NSApplication +@end + +@interface DumpRenderTreeEvent : NSEvent +@end + +@interface NSURLRequest (PrivateThingsWeShouldntReallyUse) ++(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host; +@end + +static void runTest(const string& testPathOrURL); + +// Deciding when it's OK to dump out the state is a bit tricky. All these must be true: +// - There is no load in progress +// - There is no work queued up (see workQueue var, below) +// - waitToDump==NO. This means either waitUntilDone was never called, or it was called +// and notifyDone was called subsequently. +// Note that the call to notifyDone and the end of the load can happen in either order. + +volatile bool done; + +NavigationController* gNavigationController = 0; +RefPtr<LayoutTestController> gLayoutTestController; + +WebFrame *mainFrame = 0; +// This is the topmost frame that is loading, during a given load, or nil when no load is +// in progress. Usually this is the same as the main frame, but not always. In the case +// where a frameset is loaded, and then new content is loaded into one of the child frames, +// that child frame is the "topmost frame that is loading". +WebFrame *topLoadingFrame = nil; // !nil iff a load is in progress + + +CFMutableSetRef disallowedURLs = 0; +CFRunLoopTimerRef waitToDumpWatchdog = 0; + +// Delegates +static FrameLoadDelegate *frameLoadDelegate; +static UIDelegate *uiDelegate; +static EditingDelegate *editingDelegate; +static ResourceLoadDelegate *resourceLoadDelegate; +static HistoryDelegate *historyDelegate; +PolicyDelegate *policyDelegate; +StorageTrackerDelegate *storageDelegate; + +static int dumpPixels; +static int threaded; +static int dumpTree = YES; +static int forceComplexText; +static int gcBetweenTests; +static BOOL printSeparators; +static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; + +static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test + +#if __OBJC2__ +static void swizzleAllMethods(Class imposter, Class original) +{ + unsigned int imposterMethodCount; + Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount); + + unsigned int originalMethodCount; + Method* originalMethods = class_copyMethodList(original, &originalMethodCount); + + for (unsigned int i = 0; i < imposterMethodCount; i++) { + SEL imposterMethodName = method_getName(imposterMethods[i]); + + // Attempt to add the method to the original class. If it fails, the method already exists and we should + // instead exchange the implementations. + if (class_addMethod(original, imposterMethodName, method_getImplementation(imposterMethods[i]), method_getTypeEncoding(imposterMethods[i]))) + continue; + + unsigned int j = 0; + for (; j < originalMethodCount; j++) { + SEL originalMethodName = method_getName(originalMethods[j]); + if (sel_isEqual(imposterMethodName, originalMethodName)) + break; + } + + // If class_addMethod failed above then the method must exist on the original class. + ASSERT(j < originalMethodCount); + method_exchangeImplementations(imposterMethods[i], originalMethods[j]); + } + + free(imposterMethods); + free(originalMethods); +} +#endif + +static void poseAsClass(const char* imposter, const char* original) +{ + Class imposterClass = objc_getClass(imposter); + Class originalClass = objc_getClass(original); + +#if !__OBJC2__ + class_poseAs(imposterClass, originalClass); +#else + + // Swizzle instance methods + swizzleAllMethods(imposterClass, originalClass); + // and then class methods + swizzleAllMethods(object_getClass(imposterClass), object_getClass(originalClass)); +#endif +} + +void setPersistentUserStyleSheetLocation(CFStringRef url) +{ + persistentUserStyleSheetLocation = url; +} + +static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString) +{ + static char* const ignoreSet[] = { + // Keeping this infrastructure around in case we ever need it again. + }; + static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*); + + for (int i = 0; i < ignoreSetCount; i++) { + // FIXME: ignore case + string curIgnore(ignoreSet[i]); + // Match at the end of the URLString + if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore)) + return true; + } + return false; +} + +static NSSet *allowedFontFamilySet() +{ + static NSSet *fontFamiliySet = [[NSSet setWithObjects: + @"Ahem", + @"Al Bayan", + @"American Typewriter", + @"Andale Mono", + @"Apple Braille", + @"Apple Color Emoji", + @"Apple Chancery", + @"Apple Garamond BT", + @"Apple LiGothic", + @"Apple LiSung", + @"Apple Symbols", + @"AppleGothic", + @"AppleMyungjo", + @"Arial Black", + @"Arial Hebrew", + @"Arial Narrow", + @"Arial Rounded MT Bold", + @"Arial Unicode MS", + @"Arial", + @"Ayuthaya", + @"Baghdad", + @"Baskerville", + @"BiauKai", + @"Big Caslon", + @"Brush Script MT", + @"Chalkboard", + @"Chalkduster", + @"Charcoal CY", + @"Cochin", + @"Comic Sans MS", + @"Copperplate", + @"Corsiva Hebrew", + @"Courier New", + @"Courier", + @"DecoType Naskh", + @"Devanagari MT", + @"Didot", + @"Euphemia UCAS", + @"Futura", + @"GB18030 Bitmap", + @"Geeza Pro", + @"Geneva CY", + @"Geneva", + @"Georgia", + @"Gill Sans", + @"Gujarati MT", + @"GungSeo", + @"Gurmukhi MT", + @"HeadLineA", + @"Hei", + @"Heiti SC", + @"Heiti TC", + @"Helvetica CY", + @"Helvetica Neue", + @"Helvetica", + @"Herculanum", + @"Hiragino Kaku Gothic Pro", + @"Hiragino Kaku Gothic ProN", + @"Hiragino Kaku Gothic Std", + @"Hiragino Kaku Gothic StdN", + @"Hiragino Maru Gothic Pro", + @"Hiragino Maru Gothic ProN", + @"Hiragino Mincho Pro", + @"Hiragino Mincho ProN", + @"Hiragino Sans GB", + @"Hoefler Text", + @"Impact", + @"InaiMathi", + @"Kai", + @"Kailasa", + @"Kokonor", + @"Krungthep", + @"KufiStandardGK", + @"LiHei Pro", + @"LiSong Pro", + @"Lucida Grande", + @"Marker Felt", + @"Menlo", + @"Microsoft Sans Serif", + @"Monaco", + @"Mshtakan", + @"Nadeem", + @"New Peninim MT", + @"Optima", + @"Osaka", + @"Papyrus", + @"PCMyungjo", + @"PilGi", + @"Plantagenet Cherokee", + @"Raanana", + @"Sathu", + @"Silom", + @"Skia", + @"STFangsong", + @"STHeiti", + @"STKaiti", + @"STSong", + @"Symbol", + @"Tahoma", + @"Thonburi", + @"Times New Roman", + @"Times", + @"Trebuchet MS", + @"Verdana", + @"Webdings", + @"WebKit WeightWatcher", + @"Wingdings 2", + @"Wingdings 3", + @"Wingdings", + @"Zapf Dingbats", + @"Zapfino", + nil] retain]; + + return fontFamiliySet; +} + +static IMP appKitAvailableFontFamiliesIMP; +static IMP appKitAvailableFontsIMP; + +static NSArray *drt_NSFontManager_availableFontFamilies(id self, SEL _cmd) +{ + static NSArray *availableFontFamilies; + if (availableFontFamilies) + return availableFontFamilies; + + NSArray *availableFamilies = appKitAvailableFontFamiliesIMP(self, _cmd); + + NSMutableSet *prunedFamiliesSet = [NSMutableSet setWithArray:availableFamilies]; + [prunedFamiliesSet intersectSet:allowedFontFamilySet()]; + + availableFontFamilies = [[prunedFamiliesSet allObjects] retain]; + return availableFontFamilies; +} + +static NSArray *drt_NSFontManager_availableFonts(id self, SEL _cmd) +{ + static NSArray *availableFonts; + if (availableFonts) + return availableFonts; + + NSSet *allowedFamilies = allowedFontFamilySet(); + NSMutableArray *availableFontList = [[NSMutableArray alloc] initWithCapacity:[allowedFamilies count] * 2]; + for (NSString *fontFamily in allowedFontFamilySet()) { + NSArray* fontsForFamily = [[NSFontManager sharedFontManager] availableMembersOfFontFamily:fontFamily]; + for (NSArray* fontInfo in fontsForFamily) { + // Font name is the first entry in the array. + [availableFontList addObject:[fontInfo objectAtIndex:0]]; + } + } + + availableFonts = availableFontList; + return availableFonts; +} + +static void swizzleNSFontManagerMethods() +{ + Method availableFontFamiliesMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFontFamilies)); + ASSERT(availableFontFamiliesMethod); + if (!availableFontFamiliesMethod) { + NSLog(@"Failed to swizzle the \"availableFontFamilies\" method on NSFontManager"); + return; + } + + appKitAvailableFontFamiliesIMP = method_setImplementation(availableFontFamiliesMethod, (IMP)drt_NSFontManager_availableFontFamilies); + + Method availableFontsMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFonts)); + ASSERT(availableFontsMethod); + if (!availableFontsMethod) { + NSLog(@"Failed to swizzle the \"availableFonts\" method on NSFontManager"); + return; + } + + appKitAvailableFontsIMP = method_setImplementation(availableFontsMethod, (IMP)drt_NSFontManager_availableFonts); +} + +static void activateTestingFonts() +{ + // Work around <rdar://problem/6698023> by activating fonts from disk + // FIXME: This code can be removed once <rdar://problem/6698023> is addressed. + + static const char* fontFileNames[] = { + "AHEM____.TTF", + "WebKitWeightWatcher100.ttf", + "WebKitWeightWatcher200.ttf", + "WebKitWeightWatcher300.ttf", + "WebKitWeightWatcher400.ttf", + "WebKitWeightWatcher500.ttf", + "WebKitWeightWatcher600.ttf", + "WebKitWeightWatcher700.ttf", + "WebKitWeightWatcher800.ttf", + "WebKitWeightWatcher900.ttf", + 0 + }; + + NSMutableArray *fontURLs = [NSMutableArray array]; + NSURL *resourcesDirectory = [NSURL URLWithString:@"DumpRenderTree.resources" relativeToURL:[[NSBundle mainBundle] executableURL]]; + for (unsigned i = 0; fontFileNames[i]; ++i) { + NSURL *fontURL = [resourcesDirectory URLByAppendingPathComponent:[NSString stringWithUTF8String:fontFileNames[i]]]; + [fontURLs addObject:[fontURL absoluteURL]]; + } + + CFArrayRef errors = 0; + if (!CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeProcess, &errors)) { + NSLog(@"Failed to activate fonts: %@", errors); + CFRelease(errors); + exit(1); + } +} + +static void adjustFonts() +{ + swizzleNSFontManagerMethods(); + activateTestingFonts(); +} + +WebView *createWebViewAndOffscreenWindow() +{ + NSRect rect = NSMakeRect(0, 0, LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight); + WebView *webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:@"org.webkit.DumpRenderTree"]; + + [webView setUIDelegate:uiDelegate]; + [webView setFrameLoadDelegate:frameLoadDelegate]; + [webView setEditingDelegate:editingDelegate]; + [webView setResourceLoadDelegate:resourceLoadDelegate]; + [webView _setGeolocationProvider:[MockGeolocationProvider shared]]; + [webView _setDeviceOrientationProvider:[WebDeviceOrientationProviderMock shared]]; + + // Register the same schemes that Safari does + [WebView registerURLSchemeAsLocal:@"feed"]; + [WebView registerURLSchemeAsLocal:@"feeds"]; + [WebView registerURLSchemeAsLocal:@"feedsearch"]; + + [webView setContinuousSpellCheckingEnabled:YES]; + [webView setGrammarCheckingEnabled:YES]; + [webView setInteractiveFormValidationEnabled:YES]; + [webView setValidationMessageTimerMagnification:-1]; + + // To make things like certain NSViews, dragging, and plug-ins work, put the WebView a window, but put it off-screen so you don't see it. + // Put it at -10000, -10000 in "flipped coordinates", since WebCore and the DOM use flipped coordinates. + NSRect windowRect = NSOffsetRect(rect, -10000, [(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000); + DumpRenderTreeWindow *window = [[DumpRenderTreeWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; + + [window setColorSpace:[[NSScreen mainScreen] colorSpace]]; + [[window contentView] addSubview:webView]; + [window orderBack:nil]; + [window setAutodisplay:NO]; + + [window startListeningForAcceleratedCompositingChanges]; + + // For reasons that are not entirely clear, the following pair of calls makes WebView handle its + // dynamic scrollbars properly. Without it, every frame will always have scrollbars. + NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:[webView bounds]]; + [webView cacheDisplayInRect:[webView bounds] toBitmapImageRep:imageRep]; + + return webView; +} + +static NSString *libraryPathForDumpRenderTree() +{ + //FIXME: This may not be sufficient to prevent interactions/crashes + //when running more than one copy of DumpRenderTree. + //See https://bugs.webkit.org/show_bug.cgi?id=10906 + char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP"); + if (dumpRenderTreeTemp) + return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:dumpRenderTreeTemp length:strlen(dumpRenderTreeTemp)]; + else + return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath]; +} + +// Called before each test. +static void resetDefaultsToConsistentValues() +{ + static const int NoFontSmoothing = 0; + static const int BlueTintedAppearance = 1; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on + [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"]; + [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"]; + [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"]; + [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"]; + [defaults setObject:[NSArray arrayWithObject:@"en"] forKey:@"AppleLanguages"]; + [defaults setBool:YES forKey:WebKitEnableFullDocumentTeardownPreferenceKey]; + [defaults setBool:YES forKey:WebKitFullScreenEnabledPreferenceKey]; + + // Scrollbars are drawn either using AppKit (which uses NSUserDefaults) or using HIToolbox (which uses CFPreferences / kCFPreferencesAnyApplication / kCFPreferencesCurrentUser / kCFPreferencesAnyHost) + [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; + RetainPtr<CFTypeRef> initialValue = CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), CFSTR("DoubleMax"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); +#ifndef __LP64__ + // See <rdar://problem/6347388>. + ThemeScrollBarArrowStyle style; + GetThemeScrollBarArrowStyle(&style); // Force HIToolbox to read from CFPreferences +#endif + + [defaults setBool:NO forKey:@"AppleScrollAnimationEnabled"]; + [defaults setBool:NO forKey:@"NSOverlayScrollersEnabled"]; + [defaults setObject:@"Always" forKey:@"AppleShowScrollBars"]; + + if (initialValue) + CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + + NSString *path = libraryPathForDumpRenderTree(); + [defaults setObject:[path stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey]; + [defaults setObject:[path stringByAppendingPathComponent:@"LocalStorage"] forKey:WebStorageDirectoryDefaultsKey]; + [defaults setObject:[path stringByAppendingPathComponent:@"LocalCache"] forKey:WebKitLocalCacheDefaultsKey]; + + WebPreferences *preferences = [WebPreferences standardPreferences]; + + [preferences setAllowUniversalAccessFromFileURLs:YES]; + [preferences setAllowFileAccessFromFileURLs:YES]; + [preferences setStandardFontFamily:@"Times"]; + [preferences setFixedFontFamily:@"Courier"]; + [preferences setSerifFontFamily:@"Times"]; + [preferences setSansSerifFontFamily:@"Helvetica"]; + [preferences setCursiveFontFamily:@"Apple Chancery"]; + [preferences setFantasyFontFamily:@"Papyrus"]; + [preferences setPictographFontFamily:@"Apple Color Emoji"]; + [preferences setDefaultFontSize:16]; + [preferences setDefaultFixedFontSize:13]; + [preferences setMinimumFontSize:0]; + [preferences setJavaEnabled:NO]; + [preferences setJavaScriptEnabled:YES]; + [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey]; + [preferences setTabsToLinks:NO]; + [preferences setDOMPasteAllowed:YES]; + [preferences setShouldPrintBackgrounds:YES]; + [preferences setCacheModel:WebCacheModelDocumentBrowser]; + [preferences setXSSAuditorEnabled:NO]; + [preferences setExperimentalNotificationsEnabled:NO]; + [preferences setPlugInsEnabled:YES]; + + [preferences setPrivateBrowsingEnabled:NO]; + [preferences setAuthorAndUserStylesEnabled:YES]; + [preferences setJavaScriptCanOpenWindowsAutomatically:YES]; + [preferences setJavaScriptCanAccessClipboard:YES]; + [preferences setOfflineWebApplicationCacheEnabled:YES]; + [preferences setDeveloperExtrasEnabled:NO]; + [preferences setLoadsImagesAutomatically:YES]; + [preferences setLoadsSiteIconsIgnoringImageLoadingPreference:NO]; + [preferences setFrameFlatteningEnabled:NO]; + [preferences setSpatialNavigationEnabled:NO]; + [preferences setEditingBehavior:WebKitEditingMacBehavior]; + if (persistentUserStyleSheetLocation) { + [preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]]; + [preferences setUserStyleSheetEnabled:YES]; + } else + [preferences setUserStyleSheetEnabled:NO]; + + // The back/forward cache is causing problems due to layouts during transition from one page to another. + // So, turn it off for now, but we might want to turn it back on some day. + [preferences setUsesPageCache:NO]; + [preferences setAcceleratedCompositingEnabled:YES]; +#if USE(CA) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + [preferences setCanvasUsesAcceleratedDrawing:YES]; + [preferences setAcceleratedDrawingEnabled:NO]; +#endif + [preferences setWebGLEnabled:NO]; + [preferences setUsePreHTML5ParserQuirks:NO]; + [preferences setAsynchronousSpellCheckingEnabled:NO]; + [preferences setHixie76WebSocketProtocolEnabled:YES]; + +#if ENABLE(WEB_AUDIO) + [preferences setWebAudioEnabled:YES]; +#endif + + [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain]; + + LayoutTestController::setSerializeHTTPLoads(false); + + setlocale(LC_ALL, ""); +} + +// Called once on DumpRenderTree startup. +static void setDefaultsToConsistentValuesForTesting() +{ + resetDefaultsToConsistentValues(); + + NSString *path = libraryPathForDumpRenderTree(); + NSURLCache *sharedCache = + [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024 + diskCapacity:0 + diskPath:[path stringByAppendingPathComponent:@"URLCache"]]; + [NSURLCache setSharedURLCache:sharedCache]; + [sharedCache release]; + + [WebPreferences _switchNetworkLoaderToNewTestingSession]; +} + +static void* runThread(void* arg) +{ + static ThreadIdentifier previousId = 0; + ThreadIdentifier currentId = currentThread(); + // Verify 2 successive threads do not get the same Id. + ASSERT(previousId != currentId); + previousId = currentId; + return 0; +} + +static void testThreadIdentifierMap() +{ + // Imitate 'foreign' threads that are not created by WTF. + pthread_t pthread; + pthread_create(&pthread, 0, &runThread, 0); + pthread_join(pthread, 0); + + pthread_create(&pthread, 0, &runThread, 0); + pthread_join(pthread, 0); + + // Now create another thread using WTF. On OSX, it will have the same pthread handle + // but should get a different ThreadIdentifier. + createThread(runThread, 0, "DumpRenderTree: test"); +} + +static void crashHandler(int sig) +{ + char *signalName = strsignal(sig); + write(STDERR_FILENO, signalName, strlen(signalName)); + write(STDERR_FILENO, "\n", 1); + restoreMainDisplayColorProfile(0); + exit(128 + sig); +} + +static void installSignalHandlers() +{ + signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */ + signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */ + signal(SIGEMT, crashHandler); /* 7: EMT instruction */ + signal(SIGFPE, crashHandler); /* 8: floating point exception */ + signal(SIGBUS, crashHandler); /* 10: bus error */ + signal(SIGSEGV, crashHandler); /* 11: segmentation violation */ + signal(SIGSYS, crashHandler); /* 12: bad argument to system call */ + signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */ + signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */ + signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */ +} + +static void allocateGlobalControllers() +{ + // FIXME: We should remove these and move to the ObjC standard [Foo sharedInstance] model + gNavigationController = [[NavigationController alloc] init]; + frameLoadDelegate = [[FrameLoadDelegate alloc] init]; + uiDelegate = [[UIDelegate alloc] init]; + editingDelegate = [[EditingDelegate alloc] init]; + resourceLoadDelegate = [[ResourceLoadDelegate alloc] init]; + policyDelegate = [[PolicyDelegate alloc] init]; + historyDelegate = [[HistoryDelegate alloc] init]; + storageDelegate = [[StorageTrackerDelegate alloc] init]; +} + +// ObjC++ doens't seem to let me pass NSObject*& sadly. +static inline void releaseAndZero(NSObject** object) +{ + [*object release]; + *object = nil; +} + +static void releaseGlobalControllers() +{ + releaseAndZero(&gNavigationController); + releaseAndZero(&frameLoadDelegate); + releaseAndZero(&editingDelegate); + releaseAndZero(&resourceLoadDelegate); + releaseAndZero(&uiDelegate); + releaseAndZero(&policyDelegate); + releaseAndZero(&storageDelegate); +} + +static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[]) +{ + struct option options[] = { + {"notree", no_argument, &dumpTree, NO}, + {"pixel-tests", no_argument, &dumpPixels, YES}, + {"tree", no_argument, &dumpTree, YES}, + {"threaded", no_argument, &threaded, YES}, + {"complex-text", no_argument, &forceComplexText, YES}, + {"gc-between-tests", no_argument, &gcBetweenTests, YES}, + {NULL, 0, NULL, 0} + }; + + int option; + while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) { + switch (option) { + case '?': // unknown or ambiguous option + case ':': // missing argument + exit(1); + break; + } + } +} + +static void addTestPluginsToPluginSearchPath(const char* executablePath) +{ + NSString *pwd = [[NSString stringWithUTF8String:executablePath] stringByDeletingLastPathComponent]; + [WebPluginDatabase setAdditionalWebPlugInPaths:[NSArray arrayWithObject:pwd]]; + [[WebPluginDatabase sharedDatabase] refresh]; +} + +static bool useLongRunningServerMode(int argc, const char *argv[]) +{ + // This assumes you've already called getopt_long + return (argc == optind+1 && strcmp(argv[optind], "-") == 0); +} + +static void runTestingServerLoop() +{ + // When DumpRenderTree run in server mode, we just wait around for file names + // to be passed to us and read each in turn, passing the results back to the client + char filenameBuffer[2048]; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + char *newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (strlen(filenameBuffer) == 0) + continue; + + runTest(filenameBuffer); + } +} + +static void prepareConsistentTestingEnvironment() +{ + poseAsClass("DumpRenderTreePasteboard", "NSPasteboard"); + poseAsClass("DumpRenderTreeEvent", "NSEvent"); + + setDefaultsToConsistentValuesForTesting(); + adjustFonts(); + + if (dumpPixels) + setupMainDisplayColorProfile(); + allocateGlobalControllers(); + + makeLargeMallocFailSilently(); +} + +void dumpRenderTree(int argc, const char *argv[]) +{ + initializeGlobalsFromCommandLineOptions(argc, argv); + prepareConsistentTestingEnvironment(); + addTestPluginsToPluginSearchPath(argv[0]); + if (dumpPixels) + installSignalHandlers(); + + if (forceComplexText) + [WebView _setAlwaysUsesComplexTextCodePath:YES]; + + WebView *webView = createWebViewAndOffscreenWindow(); + mainFrame = [webView mainFrame]; + + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + [WebCache empty]; + + // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL + // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1. + [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"]; + [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"]; + + // http://webkit.org/b/32689 + testThreadIdentifierMap(); + + if (threaded) + startJavaScriptThreads(); + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = YES; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + if (threaded) + stopJavaScriptThreads(); + + NSWindow *window = [webView window]; + [webView close]; + mainFrame = nil; + + // Work around problem where registering drag types leaves an outstanding + // "perform selector" on the window, which retains the window. It's a bit + // inelegant and perhaps dangerous to just blow them all away, but in practice + // it probably won't cause any trouble (and this is just a test tool, after all). + [NSObject cancelPreviousPerformRequestsWithTarget:window]; + + [window close]; // releases when closed + [webView release]; + + releaseGlobalControllers(); + + [DumpRenderTreePasteboard releaseLocalPasteboards]; + + // FIXME: This should be moved onto LayoutTestController and made into a HashSet + if (disallowedURLs) { + CFRelease(disallowedURLs); + disallowedURLs = 0; + } + + if (dumpPixels) + restoreMainDisplayColorProfile(0); +} + +int main(int argc, const char *argv[]) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [DumpRenderTreeApplication sharedApplication]; // Force AppKit to init itself + dumpRenderTree(argc, argv); + [WebCoreStatistics garbageCollectJavaScriptObjects]; + [WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts + [pool release]; + return 0; +} + +static NSInteger compareHistoryItems(id item1, id item2, void *context) +{ + return [[item1 target] caseInsensitiveCompare:[item2 target]]; +} + +static NSData *dumpAudio() +{ + const char *encodedAudioData = gLayoutTestController->encodedAudioData().c_str(); + + NSData *data = [NSData dataWithBytes:encodedAudioData length:gLayoutTestController->encodedAudioData().length()]; + return data; +} + +static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current) +{ + int start = 0; + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + NSString *urlString = [item URLString]; + if ([[NSURL URLWithString:urlString] isFileURL]) { + NSRange range = [urlString rangeOfString:@"/LayoutTests/"]; + urlString = [@"(file test):" stringByAppendingString:[urlString substringFromIndex:(range.length + range.location)]]; + } + + printf("%s", [urlString UTF8String]); + NSString *target = [item target]; + if (target && [target length] > 0) + printf(" (in frame \"%s\")", [target UTF8String]); + if ([item isTargetItem]) + printf(" **nav target**"); + putchar('\n'); + NSArray *kids = [item children]; + if (kids) { + // must sort to eliminate arbitrary result ordering which defeats reproducible testing + kids = [kids sortedArrayUsingFunction:&compareHistoryItems context:nil]; + for (unsigned i = 0; i < [kids count]; i++) + dumpHistoryItem([kids objectAtIndex:i], indent+4, NO); + } +} + +static void dumpFrameScrollPosition(WebFrame *f) +{ + WebScriptObject* scriptObject = [f windowObject]; + NSPoint scrollPosition = NSMakePoint( + [[scriptObject valueForKey:@"pageXOffset"] floatValue], + [[scriptObject valueForKey:@"pageYOffset"] floatValue]); + if (ABS(scrollPosition.x) > 0.00000001 || ABS(scrollPosition.y) > 0.00000001) { + if ([f parentFrame] != nil) + printf("frame '%s' ", [[f name] UTF8String]); + printf("scrolled to %.f,%.f\n", scrollPosition.x, scrollPosition.y); + } + + if (gLayoutTestController->dumpChildFrameScrollPositions()) { + NSArray *kids = [f childFrames]; + if (kids) + for (unsigned i = 0; i < [kids count]; i++) + dumpFrameScrollPosition([kids objectAtIndex:i]); + } +} + +static NSString *dumpFramesAsText(WebFrame *frame) +{ + DOMDocument *document = [frame DOMDocument]; + DOMElement *documentElement = [document documentElement]; + + if (!documentElement) + return @""; + + NSMutableString *result = [[[NSMutableString alloc] init] autorelease]; + + // Add header for all but the main frame. + if ([frame parentFrame]) + result = [NSMutableString stringWithFormat:@"\n--------\nFrame: '%@'\n--------\n", [frame name]]; + + [result appendFormat:@"%@\n", [documentElement innerText]]; + + if (gLayoutTestController->dumpChildFramesAsText()) { + NSArray *kids = [frame childFrames]; + if (kids) { + for (unsigned i = 0; i < [kids count]; i++) + [result appendString:dumpFramesAsText([kids objectAtIndex:i])]; + } + } + + return result; +} + +static NSData *dumpFrameAsPDF(WebFrame *frame) +{ + if (!frame) + return nil; + + // Sadly we have to dump to a file and then read from that file again + // +[NSPrintOperation PDFOperationWithView:insideRect:] requires a rect and prints to a single page + // likewise +[NSView dataWithPDFInsideRect:] also prints to a single continuous page + // The goal of this function is to test "real" printing across multiple pages. + // FIXME: It's possible there might be printing SPI to let us print a multi-page PDF to an NSData object + NSString *path = [libraryPathForDumpRenderTree() stringByAppendingPathComponent:@"test.pdf"]; + + NSMutableDictionary *printInfoDict = [NSMutableDictionary dictionaryWithDictionary:[[NSPrintInfo sharedPrintInfo] dictionary]]; + [printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition]; + [printInfoDict setObject:path forKey:NSPrintSavePath]; + + NSPrintInfo *printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict]; + [printInfo setHorizontalPagination:NSAutoPagination]; + [printInfo setVerticalPagination:NSAutoPagination]; + [printInfo setVerticallyCentered:NO]; + + NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:[frame frameView] printInfo:printInfo]; + [printOperation setShowPanels:NO]; + [printOperation runOperation]; + + [printInfo release]; + + NSData *pdfData = [NSData dataWithContentsOfFile:path]; + [[NSFileManager defaultManager] removeFileAtPath:path handler:nil]; + + return pdfData; +} + +static void dumpBackForwardListForWebView(WebView *view) +{ + printf("\n============== Back Forward List ==============\n"); + WebBackForwardList *bfList = [view backForwardList]; + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + NSMutableArray *itemsToPrint = [[NSMutableArray alloc] init]; + for (int i = [bfList forwardListCount]; i > 0; i--) { + WebHistoryItem *item = [bfList itemAtIndex:i]; + // something is wrong if the item from the last test is in the forward part of the b/f list + assert(item != prevTestBFItem); + [itemsToPrint addObject:item]; + } + + assert([bfList currentItem] != prevTestBFItem); + [itemsToPrint addObject:[bfList currentItem]]; + int currentItemIndex = [itemsToPrint count] - 1; + + for (int i = -1; i >= -[bfList backListCount]; i--) { + WebHistoryItem *item = [bfList itemAtIndex:i]; + if (item == prevTestBFItem) + break; + [itemsToPrint addObject:item]; + } + + for (int i = [itemsToPrint count]-1; i >= 0; i--) + dumpHistoryItem([itemsToPrint objectAtIndex:i], 8, i == currentItemIndex); + + [itemsToPrint release]; + printf("===============================================\n"); +} + +static void sizeWebViewForCurrentTest() +{ + // W3C SVG tests expect to be 480x360 + bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos); + if (isSVGW3CTest) + [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)]; + else + [[mainFrame webView] setFrameSize:NSMakeSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)]; +} + +static const char *methodNameStringForFailedTest() +{ + const char *errorMessage; + if (gLayoutTestController->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (gLayoutTestController->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (gLayoutTestController->dumpSourceAsWebArchive()) + errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + + return errorMessage; +} + +static void dumpBackForwardListForAllWindows() +{ + CFArrayRef openWindows = (CFArrayRef)[DumpRenderTreeWindow openWindows]; + unsigned count = CFArrayGetCount(openWindows); + for (unsigned i = 0; i < count; i++) { + NSWindow *window = (NSWindow *)CFArrayGetValueAtIndex(openWindows, i); + WebView *webView = [[[window contentView] subviews] objectAtIndex:0]; + dumpBackForwardListForWebView(webView); + } +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + CFRunLoopTimerInvalidate(waitToDumpWatchdog); + CFRelease(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } +} + +void dump() +{ + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (dumpTree) { + NSString *resultString = nil; + NSData *resultData = nil; + NSString *resultMimeType = @"text/plain"; + + if ([[[mainFrame dataSource] _responseMIMEType] isEqualToString:@"text/plain"]) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + if (gLayoutTestController->dumpAsAudio()) { + resultData = dumpAudio(); + resultMimeType = @"audio/wav"; + } else if (gLayoutTestController->dumpAsText()) { + resultString = dumpFramesAsText(mainFrame); + } else if (gLayoutTestController->dumpAsPDF()) { + resultData = dumpFrameAsPDF(mainFrame); + resultMimeType = @"application/pdf"; + } else if (gLayoutTestController->dumpDOMAsWebArchive()) { + WebArchive *webArchive = [[mainFrame DOMDocument] webArchive]; + resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data])); + resultMimeType = @"application/x-webarchive"; + } else if (gLayoutTestController->dumpSourceAsWebArchive()) { + WebArchive *webArchive = [[mainFrame dataSource] webArchive]; + resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data])); + resultMimeType = @"application/x-webarchive"; + } else { + sizeWebViewForCurrentTest(); + resultString = [mainFrame renderTreeAsExternalRepresentationForPrinting:gLayoutTestController->isPrinting()]; + } + + if (resultString && !resultData) + resultData = [resultString dataUsingEncoding:NSUTF8StringEncoding]; + + printf("Content-Type: %s\n", [resultMimeType UTF8String]); + + if (gLayoutTestController->dumpAsAudio()) + printf("Content-Transfer-Encoding: base64\n"); + + if (resultData) { + fwrite([resultData bytes], 1, [resultData length], stdout); + + if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + + if (gLayoutTestController->dumpBackForwardList()) + dumpBackForwardListForAllWindows(); + } else + printf("ERROR: nil result from %s", methodNameStringForFailedTest()); + + // Stop the watchdog thread before we leave this test to make sure it doesn't + // fire in between tests causing the next test to fail. + // This is a speculative fix for: https://bugs.webkit.org/show_bug.cgi?id=32339 + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + } + } + + if (dumpPixels && gLayoutTestController->generatePixelResults()) + // FIXME: when isPrinting is set, dump the image with page separators. + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + puts("#EOF"); // terminate the (possibly empty) pixels block + + fflush(stdout); + fflush(stderr); + + done = YES; +} + +static bool shouldLogFrameLoadDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "loading/"); +} + +static bool shouldLogHistoryDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "globalhistory/"); +} + +static bool shouldOpenWebInspector(const char* pathOrURL) +{ + return strstr(pathOrURL, "inspector/"); +} + +static bool shouldDumpAsText(const char* pathOrURL) +{ + return strstr(pathOrURL, "dumpAsText/"); +} + +static bool shouldEnableDeveloperExtras(const char* pathOrURL) +{ + return true; +} + +static void resetWebViewToConsistentStateBeforeTesting() +{ + WebView *webView = [mainFrame webView]; + [webView setEditable:NO]; + [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES]; + [webView makeTextStandardSize:nil]; + [webView resetPageZoom:nil]; + [webView _scaleWebView:1.0 atOrigin:NSZeroPoint]; + [webView _setCustomBackingScaleFactor:0]; + [webView setTabKeyCyclesThroughElements:YES]; + [webView setPolicyDelegate:nil]; + [policyDelegate setPermissive:NO]; + [policyDelegate setControllerToNotifyDone:0]; + [frameLoadDelegate resetToConsistentState]; + [webView _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO]; + [webView _clearMainFrameName]; + [[webView undoManager] removeAllActions]; + [WebView _removeAllUserContentFromGroup:[webView groupName]]; + [[webView window] setAutodisplay:NO]; + [webView _setMinimumTimerInterval:[WebView _defaultMinimumTimerInterval]]; + [webView setTracksRepaints:NO]; + + resetDefaultsToConsistentValues(); + + if (gLayoutTestController) { + WebCoreTestSupport::resetInternalsObject([mainFrame globalContext]); + // in the case that a test using the chrome input field failed, be sure to clean up for the next test + gLayoutTestController->removeChromeInputField(); + } + + [[mainFrame webView] setSmartInsertDeleteEnabled:YES]; + [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO]; + + [WebView _setUsesTestModeFocusRingColor:YES]; + [WebView _resetOriginAccessWhitelists]; + [WebView _setAllowsRoundingHacks:NO]; + + [[MockGeolocationProvider shared] stopTimer]; + + // Clear the contents of the general pasteboard + [[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; + + [mainFrame _clearOpener]; +} + +static void runTest(const string& testPathOrURL) +{ + ASSERT(!testPathOrURL.empty()); + + // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. + string pathOrURL(testPathOrURL); + string expectedPixelHash; + + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != string::npos) { + pathOrURL = string(testPathOrURL, 0, separatorPos); + expectedPixelHash = string(testPathOrURL, separatorPos + 1); + } + + NSString *pathOrURLString = [NSString stringWithUTF8String:pathOrURL.c_str()]; + if (!pathOrURLString) { + fprintf(stderr, "Failed to parse \"%s\" as UTF-8\n", pathOrURL.c_str()); + return; + } + + NSURL *url; + if ([pathOrURLString hasPrefix:@"http://"] || [pathOrURLString hasPrefix:@"https://"]) + url = [NSURL URLWithString:pathOrURLString]; + else + url = [NSURL fileURLWithPath:pathOrURLString]; + if (!url) { + fprintf(stderr, "Failed to parse \"%s\" as a URL\n", pathOrURL.c_str()); + return; + } + + const string testURL([[url absoluteString] UTF8String]); + + resetWebViewToConsistentStateBeforeTesting(); + + gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash); + topLoadingFrame = nil; + ASSERT(!draggingInfo); // the previous test should have called eventSender.mouseUp to drop! + releaseAndZero(&draggingInfo); + done = NO; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (disallowedURLs) + CFSetRemoveAllValues(disallowedURLs); + if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + if (shouldLogHistoryDelegates(pathOrURL.c_str())) + [[mainFrame webView] setHistoryDelegate:historyDelegate]; + else + [[mainFrame webView] setHistoryDelegate:nil]; + + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->setDeveloperExtrasEnabled(true); + if (shouldOpenWebInspector(pathOrURL.c_str())) + gLayoutTestController->showWebInspector(); + if (shouldDumpAsText(pathOrURL.c_str())) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + } + + if ([WebHistory optionalSharedHistory]) + [WebHistory setOptionalSharedHistory:nil]; + lastMousePosition = NSZeroPoint; + lastClickPosition = NSZeroPoint; + + [prevTestBFItem release]; + prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain]; + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + bool ignoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(testURL); + if (ignoreWebCoreNodeLeaks) + [WebCoreStatistics startIgnoringWebCoreNodeLeaks]; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [mainFrame loadRequest:[NSURLRequest requestWithURL:url]]; + [pool release]; + + while (!done) { + pool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; + [pool release]; + } + + pool = [[NSAutoreleasePool alloc] init]; + [EventSendingController clearSavedEvents]; + [[mainFrame webView] setSelectedDOMRange:nil affinity:NSSelectionAffinityDownstream]; + + WorkQueue::shared()->clear(); + + if (gLayoutTestController->closeRemainingWindowsWhenComplete()) { + NSArray* array = [DumpRenderTreeWindow openWindows]; + + unsigned count = [array count]; + for (unsigned i = 0; i < count; i++) { + NSWindow *window = [array objectAtIndex:i]; + + // Don't try to close the main window + if (window == [[mainFrame webView] window]) + continue; + + WebView *webView = [[[window contentView] subviews] objectAtIndex:0]; + + [webView close]; + [window close]; + } + } + + // If developer extras enabled Web Inspector may have been open by the test. + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } + + resetWebViewToConsistentStateBeforeTesting(); + + [mainFrame loadHTMLString:@"<html></html>" baseURL:[NSURL URLWithString:@"about:blank"]]; + [mainFrame stopLoading]; + + [pool release]; + + // We should only have our main window left open when we're done + ASSERT(CFArrayGetCount(openWindowsRef) == 1); + ASSERT(CFArrayGetValueAtIndex(openWindowsRef, 0) == [[mainFrame webView] window]); + + gLayoutTestController.clear(); + + if (ignoreWebCoreNodeLeaks) + [WebCoreStatistics stopIgnoringWebCoreNodeLeaks]; + + if (gcBetweenTests) + [WebCoreStatistics garbageCollectJavaScriptObjects]; +} + +void displayWebView() +{ + WebView *webView = [mainFrame webView]; + [webView display]; + + [webView setTracksRepaints:YES]; + [webView resetTrackedRepaints]; +} + +@implementation DumpRenderTreeEvent + ++ (NSPoint)mouseLocation +{ + return [[[mainFrame webView] window] convertBaseToScreen:lastMousePosition]; +} + +@end + +@implementation DumpRenderTreeApplication + +- (BOOL)isRunning +{ + // <rdar://problem/7686123> Java plug-in freezes unless NSApplication is running + return YES; +} + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h new file mode 100644 index 000000000..249809c94 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> + +@interface DumpRenderTreeDraggingInfo : NSObject <NSDraggingInfo> { +@private + NSSize offset; + NSImage *draggedImage; + NSPasteboard *draggingPasteboard; + id draggingSource; +} + +- (id)initWithImage:(NSImage *)image offset:(NSSize)offset pasteboard:(NSPasteboard *)pasteboard source:(id)source; + +- (NSWindow *)draggingDestinationWindow; +- (NSDragOperation)draggingSourceOperationMask; +- (NSPoint)draggingLocation; +- (NSPoint)draggedImageLocation; +- (NSImage *)draggedImage; +- (NSPasteboard *)draggingPasteboard; +- (id)draggingSource; +- (int)draggingSequenceNumber; + +- (void)slideDraggedImageTo:(NSPoint)screenPoint; +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination; +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm new file mode 100644 index 000000000..b729cf406 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTreeDraggingInfo.h" + +#import "DumpRenderTree.h" +#import "EventSendingController.h" +#import <WebKit/WebKit.h> + +@implementation DumpRenderTreeDraggingInfo + +- (id)initWithImage:(NSImage *)anImage offset:(NSSize)o pasteboard:(NSPasteboard *)pboard source:(id)source +{ + draggedImage = [anImage retain]; + draggingPasteboard = [pboard retain]; + draggingSource = [source retain]; + offset = o; + + return [super init]; +} + +- (void)dealloc +{ + [draggedImage release]; + [draggingPasteboard release]; + [draggingSource release]; + [super dealloc]; +} + +- (NSWindow *)draggingDestinationWindow +{ + return [[mainFrame webView] window]; +} + +- (NSDragOperation)draggingSourceOperationMask +{ + return [draggingSource draggingSourceOperationMaskForLocal:YES]; +} + +- (NSPoint)draggingLocation +{ + return lastMousePosition; +} + +- (NSPoint)draggedImageLocation +{ + return NSMakePoint(lastMousePosition.x + offset.width, lastMousePosition.y + offset.height); +} + +- (NSImage *)draggedImage +{ + return draggedImage; +} + +- (NSPasteboard *)draggingPasteboard +{ + return draggingPasteboard; +} + +- (id)draggingSource +{ + return draggingSource; +} + +- (int)draggingSequenceNumber +{ + NSLog(@"DumpRenderTree doesn't support draggingSequenceNumber"); + return 0; +} + +- (void)slideDraggedImageTo:(NSPoint)screenPoint +{ + NSLog(@"DumpRenderTree doesn't support slideDraggedImageTo:"); +} + +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination +{ + NSLog(@"DumpRenderTree doesn't support namesOfPromisedFilesDroppedAtDestination:"); + return nil; +} + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +- (NSDraggingFormation)draggingFormation +{ + return NSDraggingFormationDefault; +} + +- (void)setDraggingFormation:(NSDraggingFormation)formation +{ + // Ignored. +} + +- (BOOL)animatesToDestination +{ + return NO; +} + +- (void)setAnimatesToDestination:(BOOL)flag +{ + // Ignored. +} + +- (NSInteger)numberOfValidItemsForDrop +{ + return 1; +} + +- (void)setNumberOfValidItemsForDrop:(NSInteger)number +{ + // Ignored. +} + +- (void)enumerateDraggingItemsWithOptions:(NSEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block +{ + // Ignored. +} +#endif // !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h new file mode 100644 index 000000000..901008cc1 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeMac_h +#define DumpRenderTreeMac_h + +#include <CoreFoundation/CoreFoundation.h> + +#ifdef __OBJC__ +@class DumpRenderTreeDraggingInfo; +@class NavigationController; +@class PolicyDelegate; +@class StorageTrackerDelegate; +@class WebFrame; +@class WebScriptWorld; +@class WebView; +#else +class DumpRenderTreeDraggingInfo; +class NavigationController; +class PolicyDelegate; +class StorageTrackerDelegate; +class WebFrame; +class WebScriptWorld; +class WebView; +#endif + +extern CFMutableArrayRef openWindowsRef; +extern CFMutableSetRef disallowedURLs; +extern WebFrame* mainFrame; +extern WebFrame* topLoadingFrame; +extern DumpRenderTreeDraggingInfo *draggingInfo; +extern NavigationController* gNavigationController; +extern PolicyDelegate* policyDelegate; +extern StorageTrackerDelegate* storageDelegate; + +extern const unsigned maxViewHeight; +extern const unsigned maxViewWidth; + +extern CFRunLoopTimerRef waitToDumpWatchdog; + +WebView* createWebViewAndOffscreenWindow(); +void setPersistentUserStyleSheetLocation(CFStringRef); + +unsigned worldIDForWorld(WebScriptWorld *); + +#endif // DumpRenderTreeMac_h diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h new file mode 100644 index 000000000..ba2754ba7 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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> +#import <WebKit/WebTypesInternal.h> + +@interface DumpRenderTreePasteboard : NSPasteboard +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner; ++ (void)releaseLocalPasteboards; +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m new file mode 100644 index 000000000..b1b3b86c0 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTreeMac.h" +#import "DumpRenderTreePasteboard.h" + +#import <WebKit/WebTypesInternal.h> + +@interface LocalPasteboard : NSPasteboard +{ + NSMutableArray *typesArray; + NSMutableSet *typesSet; + NSMutableDictionary *dataByType; + NSInteger changeCount; +} +@end + +static NSMutableDictionary *localPasteboards; + +@implementation DumpRenderTreePasteboard + +// Return a local pasteboard so we don't disturb the real pasteboards when running tests. ++ (NSPasteboard *)_pasteboardWithName:(NSString *)name +{ + static int number = 0; + if (!name) + name = [NSString stringWithFormat:@"LocalPasteboard%d", ++number]; + if (!localPasteboards) + localPasteboards = [[NSMutableDictionary alloc] init]; + LocalPasteboard *pasteboard = [localPasteboards objectForKey:name]; + if (pasteboard) + return pasteboard; + pasteboard = [[LocalPasteboard alloc] init]; + [localPasteboards setObject:pasteboard forKey:name]; + [pasteboard release]; + return pasteboard; +} + ++ (void)releaseLocalPasteboards +{ + [localPasteboards release]; + localPasteboards = nil; +} + +// Convenience method for JS so that it doesn't have to try and create a NSArray on the objc side instead +// of the usual WebScriptObject that is passed around +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner +{ + return [self declareTypes:[NSArray arrayWithObject:type] owner:newOwner]; +} + +@end + +@implementation LocalPasteboard + ++ (id)alloc +{ + return NSAllocateObject(self, 0, 0); +} + +- (id)init +{ + typesArray = [[NSMutableArray alloc] init]; + typesSet = [[NSMutableSet alloc] init]; + dataByType = [[NSMutableDictionary alloc] init]; + return self; +} + +- (void)dealloc +{ + [typesArray release]; + [typesSet release]; + [dataByType release]; + [super dealloc]; +} + +- (NSString *)name +{ + return nil; +} + +- (void)releaseGlobally +{ +} + +- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner +{ + [typesArray removeAllObjects]; + [typesSet removeAllObjects]; + [dataByType removeAllObjects]; + return [self addTypes:newTypes owner:newOwner]; +} + +- (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner +{ + unsigned count = [newTypes count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [newTypes objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (!setType) { + setType = [type copy]; + [typesArray addObject:setType]; + [typesSet addObject:setType]; + [setType release]; + } + if (newOwner && [newOwner respondsToSelector:@selector(pasteboard:provideDataForType:)]) + [newOwner pasteboard:self provideDataForType:setType]; + } + return ++changeCount; +} + +- (NSInteger)changeCount +{ + return changeCount; +} + +- (NSArray *)types +{ + return typesArray; +} + +- (NSString *)availableTypeFromArray:(NSArray *)types +{ + unsigned count = [types count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [types objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (setType) + return setType; + } + return nil; +} + +- (BOOL)setData:(NSData *)data forType:(NSString *)dataType +{ + if (data == nil) + data = [NSData data]; + if (![typesSet containsObject:dataType]) + return NO; + [dataByType setObject:data forKey:dataType]; + ++changeCount; + return YES; +} + +- (NSData *)dataForType:(NSString *)dataType +{ + return [dataByType objectForKey:dataType]; +} + +- (BOOL)setPropertyList:(id)propertyList forType:(NSString *)dataType +{ + CFDataRef data = NULL; + if (propertyList) + data = CFPropertyListCreateXMLData(NULL, propertyList); + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +- (BOOL)setString:(NSString *)string forType:(NSString *)dataType +{ + CFDataRef data = NULL; + if (string) { + if ([string length] == 0) + data = CFDataCreate(NULL, NULL, 0); + else + data = CFStringCreateExternalRepresentation(NULL, (CFStringRef)string, kCFStringEncodingUTF8, 0); + } + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h new file mode 100644 index 000000000..a229d20e6 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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> + +@class WebView; + +@interface DumpRenderTreeWindow : NSWindow +{ +} + +// I'm not sure why we can't just use [NSApp windows] ++ (NSArray *)openWindows; + +- (WebView *)webView; + +- (void)startListeningForAcceleratedCompositingChanges; + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm new file mode 100644 index 000000000..e0cdc6b6e --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTreeWindow.h" + +#import "DumpRenderTree.h" + +// FIXME: This file is ObjC++ only because of this include. :( +#import "LayoutTestController.h" +#import <WebKit/WebViewPrivate.h> +#import <WebKit/WebTypesInternal.h> + +CFMutableArrayRef openWindowsRef = 0; + +static CFArrayCallBacks NonRetainingArrayCallbacks = { + 0, + NULL, + NULL, + CFCopyDescription, + CFEqual +}; + +@implementation DumpRenderTreeWindow + ++ (NSArray *)openWindows +{ + return [[(NSArray *)openWindowsRef copy] autorelease]; +} + +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation +{ + if (!openWindowsRef) + openWindowsRef = CFArrayCreateMutable(NULL, 0, &NonRetainingArrayCallbacks); + + CFArrayAppendValue(openWindowsRef, self); + + return [super initWithContentRect:contentRect styleMask:styleMask backing:bufferingType defer:deferCreation]; +} + +- (void)close +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + CFRange arrayRange = CFRangeMake(0, CFArrayGetCount(openWindowsRef)); + CFIndex i = CFArrayGetFirstIndexOfValue(openWindowsRef, arrayRange, self); + if (i != kCFNotFound) + CFArrayRemoveValueAtIndex(openWindowsRef, i); + + [super close]; +} + +- (BOOL)isKeyWindow +{ + return gLayoutTestController ? gLayoutTestController->windowIsKey() : YES; +} + +- (void)keyDown:(NSEvent *)event +{ + // Do nothing, avoiding the beep we'd otherwise get from NSResponder, + // once we get to the end of the responder chain. +} + +- (WebView *)webView +{ + NSView *firstView = nil; + if ([[[self contentView] subviews] count] > 0) { + firstView = [[[self contentView] subviews] objectAtIndex:0]; + if ([firstView isKindOfClass:[WebView class]]) + return static_cast<WebView *>(firstView); + } + return nil; +} + +- (void)startListeningForAcceleratedCompositingChanges +{ + [[self webView] _setPostsAcceleratedCompositingNotifications:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewStartedAcceleratedCompositing:) + name:_WebViewDidStartAcceleratedCompositingNotification object:nil]; +} + +- (void)webViewStartedAcceleratedCompositing:(NSNotification *)notification +{ + // If the WebView has gone into compositing mode, turn on window autodisplay. This is necessary for CA + // to update layers and start animations. + // We only ever turn autodisplay on here, because we turn it off before every test. + if ([[self webView] _isUsingAcceleratedCompositing]) + [self setAutodisplay:YES]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.h b/Tools/DumpRenderTree/mac/EditingDelegate.h new file mode 100644 index 000000000..b5563c887 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EditingDelegate.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> + +@interface EditingDelegate : NSObject +{ + BOOL acceptsEditing; +} + +- (void)setAcceptsEditing:(BOOL)newAcceptsEditing; + +@end diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.mm b/Tools/DumpRenderTree/mac/EditingDelegate.mm new file mode 100644 index 000000000..02e931ccd --- /dev/null +++ b/Tools/DumpRenderTree/mac/EditingDelegate.mm @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "EditingDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/WebKit.h> + +@interface DOMNode (dumpPath) +- (NSString *)dumpPath; +@end + +@implementation DOMNode (dumpPath) +- (NSString *)dumpPath +{ + DOMNode *parent = [self parentNode]; + NSString *str = [NSString stringWithFormat:@"%@", [self nodeName]]; + if (parent != nil) { + str = [str stringByAppendingString:@" > "]; + str = [str stringByAppendingString:[parent dumpPath]]; + } + return str; +} +@end + +@interface DOMRange (dump) +- (NSString *)dump; +@end + +@implementation DOMRange (dump) +- (NSString *)dump +{ + return [NSString stringWithFormat:@"range from %ld of %@ to %ld of %@", [self startOffset], [[self startContainer] dumpPath], [self endOffset], [[self endContainer] dumpPath]]; +} +@end + +@implementation EditingDelegate + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + acceptsEditing = YES; + return self; +} + +- (BOOL)webView:(WebView *)webView shouldBeginEditingInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldEndEditingInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldInsertNode:(DOMNode *)node replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action +{ + static const char *insertactionstring[] = { + "WebViewInsertActionTyped", + "WebViewInsertActionPasted", + "WebViewInsertActionDropped", + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n", [[node dumpPath] UTF8String], [[range dump] UTF8String], insertactionstring[action]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action +{ + static const char *insertactionstring[] = { + "WebViewInsertActionTyped", + "WebViewInsertActionPasted", + "WebViewInsertActionDropped", + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n", [[text description] UTF8String], [[range dump] UTF8String], insertactionstring[action]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldDeleteDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldShowDeleteInterfaceForElement:(DOMHTMLElement *)element +{ + return [[element className] isEqualToString:@"needsDeletionUI"]; +} + +- (BOOL)webView:(WebView *)webView shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag +{ + static const char *affinitystring[] = { + "NSSelectionAffinityUpstream", + "NSSelectionAffinityDownstream" + }; + static const char *boolstring[] = { + "FALSE", + "TRUE" + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n", [[currentRange dump] UTF8String], [[proposedRange dump] UTF8String], affinitystring[selectionAffinity], boolstring[flag]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldApplyStyle:(DOMCSSStyleDeclaration *)style toElementsInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n", [[style description] UTF8String], [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldChangeTypingStyle:(DOMCSSStyleDeclaration *)currentStyle toStyle:(DOMCSSStyleDeclaration *)proposedStyle +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n", [[currentStyle description] UTF8String], [[proposedStyle description] UTF8String]); + return acceptsEditing; +} + +- (void)webViewDidBeginEditing:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidBeginEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChange:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChange:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidEndEditing:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidEndEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeTypingStyle:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeSelection:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeSelection:%s\n", [[notification name] UTF8String]); +} + +- (void)setAcceptsEditing:(BOOL)newAcceptsEditing +{ + acceptsEditing = newAcceptsEditing; +} + +@end diff --git a/Tools/DumpRenderTree/mac/EventSendingController.h b/Tools/DumpRenderTree/mac/EventSendingController.h new file mode 100644 index 000000000..944057546 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EventSendingController.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> +#import <WebKit/WebKit.h> + +@interface EventSendingController : NSObject <DOMEventListener> +{ + BOOL leftMouseButtonDown; + BOOL dragMode; + int clickCount; + NSTimeInterval lastClick; + int eventNumber; + double timeOffset; +} + ++ (void)saveEvent:(NSInvocation *)event; ++ (void)replaySavedEvents; ++ (void)clearSavedEvents; + +- (void)scheduleAsynchronousClick; + +- (void)enableDOMUIEventLogging:(WebScriptObject *)node; + +- (void)handleEvent:(DOMEvent *)event; + +@end + +extern NSPoint lastMousePosition; +extern NSPoint lastClickPosition;
\ No newline at end of file diff --git a/Tools/DumpRenderTree/mac/EventSendingController.mm b/Tools/DumpRenderTree/mac/EventSendingController.mm new file mode 100644 index 000000000..f07a43e87 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EventSendingController.mm @@ -0,0 +1,873 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Jonas Witt <jonas.witt@gmail.com> + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "EventSendingController.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "DumpRenderTreeFileDraggingSource.h" + +#import <Carbon/Carbon.h> // for GetCurrentEventTime() +#import <WebKit/DOMPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebViewPrivate.h> + +extern "C" void _NSNewKillRingSequence(); + +enum MouseAction { + MouseDown, + MouseUp, + MouseDragged +}; + +// Match the DOM spec (sadly the DOM spec does not provide an enum) +enum MouseButton { + LeftMouseButton = 0, + MiddleMouseButton = 1, + RightMouseButton = 2, + NoMouseButton = -1 +}; + +NSPoint lastMousePosition; +NSPoint lastClickPosition; +int lastClickButton = NoMouseButton; +NSArray *webkitDomEventNames; +NSMutableArray *savedMouseEvents; // mouse events sent between mouseDown and mouseUp are stored here, and then executed at once. +BOOL replayingSavedEvents; + +@implementation EventSendingController + ++ (void)initialize +{ + webkitDomEventNames = [[NSArray alloc] initWithObjects: + @"abort", + @"beforecopy", + @"beforecut", + @"beforepaste", + @"blur", + @"change", + @"click", + @"contextmenu", + @"copy", + @"cut", + @"dblclick", + @"drag", + @"dragend", + @"dragenter", + @"dragleave", + @"dragover", + @"dragstart", + @"drop", + @"error", + @"focus", + @"input", + @"keydown", + @"keypress", + @"keyup", + @"load", + @"mousedown", + @"mousemove", + @"mouseout", + @"mouseover", + @"mouseup", + @"mousewheel", + @"beforeunload", + @"paste", + @"readystatechange", + @"reset", + @"resize", + @"scroll", + @"search", + @"select", + @"selectstart", + @"submit", + @"textInput", + @"textzoomin", + @"textzoomout", + @"unload", + @"zoom", + nil]; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(beginDragWithFiles:) + || aSelector == @selector(clearKillRing) + || aSelector == @selector(contextClick) + || aSelector == @selector(enableDOMUIEventLogging:) + || aSelector == @selector(fireKeyboardEventsToElement:) + || aSelector == @selector(keyDown:withModifiers:withLocation:) + || aSelector == @selector(leapForward:) + || aSelector == @selector(mouseDown:withModifiers:) + || aSelector == @selector(mouseMoveToX:Y:) + || aSelector == @selector(mouseUp:withModifiers:) + || aSelector == @selector(scheduleAsynchronousClick) + || aSelector == @selector(textZoomIn) + || aSelector == @selector(textZoomOut) + || aSelector == @selector(zoomPageIn) + || aSelector == @selector(zoomPageOut) + || aSelector == @selector(scalePageBy:atX:andY:) + || aSelector == @selector(mouseScrollByX:andY:) + || aSelector == @selector(continuousMouseScrollByX:andY:)) + return NO; + return YES; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char*)name +{ + if (strcmp(name, "dragMode") == 0) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(beginDragWithFiles:)) + return @"beginDragWithFiles"; + if (aSelector == @selector(contextClick)) + return @"contextClick"; + if (aSelector == @selector(enableDOMUIEventLogging:)) + return @"enableDOMUIEventLogging"; + if (aSelector == @selector(fireKeyboardEventsToElement:)) + return @"fireKeyboardEventsToElement"; + if (aSelector == @selector(keyDown:withModifiers:withLocation:)) + return @"keyDown"; + if (aSelector == @selector(leapForward:)) + return @"leapForward"; + if (aSelector == @selector(mouseDown:withModifiers:)) + return @"mouseDown"; + if (aSelector == @selector(mouseUp:withModifiers:)) + return @"mouseUp"; + if (aSelector == @selector(mouseMoveToX:Y:)) + return @"mouseMoveTo"; + if (aSelector == @selector(setDragMode:)) + return @"setDragMode"; + if (aSelector == @selector(mouseScrollByX:andY:)) + return @"mouseScrollBy"; + if (aSelector == @selector(continuousMouseScrollByX:andY:)) + return @"continuousMouseScrollBy"; + if (aSelector == @selector(scalePageBy:atX:andY:)) + return @"scalePageBy"; + return nil; +} + +- (id)init +{ + self = [super init]; + if (self) + dragMode = YES; + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +- (double)currentEventTime +{ + return GetCurrentEventTime() + timeOffset; +} + +- (void)leapForward:(int)milliseconds +{ + if (dragMode && leftMouseButtonDown && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(leapForward:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(leapForward:)]; + [invocation setArgument:&milliseconds atIndex:2]; + + [EventSendingController saveEvent:invocation]; + + return; + } + + timeOffset += milliseconds / 1000.0; +} + +- (void)clearKillRing +{ + _NSNewKillRingSequence(); +} + +static NSEventType eventTypeForMouseButtonAndAction(int button, MouseAction action) +{ + switch (button) { + case LeftMouseButton: + switch (action) { + case MouseDown: + return NSLeftMouseDown; + case MouseUp: + return NSLeftMouseUp; + case MouseDragged: + return NSLeftMouseDragged; + } + case RightMouseButton: + switch (action) { + case MouseDown: + return NSRightMouseDown; + case MouseUp: + return NSRightMouseUp; + case MouseDragged: + return NSRightMouseDragged; + } + default: + switch (action) { + case MouseDown: + return NSOtherMouseDown; + case MouseUp: + return NSOtherMouseUp; + case MouseDragged: + return NSOtherMouseDragged; + } + } + assert(0); + return static_cast<NSEventType>(0); +} + +- (void)beginDragWithFiles:(WebScriptObject*)jsFilePaths +{ + assert(!draggingInfo); + assert([jsFilePaths isKindOfClass:[WebScriptObject class]]); + + NSPasteboard *pboard = [NSPasteboard pasteboardWithUniqueName]; + [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil]; + + NSURL *currentTestURL = [NSURL URLWithString:[[mainFrame webView] mainFrameURL]]; + + NSMutableArray *filePaths = [NSMutableArray array]; + for (unsigned i = 0; [[jsFilePaths webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) { + NSString *filePath = (NSString *)[jsFilePaths webScriptValueAtIndex:i]; + // Have NSURL encode the name so that we handle '?' in file names correctly. + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSURL *absoluteFileURL = [NSURL URLWithString:[fileURL relativeString] relativeToURL:currentTestURL]; + [filePaths addObject:[absoluteFileURL path]]; + } + + [pboard setPropertyList:filePaths forType:NSFilenamesPboardType]; + assert([pboard propertyListForType:NSFilenamesPboardType]); // setPropertyList will silently fail on error, assert that it didn't fail + + // Provide a source, otherwise [DumpRenderTreeDraggingInfo draggingSourceOperationMask] defaults to NSDragOperationNone + DumpRenderTreeFileDraggingSource *source = [[[DumpRenderTreeFileDraggingSource alloc] init] autorelease]; + draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:nil offset:NSZeroSize pasteboard:pboard source:source]; + [[mainFrame webView] draggingEntered:draggingInfo]; + + dragMode = NO; // dragMode saves events and then replays them later. We don't need/want that. + leftMouseButtonDown = YES; // Make the rest of eventSender think a drag is in progress +} + +- (void)updateClickCountForButton:(int)buttonNumber +{ + if (([self currentEventTime] - lastClick >= 1) || + !NSEqualPoints(lastMousePosition, lastClickPosition) || + lastClickButton != buttonNumber) { + clickCount = 1; + lastClickButton = buttonNumber; + } else + clickCount++; +} + +static int buildModifierFlags(const WebScriptObject* modifiers) +{ + int flags = 0; + if (![modifiers isKindOfClass:[WebScriptObject class]]) + return flags; + for (unsigned i = 0; [[modifiers webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) { + NSString* modifierName = (NSString*)[modifiers webScriptValueAtIndex:i]; + if ([modifierName isEqual:@"ctrlKey"]) + flags |= NSControlKeyMask; + else if ([modifierName isEqual:@"shiftKey"] || [modifierName isEqual:@"rangeSelectionKey"]) + flags |= NSShiftKeyMask; + else if ([modifierName isEqual:@"altKey"]) + flags |= NSAlternateKeyMask; + else if ([modifierName isEqual:@"metaKey"] || [modifierName isEqual:@"addSelectionKey"]) + flags |= NSCommandKeyMask; + } + return flags; +} + +- (void)mouseDown:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers +{ + [[[mainFrame frameView] documentView] layout]; + [self updateClickCountForButton:buttonNumber]; + + NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseDown); + NSEvent *event = [NSEvent mouseEventWithType:eventType + location:lastMousePosition + modifierFlags:buildModifierFlags(modifiers) + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + if (subView) { + [subView mouseDown:event]; + if (buttonNumber == LeftMouseButton) + leftMouseButtonDown = YES; + } +} + +- (void)mouseDown:(int)buttonNumber +{ + [self mouseDown:buttonNumber withModifiers:nil]; +} + +- (void)textZoomIn +{ + [[mainFrame webView] makeTextLarger:self]; +} + +- (void)textZoomOut +{ + [[mainFrame webView] makeTextSmaller:self]; +} + +- (void)zoomPageIn +{ + [[mainFrame webView] zoomPageIn:self]; +} + +- (void)zoomPageOut +{ + [[mainFrame webView] zoomPageOut:self]; +} + +- (void)scalePageBy:(float)scale atX:(float)x andY:(float)y +{ + [[mainFrame webView] _scaleWebView:scale atOrigin:NSMakePoint(x, y)]; +} + +- (void)mouseUp:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers +{ + if (dragMode && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp:withModifiers:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(mouseUp:withModifiers:)]; + [invocation setArgument:&buttonNumber atIndex:2]; + [invocation setArgument:&modifiers atIndex:3]; + + [EventSendingController saveEvent:invocation]; + [EventSendingController replaySavedEvents]; + + return; + } + + [[[mainFrame frameView] documentView] layout]; + NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseUp); + NSEvent *event = [NSEvent mouseEventWithType:eventType + location:lastMousePosition + modifierFlags:buildModifierFlags(modifiers) + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *targetView = [[mainFrame webView] hitTest:[event locationInWindow]]; + // FIXME: Silly hack to teach DRT to respect capturing mouse events outside the WebView. + // The right solution is just to use NSApplication's built-in event sending methods, + // instead of rolling our own algorithm for selecting an event target. + targetView = targetView ? targetView : [[mainFrame frameView] documentView]; + assert(targetView); + [targetView mouseUp:event]; + if (buttonNumber == LeftMouseButton) + leftMouseButtonDown = NO; + lastClick = [event timestamp]; + lastClickPosition = lastMousePosition; + if (draggingInfo) { + WebView *webView = [mainFrame webView]; + + NSDragOperation dragOperation = [webView draggingUpdated:draggingInfo]; + + if (dragOperation != NSDragOperationNone) + [webView performDragOperation:draggingInfo]; + else + [webView draggingExited:draggingInfo]; + // Per NSDragging.h: draggingSources may not implement draggedImage:endedAt:operation: + if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:endedAt:operation:)]) + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] endedAt:lastMousePosition operation:dragOperation]; + [draggingInfo release]; + draggingInfo = nil; + } +} + +- (void)mouseUp:(int)buttonNumber +{ + [self mouseUp:buttonNumber withModifiers:nil]; +} + +- (void)mouseMoveToX:(int)x Y:(int)y +{ + if (dragMode && leftMouseButtonDown && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseMoveToX:Y:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(mouseMoveToX:Y:)]; + [invocation setArgument:&x atIndex:2]; + [invocation setArgument:&y atIndex:3]; + + [EventSendingController saveEvent:invocation]; + return; + } + + NSView *view = [mainFrame webView]; + lastMousePosition = [view convertPoint:NSMakePoint(x, [view frame].size.height - y) toView:nil]; + NSEvent *event = [NSEvent mouseEventWithType:(leftMouseButtonDown ? NSLeftMouseDragged : NSMouseMoved) + location:lastMousePosition + modifierFlags:0 + timestamp:[self currentEventTime] + windowNumber:[[view window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:(leftMouseButtonDown ? clickCount : 0) + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + if (subView) { + if (leftMouseButtonDown) { + if (draggingInfo) { + // Per NSDragging.h: draggingSources may not implement draggedImage:movedTo: + if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:movedTo:)]) + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] movedTo:lastMousePosition]; + [[mainFrame webView] draggingUpdated:draggingInfo]; + } else + [subView mouseDragged:event]; + } else + [subView mouseMoved:event]; + } +} + +- (void)mouseScrollByX:(int)x andY:(int)y continuously:(BOOL)c +{ + CGScrollEventUnit unit = c?kCGScrollEventUnitPixel:kCGScrollEventUnitLine; + CGEventRef cgScrollEvent = CGEventCreateScrollWheelEvent(NULL, unit, 2, y, x); + + // CGEvent locations are in global display coordinates. + CGPoint lastGlobalMousePosition = { + lastMousePosition.x, + [[NSScreen mainScreen] frame].size.height - lastMousePosition.y + }; + CGEventSetLocation(cgScrollEvent, lastGlobalMousePosition); + + NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgScrollEvent]; + CFRelease(cgScrollEvent); + + NSView *subView = [[mainFrame webView] hitTest:[scrollEvent locationInWindow]]; + if (subView) + [subView scrollWheel:scrollEvent]; +} + +- (void)continuousMouseScrollByX:(int)x andY:(int)y +{ + [self mouseScrollByX:x andY:y continuously:YES]; +} + +- (void)mouseScrollByX:(int)x andY:(int)y +{ + [self mouseScrollByX:x andY:y continuously:NO]; +} + +- (NSArray *)contextClick +{ + [[[mainFrame frameView] documentView] layout]; + [self updateClickCountForButton:RightMouseButton]; + + NSEvent *event = [NSEvent mouseEventWithType:NSRightMouseDown + location:lastMousePosition + modifierFlags:0 + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + NSMutableArray *menuItemStrings = [NSMutableArray array]; + + if (subView) { + NSMenu* menu = [subView menuForEvent:event]; + + for (int i = 0; i < [menu numberOfItems]; ++i) { + NSMenuItem* menuItem = [menu itemAtIndex:i]; + if (!strcmp("Inspect Element", [[menuItem title] UTF8String])) + continue; + + if ([menuItem isSeparatorItem]) + [menuItemStrings addObject:@"<separator>"]; + else + [menuItemStrings addObject:[menuItem title]]; + } + } + + return menuItemStrings; +} + +- (void)scheduleAsynchronousClick +{ + [self performSelector:@selector(mouseDown:) withObject:nil afterDelay:0]; + [self performSelector:@selector(mouseUp:) withObject:nil afterDelay:0]; +} + ++ (void)saveEvent:(NSInvocation *)event +{ + if (!savedMouseEvents) + savedMouseEvents = [[NSMutableArray alloc] init]; + [savedMouseEvents addObject:event]; +} + ++ (void)replaySavedEvents +{ + replayingSavedEvents = YES; + while ([savedMouseEvents count]) { + // if a drag is initiated, the remaining saved events will be dispatched from our dragging delegate + NSInvocation *invocation = [[[savedMouseEvents objectAtIndex:0] retain] autorelease]; + [savedMouseEvents removeObjectAtIndex:0]; + [invocation invoke]; + } + replayingSavedEvents = NO; +} + ++ (void)clearSavedEvents +{ + [savedMouseEvents release]; + savedMouseEvents = nil; +} + +- (void)keyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation +{ + NSString *eventCharacter = character; + unsigned short keyCode = 0; + if ([character isEqualToString:@"leftArrow"]) { + const unichar ch = NSLeftArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7B; + } else if ([character isEqualToString:@"rightArrow"]) { + const unichar ch = NSRightArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7C; + } else if ([character isEqualToString:@"upArrow"]) { + const unichar ch = NSUpArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7E; + } else if ([character isEqualToString:@"downArrow"]) { + const unichar ch = NSDownArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7D; + } else if ([character isEqualToString:@"pageUp"]) { + const unichar ch = NSPageUpFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x74; + } else if ([character isEqualToString:@"pageDown"]) { + const unichar ch = NSPageDownFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x79; + } else if ([character isEqualToString:@"home"]) { + const unichar ch = NSHomeFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x73; + } else if ([character isEqualToString:@"end"]) { + const unichar ch = NSEndFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x77; + } else if ([character isEqualToString:@"insert"]) { + const unichar ch = NSInsertFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x72; + } else if ([character isEqualToString:@"delete"]) { + const unichar ch = NSDeleteFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x75; + } else if ([character isEqualToString:@"printScreen"]) { + const unichar ch = NSPrintScreenFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x0; // There is no known virtual key code for PrintScreen. + } + + // 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 (unsigned i = 1; i <= 24; i++) { + if ([character isEqualToString:[NSString stringWithFormat:@"F%u", i]]) { + const unichar ch = NSF1FunctionKey + (i - 1); + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + switch (i) { + case 1: keyCode = 0x7A; break; + case 2: keyCode = 0x78; break; + case 3: keyCode = 0x63; break; + case 4: keyCode = 0x76; break; + case 5: keyCode = 0x60; break; + case 6: keyCode = 0x61; break; + case 7: keyCode = 0x62; break; + case 8: keyCode = 0x64; break; + case 9: keyCode = 0x65; break; + case 10: keyCode = 0x6D; break; + case 11: keyCode = 0x67; break; + case 12: keyCode = 0x6F; break; + case 13: keyCode = 0x69; break; + case 14: keyCode = 0x6B; break; + case 15: keyCode = 0x71; break; + case 16: keyCode = 0x6A; break; + case 17: keyCode = 0x40; break; + case 18: keyCode = 0x4F; break; + case 19: keyCode = 0x50; break; + case 20: keyCode = 0x5A; break; + } + } + } + + // FIXME: No keyCode is set for most keys. + if ([character isEqualToString:@"\t"]) + keyCode = 0x30; + else if ([character isEqualToString:@" "]) + keyCode = 0x31; + else if ([character isEqualToString:@"\r"]) + keyCode = 0x24; + else if ([character isEqualToString:@"\n"]) + keyCode = 0x4C; + else if ([character isEqualToString:@"\x8"]) + keyCode = 0x33; + else if ([character isEqualToString:@"7"]) + keyCode = 0x1A; + else if ([character isEqualToString:@"5"]) + keyCode = 0x17; + else if ([character isEqualToString:@"9"]) + keyCode = 0x19; + else if ([character isEqualToString:@"0"]) + keyCode = 0x1D; + else if ([character isEqualToString:@"a"]) + keyCode = 0x00; + else if ([character isEqualToString:@"b"]) + keyCode = 0x0B; + else if ([character isEqualToString:@"d"]) + keyCode = 0x02; + else if ([character isEqualToString:@"e"]) + keyCode = 0x0E; + + NSString *charactersIgnoringModifiers = eventCharacter; + + int modifierFlags = 0; + + if ([character length] == 1 && [character characterAtIndex:0] >= 'A' && [character characterAtIndex:0] <= 'Z') { + modifierFlags |= NSShiftKeyMask; + charactersIgnoringModifiers = [character lowercaseString]; + } + + modifierFlags |= buildModifierFlags(modifiers); + + if (keyLocation == DOM_KEY_LOCATION_NUMPAD) + modifierFlags |= NSNumericPadKeyMask; + + [[[mainFrame frameView] documentView] layout]; + + NSEvent *event = [NSEvent keyEventWithType:NSKeyDown + location:NSMakePoint(5, 5) + modifierFlags:modifierFlags + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + characters:eventCharacter + charactersIgnoringModifiers:charactersIgnoringModifiers + isARepeat:NO + keyCode:keyCode]; + + [[[[mainFrame webView] window] firstResponder] keyDown:event]; + + event = [NSEvent keyEventWithType:NSKeyUp + location:NSMakePoint(5, 5) + modifierFlags:modifierFlags + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + characters:eventCharacter + charactersIgnoringModifiers:charactersIgnoringModifiers + isARepeat:NO + keyCode:keyCode]; + + [[[[mainFrame webView] window] firstResponder] keyUp:event]; +} + +- (void)enableDOMUIEventLogging:(WebScriptObject *)node +{ + NSEnumerator *eventEnumerator = [webkitDomEventNames objectEnumerator]; + id eventName; + while ((eventName = [eventEnumerator nextObject])) { + [(id<DOMEventTarget>)node addEventListener:eventName listener:self useCapture:NO]; + } +} + +- (void)handleEvent:(DOMEvent *)event +{ + DOMNode *target = [event target]; + + printf("event type: %s\n", [[event type] UTF8String]); + printf(" target: <%s>\n", [[[target nodeName] lowercaseString] UTF8String]); + + if ([event isKindOfClass:[DOMEvent class]]) { + printf(" eventPhase: %d\n", [event eventPhase]); + printf(" bubbles: %d\n", [event bubbles] ? 1 : 0); + printf(" cancelable: %d\n", [event cancelable] ? 1 : 0); + } + + if ([event isKindOfClass:[DOMUIEvent class]]) { + printf(" detail: %d\n", [(DOMUIEvent*)event detail]); + + DOMAbstractView *view = [(DOMUIEvent*)event view]; + if (view) { + printf(" view: OK"); + if ([view document]) + printf(" (document: OK)"); + printf("\n"); + } + } + + if ([event isKindOfClass:[DOMKeyboardEvent class]]) { + printf(" keyIdentifier: %s\n", [[(DOMKeyboardEvent*)event keyIdentifier] UTF8String]); + printf(" keyLocation: %d\n", [(DOMKeyboardEvent*)event keyLocation]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMKeyboardEvent*)event ctrlKey] ? 1 : 0, + [(DOMKeyboardEvent*)event shiftKey] ? 1 : 0, + [(DOMKeyboardEvent*)event altKey] ? 1 : 0, + [(DOMKeyboardEvent*)event metaKey] ? 1 : 0); + printf(" keyCode: %d\n", [(DOMKeyboardEvent*)event keyCode]); + printf(" charCode: %d\n", [(DOMKeyboardEvent*)event charCode]); + } + + if ([event isKindOfClass:[DOMMouseEvent class]]) { + printf(" button: %d\n", [(DOMMouseEvent*)event button]); + printf(" clientX: %d\n", [(DOMMouseEvent*)event clientX]); + printf(" clientY: %d\n", [(DOMMouseEvent*)event clientY]); + printf(" screenX: %d\n", [(DOMMouseEvent*)event screenX]); + printf(" screenY: %d\n", [(DOMMouseEvent*)event screenY]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMMouseEvent*)event ctrlKey] ? 1 : 0, + [(DOMMouseEvent*)event shiftKey] ? 1 : 0, + [(DOMMouseEvent*)event altKey] ? 1 : 0, + [(DOMMouseEvent*)event metaKey] ? 1 : 0); + id relatedTarget = [(DOMMouseEvent*)event relatedTarget]; + if (relatedTarget) { + printf(" relatedTarget: %s", [[[relatedTarget class] description] UTF8String]); + if ([relatedTarget isKindOfClass:[DOMNode class]]) + printf(" (nodeName: %s)", [[(DOMNode*)relatedTarget nodeName] UTF8String]); + printf("\n"); + } + } + + if ([event isKindOfClass:[DOMMutationEvent class]]) { + printf(" prevValue: %s\n", [[(DOMMutationEvent*)event prevValue] UTF8String]); + printf(" newValue: %s\n", [[(DOMMutationEvent*)event newValue] UTF8String]); + printf(" attrName: %s\n", [[(DOMMutationEvent*)event attrName] UTF8String]); + printf(" attrChange: %d\n", [(DOMMutationEvent*)event attrChange]); + DOMNode *relatedNode = [(DOMMutationEvent*)event relatedNode]; + if (relatedNode) { + printf(" relatedNode: %s (nodeName: %s)\n", + [[[relatedNode class] description] UTF8String], + [[relatedNode nodeName] UTF8String]); + } + } + + if ([event isKindOfClass:[DOMWheelEvent class]]) { + printf(" clientX: %d\n", [(DOMWheelEvent*)event clientX]); + printf(" clientY: %d\n", [(DOMWheelEvent*)event clientY]); + printf(" screenX: %d\n", [(DOMWheelEvent*)event screenX]); + printf(" screenY: %d\n", [(DOMWheelEvent*)event screenY]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMWheelEvent*)event ctrlKey] ? 1 : 0, + [(DOMWheelEvent*)event shiftKey] ? 1 : 0, + [(DOMWheelEvent*)event altKey] ? 1 : 0, + [(DOMWheelEvent*)event metaKey] ? 1 : 0); + printf(" isHorizontal: %d\n", [(DOMWheelEvent*)event isHorizontal] ? 1 : 0); + printf(" wheelDelta: %d\n", [(DOMWheelEvent*)event wheelDelta]); + } +} + +// FIXME: It's not good to have a test hard-wired into this controller like this. +// Instead we need to get testing framework based on the Objective-C bindings +// to work well enough that we can test that way instead. +- (void)fireKeyboardEventsToElement:(WebScriptObject *)element { + + if (![element isKindOfClass:[DOMHTMLElement class]]) + return; + + DOMHTMLElement *target = (DOMHTMLElement*)element; + DOMDocument *document = [target ownerDocument]; + + // Keyboard Event 1 + + DOMEvent *domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keydown" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000041" + keyLocation:0 + ctrlKey:YES + altKey:NO + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + + // Keyboard Event 2 + + domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keypress" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000045" + keyLocation:1 + ctrlKey:NO + altKey:YES + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + + // Keyboard Event 3 + + domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keyup" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000056" + keyLocation:0 + ctrlKey:NO + altKey:NO + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + +} + +@end diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.h b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h new file mode 100644 index 000000000..390a88184 --- /dev/null +++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Foundation/Foundation.h> + +class AccessibilityController; +class GCController; + +@interface FrameLoadDelegate : NSObject +{ + AccessibilityController* accessibilityController; + GCController* gcController; +} + +- (void)resetToConsistentState; + +@end diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm new file mode 100644 index 000000000..e453aeaa5 --- /dev/null +++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTree.h" +#import "FrameLoadDelegate.h" + +#import "AccessibilityController.h" +#import "AppleScriptController.h" +#import "EventSendingController.h" +#import "Foundation/NSNotification.h" +#import "GCController.h" +#import "LayoutTestController.h" +#import "NavigationController.h" +#import "ObjCController.h" +#import "ObjCPlugin.h" +#import "ObjCPluginFunction.h" +#import "PlainTextController.h" +#import "TextInputController.h" +#import "WebCoreTestSupport.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <JavaScriptCore/JavaScriptCore.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebScriptWorld.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebViewPrivate.h> +#import <wtf/Assertions.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLResponse (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLRequest (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface WebFrame (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation WebFrame (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult +{ + BOOL isMainFrame = (self == [[self webView] mainFrame]); + NSString *name = [self name]; + if (isMainFrame) { + if ([name length]) + return [NSString stringWithFormat:@"main frame \"%@\"", name]; + else + return @"main frame"; + } else { + if (name) + return [NSString stringWithFormat:@"frame \"%@\"", name]; + else + return @"frame (anonymous)"; + } +} + +- (NSString *)_drt_printFrameUserGestureStatus +{ + BOOL isUserGesture = [[self webView] _isProcessingUserGesture]; + return [NSString stringWithFormat:@"Frame with user gesture \"%@\"", isUserGesture ? @"true" : @"false"]; +} +@end + +@implementation FrameLoadDelegate + +- (id)init +{ + if ((self = [super init])) { + gcController = new GCController; + accessibilityController = new AccessibilityController; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewProgressFinishedNotification:) name:WebViewProgressFinishedNotification object:nil]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + delete gcController; + delete accessibilityController; + [super dealloc]; +} + +// Exec messages in the work queue until they're all done, or one of them starts a new load +- (void)processWork:(id)dummy +{ + // if another load started, then wait for it to complete. + if (topLoadingFrame) + return; + + // if we finish all the commands, we're ready to dump state + if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) + dump(); +} + +- (void)resetToConsistentState +{ + accessibilityController->resetToConsistentState(); +} + +- (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource +{ + if ([dataSource webFrame] == topLoadingFrame) { + topLoadingFrame = nil; + WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test + if (!gLayoutTestController->waitToDump()) { + if (WorkQueue::shared()->count()) + [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; + else + dump(); + } + } +} + +- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - in didStartProvisionalLoadForFrame", [frame _drt_printFrameUserGestureStatus]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT([frame provisionalDataSource]); + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; + + if (!done && gLayoutTestController->stopProvisionalFrameLoads()) { + NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + [frame stopLoading]; + } +} + +- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT(![frame provisionalDataSource]); + ASSERT([frame dataSource]); + + gLayoutTestController->setWindowIsKey(true); + NSView *documentView = [[mainFrame frameView] documentView]; + [[[mainFrame webView] window] makeFirstResponder:documentView]; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + + if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) { + // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL + // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree. + // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need + // to apply the workaround to. + ASSERT_NOT_REACHED(); + return; + } + + ASSERT([frame provisionalDataSource]); + [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]]; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + ASSERT([frame dataSource]); + ASSERT(frame == [[frame dataSource] webFrame]); + + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed. + // After that is fixed, we will reenable painting after WebCore is done loading the document, + // and this call will no longer be needed. + if ([[sender mainFrame] isEqual:frame]) + [sender displayIfNeeded]; + [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]]; + [gNavigationController webView:sender didFinishLoadForFrame:frame]; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT(![frame provisionalDataSource]); + ASSERT([frame dataSource]); + + [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]]; +} + +- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT_NOT_REACHED(); +} + +- (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame +{ + // Make New-Style LayoutTestController + JSContextRef context = [frame globalContext]; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSValueRef exception = 0; + + ASSERT(gLayoutTestController); + gLayoutTestController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + accessibilityController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + WebCoreTestSupport::injectInternalsObject(context); + + // Make Old-Style controllers + + WebView *webView = [frame webView]; + WebScriptObject *obj = [frame windowObject]; + AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView]; + [obj setValue:asc forKey:@"appleScriptController"]; + [asc release]; + + EventSendingController *esc = [[EventSendingController alloc] init]; + [obj setValue:esc forKey:@"eventSender"]; + [esc release]; + + [obj setValue:gNavigationController forKey:@"navigationController"]; + + ObjCController *occ = [[ObjCController alloc] init]; + [obj setValue:occ forKey:@"objCController"]; + [occ release]; + + ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; + [obj setValue:plugin forKey:@"objCPlugin"]; + [plugin release]; + + ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; + [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; + [pluginFunction release]; + + [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"]; + + TextInputController *tic = [[TextInputController alloc] initWithWebView:webView]; + [obj setValue:tic forKey:@"textInputController"]; + [tic release]; +} + +- (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world +{ + JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world]; + if (!ctx) + return; + + JSObjectRef globalObject = JSContextGetGlobalObject(ctx); + if (!globalObject) + return; + + JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); +} + +- (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world +{ + if (world == [WebScriptWorld standardWorld]) + [self didClearWindowObjectInStandardWorldForFrame:frame]; + else + [self didClearWindowObjectForFrame:frame inIsolatedWorld:world]; +} + +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; + printf ("%s\n", [string UTF8String]); + } + + if (gLayoutTestController->dumpTitleChanges()) + printf("TITLE CHANGED: %s\n", [title UTF8String]); +} + +- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - in willPerformClientRedirect", [frame _drt_printFrameUserGestureStatus]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } else if (!done) { + unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount]; + if (pendingFrameUnloadEvents) { + NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents]; + printf ("%s\n", [string UTF8String]); + } + } +} + +- (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webViewDidDisplayInsecureContent:(WebView *)sender +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf ("didDisplayInsecureContent\n"); +} + +- (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf ("didRunInsecureContent\n"); +} + +- (void)webView:(WebView *)sender didDetectXSS:(NSURL *)insecureURL +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf ("didDetectXSS\n"); +} + +- (void)webViewProgressFinishedNotification:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpProgressFinishedCallback()) + printf ("postProgressFinishedNotification\n"); +} + +@end diff --git a/Tools/DumpRenderTree/mac/GCControllerMac.mm b/Tools/DumpRenderTree/mac/GCControllerMac.mm new file mode 100644 index 000000000..de8a61e59 --- /dev/null +++ b/Tools/DumpRenderTree/mac/GCControllerMac.mm @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "GCController.h" + +#import <WebKit/WebCoreStatistics.h> + + +void GCController::collect() const +{ + [WebCoreStatistics garbageCollectJavaScriptObjects]; +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + [WebCoreStatistics garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging:waitUntilDone]; +} + +size_t GCController::getJSObjectCount() const +{ + return [WebCoreStatistics javaScriptObjectsCount]; +} diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.h b/Tools/DumpRenderTree/mac/HistoryDelegate.h new file mode 100644 index 000000000..c56d20368 --- /dev/null +++ b/Tools/DumpRenderTree/mac/HistoryDelegate.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 <Cocoa/Cocoa.h> + +@interface HistoryDelegate : NSObject +{ +} + +@end diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.mm b/Tools/DumpRenderTree/mac/HistoryDelegate.mm new file mode 100644 index 000000000..cbc409327 --- /dev/null +++ b/Tools/DumpRenderTree/mac/HistoryDelegate.mm @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#import "HistoryDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" + +#import <WebKit/WebNavigationData.h> +#import <WebKit/WebView.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation HistoryDelegate + +- (void)webView:(WebView *)webView didNavigateWithNavigationData:(WebNavigationData *)navigationData inFrame:(WebFrame *)webFrame +{ + NSURL *url = [navigationData url] ? [NSURL URLWithString:[navigationData url]] : nil; + bool hasClientRedirect = [[navigationData clientRedirectSource] length]; + NSHTTPURLResponse *httpResponse = [[navigationData response] isKindOfClass:[NSHTTPURLResponse class]] ? (NSHTTPURLResponse *)[navigationData response] : nil; + bool wasFailure = [navigationData hasSubstituteData] || (httpResponse && [httpResponse statusCode] >= 400); + + printf("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was %s and was %s%s.\n", + url ? [[url _drt_descriptionSuitableForTestResult] UTF8String] : "<none>", + [navigationData title] ? [[navigationData title] UTF8String] : "", + [navigationData originalRequest] ? [[[navigationData originalRequest] HTTPMethod] UTF8String] : "", + wasFailure ? "a failure" : "successful", + hasClientRedirect ? "a client redirect from " : "not a client redirect", + hasClientRedirect ? [[navigationData clientRedirectSource] UTF8String] : ""); +} + +- (void)webView:(WebView *)webView didPerformClientRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame +{ + NSURL *source = [NSURL URLWithString:sourceURL]; + NSURL *dest = [NSURL URLWithString:destinationURL]; + printf("WebView performed a client redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]); +} + +- (void)webView:(WebView *)webView didPerformServerRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame +{ + NSURL *source = [NSURL URLWithString:sourceURL]; + NSURL *dest = [NSURL URLWithString:destinationURL]; + printf("WebView performed a server redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]); +} + +- (void)webView:(WebView *)webView updateHistoryTitle:(NSString *)title forURL:(NSString *)url +{ + printf("WebView updated the title for history URL \"%s\" to \"%s\".\n", [[[NSURL URLWithString:url]_drt_descriptionSuitableForTestResult] UTF8String], [title UTF8String]); +} + +- (void)populateVisitedLinksForWebView:(WebView *)webView +{ + if (gLayoutTestController->dumpVisitedLinksCallback()) + printf("Asked to populate visited links for WebView \"%s\"\n", [[[NSURL URLWithString:[webView mainFrameURL]] _drt_descriptionSuitableForTestResult] UTF8String]); +} + +@end diff --git a/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h new file mode 100644 index 000000000..ae1371fc6 --- /dev/null +++ b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h @@ -0,0 +1 @@ +#include "../../../../Source/WebKit/mac/Misc/WebTypesInternal.h" diff --git a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm new file mode 100644 index 000000000..b7b14a79a --- /dev/null +++ b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -0,0 +1,1243 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTree.h" +#import "LayoutTestController.h" + +#import "EditingDelegate.h" +#import "MockGeolocationProvider.h" +#import "PolicyDelegate.h" +#import "StorageTrackerDelegate.h" +#import "UIDelegate.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JSRetainPtr.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/DOMDocument.h> +#import <WebKit/DOMElement.h> +#import <WebKit/WebApplicationCache.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDOMOperationsPrivate.h> +#import <WebKit/WebDataSource.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebDeviceOrientation.h> +#import <WebKit/WebDeviceOrientationProviderMock.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFrameViewPrivate.h> +#import <WebKit/WebGeolocationPosition.h> +#import <WebKit/WebHTMLRepresentation.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebHistoryPrivate.h> +#import <WebKit/WebIconDatabasePrivate.h> +#import <WebKit/WebInspectorPrivate.h> +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebKitErrors.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebQuotaManager.h> +#import <WebKit/WebScriptWorld.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebStorageManagerPrivate.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> +#import <WebKit/WebWorkersPrivate.h> +#import <wtf/CurrentTime.h> +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +@interface CommandValidationTarget : NSObject <NSValidatedUserInterfaceItem> +{ + SEL _action; +} +- (id)initWithAction:(SEL)action; +@end + +@implementation CommandValidationTarget + +- (id)initWithAction:(SEL)action +{ + self = [super init]; + if (!self) + return nil; + + _action = action; + return self; +} + +- (SEL)action +{ + return _action; +} + +- (NSInteger)tag +{ + return 0; +} + +@end + +LayoutTestController::~LayoutTestController() +{ +} + +void LayoutTestController::addDisallowedURL(JSStringRef url) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + + if (!disallowedURLs) + disallowedURLs = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); + + // Canonicalize the URL + NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + request = [NSURLProtocol canonicalRequestForRequest:request]; + + CFSetAddValue(disallowedURLs, [request URL]); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + return [[mainFrame webView] shouldClose]; +} + +void LayoutTestController::clearAllApplicationCaches() +{ + [WebApplicationCache deleteAllApplicationCaches]; +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef url) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + long long usage = [WebApplicationCache diskUsageForOrigin:origin]; + [origin release]; + return usage; +} + +void LayoutTestController::syncLocalStorage() +{ + [[WebStorageManager sharedWebStorageManager] syncLocalStorage]; +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef url) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + long long usage = [[WebStorageManager sharedWebStorageManager] diskUsageForOrigin:origin]; + [origin release]; + return usage; +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned number) +{ + [storageDelegate logNotifications:number controller:this]; +} + +void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef url) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + [WebApplicationCache deleteCacheForOrigin:origin]; + [origin release]; +} + +JSValueRef originsArrayToJS(JSContextRef context, NSArray *origins) +{ + NSUInteger count = [origins count]; + + JSValueRef jsOriginsArray[count]; + for (NSUInteger i = 0; i < count; i++) { + NSString *origin = [[origins objectAtIndex:i] databaseIdentifier]; + JSRetainPtr<JSStringRef> originJS(Adopt, JSStringCreateWithCFString((CFStringRef)origin)); + jsOriginsArray[i] = JSValueMakeString(context, originJS.get()); + } + + return JSObjectMakeArray(context, count, jsOriginsArray, NULL); +} + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + return originsArrayToJS(context, [WebApplicationCache originsWithCache]); +} + +void LayoutTestController::clearAllDatabases() +{ + [[WebDatabaseManager sharedWebDatabaseManager] deleteAllDatabases]; +} + +void LayoutTestController::deleteAllLocalStorage() +{ + [[WebStorageManager sharedWebStorageManager] deleteAllOrigins]; +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + return originsArrayToJS(context, [[WebStorageManager sharedWebStorageManager] origins]); +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, URL)); + + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + [[WebStorageManager sharedWebStorageManager] deleteOrigin:origin]; + [origin release]; +} + +void LayoutTestController::clearBackForwardList() +{ + WebBackForwardList *backForwardList = [[mainFrame webView] backForwardList]; + WebHistoryItem *item = [[backForwardList currentItem] retain]; + + // We clear the history by setting the back/forward list's capacity to 0 + // then restoring it back and adding back the current item. + int capacity = [backForwardList capacity]; + [backForwardList setCapacity:0]; + [backForwardList setCapacity:capacity]; + [backForwardList addItem:item]; + [backForwardList goToItem:item]; + [item release]; +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + return JSStringCreateWithCFString((CFStringRef)[nameNS _web_decodeHostName]); +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + return JSStringCreateWithCFString((CFStringRef)[nameNS _web_encodeHostName]); +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + if (!element) + return 0; + + JSRetainPtr<JSStringRef> counterValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame counterValueForElement:element])); + return counterValue; +} + +void LayoutTestController::keepWebHistory() +{ + if (![WebHistory optionalSharedHistory]) { + WebHistory *history = [[WebHistory alloc] init]; + [WebHistory setOptionalSharedHistory:history]; + [history release]; + } +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value) +{ + return [[mainFrame webView] _computedStyleIncludingVisitedInfo:context forElement:value]; +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + return [[mainFrame webView] _nodesFromRect:context forDocument:value x:x y:y top:top right:right bottom:bottom left:left ignoreClipping:ignoreClipping]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame _layerTreeAsText])); + return string; +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const +{ + DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject]; + if (!element) + return JSRetainPtr<JSStringRef>(); + + JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithCFString((CFStringRef)[element _markerTextForListItem])); + return markerText; +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + if (!element) + return -1; + + return [mainFrame pageNumberForElement:element:pageWidthInPixels:pageHeightInPixels]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageProperty:propertyName:pageNumber])); + return propertyValue; +} + +bool LayoutTestController::isPageBoxVisible(int pageNumber) const +{ + return [mainFrame isPageBoxVisible:pageNumber]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageSizeAndMarginsInPixels:pageNumber:width:height:marginTop:marginRight:marginBottom:marginLeft])); + return propertyValue; +} + +int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels) +{ + return [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels]; +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + return [[[mainFrame webView] UIDelegate] numberOfPendingGeolocationPermissionRequests]; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + return [[[WebHistory optionalSharedHistory] allItems] count]; +} + +unsigned LayoutTestController::workerThreadCount() const +{ + return [WebWorkersPrivate workerThreadCount]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::platformName() const +{ + JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("mac")); + return platformName; +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; +} + +static inline std::string stringFromJSString(JSStringRef jsString) +{ + size_t maxBufferSize = JSStringGetMaximumUTF8CStringSize(jsString); + char* utf8Buffer = new char[maxBufferSize]; + size_t bytesWrittenToUTF8Buffer = JSStringGetUTF8CString(jsString, utf8Buffer, maxBufferSize); + std::string stdString(utf8Buffer, bytesWrittenToUTF8Buffer - 1); // bytesWrittenToUTF8Buffer includes a trailing \0 which std::string doesn't need. + delete[] utf8Buffer; + return stdString; +} + +static inline size_t indexOfSeparatorAfterDirectoryName(const std::string& directoryName, const std::string& fullPath) +{ + std::string searchKey = "/" + directoryName + "/"; + size_t indexOfSearchKeyStart = fullPath.rfind(searchKey); + if (indexOfSearchKeyStart == std::string::npos) { + ASSERT_NOT_REACHED(); + return 0; + } + // Callers expect the return value not to end in "/", so searchKey.length() - 1. + return indexOfSearchKeyStart + searchKey.length() - 1; +} + +static inline std::string resourceRootAbsolutePath(const std::string& testPathOrURL, const std::string& expectedRootName) +{ + char* localResourceRootEnv = getenv("LOCAL_RESOURCE_ROOT"); + if (localResourceRootEnv) + return std::string(localResourceRootEnv); + + // This fallback approach works for non-http tests and is useful + // in the case when we're running DRT directly from the command line. + return testPathOrURL.substr(0, indexOfSeparatorAfterDirectoryName(expectedRootName, testPathOrURL)); +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef localResourceJSString) +{ + // The passed in path will be an absolute path to the resource starting + // with "/tmp" or "/tmp/LayoutTests", optionally starting with the explicit file:// protocol. + // /tmp maps to DUMPRENDERTREE_TEMP, and /tmp/LayoutTests maps to LOCAL_RESOURCE_ROOT. + // FIXME: This code should work on all *nix platforms and can be moved into LayoutTestController.cpp. + std::string expectedRootName; + std::string absolutePathToResourceRoot; + std::string localResourceString = stringFromJSString(localResourceJSString); + + if (localResourceString.find("LayoutTests") != std::string::npos) { + expectedRootName = "LayoutTests"; + absolutePathToResourceRoot = resourceRootAbsolutePath(m_testPathOrURL, expectedRootName); + } else if (localResourceString.find("tmp") != std::string::npos) { + expectedRootName = "tmp"; + absolutePathToResourceRoot = getenv("DUMPRENDERTREE_TEMP"); + } else { + ASSERT_NOT_REACHED(); // pathToLocalResource was passed a path it doesn't know how to map. + } + ASSERT(!absolutePathToResourceRoot.empty()); + size_t indexOfSeparatorAfterRootName = indexOfSeparatorAfterDirectoryName(expectedRootName, localResourceString); + std::string absolutePathToLocalResource = absolutePathToResourceRoot + localResourceString.substr(indexOfSeparatorAfterRootName); + + // Note: It's important that we keep the file:// or http tests will get confused. + if (localResourceString.find("file://") != std::string::npos) { + ASSERT(absolutePathToLocalResource[0] == '/'); + absolutePathToLocalResource = std::string("file://") + absolutePathToLocalResource; + } + return JSStringCreateWithUTF8CString(absolutePathToLocalResource.c_str()); +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + NSString *urlNS = (NSString *)urlCF.get(); + + NSURL *nsurl = [NSURL URLWithString:urlNS relativeToURL:[[[mainFrame dataSource] response] URL]]; + NSString *nsurlString = [nsurl absoluteString]; + + JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString([nsurlString UTF8String])); + WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool newAcceptsEditing) +{ + [(EditingDelegate *)[[mainFrame webView] editingDelegate] setAcceptsEditing:newAcceptsEditing]; +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + if (alwaysAcceptCookies == m_alwaysAcceptCookies) + return; + + m_alwaysAcceptCookies = alwaysAcceptCookies; + NSHTTPCookieAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? NSHTTPCookieAcceptPolicyAlways : NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; + [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:cookieAcceptPolicy]; +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + [WebApplicationCache setMaximumSize:size]; +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"http://127.0.0.1:8000"]]; + [[origin applicationCacheQuotaManager] setQuota:quota]; + [origin release]; +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + [[[mainFrame webView] preferences] setAuthorAndUserStylesEnabled:flag]; +} + +void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled) +{ + DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject]; + if (!element || ![element isKindOfClass:[DOMHTMLInputElement class]]) + return; + + [(DOMHTMLInputElement *)element _setAutofilled:autofilled]; +} + +void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive) +{ + if (setDelegate) { + [policyDelegate setPermissive:permissive]; + [[mainFrame webView] setPolicyDelegate:policyDelegate]; + } else + [[mainFrame webView] setPolicyDelegate:nil]; +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"file:///"]]; + [[origin databaseQuotaManager] setQuota:quota]; + [origin release]; +} + +void LayoutTestController::goBack() +{ + [[mainFrame webView] goBack]; +} + +void LayoutTestController::setDefersLoading(bool defers) +{ + [[mainFrame webView] setDefersCallbacks:defers]; +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme) +{ + RetainPtr<CFStringRef> schemeCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, scheme)); + [WebView _setDomainRelaxationForbidden:forbidden forURLScheme:(NSString *)schemeCFString.get()]; +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + // DumpRenderTree configured the WebView to use WebDeviceOrientationProviderMock. + id<WebDeviceOrientationProvider> provider = [[mainFrame webView] _deviceOrientationProvider]; + WebDeviceOrientationProviderMock *mockProvider = static_cast<WebDeviceOrientationProviderMock*>(provider); + WebDeviceOrientation *orientation = [[WebDeviceOrientation alloc] initWithCanProvideAlpha:canProvideAlpha alpha:alpha canProvideBeta:canProvideBeta beta:beta canProvideGamma:canProvideGamma gamma:gamma]; + [mockProvider setOrientation:orientation]; + [orientation release]; +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + WebGeolocationPosition *position = [[WebGeolocationPosition alloc] initWithTimestamp:currentTime() latitude:latitude longitude:longitude accuracy:accuracy]; + [[MockGeolocationProvider shared] setPosition:position]; + [position release]; +} + +void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) +{ + RetainPtr<CFStringRef> messageCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, message)); + NSString *messageNS = (NSString *)messageCF.get(); + NSError *error = [NSError errorWithDomain:WebKitErrorDomain code:code userInfo:[NSDictionary dictionaryWithObject:messageNS forKey:NSLocalizedDescriptionKey]]; + [[MockGeolocationProvider shared] setError:error]; +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + setGeolocationPermissionCommon(allow); + [[[mainFrame webView] UIDelegate] didSetMockGeolocationPermission]; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled) +{ + // FIXME: Workaround <rdar://problem/6480108> + static WebIconDatabase *sharedWebIconDatabase = NULL; + if (!sharedWebIconDatabase) { + if (!iconDatabaseEnabled) + return; + sharedWebIconDatabase = [WebIconDatabase sharedIconDatabase]; + if ([sharedWebIconDatabase isEnabled] == iconDatabaseEnabled) + return; + } + [sharedWebIconDatabase setEnabled:iconDatabaseEnabled]; +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool profilingEnabled) +{ + setDeveloperExtrasEnabled(profilingEnabled); + [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:profilingEnabled]; +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + NSView *documentView = [[mainFrame frameView] documentView]; + + NSResponder *firstResponder = flag ? documentView : nil; + [[[mainFrame webView] window] makeFirstResponder:firstResponder]; +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + [[[mainFrame webView] preferences] setPrivateBrowsingEnabled:privateBrowsingEnabled]; +} + +void LayoutTestController::setXSSAuditorEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setXSSAuditorEnabled:enabled]; +} + +void LayoutTestController::setFrameFlatteningEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setFrameFlatteningEnabled:enabled]; +} + +void LayoutTestController::setSpatialNavigationEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setSpatialNavigationEnabled:enabled]; +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) +{ + [[[mainFrame webView] preferences] setAllowUniversalAccessFromFileURLs:enabled]; +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + [[[mainFrame webView] preferences] setAllowFileAccessFromFileURLs:enabled]; +} + +void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled) +{ + [[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled]; +} + +void LayoutTestController::setPluginsEnabled(bool pluginsEnabled) +{ + [[[mainFrame webView] preferences] setPlugInsEnabled:pluginsEnabled]; +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled) +{ + [[[mainFrame webView] preferences] setJavaScriptCanAccessClipboard:enabled]; +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles) +{ + [[mainFrame webView] setTabKeyCyclesThroughElements:cycles]; +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + [[mainFrame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:flag]; +} + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + [[WebPreferences standardPreferences] setUserStyleSheetEnabled:flag]; +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + RetainPtr<CFStringRef> pathCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, path)); + NSURL *url = [NSURL URLWithString:(NSString *)pathCF.get()]; + [[WebPreferences standardPreferences] setUserStyleSheetLocation:url]; +} + +void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value) +{ + DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject]; + if (!element || ![element isKindOfClass:[DOMHTMLInputElement class]]) + return; + + RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value)); + [(DOMHTMLInputElement *)element _setValueForUser:(NSString *)valueCF.get()]; +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef mode) +{ + // FIXME: implement +} + +void LayoutTestController::disableImageLoading() +{ + [[WebPreferences standardPreferences] setLoadsImagesAutomatically:NO]; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + [[mainFrame webView] _dispatchPendingLoadRequests]; +} + +void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value) +{ + RetainPtr<CFStringRef> keyCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, key)); + NSString *keyNS = (NSString *)keyCF.get(); + + RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value)); + NSString *valueNS = (NSString *)valueCF.get(); + + [[WebPreferences standardPreferences] _setPreferenceForTestWithValue:valueNS forKey:keyNS]; +} + +void LayoutTestController::removeAllVisitedLinks() +{ + [WebHistory _removeAllVisitedLinks]; +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL)); + ::setPersistentUserStyleSheetLocation(urlString.get()); +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + ::setPersistentUserStyleSheetLocation(0); +} + +void LayoutTestController::setWindowIsKey(bool windowIsKey) +{ + m_windowIsKey = windowIsKey; + [[mainFrame webView] _updateActiveState]; +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool flag) +{ + [[mainFrame webView] setSmartInsertDeleteEnabled:flag]; +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag) +{ + [[mainFrame webView] setSelectTrailingWhitespaceEnabled:flag]; +} + +static const CFTimeInterval waitToDumpWatchdogInterval = 30.0; + +static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info) +{ + gLayoutTestController->waitToDumpWatchdogTimerFired(); +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) { + waitToDumpWatchdog = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogInterval, 0, 0, 0, waitUntilDoneWatchdogFired, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), waitToDumpWatchdog, kCFRunLoopCommonModes); + } +} + +int LayoutTestController::windowCount() +{ + return CFArrayGetCount(openWindowsRef); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef jsString) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, jsString)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + id rep = [[mainFrame dataSource] representation]; + + if ([rep class] == [WebHTMLRepresentation class]) + return [(WebHTMLRepresentation *)rep elementDoesAutoComplete:element]; + + return false; +} + +void LayoutTestController::execCommand(JSStringRef name, JSStringRef value) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + + RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value)); + NSString *valueNS = (NSString *)valueCF.get(); + + [[mainFrame webView] _executeCoreCommandByName:nameNS value:valueNS]; +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + WebFindOptions options = 0; + + JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); + if (!JSValueIsNumber(context, lengthValue)) + return false; + + RetainPtr<CFStringRef> targetCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, target)); + + size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); + for (size_t i = 0; i < length; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); + if (!JSValueIsString(context, value)) + continue; + + JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); + + if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive")) + options |= WebFindOptionsCaseInsensitive; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts")) + options |= WebFindOptionsAtWordStarts; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart")) + options |= WebFindOptionsTreatMedialCapitalAsWordStart; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards")) + options |= WebFindOptionsBackwards; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround")) + options |= WebFindOptionsWrapAround; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) + options |= WebFindOptionsStartInSelection; + } + + return [[mainFrame webView] findString:(NSString *)targetCFString.get() options:options]; +} + +void LayoutTestController::setCacheModel(int cacheModel) +{ + [[WebPreferences standardPreferences] setCacheModel:cacheModel]; +} + +bool LayoutTestController::isCommandEnabled(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + + // Accept command strings with capital letters for first letter without trailing colon. + if (![nameNS hasSuffix:@":"] && [nameNS length]) { + nameNS = [[[[nameNS substringToIndex:1] lowercaseString] + stringByAppendingString:[nameNS substringFromIndex:1]] + stringByAppendingString:@":"]; + } + + SEL selector = NSSelectorFromString(nameNS); + RetainPtr<CommandValidationTarget> target(AdoptNS, [[CommandValidationTarget alloc] initWithAction:selector]); + id validator = [NSApp targetForAction:selector to:[mainFrame webView] from:target.get()]; + if (!validator) + return false; + if (![validator respondsToSelector:selector]) + return false; + if (![validator respondsToSelector:@selector(validateUserInterfaceItem:)]) + return true; + return [validator validateUserInterfaceItem:target.get()]; +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *idNS = (NSString *)idCF.get(); + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationName)); + NSString *nameNS = (NSString *)nameCF.get(); + + return [mainFrame _pauseAnimation:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time]; +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *idNS = (NSString *)idCF.get(); + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, propertyName)); + NSString *nameNS = (NSString *)nameCF.get(); + + return [mainFrame _pauseTransitionOfProperty:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time]; +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> animationIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationId)); + NSString *animationIDNS = (NSString *)animationIDCF.get(); + RetainPtr<CFStringRef> elementIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *elementIDNS = (NSString *)elementIDCF.get(); + + return [mainFrame _pauseSVGAnimation:elementIDNS onSMILNode:[[mainFrame DOMDocument] getElementById:animationIDNS] atTime:time]; +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + return [mainFrame _numberOfActiveAnimations]; +} + +void LayoutTestController::suspendAnimations() const +{ + return [mainFrame _suspendAnimations]; +} + +void LayoutTestController::resumeAnimations() const +{ + return [mainFrame _resumeAnimations]; +} + +void LayoutTestController::waitForPolicyDelegate() +{ + setWaitToDump(true); + [policyDelegate setControllerToNotifyDone:this]; + [[mainFrame webView] setPolicyDelegate:policyDelegate]; +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin)); + NSString *sourceOriginNS = (NSString *)sourceOriginCF.get(); + RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol)); + NSString *destinationProtocolNS = (NSString *)protocolCF.get(); + RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost)); + NSString *destinationHostNS = (NSString *)hostCF.get(); + [WebView _addOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains]; +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin)); + NSString *sourceOriginNS = (NSString *)sourceOriginCF.get(); + RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol)); + NSString *destinationProtocolNS = (NSString *)protocolCF.get(); + RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost)); + NSString *destinationHostNS = (NSString *)hostCF.get(); + [WebView _removeOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains]; +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source)); + NSString *sourceNS = (NSString *)sourceCF.get(); + [WebView _addUserScriptToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectionTime:(runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd) injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)]; +} + +void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source)); + NSString *sourceNS = (NSString *)sourceCF.get(); + [WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)]; +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:enabled]; +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setAsynchronousSpellCheckingEnabled:enabled]; +} + +void LayoutTestController::showWebInspector() +{ + [[[mainFrame webView] inspector] show:nil]; +} + +void LayoutTestController::closeWebInspector() +{ + [[[mainFrame webView] inspector] close:nil]; +} + +void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script) +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script)); + NSString *scriptNS = (NSString *)scriptCF.get(); + [[[mainFrame webView] inspector] evaluateInFrontend:nil callId:callId script:scriptNS]; +} + +typedef HashMap<unsigned, RetainPtr<WebScriptWorld> > WorldMap; +static WorldMap& worldMap() +{ + static WorldMap& map = *new WorldMap; + return map; +} + +unsigned worldIDForWorld(WebScriptWorld *world) +{ + WorldMap::const_iterator end = worldMap().end(); + for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) { + if (it->second == world) + return it->first; + } + + return 0; +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script)); + NSString *scriptNS = (NSString *)scriptCF.get(); + + // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world + // that is created once and cached forever. + WebScriptWorld *world; + if (!worldID) + world = [WebScriptWorld world]; + else { + RetainPtr<WebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second; + if (!worldSlot) + worldSlot.adoptNS([[WebScriptWorld alloc] init]); + world = worldSlot.get(); + } + + [mainFrame _stringByEvaluatingJavaScriptFromString:scriptNS withGlobalObject:globalObject inScriptWorld:world]; +} + +void LayoutTestController::allowRoundingHacks() +{ + [WebView _setAllowsRoundingHacks:YES]; +} + +@interface APITestDelegate : NSObject +{ + bool* m_condition; +} +@end + +@implementation APITestDelegate + +- (id)initWithCompletionCondition:(bool*)condition +{ + [super init]; + ASSERT(condition); + m_condition = condition; + *m_condition = false; + return self; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed provisional\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + printf("API Test load succeeded\n"); + *m_condition = true; +} + +@end + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + RetainPtr<CFStringRef> utf8DataCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, utf8Data)); + RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, baseURL)); + + WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""]; + + bool done = false; + APITestDelegate *delegate = [[APITestDelegate alloc] initWithCompletionCondition:&done]; + [webView setFrameLoadDelegate:delegate]; + + [[webView mainFrame] loadData:[(NSString *)utf8DataCF.get() dataUsingEncoding:NSUTF8StringEncoding] MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]]; + + while (!done) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; + [pool release]; + } + + [webView close]; + [webView release]; + [delegate release]; + [pool release]; +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + WebView *view = [mainFrame webView]; + [view goToBackForwardItem:[[view backForwardList] currentItem]]; +} + +void LayoutTestController::setWebViewEditable(bool editable) +{ + WebView *view = [mainFrame webView]; + [view setEditable:editable]; +} + +static NSString *SynchronousLoaderRunLoopMode = @"DumpRenderTreeSynchronousLoaderRunLoopMode"; + +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) +@protocol NSURLConnectionDelegate <NSObject> +@end +#endif + +@interface SynchronousLoader : NSObject <NSURLConnectionDelegate> +{ + NSString *m_username; + NSString *m_password; + BOOL m_isDone; +} ++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password; +@end + +@implementation SynchronousLoader : NSObject +- (void)dealloc +{ + [m_username release]; + [m_password release]; + + [super dealloc]; +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection +{ + return YES; +} + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if ([challenge previousFailureCount] == 0) { + RetainPtr<NSURLCredential> credential(AdoptNS, [[NSURLCredential alloc] initWithUser:m_username password:m_password persistence:NSURLCredentialPersistenceForSession]); + [[challenge sender] useCredential:credential.get() forAuthenticationChallenge:challenge]; + return; + } + [[challenge sender] cancelAuthenticationChallenge:challenge]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + printf("SynchronousLoader failed: %s\n", [[error description] UTF8String]); + m_isDone = YES; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + m_isDone = YES; +} + ++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password +{ + ASSERT(![[request URL] user]); + ASSERT(![[request URL] password]); + + SynchronousLoader *delegate = [[SynchronousLoader alloc] init]; + delegate->m_username = [username copy]; + delegate->m_password = [password copy]; + + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO]; + [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:SynchronousLoaderRunLoopMode]; + [connection start]; + + while (!delegate->m_isDone) + [[NSRunLoop currentRunLoop] runMode:SynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]]; + + [connection cancel]; + + [connection release]; + [delegate release]; +} + +@end + +void LayoutTestController::authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password) +{ + // See <rdar://problem/7880699>. +#ifndef BUILDING_ON_LEOPARD + RetainPtr<CFStringRef> urlStringCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + RetainPtr<CFStringRef> usernameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, username)); + RetainPtr<CFStringRef> passwordCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, password)); + + RetainPtr<NSURLRequest> request(AdoptNS, [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:(NSString *)urlStringCF.get()]]); + + [SynchronousLoader makeRequest:request.get() withUsername:(NSString *)usernameCF.get() password:(NSString *)passwordCF.get()]; +#endif +} + +void LayoutTestController::setEditingBehavior(const char* editingBehavior) +{ + NSString *editingBehaviorNS = [[NSString alloc] initWithUTF8String:editingBehavior]; + if ([editingBehaviorNS isEqualToString:@"mac"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingMacBehavior]; + else if ([editingBehaviorNS isEqualToString:@"win"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingWinBehavior]; + else if ([editingBehaviorNS isEqualToString:@"unix"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingUnixBehavior]; + [editingBehaviorNS release]; +} + +void LayoutTestController::abortModal() +{ + [NSApp abortModal]; +} + +bool LayoutTestController::hasSpellingMarker(int from, int length) +{ + return [mainFrame hasSpellingMarker:from length:length]; +} + +bool LayoutTestController::hasGrammarMarker(int from, int length) +{ + return [mainFrame hasGrammarMarker:from length:length]; +} + +void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/) +{ + +} + +void LayoutTestController::setSerializeHTTPLoads(bool serialize) +{ + [WebView _setLoadResourcesSerially:serialize]; +} + +void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval) +{ + [[mainFrame webView] _setMinimumTimerInterval:minimumTimerInterval]; +} + +void LayoutTestController::setTextDirection(JSStringRef directionName) +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + if (JSStringIsEqualToUTF8CString(directionName, "ltr")) + [[mainFrame webView] makeBaseWritingDirectionLeftToRight:0]; + else if (JSStringIsEqualToUTF8CString(directionName, "rtl")) + [[mainFrame webView] makeBaseWritingDirectionRightToLeft:0]; + else + ASSERT_NOT_REACHED(); +#endif +} + +void LayoutTestController::addChromeInputField() +{ + NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)]; + textField.tag = 1; + [[[[mainFrame webView] window] contentView] addSubview:textField]; + [textField release]; + + [textField setNextKeyView:[mainFrame webView]]; + [[mainFrame webView] setNextKeyView:textField]; +} + +void LayoutTestController::removeChromeInputField() +{ + NSView* textField = [[[[mainFrame webView] window] contentView] viewWithTag:1]; + if (textField) { + [textField removeFromSuperview]; + focusWebView(); + } +} + +void LayoutTestController::focusWebView() +{ + [[[mainFrame webView] window] makeFirstResponder:[mainFrame webView]]; +} + +void LayoutTestController::setBackingScaleFactor(double backingScaleFactor) +{ + [[mainFrame webView] _setCustomBackingScaleFactor:backingScaleFactor]; +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ + // FIXME: Implement. +} diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.h b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h new file mode 100644 index 000000000..311d1e918 --- /dev/null +++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 MockGeolocationProvider_h +#define MockGeolocationProvider_h + +#import <WebKit/WebViewPrivate.h> +#import <wtf/HashSet.h> + +@interface MockGeolocationProvider : NSObject<WebGeolocationProvider> { + WebGeolocationPosition *_lastPosition; + NSError *_error; + NSTimer *_timer; + HashSet<WebView *> _registeredViews; +} + ++ (MockGeolocationProvider *)shared; + +- (void)setPosition:(WebGeolocationPosition *)position; +- (void)setError:(NSError *)error; + +- (void)stopTimer; + +@end +#endif diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm new file mode 100644 index 000000000..e03cae24a --- /dev/null +++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "MockGeolocationProvider.h" + + +@implementation MockGeolocationProvider + ++ (MockGeolocationProvider *)shared +{ + static MockGeolocationProvider *provider = [[MockGeolocationProvider alloc] init]; + return provider; +} + +- (void)dealloc +{ + ASSERT(_registeredViews.isEmpty()); + + [_lastPosition release]; + [_error release]; + [super dealloc]; +} + +- (void)setPosition:(WebGeolocationPosition *)position +{ + if (_lastPosition != position) { + [_lastPosition release]; + _lastPosition = [position retain]; + } + + [_error release]; + _error = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)setError:(NSError *)error +{ + if (_error != error) { + [_error release]; + _error = [error retain]; + } + + [_lastPosition release]; + _lastPosition = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)registerWebView:(WebView *)webView +{ + _registeredViews.add(webView); + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)unregisterWebView:(WebView *)webView +{ + _registeredViews.remove(webView); +} + +- (WebGeolocationPosition *)lastPosition +{ + return _lastPosition; +} + +- (void)stopTimer +{ + [_timer invalidate]; + _timer = 0; +} + +- (void)timerFired +{ + _timer = 0; + + // Expect that views won't be (un)registered while iterating. + HashSet<WebView*> views = _registeredViews; + for (HashSet<WebView*>::iterator iter = views.begin(); iter != views.end(); ++iter) { + if (_error) + [*iter _geolocationDidFailWithError:_error]; + else + [*iter _geolocationDidChangePosition:_lastPosition]; + } +} + +@end diff --git a/Tools/DumpRenderTree/mac/NavigationController.h b/Tools/DumpRenderTree/mac/NavigationController.h new file mode 100644 index 000000000..8ee3432d9 --- /dev/null +++ b/Tools/DumpRenderTree/mac/NavigationController.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> +#import <WebKit/WebView.h> + +@interface NavigationController : NSObject +{ + enum { None, Load, GoBack, ExecuteScript } pendingAction; + NSString *pendingScript; + NSURLRequest *pendingRequest; +} +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame; +@end diff --git a/Tools/DumpRenderTree/mac/NavigationController.m b/Tools/DumpRenderTree/mac/NavigationController.m new file mode 100644 index 000000000..8c01d507b --- /dev/null +++ b/Tools/DumpRenderTree/mac/NavigationController.m @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "NavigationController.h" + +#import <WebKit/WebFrame.h> +#import <WebKit/WebScriptObject.h> + + +@implementation NavigationController ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:)) + return @"evalAfterBackForwardNavigation"; + return nil; +} + +- (void)setPendingScript:(NSString *)script +{ + if (script != pendingScript) { + [pendingScript release]; + pendingScript = [script copy]; + } +} + +- (void)setPendingRequest:(NSURLRequest *)request +{ + if (request != pendingRequest) { + [pendingRequest release]; + pendingRequest = [request copy]; + } +} + +- (void)evaluateWebScript:(NSString *)script afterBackForwardNavigation:(NSString *)navigation +{ + // Allow both arguments to be optional + if (![script isKindOfClass:[NSString class]]) + script = @""; + if (![navigation isKindOfClass:[NSString class]]) + navigation = @"about:blank"; + + [self setPendingScript:script]; + [self setPendingRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:navigation]]]; + pendingAction = Load; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + if (frame == [[frame webView] mainFrame]) { + switch (pendingAction) { + case Load: + pendingAction = GoBack; + [frame loadRequest:pendingRequest]; + [self setPendingRequest:nil]; + break; + case GoBack: + pendingAction = ExecuteScript; + [[frame webView] goBack]; + break; + case ExecuteScript: + pendingAction = None; + [[[frame webView] windowScriptObject] evaluateWebScript:pendingScript]; + [self setPendingScript:nil]; + break; + case None: + default: + break; + } + } +} + +- (void)dealloc +{ + [self setPendingScript:nil]; + [self setPendingRequest:nil]; + [super dealloc]; +} +@end + diff --git a/Tools/DumpRenderTree/mac/ObjCController.h b/Tools/DumpRenderTree/mac/ObjCController.h new file mode 100644 index 000000000..d1d001cc5 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCController.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Foundation/Foundation.h> + +@class WebScriptObject; + +// This controller should be used to test Objective-C language features and the WebScriptObject. +@interface ObjCController : NSObject +{ + WebScriptObject *storedWebScriptObject; +} +@end diff --git a/Tools/DumpRenderTree/mac/ObjCController.m b/Tools/DumpRenderTree/mac/ObjCController.m new file mode 100644 index 000000000..af237bf69 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCController.m @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "ObjCController.h" + +// Avoid compile error in DOMPrivate.h. +@class NSFont; + +#import <JavaScriptCore/JavaScriptCore.h> +#import <WebKit/DOMAbstractView.h> +#import <WebKit/DOMPrivate.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebView.h> +#import <pthread.h> +#import <wtf/Assertions.h> + +// Remove this once hasWebScriptKey has been made public. +@interface WebScriptObject (StagedForPublic) +- (BOOL)hasWebScriptKey:(NSString *)name; +@end + +static void* runJavaScriptThread(void* arg) +{ + JSGlobalContextRef ctx = JSGlobalContextCreate(0); + JSStringRef scriptRef = JSStringCreateWithUTF8CString("'Hello World!'"); + + JSValueRef exception = 0; + JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); + ASSERT(!exception); + + JSGlobalContextRelease(ctx); + JSStringRelease(scriptRef); + + return 0; +} + +@implementation ObjCController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (0 + || aSelector == @selector(classNameOf:) + || aSelector == @selector(isObject:instanceOf:) + || aSelector == @selector(objectOfClass:) + || aSelector == @selector(arrayOfString) + || aSelector == @selector(identityIsEqual::) + || aSelector == @selector(longLongRoundTrip:) + || aSelector == @selector(unsignedLongLongRoundTrip:) + || aSelector == @selector(testWrapperRoundTripping:) + || aSelector == @selector(accessStoredWebScriptObject) + || aSelector == @selector(storeWebScriptObject:) + || aSelector == @selector(testValueForKey) + || aSelector == @selector(testHasWebScriptKey:) + || aSelector == @selector(testArray) + || aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:) + ) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(classNameOf:)) + return @"className"; + if (aSelector == @selector(isObject:instanceOf:)) + return @"isObjectInstanceOf"; + if (aSelector == @selector(objectOfClass:)) + return @"objectOfClass"; + if (aSelector == @selector(arrayOfString)) + return @"arrayOfString"; + if (aSelector == @selector(identityIsEqual::)) + return @"identityIsEqual"; + if (aSelector == @selector(longLongRoundTrip:)) + return @"longLongRoundTrip"; + if (aSelector == @selector(unsignedLongLongRoundTrip:)) + return @"unsignedLongLongRoundTrip"; + if (aSelector == @selector(testWrapperRoundTripping:)) + return @"testWrapperRoundTripping"; + if (aSelector == @selector(storeWebScriptObject:)) + return @"storeWebScriptObject"; + if (aSelector == @selector(testValueForKey)) + return @"testValueForKey"; + if (aSelector == @selector(testHasWebScriptKey:)) + return @"testHasWebScriptKey"; + if (aSelector == @selector(testArray)) + return @"testArray"; + if (aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:)) + return @"setSelectElementSelectedIndexAllowingMultiple"; + + return nil; +} + +- (BOOL)isObject:(id)object instanceOf:(NSString *)aClass +{ + if (!object) + return [aClass isEqualToString:@"nil"]; + + return [object isKindOfClass:NSClassFromString(aClass)]; +} + +- (NSString *)classNameOf:(id)object +{ + if (!object) + return @"nil"; + return NSStringFromClass([object class]); +} + +- (id)objectOfClass:(NSString *)aClass +{ + if ([aClass isEqualToString:@"NSNull"]) + return [NSNull null]; + if ([aClass isEqualToString:@"WebUndefined"]) + return [WebUndefined undefined]; + if ([aClass isEqualToString:@"NSCFBoolean"]) + return [NSNumber numberWithBool:true]; + if ([aClass isEqualToString:@"NSCFNumber"]) + return [NSNumber numberWithInt:1]; + if ([aClass isEqualToString:@"NSCFString"]) + return @""; + if ([aClass isEqualToString:@"WebScriptObject"]) + return self; + if ([aClass isEqualToString:@"NSArray"]) + return [NSArray array]; + + return nil; +} + +- (NSArray *)arrayOfString +{ + NSString *strings[3]; + strings[0] = @"one"; + strings[1] = @"two"; + strings[2] = @"three"; + NSArray *array = [NSArray arrayWithObjects:strings count:3]; + return array; +} + +- (BOOL)identityIsEqual:(WebScriptObject *)a :(WebScriptObject *)b +{ + if ([a isKindOfClass:[NSString class]] && [b isKindOfClass:[NSString class]]) + return [(NSString *)a isEqualToString:(NSString *)b]; + return a == b; +} + +- (long long)longLongRoundTrip:(long long)num +{ + return num; +} + +- (unsigned long long)unsignedLongLongRoundTrip:(unsigned long long)num +{ + return num; +} + +- (void)testValueForKey +{ + ASSERT(storedWebScriptObject); + + @try { + [storedWebScriptObject valueForKey:@"ThisKeyDoesNotExist"]; + } @catch (NSException *e) { + } + + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_join(pthread, 0); +} + +- (BOOL)testHasWebScriptKey:(NSString *)key +{ + ASSERT(storedWebScriptObject); + return [storedWebScriptObject hasWebScriptKey:key]; +} + +- (BOOL)testWrapperRoundTripping:(WebScriptObject *)webScriptObject +{ + JSObjectRef jsObject = [webScriptObject JSObject]; + + if (!jsObject) + return false; + + if (!webScriptObject) + return false; + + if ([[webScriptObject evaluateWebScript:@"({ })"] class] != [webScriptObject class]) + return false; + + [webScriptObject setValue:[NSNumber numberWithInt:666] forKey:@"key"]; + if (![[webScriptObject valueForKey:@"key"] isKindOfClass:[NSNumber class]] || + ![[webScriptObject valueForKey:@"key"] isEqualToNumber:[NSNumber numberWithInt:666]]) + return false; + + [webScriptObject removeWebScriptKey:@"key"]; + @try { + if ([webScriptObject valueForKey:@"key"]) + return false; + } @catch(NSException *exception) { + // NSObject throws an exception if the key doesn't exist. + } + + [webScriptObject setWebScriptValueAtIndex:0 value:webScriptObject]; + if ([webScriptObject webScriptValueAtIndex:0] != webScriptObject) + return false; + + if ([[webScriptObject stringRepresentation] isEqualToString:@"[Object object]"]) + return false; + + if ([webScriptObject callWebScriptMethod:@"returnThis" withArguments:nil] != webScriptObject) + return false; + + return true; +} + +- (void)accessStoredWebScriptObject +{ +#if !ASSERT_DISABLED + BOOL isWindowObject = [storedWebScriptObject isKindOfClass:[DOMAbstractView class]]; + JSObjectRef jsObject = [storedWebScriptObject JSObject]; + ASSERT((jsObject && isWindowObject) || (!jsObject && !isWindowObject)); +#endif + [storedWebScriptObject callWebScriptMethod:@"" withArguments:nil]; + [storedWebScriptObject evaluateWebScript:@""]; + [storedWebScriptObject setValue:[WebUndefined undefined] forKey:@"key"]; + [storedWebScriptObject valueForKey:@"key"]; + [storedWebScriptObject removeWebScriptKey:@"key"]; + [storedWebScriptObject stringRepresentation]; + [storedWebScriptObject webScriptValueAtIndex:0]; + [storedWebScriptObject setWebScriptValueAtIndex:0 value:[WebUndefined undefined]]; + [storedWebScriptObject setException:@"exception"]; +} + +- (void)storeWebScriptObject:(WebScriptObject *)webScriptObject +{ + if (webScriptObject == storedWebScriptObject) + return; + + [storedWebScriptObject release]; + storedWebScriptObject = [webScriptObject retain]; +} + +- (NSArray *)testArray +{ + return [NSArray array]; +} + +- (void)dealloc +{ + [storedWebScriptObject release]; + [super dealloc]; +} + +- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args +{ + // FIXME: Perhaps we should log that this has been called. + return nil; +} + +// MARK: - +// MARK: Testing Objective-C DOM HTML Bindings + +- (void)setSelectElement:(WebScriptObject *)element selectedIndex:(int)index allowingMultiple:(BOOL)allowingMultiple +{ + if (![element isKindOfClass:[DOMHTMLSelectElement class]]) + return; + + DOMHTMLSelectElement *select = (DOMHTMLSelectElement*)element; + [select _activateItemAtIndex:index allowMultipleSelection:allowingMultiple]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.h b/Tools/DumpRenderTree/mac/ObjCPlugin.h new file mode 100644 index 000000000..a6d3e50c1 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPlugin.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005 Apple Computer, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <Cocoa/Cocoa.h> + + +@interface ObjCPlugin : NSObject +{ + BOOL throwOnDealloc; +} + +- (void)removeBridgeRestrictions:(id)container; + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.m b/Tools/DumpRenderTree/mac/ObjCPlugin.m new file mode 100644 index 000000000..023eae17f --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPlugin.m @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 James G. Speth (speth@end.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "config.h" +#import "ObjCPlugin.h" + +#import <WebKit/WebKit.h> +#import <objc/objc-runtime.h> + +// === NSObject category to expose almost everything to JavaScript === + +// Warning: this class introduces huge security weaknesses, and should only be used +// for testing inside of DumpRenderTree, and only with trusted code. By default, it has +// the same restrictive behavior as the standard WebKit setup. However, scripts can use the +// plugin's removeBridgeRestrictions: method to open up almost total access to the Cocoa +// frameworks. + +static BOOL _allowsScriptsFullAccess = NO; + +@interface NSObject (ObjCScriptAccess) + ++ (void)setAllowsScriptsFullAccess:(BOOL)value; ++ (BOOL)allowsScriptsFullAccess; + +@end + +@implementation NSObject (ObjCScriptAccess) + ++ (void)setAllowsScriptsFullAccess:(BOOL)value +{ + _allowsScriptsFullAccess = value; +} + ++ (BOOL)allowsScriptsFullAccess +{ + return _allowsScriptsFullAccess; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + return !_allowsScriptsFullAccess; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + return nil; +} + +@end + +@interface JSObjC : NSObject { +} + +// expose some useful objc functions to the scripting environment +- (id)lookUpClass:(NSString *)name; +- (void)log:(NSString *)message; +- (id)retainObject:(id)obj; +- (id)classOfObject:(id)obj; +- (NSString *)classNameOfObject:(id)obj; + +@end + +@implementation JSObjC + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + return nil; +} + +- (id)invokeDefaultMethodWithArguments:(NSArray *)args +{ + // this is a useful shortcut for accessing objective-c classes from the scripting + // environment, e.g. 'var myObject = objc("NSObject").alloc().init();' + if ([args count] == 1) + return [self lookUpClass:[args objectAtIndex:0]]; + return nil; +} + +- (id)lookUpClass:(NSString *)name +{ + return NSClassFromString(name); +} + +- (void)log:(NSString *)message +{ + NSLog(@"%@", message); +} + +- (id)retainObject:(id)obj +{ + return [obj retain]; +} + +- (id)classOfObject:(id)obj +{ + return (id)[obj class]; +} + +- (NSString *)classNameOfObject:(id)obj +{ + return [obj className]; +} + +@end + +@implementation ObjCPlugin + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(removeBridgeRestrictions:)) + return NO; + + if (aSelector == @selector(echo:)) + return NO; + + if (aSelector == @selector(throwIfArgumentIsNotHello:)) + return NO; + + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(echo:)) + return @"echo"; + + if (aSelector == @selector(throwIfArgumentIsNotHello:)) + return @"throwIfArgumentIsNotHello"; + + return nil; +} + ++ (NSString *)webScriptNameForKey:(const char *)key +{ + if (strcmp(key, "throwOnDealloc") == 0) + return @"throwOnDealloc"; + + return nil; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char *)key +{ + if (strcmp(key, "throwOnDealloc") == 0) + return NO; + + return YES; +} + +- (void)removeBridgeRestrictions:(id)container +{ + // let scripts invoke any selector + [NSObject setAllowsScriptsFullAccess:YES]; + + // store a JSObjC instance into the provided container + JSObjC *objc = [[JSObjC alloc] init]; + [container setValue:objc forKey:@"objc"]; + [objc release]; +} + +- (id)echo:(id)obj +{ + return obj; +} + +- (void)throwIfArgumentIsNotHello:(NSString *)str +{ + if (![str isEqualToString:@"Hello"]) + [WebScriptObject throwException:[NSString stringWithFormat:@"%@ != Hello", str]]; +} + +- (void)dealloc +{ + if (throwOnDealloc) + [WebScriptObject throwException:@"Throwing exception on dealloc of ObjCPlugin"]; + + [super dealloc]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.h b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h new file mode 100644 index 000000000..1e81b21f4 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <Cocoa/Cocoa.h> + + +@interface ObjCPluginFunction : NSObject +{ +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.m b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m new file mode 100644 index 000000000..5bf3617fc --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "config.h" +#import "ObjCPluginFunction.h" + + +@implementation ObjCPluginFunction + +- (id)invokeDefaultMethodWithArguments:(NSArray *)args +{ + return @"test"; +} + +@end diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c new file mode 100644 index 000000000..35f051c14 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 <sys/sysctl.h> + +int processIsCrashing(int pid) +{ + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; + struct kinfo_proc info; + size_t bufferSize = sizeof(info); + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &info, &bufferSize, 0, 0)) { + perror("sysctl"); + return 0; + } + + struct extern_proc proc = info.kp_proc; + + // The process is crashing if it is waiting to exit, is not a zombie, and has a non-zero exit code. + return proc.p_stat != SZOMB && (proc.p_flag & P_WEXIT) && proc.p_xstat; +} diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm new file mode 100644 index 000000000..7b4ea34e5 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm @@ -0,0 +1,54 @@ +# This file was automatically generated by SWIG +package DumpRenderTreeSupport; +require Exporter; +require DynaLoader; +@ISA = qw(Exporter DynaLoader); +package DumpRenderTreeSupportc; +bootstrap DumpRenderTreeSupport; +package DumpRenderTreeSupport; +@EXPORT = qw( ); + +# ---------- BASE METHODS ------------- + +package DumpRenderTreeSupport; + +sub TIEHASH { + my ($classname,$obj) = @_; + return bless $obj, $classname; +} + +sub CLEAR { } + +sub FIRSTKEY { } + +sub NEXTKEY { } + +sub FETCH { + my ($self,$field) = @_; + my $member_func = "swig_${field}_get"; + $self->$member_func(); +} + +sub STORE { + my ($self,$field,$newval) = @_; + my $member_func = "swig_${field}_set"; + $self->$member_func($newval); +} + +sub this { + my $ptr = shift; + return tied(%$ptr); +} + + +# ------- FUNCTION WRAPPERS -------- + +package DumpRenderTreeSupport; + +*processIsCrashing = *DumpRenderTreeSupportc::processIsCrashing; + +# ------- VARIABLE STUBS -------- + +package DumpRenderTreeSupport; + +1; diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c new file mode 100644 index 000000000..f73498934 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c @@ -0,0 +1,1167 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.24 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + + +#ifndef SWIG_TEMPLATE_DISAMBIGUATOR +# if defined(__SUNPRO_CC) +# define SWIG_TEMPLATE_DISAMBIGUATOR template +# else +# define SWIG_TEMPLATE_DISAMBIGUATOR +# endif +#endif + +/*********************************************************************** + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * + ************************************************************************/ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "1" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +#define SWIG_QUOTE_STRING(x) #x +#define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +#define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +#define SWIG_TYPE_TABLE_NAME +#endif + +#include <string.h> + +#ifndef SWIGINLINE +#if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +#else +# define SWIGINLINE +#endif +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ +#ifndef SWIGRUNTIME +#define SWIGRUNTIME static +#endif +#ifndef SWIGRUNTIMEINLINE +#define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +typedef struct swig_type_info { + const char *name; + swig_converter_func converter; + const char *str; + void *clientdata; + swig_dycast_func dcast; + struct swig_type_info *next; + struct swig_type_info *prev; +} swig_type_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class<int>" == "Class<int >", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return *f1 - *f2; + } + return (l1 - f1) - (l2 - f2); +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = SWIG_TypeNameComp(nb, ne, tb, te) == 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Register a type mapping with the type-checking +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeRegisterTL(swig_type_info **tl, swig_type_info *ti) { + swig_type_info *tc, *head, *ret, *next; + /* Check to see if this type has already been registered */ + tc = *tl; + while (tc) { + /* check simple type equivalence */ + int typeequiv = (strcmp(tc->name, ti->name) == 0); + /* check full type equivalence, resolving typedefs */ + if (!typeequiv) { + /* only if tc is not a typedef (no '|' on it) */ + if (tc->str && ti->str && !strstr(tc->str,"|")) { + typeequiv = SWIG_TypeEquiv(ti->str,tc->str); + } + } + if (typeequiv) { + /* Already exists in the table. Just add additional types to the list */ + if (ti->clientdata) tc->clientdata = ti->clientdata; + head = tc; + next = tc->next; + goto l1; + } + tc = tc->prev; + } + head = ti; + next = 0; + + /* Place in list */ + ti->prev = *tl; + *tl = ti; + + /* Build linked lists */ + l1: + ret = head; + tc = ti + 1; + /* Patch up the rest of the links */ + while (tc->name) { + head->next = tc; + tc->prev = head; + head = tc; + tc++; + } + if (next) next->prev = head; + head->next = next; + + return ret; +} + +/* + Check the typename +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + swig_type_info *s; + if (!ty) return 0; /* Void pointer */ + s = ty->next; /* First element always just a name */ + do { + if (strcmp(s->name,c) == 0) { + if (s == ty->next) return s; + /* Move s to the top of the linked list */ + s->prev->next = s->next; + if (s->next) { + s->next->prev = s->prev; + } + /* Insert s as second element in the list */ + s->next = ty->next; + if (ty->next) ty->next->prev = s; + ty->next = s; + s->prev = ty; + return s; + } + s = s->next; + } while (s && (s != ty->next)); + return 0; +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_type_info *ty, void *ptr) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Search for a swig_type_info structure +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryTL(swig_type_info *tl, const char *name) { + swig_type_info *ty = tl; + while (ty) { + if (ty->str && (SWIG_TypeEquiv(ty->str,name))) return ty; + if (ty->name && (strcmp(name,ty->name) == 0)) return ty; + ty = ty->prev; + } + return 0; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientDataTL(swig_type_info *tl, swig_type_info *ti, void *clientdata) { + swig_type_info *tc, *equiv; + if (ti->clientdata) return; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + equiv = ti->next; + while (equiv) { + if (!equiv->converter) { + tc = tl; + while (tc) { + if ((strcmp(tc->name, equiv->name) == 0)) + SWIG_TypeClientDataTL(tl,tc,clientdata); + tc = tc->prev; + } + } + equiv = equiv->next; + } +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static char hex[17] = "0123456789abcdef"; + unsigned char *u = (unsigned char *) ptr; + const unsigned char *eu = u + sz; + register unsigned char uu; + for (; u != eu; ++u) { + uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register int d = *(c++); + register unsigned char uu = 0; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + This function will propagate the clientdata field of type to any new + swig_type_info structures that have been added into the list of + equivalent types. It is like calling SWIG_TypeClientData(type, + clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientDataTL(swig_type_info *tl, swig_type_info *type) { + swig_type_info *equiv = type->next; + swig_type_info *tc; + if (!type->clientdata) return; + while (equiv) { + if (!equiv->converter) { + tc = tl; + while (tc) { + if ((strcmp(tc->name, equiv->name) == 0) && !tc->clientdata) + SWIG_TypeClientDataTL(tl,tc, type->clientdata); + tc = tc->prev; + } + } + equiv = equiv->next; + } +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/*********************************************************************** + * common.swg + * + * This file contains generic SWIG runtime support for pointer + * type checking as well as a few commonly used macros to control + * external linkage. + * + * Author : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (c) 1999-2000, The University of Chicago + * + * This file may be freely redistributed without license or fee provided + * this copyright message remains intact. + ************************************************************************/ + + +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if !defined(STATIC_LINKED) +# define SWIGEXPORT(a) __declspec(dllexport) a +# else +# define SWIGEXPORT(a) a +# endif +#else +# define SWIGEXPORT(a) a +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/*************************************************************************/ + + +/* The static type info list */ + +static swig_type_info *swig_type_list = 0; +static swig_type_info **swig_type_list_handle = &swig_type_list; + + +/* Register a type mapping with the type-checking */ +static swig_type_info * +SWIG_TypeRegister(swig_type_info *ti) { + return SWIG_TypeRegisterTL(swig_type_list_handle, ti); +} + +/* Search for a swig_type_info structure */ +static swig_type_info * +SWIG_TypeQuery(const char *name) { + return SWIG_TypeQueryTL(*swig_type_list_handle, name); +} + +/* Set the clientdata field for a type */ +static void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientDataTL(*swig_type_list_handle, ti, clientdata); +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +static void +SWIG_PropagateClientData(swig_type_info *type) { + SWIG_PropagateClientDataTL(*swig_type_list_handle, type); +} + +#ifdef __cplusplus +} +#endif + +/* ---------------------------------------------------------------------- -*- c -*- + * perl5.swg + * + * Perl5 runtime library + * $Header: /cvsroot/swig/SWIG/Lib/perl5/perlrun.swg,v 1.20 2004/11/29 23:13:57 wuzzeb Exp $ + * ----------------------------------------------------------------------------- */ + +#define SWIGPERL +#define SWIGPERL5 +#ifdef __cplusplus +/* Needed on some windows machines---since MS plays funny games with the header files under C++ */ +#include <math.h> +#include <stdlib.h> +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +/* Get rid of free and malloc defined by perl */ +#undef free +#undef malloc + +#ifndef pTHX_ +#define pTHX_ +#endif + +#include <string.h> +#ifdef __cplusplus +} +#endif + +/* Macro to call an XS function */ + +#ifdef PERL_OBJECT +# define SWIG_CALLXS(_name) _name(cv,pPerl) +#else +# ifndef MULTIPLICITY +# define SWIG_CALLXS(_name) _name(cv) +# else +# define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) +# endif +#endif + +/* Contract support */ + +#define SWIG_contract_assert(expr,msg) if (!(expr)) { SWIG_croak(msg); } else + +/* Note: SwigMagicFuncHack is a typedef used to get the C++ compiler to just shut up already */ + +#ifdef PERL_OBJECT +#define MAGIC_PPERL CPerlObj *pPerl = (CPerlObj *) this; +typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *); + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (CPerlObj::*SwigMagicFuncHack)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) +#define SWIGCLASS_STATIC +#else +#define MAGIC_PPERL +#define SWIGCLASS_STATIC static +#ifndef MULTIPLICITY +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) +typedef int (*SwigMagicFunc)(SV *, MAGIC *); + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFuncHack)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + + +#else +#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b) +typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *); +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFuncHack)(struct interpreter *, SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#endif +#endif + +#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE) +#define PerlIO_exportFILE(fh,fl) (FILE*)(fh) +#endif + +/* Modifications for newer Perl 5.005 releases */ + +#if !defined(PERL_REVISION) || ((PERL_REVISION >= 5) && ((PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION < 50)))) +# ifndef PL_sv_yes +# define PL_sv_yes sv_yes +# endif +# ifndef PL_sv_undef +# define PL_sv_undef sv_undef +# endif +# ifndef PL_na +# define PL_na na +# endif +#endif + +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWIG_OWNER 1 +#define SWIG_SHADOW 2 + +/* Common SWIG API */ + +#ifdef PERL_OBJECT +# define SWIG_ConvertPtr(obj, pp, type, flags) \ + SWIG_Perl_ConvertPtr(pPerl, obj, pp, type, flags) +# define SWIG_NewPointerObj(p, type, flags) \ + SWIG_Perl_NewPointerObj(pPerl, p, type, flags) +# define SWIG_MakePackedObj(sv, p, s, type) \ + SWIG_Perl_MakePackedObj(pPerl, sv, p, s, type) +# define SWIG_ConvertPacked(obj, p, s, type, flags) \ + SWIG_Perl_ConvertPacked(pPerl, obj, p, s, type, flags) + +#else +# define SWIG_ConvertPtr(obj, pp, type, flags) \ + SWIG_Perl_ConvertPtr(obj, pp, type, flags) +# define SWIG_NewPointerObj(p, type, flags) \ + SWIG_Perl_NewPointerObj(p, type, flags) +# define SWIG_MakePackedObj(sv, p, s, type) \ + SWIG_Perl_MakePackedObj(sv, p, s, type ) +# define SWIG_ConvertPacked(obj, p, s, type, flags) \ + SWIG_Perl_ConvertPacked(obj, p, s, type, flags) +#endif + +/* Perl-specific API */ +#ifdef PERL_OBJECT +# define SWIG_MakePtr(sv, ptr, type, flags) \ + SWIG_Perl_MakePtr(pPerl, sv, ptr, type, flags) +# define SWIG_SetError(str) \ + SWIG_Perl_SetError(pPerl, str) +#else +# define SWIG_MakePtr(sv, ptr, type, flags) \ + SWIG_Perl_MakePtr(sv, ptr, type, flags) +# define SWIG_SetError(str) \ + SWIG_Perl_SetError(str) +# define SWIG_SetErrorSV(str) \ + SWIG_Perl_SetErrorSV(str) +#endif + +#define SWIG_SetErrorf SWIG_Perl_SetErrorf + + +#ifdef PERL_OBJECT +# define SWIG_MAYBE_PERL_OBJECT CPerlObj *pPerl, +#else +# define SWIG_MAYBE_PERL_OBJECT +#endif + +static swig_type_info ** +SWIG_Perl_GetTypeListHandle() { + static void *type_pointer = (void *)0; + SV *pointer; + + /* first check if pointer already created */ + if (!type_pointer) { + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE); + if (pointer && SvOK(pointer)) { + type_pointer = INT2PTR(swig_type_info **, SvIV(pointer)); + } + } + + return (swig_type_info **) type_pointer; +} + +/* + Search for a swig_type_info structure + */ +SWIGRUNTIMEINLINE swig_type_info * +SWIG_Perl_GetTypeList() { + swig_type_info **tlh = SWIG_Perl_GetTypeListHandle(); + return tlh ? *tlh : (swig_type_info*)0; +} + +#define SWIG_Runtime_GetTypeList SWIG_Perl_GetTypeList + +static swig_type_info * +SWIG_Perl_TypeCheckRV(SWIG_MAYBE_PERL_OBJECT SV *rv, swig_type_info *ty) { + swig_type_info *s; + if (!ty) return 0; /* Void pointer */ + s = ty->next; /* First element always just a name */ + do { + if (sv_derived_from(rv, (char *) s->name)) { + if (s == ty->next) return s; + /* Move s to the top of the linked list */ + s->prev->next = s->next; + if (s->next) { + s->next->prev = s->prev; + } + /* Insert s as second element in the list */ + s->next = ty->next; + if (ty->next) ty->next->prev = s; + ty->next = s; + s->prev = ty; + return s; + } + s = s->next; + } while (s && (s != ty->next)); + return 0; +} + +/* Function for getting a pointer value */ + +static int +SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) { + swig_type_info *tc; + void *voidptr = (void *)0; + + /* If magical, apply more magic */ + if (SvGMAGICAL(sv)) + mg_get(sv); + + /* Check to see if this is an object */ + if (sv_isobject(sv)) { + SV *tsv = (SV*) SvRV(sv); + IV tmp = 0; + if ((SvTYPE(tsv) == SVt_PVHV)) { + MAGIC *mg; + if (SvMAGICAL(tsv)) { + mg = mg_find(tsv,'P'); + if (mg) { + sv = mg->mg_obj; + if (sv_isobject(sv)) { + tmp = SvIV((SV*)SvRV(sv)); + } + } + } else { + return -1; + } + } else { + tmp = SvIV((SV*)SvRV(sv)); + } + voidptr = (void *)tmp; + if (!_t) { + *(ptr) = voidptr; + return 0; + } + } else if (! SvOK(sv)) { /* Check for undef */ + *(ptr) = (void *) 0; + return 0; + } else if (SvTYPE(sv) == SVt_RV) { /* Check for NULL pointer */ + *(ptr) = (void *) 0; + if (!SvROK(sv)) + return 0; + else + return -1; + } else { /* Don't know what it is */ + *(ptr) = (void *) 0; + return -1; + } + if (_t) { + /* Now see if the types match */ + char *_c = HvNAME(SvSTASH(SvRV(sv))); + tc = SWIG_TypeCheck(_c,_t); + if (!tc) { + *ptr = voidptr; + return -1; + } + *ptr = SWIG_TypeCast(tc,voidptr); + return 0; + } + *ptr = voidptr; + return 0; +} + +static void +SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) { + if (ptr && (flags & SWIG_SHADOW)) { + SV *self; + SV *obj=newSV(0); + HV *hash=newHV(); + HV *stash; + sv_setref_pv(obj, (char *) t->name, ptr); + stash=SvSTASH(SvRV(obj)); + if (flags & SWIG_OWNER) { + HV *hv; + GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE); + if (!isGV(gv)) + gv_init(gv, stash, "OWNER", 5, FALSE); + hv=GvHVn(gv); + hv_store_ent(hv, obj, newSViv(1), 0); + } + sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0); + SvREFCNT_dec(obj); + self=newRV_noinc((SV *)hash); + sv_setsv(sv, self); + SvREFCNT_dec((SV *)self); + sv_bless(sv, stash); + } + else { + sv_setref_pv(sv, (char *) t->name, ptr); + } +} + +static SWIGINLINE SV * +SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) { + SV *result = sv_newmortal(); + SWIG_MakePtr(result, ptr, t, flags); + return result; +} + +static void + SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) { + char result[1024]; + char *r = result; + if ((2*sz + 1 + strlen(type->name)) > 1000) return; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + strcpy(r,type->name); + sv_setpv(sv, result); +} + +/* Convert a packed value value */ +static int +SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty, int flags) { + swig_type_info *tc; + const char *c = 0; + + if ((!obj) || (!SvOK(obj))) return -1; + c = SvPV(obj, PL_na); + /* Pointer values must start with leading underscore */ + if (*c != '_') return -1; + c++; + c = SWIG_UnpackData(c,ptr,sz); + if (ty) { + tc = SWIG_TypeCheck(c,ty); + if (!tc) return -1; + } + return 0; +} + +static SWIGINLINE void +SWIG_Perl_SetError(SWIG_MAYBE_PERL_OBJECT const char *error) { + if (error) sv_setpv(perl_get_sv("@", TRUE), error); +} + +static SWIGINLINE void +SWIG_Perl_SetErrorSV(SWIG_MAYBE_PERL_OBJECT SV *error) { + if (error) sv_setsv(perl_get_sv("@", TRUE), error); +} + +static void +SWIG_Perl_SetErrorf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + sv_vsetpvfn(perl_get_sv("@", TRUE), fmt, strlen(fmt), &args, Null(SV**), 0, Null(bool*)); + va_end(args); +} + +/* Macros for low-level exception handling */ +#define SWIG_fail goto fail +#define SWIG_croak(x) { SWIG_SetError(x); goto fail; } +#define SWIG_croakSV(x) { SWIG_SetErrorSV(x); goto fail; } +/* most preprocessors do not support vararg macros :-( */ +/* #define SWIG_croakf(x...) { SWIG_SetErrorf(x); goto fail; } */ + + +typedef XS(SwigPerlWrapper); +typedef SwigPerlWrapper *SwigPerlWrapperPtr; + +/* Structure for command table */ +typedef struct { + const char *name; + SwigPerlWrapperPtr wrapper; +} swig_command_info; + +/* Information for constant table */ + +#define SWIG_INT 1 +#define SWIG_FLOAT 2 +#define SWIG_STRING 3 +#define SWIG_POINTER 4 +#define SWIG_BINARY 5 + +/* Constant information structure */ +typedef struct swig_constant_info { + int type; + const char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_constant_info; + +#ifdef __cplusplus +} +#endif + +/* Structure for variable table */ +typedef struct { + const char *name; + SwigMagicFunc set; + SwigMagicFunc get; + swig_type_info **type; +} swig_variable_info; + +/* Magic variable code */ +#ifndef PERL_OBJECT +#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c) + #ifndef MULTIPLICITY + static void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) { + #else + static void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) { + #endif +#else +# define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c) +static void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) { +#endif + MAGIC *mg; + sv_magic(sv,sv,'U',(char *) name,strlen(name)); + mg = mg_find(sv,'U'); + mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL)); + mg->mg_virtual->svt_get = (SwigMagicFuncHack) get; + mg->mg_virtual->svt_set = (SwigMagicFuncHack) set; + mg->mg_virtual->svt_len = 0; + mg->mg_virtual->svt_clear = 0; + mg->mg_virtual->svt_free = 0; +} + + + + + + +#ifdef do_open + #undef do_open +#endif +#ifdef do_close + #undef do_close +#endif +#ifdef scalar + #undef scalar +#endif +#ifdef list + #undef list +#endif +#ifdef apply + #undef apply +#endif +#ifdef convert + #undef convert +#endif +#ifdef Error + #undef Error +#endif +#ifdef form + #undef form +#endif +#ifdef vform + #undef vform +#endif +#ifdef LABEL + #undef LABEL +#endif +#ifdef METHOD + #undef METHOD +#endif +#ifdef Move + #undef Move +#endif +#ifdef yylex + #undef yylex +#endif +#ifdef yyparse + #undef yyparse +#endif +#ifdef yyerror + #undef yyerror +#endif +#ifdef invert + #undef invert +#endif +#ifdef ref + #undef ref +#endif +#ifdef ENTER + #undef ENTER +#endif + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +static swig_type_info *swig_types[1]; + +/* -------- TYPES TABLE (END) -------- */ + +#define SWIG_init boot_DumpRenderTreeSupport + +#define SWIG_name "DumpRenderTreeSupportc::boot_DumpRenderTreeSupport" +#define SWIG_prefix "DumpRenderTreeSupportc::" + +#ifdef __cplusplus +extern "C" +#endif +#ifndef PERL_OBJECT +#ifndef MULTIPLICITY +SWIGEXPORT(void) SWIG_init (CV* cv); +#else +SWIGEXPORT(void) SWIG_init (pTHXo_ CV* cv); +#endif +#else +SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *); +#endif + +int processIsCrashing(int); +#ifdef PERL_OBJECT +#define MAGIC_CLASS _wrap_DumpRenderTreeSupport_var:: +class _wrap_DumpRenderTreeSupport_var : public CPerlObj { +public: +#else +#define MAGIC_CLASS +#endif +SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *sv, MAGIC *mg) { + MAGIC_PPERL + sv = sv; mg = mg; + croak("Value is read-only."); + return 0; +} + + +#ifdef PERL_OBJECT +}; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +XS(_wrap_processIsCrashing) { + { + int arg1 ; + int result; + int argvi = 0; + dXSARGS; + + if ((items < 1) || (items > 1)) { + SWIG_croak("Usage: processIsCrashing(pid);"); + } + arg1 = (int) SvIV(ST(0)); + result = (int)processIsCrashing(arg1); + + ST(argvi) = sv_newmortal(); + sv_setiv(ST(argvi++), (IV) result); + XSRETURN(argvi); + fail: + ; + } + croak(Nullch); +} + + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + + +static swig_type_info *swig_types_initial[] = { +0 +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_constant_info swig_constants[] = { +{0,0,0,0,0,0} +}; +#ifdef __cplusplus +} +#endif +static swig_variable_info swig_variables[] = { +{0,0,0,0} +}; +static swig_command_info swig_commands[] = { +{"DumpRenderTreeSupportc::processIsCrashing", _wrap_processIsCrashing}, +{0,0} +}; + + +static void SWIG_Perl_SetTypeListHandle(swig_type_info **handle) { + SV *pointer; + + /* create a new pointer */ + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE); + sv_setiv(pointer, PTR2IV(swig_type_list_handle)); +} + +static swig_type_info ** +SWIG_Perl_LookupTypePointer(swig_type_info **type_list_handle) { + swig_type_info **type_pointer; + + /* first check if module already created */ + type_pointer = SWIG_Perl_GetTypeListHandle(); + if (type_pointer) { + return type_pointer; + } else { + /* create a new module and variable */ + SWIG_Perl_SetTypeListHandle(type_list_handle); + return type_list_handle; + } +} + + +#ifdef __cplusplus +extern "C" +#endif + +XS(SWIG_init) { + dXSARGS; + int i; + static int _init = 0; + if (!_init) { + swig_type_list_handle = SWIG_Perl_LookupTypePointer(swig_type_list_handle); + for (i = 0; swig_types_initial[i]; i++) { + swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]); + } + _init = 1; + } + + /* Install commands */ + for (i = 0; swig_commands[i].name; i++) { + newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__); + } + + /* Install variables */ + for (i = 0; swig_variables[i].name; i++) { + SV *sv; + sv = perl_get_sv((char*) swig_variables[i].name, TRUE | 0x2); + if (swig_variables[i].type) { + SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0); + } else { + sv_setiv(sv,(IV) 0); + } + swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); + } + + /* Install constant */ + for (i = 0; swig_constants[i].type; i++) { + SV *sv; + sv = perl_get_sv((char*)swig_constants[i].name, TRUE | 0x2); + switch(swig_constants[i].type) { + case SWIG_INT: + sv_setiv(sv, (IV) swig_constants[i].lvalue); + break; + case SWIG_FLOAT: + sv_setnv(sv, (double) swig_constants[i].dvalue); + break; + case SWIG_STRING: + sv_setpv(sv, (char *) swig_constants[i].pvalue); + break; + case SWIG_POINTER: + SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0); + break; + case SWIG_BINARY: + SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype)); + break; + default: + break; + } + SvREADONLY_on(sv); + } + + ST(0) = &PL_sv_yes; + XSRETURN(1); +} + diff --git a/Tools/DumpRenderTree/mac/PerlSupport/Makefile b/Tools/DumpRenderTree/mac/PerlSupport/Makefile new file mode 100644 index 000000000..f7808dc3c --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/Makefile @@ -0,0 +1,82 @@ +# Copyright (C) 2009 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + +CONFIGURATION_BUILD_DIR ?= . +OUTPUT_DIR=$(CONFIGURATION_BUILD_DIR) + +WRAPPER_DIR=$(OUTPUT_DIR)/DerivedSources/DumpRenderTree +WRAPPER=$(WRAPPER_DIR)/DumpRenderTreeSupport_wrap.c +PERL_MODULE=$(OUTPUT_DIR)/DumpRenderTreeSupport.pm +DYLIB=$(OUTPUT_DIR)/DumpRenderTreeSupport.dylib +DUMPRENDERTREE=$(OUTPUT_DIR)/DumpRenderTree +PERL=/usr/bin/perl + +OSX_VERSION = $(shell sw_vers -productVersion | cut -d. -f 2) +ifeq "$(OSX_VERSION)" "5" +GENERATE_WRAPPER = YES +endif +ifeq "$(OSX_VERSION)" "6" +GENERATE_WRAPPER = NO +endif + +ifeq "$(GENERATE_WRAPPER)" "YES" + +SWIG=/usr/bin/swig + +all: $(DYLIB) $(PERL_MODULE) + +$(WRAPPER) $(PERL_MODULE): DumpRenderTreeSupport.c $(DUMPRENDERTREE) + mkdir -p $(WRAPPER_DIR) + $(SWIG) -o $(WRAPPER) -outdir $(OUTPUT_DIR) -perl -module DumpRenderTreeSupport $< + + +else + + +all: $(DYLIB) $(PERL_MODULE) + +$(WRAPPER): DumpRenderTreeSupport_wrapPregenerated.c $(DUMPRENDERTREE) + mkdir -p $(WRAPPER_DIR) + cp DumpRenderTreeSupport_wrapPregenerated.c $(WRAPPER) + +$(PERL_MODULE): DumpRenderTreeSupportPregenerated.pm $(DUMPRENDERTREE) + cp DumpRenderTreeSupportPregenerated.pm $(PERL_MODULE) + + +endif + +$(DYLIB): DumpRenderTreeSupport.c $(WRAPPER) + gcc -g -dynamiclib -o $(DYLIB) `$(PERL) -MExtUtils::Embed -eperl_inc` `$(PERL) -MExtUtils::Embed -e'my $$opts = ldopts(0); $$opts =~ s/-arch [^ ]*( |$$)//g; print $$opts, " -arch ", join(" -arch ", split(" ",$$ENV{ARCHS}))'` $^ + +clean: + rm -f $(WRAPPER) $(PERL_MODULE) $(DYLIB) + +installhdrs installsrc: + +INSTALL_LOCATION=$(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH) + +install: all + mkdir -p $(INSTALL_LOCATION) + cp $(DYLIB) $(INSTALL_LOCATION)/DumpRenderTreeSupport.dylib + cp $(PERL_MODULE) $(INSTALL_LOCATION)/DumpRenderTreeSupport.pm + diff --git a/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm new file mode 100644 index 000000000..3d6fbdd59 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupport.h" +#include "PixelDumpSupportCG.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <CoreGraphics/CGBitmapContext.h> +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> + +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebViewPrivate.h> + + +// To ensure pixel tests consistency, we need to always render in the same colorspace. +// Unfortunately, because of AppKit / WebKit constraints, we can't render directly in the colorspace of our choice. +// This implies we have to temporarily change the profile of the main display to the colorspace we want to render into. +// We also need to make sure the CGBitmapContext we return is in that same colorspace. + +#define PROFILE_PATH "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" // FIXME: This cannot be more than CS_MAX_PATH (256 characters) + +static CMProfileLocation sInitialProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase + +void restoreMainDisplayColorProfile(int ignored) +{ + // This is used as a signal handler, and thus the calls into ColorSync are unsafe + // But we might as well try to restore the user's color profile, we're going down anyway... + if (sInitialProfileLocation.locType != cmNoProfileBase) { + const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; + int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &sInitialProfileLocation); + if (error) + fprintf(stderr, "Failed to restore initial color profile for main display! Open System Preferences > Displays > Color and manually re-select the profile. (Error: %i)\n", error); + sInitialProfileLocation.locType = cmNoProfileBase; + } +} + +void setupMainDisplayColorProfile() +{ + const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; + int error; + + CMProfileRef profile = 0; + error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile); + if (!error) { + UInt32 size = sizeof(CMProfileLocation); + error = NCMGetProfileLocation(profile, &sInitialProfileLocation, &size); + CMCloseProfile(profile); + } + if (error) { + fprintf(stderr, "Failed to retrieve current color profile for main display, thus it won't be changed. Many pixel tests may fail as a result. (Error: %i)\n", error); + sInitialProfileLocation.locType = cmNoProfileBase; + return; + } + + CMProfileLocation location; + location.locType = cmPathBasedProfile; + strcpy(location.u.pathLoc.path, PROFILE_PATH); + error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location); + if (error) { + fprintf(stderr, "Failed to set color profile for main display! Many pixel tests may fail as a result. (Error: %i)\n", error); + sInitialProfileLocation.locType = cmNoProfileBase; + return; + } + + // Other signals are handled in installSignalHandlers() which also calls restoreMainDisplayColorProfile() + signal(SIGINT, restoreMainDisplayColorProfile); + signal(SIGHUP, restoreMainDisplayColorProfile); + signal(SIGTERM, restoreMainDisplayColorProfile); +} + +static PassRefPtr<BitmapContext> createBitmapContext(size_t pixelsWide, size_t pixelsHigh, size_t& rowBytes, void*& buffer) +{ + rowBytes = (4 * pixelsWide + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance + + buffer = calloc(pixelsHigh, rowBytes); + if (!buffer) + return 0; + + static CGColorSpaceRef colorSpace = 0; + if (!colorSpace) { + CMProfileLocation location; + location.locType = cmPathBasedProfile; + strcpy(location.u.pathLoc.path, PROFILE_PATH); + CMProfileRef profile; + if (CMOpenProfile(&profile, &location) == noErr) { + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(profile); + CMCloseProfile(profile); + } + } + + CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); // Use ARGB8 on PPC or BGRA8 on X86 to improve CG performance + if (!context) { + free(buffer); + return 0; + } + + return BitmapContext::createByAdoptingBitmapAndContext(buffer, context); +} + +static void paintRepaintRectOverlay(WebView* webView, CGContextRef context) +{ + CGRect viewRect = NSRectToCGRect([webView bounds]); + + CGContextSaveGState(context); + + // Using a transparency layer is easier than futzing with clipping. + CGContextBeginTransparencyLayer(context, 0); + + // Flip the context. + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -viewRect.size.height); + + CGContextSetRGBFillColor(context, 0, 0, 0, static_cast<CGFloat>(0.66)); + CGContextFillRect(context, viewRect); + + NSArray *repaintRects = [webView trackedRepaintRects]; + if (repaintRects) { + + for (NSValue *value in repaintRects) { + CGRect currRect = NSRectToCGRect([value rectValue]); + CGContextClearRect(context, currRect); + } + } + + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); +} + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) +{ + WebView* view = [mainFrame webView]; + + // If the WebHTMLView uses accelerated compositing, we need for force the on-screen capture path + // and also force Core Animation to start its animations with -display since the DRT window has autodisplay disabled. + if ([view _isUsingAcceleratedCompositing]) + onscreen = YES; + + float deviceScaleFactor = [view _backingScaleFactor]; + NSSize webViewSize = [view frame].size; + size_t pixelsWide = static_cast<size_t>(webViewSize.width * deviceScaleFactor); + size_t pixelsHigh = static_cast<size_t>(webViewSize.height * deviceScaleFactor); + size_t rowBytes = 0; + void* buffer = 0; + RefPtr<BitmapContext> bitmapContext = createBitmapContext(pixelsWide, pixelsHigh, rowBytes, buffer); + if (!bitmapContext) + return 0; + CGContextRef context = bitmapContext->cgContext(); + CGContextScaleCTM(context, deviceScaleFactor, deviceScaleFactor); + + NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; + ASSERT(nsContext); + + if (incrementalRepaint) { + if (sweepHorizontally) { + for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++) + [view displayRectIgnoringOpacity:column inContext:nsContext]; + } else { + for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++) + [view displayRectIgnoringOpacity:line inContext:nsContext]; + } + } else { + if (deviceScaleFactor != 1) { + // Call displayRectIgnoringOpacity for HiDPI tests since it ensures we paint directly into the context + // that we have appropriately sized and scaled. + [view displayRectIgnoringOpacity:[view bounds] inContext:nsContext]; + if ([view isTrackingRepaints]) + paintRepaintRectOverlay(view, context); + } else if (onscreen) { + // displayIfNeeded does not update the CA layers if the layer-hosting view was not marked as needing display, so + // we're at the mercy of CA's display-link callback to update layers in time. So we need to force a display of the view + // to get AppKit to update the CA layers synchronously. + // FIXME: this will break repaint testing if we have compositing in repaint tests + // (displayWebView() painted gray over the webview, but we'll be making everything repaint again). + [view display]; + + // Ask the window server to provide us a composited version of the *real* window content including surfaces (i.e. OpenGL content) + // Note that the returned image might differ very slightly from the window backing because of dithering artifacts in the window server compositor + CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque); + CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); + CGImageRelease(image); + + if ([view isTrackingRepaints]) + paintRepaintRectOverlay(view, context); + } else { + // Make sure the view has been painted. + [view displayIfNeeded]; + + // Grab directly the contents of the window backing buffer (this ignores any surfaces on the window) + // FIXME: This path is suboptimal: data is read from window backing store, converted to RGB8 then drawn again into an RGBA8 bitmap + [view lockFocus]; + NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]] autorelease]; + [view unlockFocus]; + + RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; + [NSGraphicsContext setCurrentContext:nsContext]; + [imageRep draw]; + + if ([view isTrackingRepaints]) + paintRepaintRectOverlay(view, context); + + [NSGraphicsContext setCurrentContext:savedContext.get()]; + } + } + + if (drawSelectionRect) { + NSView *documentView = [[mainFrame frameView] documentView]; + ASSERT([documentView conformsToProtocol:@protocol(WebDocumentSelection)]); + NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil]; + CGContextSaveGState(context); + CGContextSetLineWidth(context, 1.0); + CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); + CGContextStrokeRect(context, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); + CGContextRestoreGState(context); + } + + return bitmapContext.release(); +} + +PassRefPtr<BitmapContext> createPagedBitmapContext() +{ + int pageWidthInPixels = LayoutTestController::maxViewWidth; + int pageHeightInPixels = LayoutTestController::maxViewHeight; + int numberOfPages = [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels]; + size_t rowBytes = 0; + void* buffer = 0; + + RefPtr<BitmapContext> bitmapContext = createBitmapContext(pageWidthInPixels, numberOfPages * (pageHeightInPixels + 1) - 1, rowBytes, buffer); + [mainFrame printToCGContext:bitmapContext->cgContext():pageWidthInPixels:pageHeightInPixels]; + return bitmapContext.release(); +} diff --git a/Tools/DumpRenderTree/mac/PlainTextController.h b/Tools/DumpRenderTree/mac/PlainTextController.h new file mode 100644 index 000000000..1488f2fde --- /dev/null +++ b/Tools/DumpRenderTree/mac/PlainTextController.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + */ + +@interface PlainTextController : NSObject ++ (PlainTextController *)sharedPlainTextController; +@end diff --git a/Tools/DumpRenderTree/mac/PlainTextController.mm b/Tools/DumpRenderTree/mac/PlainTextController.mm new file mode 100644 index 000000000..eb89bce4d --- /dev/null +++ b/Tools/DumpRenderTree/mac/PlainTextController.mm @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#import "PlainTextController.h" + +#import <WebKit/WebKit.h> + +@implementation PlainTextController + ++ (PlainTextController *)sharedPlainTextController +{ + static PlainTextController *controller = [[PlainTextController alloc] init]; + return controller; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + if (selector == @selector(plainTextForRange:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + if (selector == @selector(plainTextForRange:)) + return @"plainText"; + return nil; +} + +- (NSString *)plainTextForRange:(DOMRange *)range +{ + if (![range isKindOfClass:[DOMRange class]]) + return nil; + return [range text]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.h b/Tools/DumpRenderTree/mac/PolicyDelegate.h new file mode 100644 index 000000000..3b954557d --- /dev/null +++ b/Tools/DumpRenderTree/mac/PolicyDelegate.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> + +class LayoutTestController; + +@interface PolicyDelegate : NSObject { + BOOL permissiveDelegate; + LayoutTestController* controllerToNotifyDone; +} + +- (void)setPermissive:(BOOL)permissive; +- (void)setControllerToNotifyDone:(LayoutTestController*)controller; + +@end diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.mm b/Tools/DumpRenderTree/mac/PolicyDelegate.mm new file mode 100644 index 000000000..6935ea721 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PolicyDelegate.mm @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "PolicyDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/DOMElement.h> +#import <WebKit/WebPolicyDelegate.h> +#import <WebKit/WebView.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface DOMNode (dumpPath) +- (NSString *)dumpPath; +@end + +@implementation PolicyDelegate + +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation + request:(NSURLRequest *)request + frame:(WebFrame *)frame + decisionListener:(id<WebPolicyDecisionListener>)listener +{ + WebNavigationType navType = (WebNavigationType)[[actionInformation objectForKey:WebActionNavigationTypeKey] intValue]; + + const char* typeDescription; + switch (navType) { + case WebNavigationTypeLinkClicked: + typeDescription = "link clicked"; + break; + case WebNavigationTypeFormSubmitted: + typeDescription = "form submitted"; + break; + case WebNavigationTypeBackForward: + typeDescription = "back/forward"; + break; + case WebNavigationTypeReload: + typeDescription = "reload"; + break; + case WebNavigationTypeFormResubmitted: + typeDescription = "form resubmitted"; + break; + case WebNavigationTypeOther: + typeDescription = "other"; + break; + default: + typeDescription = "illegal value"; + } + + NSString *message = [NSString stringWithFormat:@"Policy delegate: attempt to load %@ with navigation type '%s'", [[request URL] _drt_descriptionSuitableForTestResult], typeDescription]; + + if (DOMElement *originatingNode = [[actionInformation objectForKey:WebActionElementKey] objectForKey:WebElementDOMNodeKey]) + message = [message stringByAppendingFormat:@" originating from %@", [originatingNode dumpPath]]; + + printf("%s\n", [message UTF8String]); + + if (permissiveDelegate) + [listener use]; + else + [listener ignore]; + + if (controllerToNotifyDone) { + controllerToNotifyDone->notifyDone(); + controllerToNotifyDone = 0; + } +} + +- (void)webView:(WebView *)webView unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame +{ + NSString *message = [NSString stringWithFormat:@"Policy delegate: unable to implement policy with error domain '%@', error code %d, in frame '%@'", [error domain], [error code], [frame name]]; + printf("%s\n", [message UTF8String]); +} + +- (void)setPermissive:(BOOL)permissive +{ + permissiveDelegate = permissive; +} + +- (void)setControllerToNotifyDone:(LayoutTestController*)controller +{ + controllerToNotifyDone = controller; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h new file mode 100644 index 000000000..0c4618e93 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> + + +@interface ResourceLoadDelegate : NSObject { +} + +@end diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm new file mode 100644 index 000000000..5e451f14d --- /dev/null +++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2007, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "ResourceLoadDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/WebKit.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebDataSourcePrivate.h> +#import <wtf/Assertions.h> + +using namespace std; + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLResponse (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLRequest (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult +{ + NSString *str = [NSString stringWithFormat:@"<NSError domain %@, code %d", [self domain], [self code]]; + NSURL *failingURL; + + if ((failingURL = [[self userInfo] objectForKey:@"NSErrorFailingURLKey"])) + str = [str stringByAppendingFormat:@", failing URL \"%@\"", [failingURL _drt_descriptionSuitableForTestResult]]; + + str = [str stringByAppendingFormat:@">"]; + + return str; +} + +@end + +@implementation NSURL (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + if (![self isFileURL]) + return [self absoluteString]; + + WebDataSource *dataSource = [mainFrame dataSource]; + if (!dataSource) + dataSource = [mainFrame provisionalDataSource]; + + NSString *basePath = [[[[dataSource request] URL] path] stringByDeletingLastPathComponent]; + basePath = [basePath stringByAppendingString:@"/"]; + + if ([[self path] hasPrefix:basePath]) + return [[self path] substringFromIndex:[basePath length]]; + return [self absoluteString]; +} + +@end + +@implementation NSURLResponse (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + int statusCode = 0; + if ([self isKindOfClass:[NSHTTPURLResponse class]]) + statusCode = [(NSHTTPURLResponse *)self statusCode]; + return [NSString stringWithFormat:@"<NSURLResponse %@, http status code %i>", [[self URL] _drt_descriptionSuitableForTestResult], statusCode]; +} + +@end + +@implementation NSURLRequest (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + NSString *httpMethod = [self HTTPMethod]; + if (!httpMethod) + httpMethod = @"(none)"; + return [NSString stringWithFormat:@"<NSURLRequest URL %@, main document URL %@, http method %@>", [[self URL] _drt_descriptionSuitableForTestResult], [[self mainDocumentURL] _drt_descriptionSuitableForTestResult], httpMethod]; +} + +@end + +@implementation ResourceLoadDelegate + +- (id)webView: (WebView *)wv identifierForInitialRequest: (NSURLRequest *)request fromDataSource: (WebDataSource *)dataSource +{ + ASSERT([[dataSource webFrame] dataSource] || [[dataSource webFrame] provisionalDataSource]); + + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) + return [[request URL] _drt_descriptionSuitableForTestResult]; + + return @"<unknown>"; +} + +-(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [request _drt_descriptionSuitableForTestResult], + [redirectResponse _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + + if (!done && !gLayoutTestController->deferMainResourceDataLoad()) { + [dataSource _setDeferMainResourceDataLoad:false]; + } + + if (!done && gLayoutTestController->willSendRequestReturnsNull()) + return nil; + + if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) { + printf("Returning null for this redirect\n"); + return nil; + } + + NSURL *url = [request URL]; + NSString *host = [url host]; + if (host + && (NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"http"] || NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"https"]) + && NSOrderedSame != [host compare:@"127.0.0.1"] + && NSOrderedSame != [host compare:@"255.255.255.255"] // used in some tests that expect to get back an error + && NSOrderedSame != [host caseInsensitiveCompare:@"localhost"]) { + printf("Blocked access to external URL %s\n", [[url absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]); + return nil; + } + + if (disallowedURLs && CFSetContainsValue(disallowedURLs, url)) + return nil; + + NSMutableURLRequest *newRequest = [request mutableCopy]; + const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) { + NSString *nsHeader = [[NSString alloc] initWithUTF8String:header->c_str()]; + [newRequest setValue:nil forHTTPHeaderField:nsHeader]; + [nsHeader release]; + } + const std::string& destination = gLayoutTestController->redirectionDestinationForURL([[url absoluteString] UTF8String]); + if (destination.length()) + [newRequest setURL:[NSURL URLWithString:[NSString stringWithUTF8String:destination.data()]]]; + + return [newRequest autorelease]; +} + +- (void)webView:(WebView *)wv resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource +{ + if (!gLayoutTestController->handlesAuthenticationChallenges()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet", identifier]; + printf("%s\n", [string UTF8String]); + + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + return; + } + + const char* user = gLayoutTestController->authenticationUsername().c_str(); + NSString *nsUser = [NSString stringWithFormat:@"%s", user ? user : ""]; + + const char* password = gLayoutTestController->authenticationPassword().c_str(); + NSString *nsPassword = [NSString stringWithFormat:@"%s", password ? password : ""]; + + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Responding with %@:%@", identifier, nsUser, nsPassword]; + printf("%s\n", [string UTF8String]); + + [[challenge sender] useCredential:[NSURLCredential credentialWithUser:nsUser password:nsPassword persistence:NSURLCredentialPersistenceForSession] + forAuthenticationChallenge:challenge]; +} + +- (void)webView:(WebView *)wv resource:(id)identifier didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource +{ +} + +-(void)webView: (WebView *)wv resource:identifier didReceiveResponse: (NSURLResponse *)response fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveResponse %@", identifier, [response _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) + printf("%s has MIME type %s\n", [[[[response URL] relativePath] lastPathComponent] UTF8String], [[response MIMEType] UTF8String]); +} + +-(void)webView: (WebView *)wv resource:identifier didReceiveContentLength: (NSInteger)length fromDataSource:(WebDataSource *)dataSource +{ +} + +-(void)webView: (WebView *)wv resource:identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoading", identifier]; + printf("%s\n", [string UTF8String]); + } +} + +-(void)webView: (WebView *)wv resource:identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadingWithError: %@", identifier, [error _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } +} + +- (void)webView: (WebView *)wv plugInFailedWithError:(NSError *)error dataSource:(WebDataSource *)dataSource +{ + // The call to -display here simulates the "Plug-in not found" sheet that Safari shows. + // It is used for platform/mac/plugins/update-widget-from-style-recalc.html + [wv display]; +} + +-(NSCachedURLResponse *) webView: (WebView *)wv resource:(id)identifier willCacheResponse:(NSCachedURLResponse *)response fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpWillCacheResponse()) { + NSString *string = [NSString stringWithFormat:@"%@ - willCacheResponse: called", identifier]; + printf("%s\n", [string UTF8String]); + } + return response; +} + +-(BOOL)webView: (WebView*)webView shouldPaintBrokenImageForURL:(NSURL*)imageURL +{ + // Only log the message when shouldPaintBrokenImage() returns NO; this avoids changing results of layout tests with failed + // images, e.g., security/block-test-no-port.html. + if (!done && gLayoutTestController->dumpResourceLoadCallbacks() && !gLayoutTestController->shouldPaintBrokenImage()) { + NSString *string = [NSString stringWithFormat:@"%@ - shouldPaintBrokenImage: NO", [imageURL _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + + return gLayoutTestController->shouldPaintBrokenImage(); +} +@end diff --git a/Tools/DumpRenderTree/mac/TextInputController.h b/Tools/DumpRenderTree/mac/TextInputController.h new file mode 100644 index 000000000..767e72f0c --- /dev/null +++ b/Tools/DumpRenderTree/mac/TextInputController.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Foundation/Foundation.h> + +@class WebView; +@class WebHTMLView; +@class WebScriptObject; + +@interface TextInputController : NSObject +{ + WebView *webView; + WebHTMLView *inputMethodView; + WebScriptObject *inputMethodHandler; +} +- (id)initWithWebView:(WebView *)view; +@end diff --git a/Tools/DumpRenderTree/mac/TextInputController.m b/Tools/DumpRenderTree/mac/TextInputController.m new file mode 100644 index 000000000..f78079446 --- /dev/null +++ b/Tools/DumpRenderTree/mac/TextInputController.m @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "TextInputController.h" + +#import "DumpRenderTreeMac.h" +#import <AppKit/NSInputManager.h> +#import <WebKit/WebDocument.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebView.h> + +@interface TextInputController (DumpRenderTreeInputMethodHandler) +- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender; +@end + +@interface WebHTMLView (DumpRenderTreeInputMethodHandler) +- (void)interpretKeyEvents:(NSArray *)eventArray; +@end + +@interface WebHTMLView (WebKitSecretsTextInputControllerIsAwareOf) +- (WebFrame *)_frame; +@end + +@implementation WebHTMLView (DumpRenderTreeInputMethodHandler) +- (void)interpretKeyEvents:(NSArray *)eventArray +{ + WebScriptObject *obj = [[self _frame] windowObject]; + TextInputController *tic = [obj valueForKey:@"textInputController"]; + if (![tic interpretKeyEvents:eventArray withSender:self]) + [super interpretKeyEvents:eventArray]; +} +@end + +@implementation NSMutableAttributedString (TextInputController) + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(string) + || aSelector == @selector(getLength) + || aSelector == @selector(attributeNamesAtIndex:) + || aSelector == @selector(valueOfAttribute:atIndex:) + || aSelector == @selector(addAttribute:value:) + || aSelector == @selector(addAttribute:value:from:length:) + || aSelector == @selector(addColorAttribute:red:green:blue:alpha:) + || aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:) + || aSelector == @selector(addFontAttribute:fontName:size:) + || aSelector == @selector(addFontAttribute:fontName:size:from:length:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(getLength)) + return @"length"; + if (aSelector == @selector(attributeNamesAtIndex:)) + return @"getAttributeNamesAtIndex"; + if (aSelector == @selector(valueOfAttribute:atIndex:)) + return @"getAttributeValueAtIndex"; + if (aSelector == @selector(addAttribute:value:)) + return @"addAttribute"; + if (aSelector == @selector(addAttribute:value:from:length:)) + return @"addAttributeForRange"; + if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:)) + return @"addColorAttribute"; + if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:)) + return @"addColorAttributeForRange"; + if (aSelector == @selector(addFontAttribute:fontName:size:)) + return @"addFontAttribute"; + if (aSelector == @selector(addFontAttribute:fontName:size:from:length:)) + return @"addFontAttributeForRange"; + + return nil; +} + +- (int)getLength +{ + return (int)[self length]; +} + +- (NSArray *)attributeNamesAtIndex:(int)index +{ + NSDictionary *attributes = [self attributesAtIndex:(unsigned)index effectiveRange:nil]; + return [attributes allKeys]; +} + +- (id)valueOfAttribute:(NSString *)attrName atIndex:(int)index +{ + return [self attribute:attrName atIndex:(unsigned)index effectiveRange:nil]; +} + +- (void)addAttribute:(NSString *)attrName value:(id)value +{ + [self addAttribute:attrName value:value range:NSMakeRange(0, [self length])]; +} + +- (void)addAttribute:(NSString *)attrName value:(id)value from:(int)from length:(int)length +{ + [self addAttribute:attrName value:value range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha +{ + [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange(0, [self length])]; +} + +- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha from:(int)from length:(int)length +{ + [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize +{ + [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange(0, [self length])]; +} + +- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize from:(int)from length:(int)length +{ + [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +@end + +@implementation TextInputController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(insertText:) + || aSelector == @selector(doCommand:) + || aSelector == @selector(setMarkedText:selectedFrom:length:) + || aSelector == @selector(unmarkText) + || aSelector == @selector(hasMarkedText) + || aSelector == @selector(conversationIdentifier) + || aSelector == @selector(substringFrom:length:) + || aSelector == @selector(attributedSubstringFrom:length:) + || aSelector == @selector(markedRange) + || aSelector == @selector(selectedRange) + || aSelector == @selector(firstRectForCharactersFrom:length:) + || aSelector == @selector(characterIndexForPointX:Y:) + || aSelector == @selector(validAttributesForMarkedText) + || aSelector == @selector(attributedStringWithString:) + || aSelector == @selector(setInputMethodHandler:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(insertText:)) + return @"insertText"; + else if (aSelector == @selector(doCommand:)) + return @"doCommand"; + else if (aSelector == @selector(setMarkedText:selectedFrom:length:)) + return @"setMarkedText"; + else if (aSelector == @selector(substringFrom:length:)) + return @"substringFromRange"; + else if (aSelector == @selector(attributedSubstringFrom:length:)) + return @"attributedSubstringFromRange"; + else if (aSelector == @selector(firstRectForCharactersFrom:length:)) + return @"firstRectForCharacterRange"; + else if (aSelector == @selector(characterIndexForPointX:Y:)) + return @"characterIndexForPoint"; + else if (aSelector == @selector(attributedStringWithString:)) + return @"makeAttributedString"; // just a factory method, doesn't call into NSTextInput + else if (aSelector == @selector(setInputMethodHandler:)) + return @"setInputMethodHandler"; + + return nil; +} + +- (id)initWithWebView:(WebView *)wv +{ + self = [super init]; + webView = wv; + inputMethodView = nil; + inputMethodHandler = nil; + return self; +} + +- (void)dealloc +{ + [inputMethodHandler release]; + inputMethodHandler = nil; + + [super dealloc]; +} + +- (NSObject <NSTextInput> *)textInput +{ + NSView <NSTextInput> *view = inputMethodView ? inputMethodView : (id)[[[webView mainFrame] frameView] documentView]; + return [view conformsToProtocol:@protocol(NSTextInput)] ? view : nil; +} + +- (void)insertText:(id)aString +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput insertText:aString]; +} + +- (void)doCommand:(NSString *)aCommand +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput doCommandBySelector:NSSelectorFromString(aCommand)]; +} + +- (void)setMarkedText:(NSString *)aString selectedFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput setMarkedText:aString selectedRange:NSMakeRange(from, length)]; +} + +- (void)unmarkText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput unmarkText]; +} + +- (BOOL)hasMarkedText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput hasMarkedText]; + + return FALSE; +} + +- (long)conversationIdentifier +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput conversationIdentifier]; + + return 0; +} + +- (NSString *)substringFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [[textInput attributedSubstringFromRange:NSMakeRange(from, length)] string]; + + return @""; +} + +- (NSMutableAttributedString *)attributedSubstringFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + NSMutableAttributedString *ret = [[[NSMutableAttributedString alloc] init] autorelease]; + + if (textInput) + [ret setAttributedString:[textInput attributedSubstringFromRange:NSMakeRange(from, length)]]; + + return ret; +} + +- (NSArray *)markedRange +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRange range = [textInput markedRange]; + return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil]; + } + + return nil; +} + +- (NSArray *)selectedRange +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRange range = [textInput selectedRange]; + return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil]; + } + + return nil; +} + + +- (NSArray *)firstRectForCharactersFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRect rect = [textInput firstRectForCharacterRange:NSMakeRange(from, length)]; + if (rect.origin.x || rect.origin.y || rect.size.width || rect.size.height) { + rect.origin = [[webView window] convertScreenToBase:rect.origin]; + rect = [webView convertRect:rect fromView:nil]; + } + return [NSArray arrayWithObjects: + [NSNumber numberWithFloat:rect.origin.x], + [NSNumber numberWithFloat:rect.origin.y], + [NSNumber numberWithFloat:rect.size.width], + [NSNumber numberWithFloat:rect.size.height], + nil]; + } + + return nil; +} + +- (NSInteger)characterIndexForPointX:(float)x Y:(float)y +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSPoint point = NSMakePoint(x, y); + point = [webView convertPoint:point toView:nil]; + point = [[webView window] convertBaseToScreen:point]; + NSInteger index = [textInput characterIndexForPoint:point]; + if (index == NSNotFound) + return -1; + + return index; + } + + return 0; +} + +- (NSArray *)validAttributesForMarkedText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput validAttributesForMarkedText]; + + return nil; +} + +- (NSMutableAttributedString *)attributedStringWithString:(NSString *)aString +{ + return [[[NSMutableAttributedString alloc] initWithString:aString] autorelease]; +} + +- (void)setInputMethodHandler:(WebScriptObject *)handler +{ + if (inputMethodHandler == handler) + return; + [handler retain]; + [inputMethodHandler release]; + inputMethodHandler = handler; +} + +- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender +{ + if (!inputMethodHandler) + return NO; + + inputMethodView = sender; + + NSEvent *event = [eventArray objectAtIndex:0]; + unsigned modifierFlags = [event modifierFlags]; + NSMutableArray *modifiers = [[NSMutableArray alloc] init]; + if (modifierFlags & NSAlphaShiftKeyMask) + [modifiers addObject:@"NSAlphaShiftKeyMask"]; + if (modifierFlags & NSShiftKeyMask) + [modifiers addObject:@"NSShiftKeyMask"]; + if (modifierFlags & NSControlKeyMask) + [modifiers addObject:@"NSControlKeyMask"]; + if (modifierFlags & NSAlternateKeyMask) + [modifiers addObject:@"NSAlternateKeyMask"]; + if (modifierFlags & NSCommandKeyMask) + [modifiers addObject:@"NSCommandKeyMask"]; + if (modifierFlags & NSNumericPadKeyMask) + [modifiers addObject:@"NSNumericPadKeyMask"]; + if (modifierFlags & NSHelpKeyMask) + [modifiers addObject:@"NSHelpKeyMask"]; + if (modifierFlags & NSFunctionKeyMask) + [modifiers addObject:@"NSFunctionKeyMask"]; + + WebScriptObject* eventParam = [inputMethodHandler evaluateWebScript:@"new Object();"]; + [eventParam setValue:[event characters] forKey:@"characters"]; + [eventParam setValue:[event charactersIgnoringModifiers] forKey:@"charactersIgnoringModifiers"]; + [eventParam setValue:[NSNumber numberWithBool:[event isARepeat]] forKey:@"isARepeat"]; + [eventParam setValue:[NSNumber numberWithUnsignedShort:[event keyCode]] forKey:@"keyCode"]; + [eventParam setValue:modifiers forKey:@"modifierFlags"]; + + [modifiers release]; + + id result = [inputMethodHandler callWebScriptMethod:@"call" withArguments:[NSArray arrayWithObjects:inputMethodHandler, eventParam, nil]]; + if (![result respondsToSelector:@selector(boolValue)] || ![result boolValue]) + [sender doCommandBySelector:@selector(noop:)]; // AppKit sends noop: if the ime does not handle an event + + inputMethodView = nil; + return YES; +} + +@end diff --git a/Tools/DumpRenderTree/mac/UIDelegate.h b/Tools/DumpRenderTree/mac/UIDelegate.h new file mode 100644 index 000000000..982b4802c --- /dev/null +++ b/Tools/DumpRenderTree/mac/UIDelegate.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 Apple Computer, 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Cocoa/Cocoa.h> + +@interface UIDelegate : NSObject { + +@private + NSRect m_frame; + NSMutableSet *m_pendingGeolocationPermissionListeners; + NSTimer *m_timer; +} + +- (void)didSetMockGeolocationPermission; +- (int)numberOfPendingGeolocationPermissionRequests; + +@end diff --git a/Tools/DumpRenderTree/mac/UIDelegate.mm b/Tools/DumpRenderTree/mac/UIDelegate.mm new file mode 100644 index 000000000..8b462172d --- /dev/null +++ b/Tools/DumpRenderTree/mac/UIDelegate.mm @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2006. 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "UIDelegate.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "EventSendingController.h" +#import "LayoutTestController.h" +#import <WebKit/WebApplicationCache.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebQuotaManager.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebUIDelegatePrivate.h> +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> +#import <wtf/Assertions.h> + +DumpRenderTreeDraggingInfo *draggingInfo = nil; + +@implementation UIDelegate + +- (void)webView:(WebView *)sender setFrame:(NSRect)frame +{ + m_frame = frame; +} + +- (NSRect)webViewFrame:(WebView *)sender +{ + return m_frame; +} + +- (void)webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary withSource:(NSString *)source +{ + NSString *message = [dictionary objectForKey:@"message"]; + NSNumber *lineNumber = [dictionary objectForKey:@"lineNumber"]; + + NSRange range = [message rangeOfString:@"file://"]; + if (range.location != NSNotFound) + message = [[message substringToIndex:range.location] stringByAppendingString:[[message substringFromIndex:NSMaxRange(range)] lastPathComponent]]; + + printf ("CONSOLE MESSAGE: line %d: %s\n", [lineNumber intValue], [message UTF8String]); +} + +- (void)modalWindowWillClose:(NSNotification *)notification +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:nil]; + [NSApp abortModal]; +} + +- (void)webViewRunModal:(WebView *)sender +{ + gLayoutTestController->setWindowIsKey(false); + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modalWindowWillClose:) name:NSWindowWillCloseNotification object:nil]; + [NSApp runModalForWindow:[sender window]]; + gLayoutTestController->setWindowIsKey(true); +} + +- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("ALERT: %s\n", [message UTF8String]); +} + +- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("CONFIRM: %s\n", [message UTF8String]); + return YES; +} + +- (NSString *)webView:(WebView *)sender runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("PROMPT: %s, default text: %s\n", [prompt UTF8String], [defaultText UTF8String]); + return defaultText; +} + +- (BOOL)webView:(WebView *)c runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("CONFIRM NAVIGATION: %s\n", [message UTF8String]); + + return !gLayoutTestController->shouldStayOnPageAfterHandlingBeforeUnload(); +} + + +- (void)webView:(WebView *)sender dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag forView:(NSView *)view +{ + assert(!draggingInfo); + draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj]; + [sender draggingUpdated:draggingInfo]; + [EventSendingController replaySavedEvents]; +} + +- (void)webViewFocus:(WebView *)webView +{ + gLayoutTestController->setWindowIsKey(true); +} + +- (void)webViewUnfocus:(WebView *)webView +{ + gLayoutTestController->setWindowIsKey(false); +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request +{ + if (!gLayoutTestController->canOpenWindows()) + return nil; + + // Make sure that waitUntilDone has been called. + ASSERT(gLayoutTestController->waitToDump()); + + WebView *webView = createWebViewAndOffscreenWindow(); + + if (gLayoutTestController->newWindowsCopyBackForwardList()) + [webView _loadBackForwardListFromOtherView:sender]; + + return [webView autorelease]; +} + +- (void)webViewClose:(WebView *)sender +{ + NSWindow* window = [sender window]; + + if (gLayoutTestController->callCloseOnWebViews()) + [sender close]; + + [window close]; +} + +- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier +{ + if (!done && gLayoutTestController->dumpDatabaseCallbacks()) { + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin host] UTF8String], + [origin port], [databaseIdentifier UTF8String]); + } + + static const unsigned long long defaultQuota = 5 * 1024 * 1024; + [[origin databaseQuotaManager] setQuota:defaultQuota]; +} + +- (void)webView:(WebView *)sender exceededApplicationCacheOriginQuotaForSecurityOrigin:(WebSecurityOrigin *)origin totalSpaceNeeded:(NSUInteger)totalSpaceNeeded +{ + if (!done && gLayoutTestController->dumpApplicationCacheDelegateCallbacks()) { + // For example, numbers from 30000 - 39999 will output as 30000. + // Rounding up or down not really matter for these tests. It's + // sufficient to just get a range of 10000 to determine if we were + // above or below a threshold. + unsigned long truncatedSpaceNeeded = static_cast<unsigned long>((totalSpaceNeeded / 10000) * 10000); + printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i} totalSpaceNeeded:~%lu\n", + [[origin protocol] UTF8String], [[origin host] UTF8String], [origin port], truncatedSpaceNeeded); + } + + if (gLayoutTestController->disallowIncreaseForApplicationCacheQuota()) + return; + + static const unsigned long long defaultOriginQuota = [WebApplicationCache defaultOriginQuota]; + [[origin applicationCacheQuotaManager] setQuota:defaultOriginQuota]; +} + +- (void)webView:(WebView *)sender setStatusText:(NSString *)text +{ + if (gLayoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]); +} + +- (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebGeolocationPolicyListener>)listener +{ + if (!gLayoutTestController->isGeolocationPermissionSet()) { + if (!m_pendingGeolocationPermissionListeners) + m_pendingGeolocationPermissionListeners = [[NSMutableSet set] retain]; + [m_pendingGeolocationPermissionListeners addObject:listener]; + return; + } + + if (gLayoutTestController->geolocationPermission()) + [listener allow]; + else + [listener deny]; +} + +- (void)didSetMockGeolocationPermission +{ + ASSERT(gLayoutTestController->isGeolocationPermissionSet()); + if (m_pendingGeolocationPermissionListeners && !m_timer) + m_timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (int)numberOfPendingGeolocationPermissionRequests +{ + if (!m_pendingGeolocationPermissionListeners) + return 0; + return [m_pendingGeolocationPermissionListeners count]; +} + + +- (void)timerFired +{ + ASSERT(gLayoutTestController->isGeolocationPermissionSet()); + m_timer = 0; + NSEnumerator* enumerator = [m_pendingGeolocationPermissionListeners objectEnumerator]; + id<WebGeolocationPolicyListener> listener; + while ((listener = [enumerator nextObject])) { + if (gLayoutTestController->geolocationPermission()) + [listener allow]; + else + [listener deny]; + } + [m_pendingGeolocationPermissionListeners removeAllObjects]; + [m_pendingGeolocationPermissionListeners release]; + m_pendingGeolocationPermissionListeners = nil; +} + +- (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode +{ + return NO; +} + +- (BOOL)webView:(WebView *)webView supportsFullScreenForElement:(DOMElement*)element withKeyboard:(BOOL)withKeyboard +{ + return YES; +} + +- (void)webView:(WebView *)webView enterFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener +{ + [listener webkitWillEnterFullScreen]; + [listener webkitDidEnterFullScreen]; +} + +- (void)webView:(WebView *)webView exitFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener +{ + [listener webkitWillExitFullScreen]; + [listener webkitDidExitFullScreen]; +} + +- (BOOL)webView:(WebView *)webView didPressMissingPluginButton:(DOMElement *)element +{ + printf("MISSING PLUGIN BUTTON PRESSED\n"); + return TRUE; +} + +- (void)dealloc +{ + [draggingInfo release]; + draggingInfo = nil; + [m_pendingGeolocationPermissionListeners release]; + m_pendingGeolocationPermissionListeners = nil; + + [super dealloc]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm new file mode 100644 index 000000000..9f94ecbc4 --- /dev/null +++ b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "WebArchiveDumpSupport.h" + +#import <CFNetwork/CFHTTPMessage.h> +#import <Foundation/Foundation.h> +#import <WebKit/WebHTMLRepresentation.h> +#import <wtf/RetainPtr.h> + +extern "C" { + +enum CFURLCacheStoragePolicy { + kCFURLCacheStorageAllowed = 0, + kCFURLCacheStorageAllowedInMemoryOnly = 1, + kCFURLCacheStorageNotAllowed = 2 +}; +typedef enum CFURLCacheStoragePolicy CFURLCacheStoragePolicy; + +extern const CFStringRef kCFHTTPVersion1_1; + +CFURLResponseRef CFURLResponseCreate(CFAllocatorRef alloc, CFURLRef URL, CFStringRef mimeType, SInt64 expectedContentLength, CFStringRef textEncodingName, CFURLCacheStoragePolicy recommendedPolicy); +CFURLResponseRef CFURLResponseCreateWithHTTPResponse(CFAllocatorRef alloc, CFURLRef URL, CFHTTPMessageRef httpResponse, CFURLCacheStoragePolicy recommendedPolicy); +void CFURLResponseSetExpectedContentLength(CFURLResponseRef response, SInt64 length); +void CFURLResponseSetMIMEType(CFURLResponseRef response, CFStringRef mimeType); + +} + +CFURLResponseRef createCFURLResponseFromResponseData(CFDataRef responseData) +{ + // Decode NSURLResponse + RetainPtr<NSKeyedUnarchiver> unarchiver(AdoptNS, [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)responseData]); + NSURLResponse *response = [unarchiver.get() decodeObjectForKey:@"WebResourceResponse"]; // WebResourceResponseKey in WebResource.m + [unarchiver.get() finishDecoding]; + + if (![response isKindOfClass:[NSHTTPURLResponse class]]) + return CFURLResponseCreate(kCFAllocatorDefault, (CFURLRef)[response URL], (CFStringRef)[response MIMEType], [response expectedContentLength], (CFStringRef)[response textEncodingName], kCFURLCacheStorageAllowed); + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + // NSURLResponse is not toll-free bridged to CFURLResponse. + RetainPtr<CFHTTPMessageRef> httpMessage(AdoptCF, CFHTTPMessageCreateResponse(kCFAllocatorDefault, [httpResponse statusCode], 0, kCFHTTPVersion1_1)); + + NSDictionary *headerFields = [httpResponse allHeaderFields]; + for (NSString *headerField in [headerFields keyEnumerator]) + CFHTTPMessageSetHeaderFieldValue(httpMessage.get(), (CFStringRef)headerField, (CFStringRef)[headerFields objectForKey:headerField]); + + return CFURLResponseCreateWithHTTPResponse(kCFAllocatorDefault, (CFURLRef)[response URL], httpMessage.get(), kCFURLCacheStorageAllowed); +} + +CFArrayRef supportedNonImageMIMETypes() +{ + return (CFArrayRef)[WebHTMLRepresentation supportedNonImageMIMETypes]; +} diff --git a/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm new file mode 100644 index 000000000..c28e991e2 --- /dev/null +++ b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h" +#import "DumpRenderTree.h" +#import "WorkQueueItem.h" + +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebView.h> +#import <wtf/RetainPtr.h> + +bool LoadItem::invoke() const +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_url.get())); + NSString *urlNS = (NSString *)urlCF.get(); + RetainPtr<CFStringRef> targetCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_target.get())); + NSString *targetNS = (NSString *)targetCF.get(); + + WebFrame *targetFrame; + if (targetNS && [targetNS length]) + targetFrame = [mainFrame findFrameNamed:targetNS]; + else + targetFrame = mainFrame; + [targetFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlNS]]]; + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + RetainPtr<CFStringRef> contentCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_content.get())); + RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_baseURL.get())); + + if (m_unreachableURL) { + RetainPtr<CFStringRef> unreachableURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_unreachableURL.get())); + [mainFrame loadAlternateHTMLString:(NSString *)contentCF.get() baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()] forUnreachableURL:[NSURL URLWithString:(NSString *)unreachableURLCF.get()]]; + return true; + } + + [mainFrame loadHTMLString:(NSString *)contentCF.get() baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]]; + return true; +} + +bool ReloadItem::invoke() const +{ + [[mainFrame webView] reload:nil]; + return true; +} + +bool ScriptItem::invoke() const +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_script.get())); + NSString *scriptNS = (NSString *)scriptCF.get(); + [[mainFrame webView] stringByEvaluatingJavaScriptFromString:scriptNS]; + return true; +} + +bool BackForwardItem::invoke() const +{ + if (m_howFar == 1) + [[mainFrame webView] goForward]; + else if (m_howFar == -1) + [[mainFrame webView] goBack]; + else { + WebBackForwardList *bfList = [[mainFrame webView] backForwardList]; + [[mainFrame webView] goToBackForwardItem:[bfList itemAtIndex:m_howFar]]; + } + return true; +} diff --git a/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp new file mode 100644 index 000000000..1266c020e --- /dev/null +++ b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "JavaScriptThreading.h" + +#include <CoreFoundation/CoreFoundation.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <pthread.h> +#include <wtf/Assertions.h> +#include <wtf/HashSet.h> + +static JSContextGroupRef javaScriptThreadsGroup; + +static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER; +static bool javaScriptThreadsShouldTerminate; + +static const int javaScriptThreadsCount = 4; + +typedef HashSet<pthread_t> ThreadSet; + +static ThreadSet* javaScriptThreads() +{ + ASSERT(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY); + static ThreadSet staticJavaScriptThreads; + return &staticJavaScriptThreads; +} + +// This function exercises JSC in a loop until javaScriptThreadsShouldTerminate +// becomes true or it probabilistically decides to spawn a replacement thread and exit. +void* runJavaScriptThread(void* arg) +{ + static const char* const script = + "var array = [];" + "for (var i = 0; i < 1024; i++) {" + " array.push(String(i));" + "}"; + + pthread_mutex_lock(&javaScriptThreadsMutex); + JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0); + pthread_mutex_unlock(&javaScriptThreadsMutex); + + pthread_mutex_lock(&javaScriptThreadsMutex); + JSStringRef scriptRef = JSStringCreateWithUTF8CString(script); + pthread_mutex_unlock(&javaScriptThreadsMutex); + + while (1) { + pthread_mutex_lock(&javaScriptThreadsMutex); + JSValueRef exception = 0; + JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); + ASSERT(!exception); + pthread_mutex_unlock(&javaScriptThreadsMutex); + + pthread_mutex_lock(&javaScriptThreadsMutex); + size_t valuesCount = 1024; + JSValueRef values[valuesCount]; + for (size_t i = 0; i < valuesCount; ++i) + values[i] = JSObjectMake(ctx, 0, 0); + pthread_mutex_unlock(&javaScriptThreadsMutex); + + // Check for cancellation. + if (javaScriptThreadsShouldTerminate) + goto done; + + // Respawn probabilistically. + if (random() % 5 == 0) { + pthread_mutex_lock(&javaScriptThreadsMutex); + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_detach(pthread); + javaScriptThreads()->add(pthread); + pthread_mutex_unlock(&javaScriptThreadsMutex); + goto done; + } + } + +done: + pthread_mutex_lock(&javaScriptThreadsMutex); + JSStringRelease(scriptRef); + JSGarbageCollect(ctx); + JSGlobalContextRelease(ctx); + javaScriptThreads()->remove(pthread_self()); + pthread_mutex_unlock(&javaScriptThreadsMutex); + return 0; +} + +void startJavaScriptThreads() +{ + javaScriptThreadsGroup = JSContextGroupCreate(); + + pthread_mutex_lock(&javaScriptThreadsMutex); + + for (int i = 0; i < javaScriptThreadsCount; i++) { + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_detach(pthread); + javaScriptThreads()->add(pthread); + } + + pthread_mutex_unlock(&javaScriptThreadsMutex); +} + +void stopJavaScriptThreads() +{ + pthread_mutex_lock(&javaScriptThreadsMutex); + + javaScriptThreadsShouldTerminate = true; + + pthread_mutex_unlock(&javaScriptThreadsMutex); + + while (true) { + pthread_mutex_lock(&javaScriptThreadsMutex); + int threadCount = javaScriptThreads()->size(); + pthread_mutex_unlock(&javaScriptThreadsMutex); + + if (!threadCount) + break; + + usleep(1000); + } +} diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.pro b/Tools/DumpRenderTree/qt/DumpRenderTree.pro new file mode 100644 index 000000000..772cb35d5 --- /dev/null +++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro @@ -0,0 +1,61 @@ +# ------------------------------------------------------------------- +# Project file for the DumpRenderTree binary (DRT) +# +# See 'Tools/qmake/README' for an overview of the build system +# ------------------------------------------------------------------- + +TEMPLATE = app + +TARGET = DumpRenderTree +DESTDIR = $$ROOT_BUILD_DIR/bin + +load(features) +CONFIG += uitools + +WEBKIT += wtf webcore + +CONFIG += qtwebkit + +INCLUDEPATH += \ + $$PWD/.. \ + $${ROOT_WEBKIT_DIR}/Source/WebKit/qt/WebCoreSupport + +QT = core gui network testlib +macx: QT += xml +haveQt(5): QT += widgets printsupport + +contains(DEFINES, HAVE_FONTCONFIG=1): PKGCONFIG += fontconfig + +HEADERS += \ + $$PWD/../WorkQueue.h \ + DumpRenderTreeQt.h \ + EventSenderQt.h \ + TextInputControllerQt.h \ + WorkQueueItemQt.h \ + LayoutTestControllerQt.h \ + GCControllerQt.h \ + PlainTextControllerQt.h \ + testplugin.h + +SOURCES += \ + $${ROOT_WEBKIT_DIR}/Source/JavaScriptCore/wtf/Assertions.cpp \ + $$PWD/../WorkQueue.cpp \ + DumpRenderTreeQt.cpp \ + EventSenderQt.cpp \ + TextInputControllerQt.cpp \ + PlainTextControllerQt.cpp \ + WorkQueueItemQt.cpp \ + LayoutTestControllerQt.cpp \ + GCControllerQt.cpp \ + testplugin.cpp \ + main.cpp + +wince*: { + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat $$WCECOMPAT/include + LIBS += $$WCECOMPAT/lib/wcecompat.lib +} + +DEFINES -= USE_SYSTEM_MALLOC=0 +DEFINES += USE_SYSTEM_MALLOC=1 + +RESOURCES = DumpRenderTree.qrc diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.qrc b/Tools/DumpRenderTree/qt/DumpRenderTree.qrc new file mode 100644 index 000000000..71d163aa7 --- /dev/null +++ b/Tools/DumpRenderTree/qt/DumpRenderTree.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>resources/user.css</file> + </qresource> +</RCC> diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp new file mode 100644 index 000000000..c1a3ed450 --- /dev/null +++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -0,0 +1,1185 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTreeQt.h" +#include "DumpRenderTreeSupportQt.h" +#include "EventSenderQt.h" +#include "GCControllerQt.h" +#include "LayoutTestControllerQt.h" +#include "TextInputControllerQt.h" +#include "PlainTextControllerQt.h" +#include "testplugin.h" +#include "WorkQueue.h" + +#include <QApplication> +#include <QBuffer> +#include <QCryptographicHash> +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QFocusEvent> +#include <QFontDatabase> +#include <QLocale> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QPaintDevice> +#include <QPaintEngine> +#ifndef QT_NO_PRINTER +#include <QPrinter> +#endif +#include <QUndoStack> +#include <QUrl> + +#include <qwebsettings.h> +#include <qwebsecurityorigin.h> + +#ifndef QT_NO_UITOOLS +#include <QtUiTools/QUiLoader> +#endif + +#if HAVE(FONTCONFIG) +#include <fontconfig/fontconfig.h> +#endif + +#include <limits.h> +#include <locale.h> + +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +#include <qdebug.h> + +namespace WebCore { + +const int databaseDefaultQuota = 5 * 1024 * 1024; + +NetworkAccessManager::NetworkAccessManager(QObject* parent) + : QNetworkAccessManager(parent) +{ +#ifndef QT_NO_OPENSSL + connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), + this, SLOT(sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&))); +#endif +} + +#ifndef QT_NO_OPENSSL +void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QList<QSslError>& errors) +{ + if (reply->url().host() == "127.0.0.1" || reply->url().host() == "localhost") { + bool ignore = true; + + // Accept any HTTPS certificate. + foreach (const QSslError& error, errors) { + if (error.error() < QSslError::UnableToGetIssuerCertificate || error.error() > QSslError::HostNameMismatch) { + ignore = false; + break; + } + } + + if (ignore) + reply->ignoreSslErrors(); + } +} +#endif + + +#ifndef QT_NO_PRINTER +class NullPrinter : public QPrinter { +public: + class NullPaintEngine : public QPaintEngine { + public: + virtual bool begin(QPaintDevice*) { return true; } + virtual bool end() { return true; } + virtual QPaintEngine::Type type() const { return QPaintEngine::User; } + virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) { } + virtual void updateState(const QPaintEngineState& state) { } + }; + + virtual QPaintEngine* paintEngine() const { return const_cast<NullPaintEngine*>(&m_engine); } + + NullPaintEngine m_engine; +}; +#endif + +WebPage::WebPage(QObject* parent, DumpRenderTree* drt) + : QWebPage(parent) + , m_webInspector(0) + , m_drt(drt) +{ + QWebSettings* globalSettings = QWebSettings::globalSettings(); + + globalSettings->setFontSize(QWebSettings::MinimumFontSize, 0); + globalSettings->setFontSize(QWebSettings::MinimumLogicalFontSize, 5); + globalSettings->setFontSize(QWebSettings::DefaultFontSize, 16); + globalSettings->setFontSize(QWebSettings::DefaultFixedFontSize, 13); + + globalSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true); + globalSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true); + globalSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, false); + globalSettings->setAttribute(QWebSettings::PluginsEnabled, true); + globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true); + globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true); + globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false); + globalSettings->setAttribute(QWebSettings::SpatialNavigationEnabled, false); + + connect(this, SIGNAL(geometryChangeRequested(const QRect &)), + this, SLOT(setViewGeometry(const QRect & ))); + + setNetworkAccessManager(m_drt->networkAccessManager()); + setPluginFactory(new TestPlugin(this)); + + connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature))); + connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(cancelPermission(QWebFrame*, QWebPage::Feature))); +} + +WebPage::~WebPage() +{ + delete m_webInspector; +} + +QWebInspector* WebPage::webInspector() +{ + if (!m_webInspector) { + m_webInspector = new QWebInspector; + m_webInspector->setPage(this); + } + return m_webInspector; +} + +void WebPage::resetSettings() +{ + // After each layout test, reset the settings that may have been changed by + // layoutTestController.overridePreference() or similar. + settings()->resetFontSize(QWebSettings::DefaultFontSize); + settings()->resetAttribute(QWebSettings::JavascriptCanOpenWindows); + settings()->resetAttribute(QWebSettings::JavascriptEnabled); + settings()->resetAttribute(QWebSettings::PrivateBrowsingEnabled); + settings()->resetAttribute(QWebSettings::SpatialNavigationEnabled); + settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain); + settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled); + settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls); + settings()->resetAttribute(QWebSettings::LocalContentCanAccessFileUrls); + settings()->resetAttribute(QWebSettings::PluginsEnabled); + settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard); + settings()->resetAttribute(QWebSettings::AutoLoadImages); + settings()->resetAttribute(QWebSettings::ZoomTextOnly); + + m_drt->layoutTestController()->setCaretBrowsingEnabled(false); + m_drt->layoutTestController()->setAuthorAndUserStylesEnabled(true); + m_drt->layoutTestController()->setFrameFlatteningEnabled(false); + m_drt->layoutTestController()->setSmartInsertDeleteEnabled(true); + m_drt->layoutTestController()->setSelectTrailingWhitespaceEnabled(false); + m_drt->layoutTestController()->setDefersLoading(false); + + // globalSettings must be reset explicitly. + m_drt->layoutTestController()->setXSSAuditorEnabled(false); + + QWebSettings::setMaximumPagesInCache(0); // reset to default + settings()->setUserStyleSheetUrl(QUrl()); // reset to default + + DumpRenderTreeSupportQt::setMinimumTimerInterval(this, DumpRenderTreeSupportQt::defaultMinimumTimerInterval()); + DumpRenderTreeSupportQt::setHixie76WebSocketProtocolEnabled(this, DumpRenderTreeSupportQt::defaultHixie76WebSocketProtocolEnabled()); + + DumpRenderTreeSupportQt::resetInternalsObject(mainFrame()); + + m_pendingGeolocationRequests.clear(); +} + +QWebPage *WebPage::createWindow(QWebPage::WebWindowType) +{ + return m_drt->createWindow(); +} + +void WebPage::javaScriptAlert(QWebFrame*, const QString& message) +{ + if (!isTextOutputEnabled()) + return; + + fprintf(stdout, "ALERT: %s\n", message.toUtf8().constData()); +} + +void WebPage::requestPermission(QWebFrame* frame, QWebPage::Feature feature) +{ + switch (feature) { + case Notifications: + if (!m_drt->layoutTestController()->ignoreReqestForPermission()) + setFeaturePermission(frame, feature, PermissionGrantedByUser); + break; + case Geolocation: + if (m_drt->layoutTestController()->isGeolocationPermissionSet()) + if (m_drt->layoutTestController()->geolocationPermission()) + setFeaturePermission(frame, feature, PermissionGrantedByUser); + else + setFeaturePermission(frame, feature, PermissionDeniedByUser); + else + m_pendingGeolocationRequests.append(frame); + break; + default: + break; + } +} + +void WebPage::cancelPermission(QWebFrame* frame, QWebPage::Feature feature) +{ + switch (feature) { + case Geolocation: + m_pendingGeolocationRequests.removeOne(frame); + break; + default: + break; + } +} + +void WebPage::permissionSet(QWebPage::Feature feature) +{ + switch (feature) { + case Geolocation: + { + Q_ASSERT(m_drt->layoutTestController()->isGeolocationPermissionSet()); + foreach (QWebFrame* frame, m_pendingGeolocationRequests) + if (m_drt->layoutTestController()->geolocationPermission()) + setFeaturePermission(frame, feature, PermissionGrantedByUser); + else + setFeaturePermission(frame, feature, PermissionDeniedByUser); + + m_pendingGeolocationRequests.clear(); + break; + } + default: + break; + } +} + +static QString urlSuitableForTestResult(const QString& url) +{ + if (url.isEmpty() || !url.startsWith(QLatin1String("file://"))) + return url; + + return QFileInfo(url).fileName(); +} + +void WebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString&) +{ + if (!isTextOutputEnabled()) + return; + + QString newMessage; + if (!message.isEmpty()) { + newMessage = message; + + size_t fileProtocol = newMessage.indexOf(QLatin1String("file://")); + if (fileProtocol != -1) { + newMessage = newMessage.left(fileProtocol) + urlSuitableForTestResult(newMessage.mid(fileProtocol)); + } + } + + fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, newMessage.toUtf8().constData()); +} + +bool WebPage::javaScriptConfirm(QWebFrame*, const QString& msg) +{ + if (!isTextOutputEnabled()) + return true; + + fprintf(stdout, "CONFIRM: %s\n", msg.toUtf8().constData()); + return true; +} + +bool WebPage::javaScriptPrompt(QWebFrame*, const QString& msg, const QString& defaultValue, QString* result) +{ + if (!isTextOutputEnabled()) + return true; + + fprintf(stdout, "PROMPT: %s, default text: %s\n", msg.toUtf8().constData(), defaultValue.toUtf8().constData()); + *result = defaultValue; + return true; +} + +bool WebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type) +{ + if (m_drt->layoutTestController()->waitForPolicy()) + m_drt->layoutTestController()->notifyDone(); + + return QWebPage::acceptNavigationRequest(frame, request, type); +} + +bool WebPage::supportsExtension(QWebPage::Extension extension) const +{ + if (extension == QWebPage::ErrorPageExtension) + return m_drt->layoutTestController()->shouldHandleErrorPages(); + + return false; +} + +bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) +{ + const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option); + + // Lets handle error pages for the main frame for now. + if (info->frame != mainFrame()) + return false; + + QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output); + + errorPage->content = QString("data:text/html,<body/>").toUtf8(); + + return true; +} + +QObject* WebPage::createPlugin(const QString& classId, const QUrl& url, const QStringList& paramNames, const QStringList& paramValues) +{ + Q_UNUSED(url); + Q_UNUSED(paramNames); + Q_UNUSED(paramValues); +#ifndef QT_NO_UITOOLS + QUiLoader loader; + return loader.createWidget(classId, view()); +#else + Q_UNUSED(classId); + return 0; +#endif +} + +void WebPage::setViewGeometry(const QRect& rect) +{ + if (WebViewGraphicsBased* v = qobject_cast<WebViewGraphicsBased*>(view())) + v->scene()->setSceneRect(QRectF(rect)); + else if (QWidget *v = view()) + v->setGeometry(rect); +} + +WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) + : m_item(new QGraphicsWebView) +{ + setScene(new QGraphicsScene(this)); + scene()->addItem(m_item); +} + +DumpRenderTree::DumpRenderTree() + : m_dumpPixels(false) + , m_stdin(0) + , m_enableTextOutput(false) + , m_standAloneMode(false) + , m_graphicsBased(false) + , m_persistentStoragePath(QString(getenv("DUMPRENDERTREE_TEMP"))) +{ + QByteArray viewMode = getenv("QT_DRT_WEBVIEW_MODE"); + if (viewMode == "graphics") + setGraphicsBased(true); + + DumpRenderTreeSupportQt::initialize(); + + // Set running in DRT mode for qwebpage to create testable objects. + DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true); + DumpRenderTreeSupportQt::overwritePluginDirectories(); + QWebSettings::enablePersistentStorage(m_persistentStoragePath); + + m_networkAccessManager = new NetworkAccessManager(this); + // create our primary testing page/view. + if (isGraphicsBased()) { + WebViewGraphicsBased* view = new WebViewGraphicsBased(0); + m_page = new WebPage(view, this); + view->setPage(m_page); + m_mainView = view; + } else { + QWebView* view = new QWebView(0); + m_page = new WebPage(view, this); + view->setPage(m_page); + m_mainView = view; + } + // Use a frame group name for all pages created by DumpRenderTree to allow + // testing of cross-page frame lookup. + DumpRenderTreeSupportQt::webPageSetGroupName(m_page, "org.webkit.qt.DumpRenderTree"); + + m_mainView->setContextMenuPolicy(Qt::NoContextMenu); + m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)); + + // clean up cache by resetting quota. + qint64 quota = webPage()->settings()->offlineWebApplicationCacheQuota(); + webPage()->settings()->setOfflineWebApplicationCacheQuota(quota); + + // create our controllers. This has to be done before connectFrame, + // as it exports there to the JavaScript DOM window. + m_controller = new LayoutTestController(this); + connect(m_controller, SIGNAL(showPage()), this, SLOT(showPage())); + connect(m_controller, SIGNAL(hidePage()), this, SLOT(hidePage())); + + // async geolocation permission set by controller + connect(m_controller, SIGNAL(geolocationPermissionSet()), this, SLOT(geolocationPermissionSet())); + + connect(m_controller, SIGNAL(done()), this, SLOT(dump())); + m_eventSender = new EventSender(m_page); + m_textInputController = new TextInputController(m_page); + m_plainTextController = new PlainTextController(m_page); + m_gcController = new GCController(m_page); + + // now connect our different signals + connect(m_page, SIGNAL(frameCreated(QWebFrame *)), + this, SLOT(connectFrame(QWebFrame *))); + connectFrame(m_page->mainFrame()); + + connect(m_page, SIGNAL(loadFinished(bool)), + m_controller, SLOT(maybeDump(bool))); + // We need to connect to loadStarted() because notifyDone should only + // dump results itself when the last page loaded in the test has finished loading. + connect(m_page, SIGNAL(loadStarted()), + m_controller, SLOT(resetLoadFinished())); + connect(m_page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested())); + connect(m_page, SIGNAL(printRequested(QWebFrame*)), this, SLOT(dryRunPrint(QWebFrame*))); + + connect(m_page->mainFrame(), SIGNAL(titleChanged(const QString&)), + SLOT(titleChanged(const QString&))); + connect(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)), + this, SLOT(dumpDatabaseQuota(QWebFrame*,QString))); + connect(m_page, SIGNAL(applicationCacheQuotaExceeded(QWebSecurityOrigin *, quint64, quint64)), + this, SLOT(dumpApplicationCacheQuota(QWebSecurityOrigin *, quint64, quint64))); + connect(m_page, SIGNAL(statusBarMessage(const QString&)), + this, SLOT(statusBarMessage(const QString&))); + + QObject::connect(this, SIGNAL(quit()), qApp, SLOT(quit()), Qt::QueuedConnection); + + DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true); + DumpRenderTreeSupportQt::setInteractiveFormValidationEnabled(webPage(), true); + QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason); + QApplication::sendEvent(m_mainView, &event); +} + +DumpRenderTree::~DumpRenderTree() +{ + if (!m_redirectOutputFileName.isEmpty()) + fclose(stdout); + if (!m_redirectErrorFileName.isEmpty()) + fclose(stderr); + delete m_mainView; + delete m_stdin; +} + +static void clearHistory(QWebPage* page) +{ + // QWebHistory::clear() leaves current page, so remove it as well by setting + // max item count to 0, and then setting it back to it's original value. + + QWebHistory* history = page->history(); + int itemCount = history->maximumItemCount(); + + history->clear(); + history->setMaximumItemCount(0); + history->setMaximumItemCount(itemCount); +} + +void DumpRenderTree::dryRunPrint(QWebFrame* frame) +{ +#ifndef QT_NO_PRINTER + NullPrinter printer; + frame->print(&printer); +#endif +} + +void DumpRenderTree::resetToConsistentStateBeforeTesting(const QUrl& url) +{ + // reset so that any current loads are stopped + // NOTE: that this has to be done before the layoutTestController is + // reset or we get timeouts for some tests. + m_page->blockSignals(true); + m_page->triggerAction(QWebPage::Stop); + m_page->blockSignals(false); + + QList<QWebSecurityOrigin> knownOrigins = QWebSecurityOrigin::allOrigins(); + for (int i = 0; i < knownOrigins.size(); ++i) + knownOrigins[i].setDatabaseQuota(databaseDefaultQuota); + + // reset the layoutTestController at this point, so that we under no + // circumstance dump (stop the waitUntilDone timer) during the reset + // of the DRT. + m_controller->reset(); + + // reset mouse clicks counter + m_eventSender->resetClickCount(); + + closeRemainingWindows(); + + // Call setTextSizeMultiplier(1.0) to reset TextZoomFactor and PageZoomFactor too. + // It should be done before resetSettings() to guarantee resetting QWebSettings::ZoomTextOnly correctly. + m_page->mainFrame()->setTextSizeMultiplier(1.0); + + m_page->resetSettings(); +#ifndef QT_NO_UNDOSTACK + m_page->undoStack()->clear(); +#endif + + clearHistory(m_page); + DumpRenderTreeSupportQt::scalePageBy(m_page->mainFrame(), 1, QPoint(0, 0)); + DumpRenderTreeSupportQt::clearFrameName(m_page->mainFrame()); + + m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded); + m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded); + + if (url.scheme() == "http" || url.scheme() == "https") { + // credentials may exist from previous tests. + m_page->setNetworkAccessManager(0); + delete m_networkAccessManager; + m_networkAccessManager = new NetworkAccessManager(this); + m_page->setNetworkAccessManager(m_networkAccessManager); + } + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + DumpRenderTreeSupportQt::resetOriginAccessWhiteLists(); + + // Qt defaults to Windows editing behavior. + DumpRenderTreeSupportQt::setEditingBehavior(m_page, "win"); + + QLocale::setDefault(QLocale::c()); + + layoutTestController()->setDeveloperExtrasEnabled(true); +#ifndef Q_OS_WINCE + setlocale(LC_ALL, ""); +#endif + + DumpRenderTreeSupportQt::clearOpener(m_page->mainFrame()); +} + +static bool isGlobalHistoryTest(const QUrl& url) +{ + if (url.path().contains("globalhistory/")) + return true; + return false; +} + +static bool isWebInspectorTest(const QUrl& url) +{ + if (url.path().contains("inspector/")) + return true; + return false; +} + +static bool isDumpAsTextTest(const QUrl& url) +{ + if (url.path().contains("dumpAsText/")) + return true; + return false; +} + + +void DumpRenderTree::open(const QUrl& url) +{ + DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(QFileInfo(url.toString()).path()); + resetToConsistentStateBeforeTesting(url); + + if (isWebInspectorTest(m_page->mainFrame()->url())) + layoutTestController()->closeWebInspector(); + + if (isWebInspectorTest(url)) + layoutTestController()->showWebInspector(); + + if (isDumpAsTextTest(url)) { + layoutTestController()->dumpAsText(); + setDumpPixels(false); + } + + if (isGlobalHistoryTest(url)) + layoutTestController()->dumpHistoryCallbacks(); + + // W3C SVG tests expect to be 480x360 + bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1"); + int width = isW3CTest ? 480 : LayoutTestController::maxViewWidth; + int height = isW3CTest ? 360 : LayoutTestController::maxViewHeight; + m_mainView->resize(QSize(width, height)); + m_page->setPreferredContentsSize(QSize()); + m_page->setViewportSize(QSize(width, height)); + + QFocusEvent ev(QEvent::FocusIn); + m_page->event(&ev); + + QWebSettings::clearMemoryCaches(); +#if !(QT_VERSION <= QT_VERSION_CHECK(4, 6, 2)) + QFontDatabase::removeAllApplicationFonts(); +#endif + initializeFonts(); + + DumpRenderTreeSupportQt::dumpFrameLoader(url.toString().contains("loading/")); + setTextOutputEnabled(true); + m_page->mainFrame()->load(url); +} + +void DumpRenderTree::readLine() +{ + if (!m_stdin) { + m_stdin = new QFile; + m_stdin->open(stdin, QFile::ReadOnly); + + if (!m_stdin->isReadable()) { + emit quit(); + return; + } + } + + QByteArray line = m_stdin->readLine().trimmed(); + + if (line.isEmpty()) { + emit quit(); + return; + } + + processLine(QString::fromLocal8Bit(line.constData(), line.length())); +} + +void DumpRenderTree::processArgsLine(const QStringList &args) +{ + setStandAloneMode(true); + + m_standAloneModeTestList = args; + + QFileInfo firstEntry(m_standAloneModeTestList.first()); + if (firstEntry.isDir()) { + QDir folderEntry(m_standAloneModeTestList.first()); + QStringList supportedExt; + // Check for all supported extensions (from Scripts/webkitpy/layout_tests/layout_package/test_files.py). + supportedExt << "*.html" << "*.shtml" << "*.xml" << "*.xhtml" << "*.xhtmlmp" << "*.pl" << "*.php" << "*.svg"; + m_standAloneModeTestList = folderEntry.entryList(supportedExt, QDir::Files); + for (int i = 0; i < m_standAloneModeTestList.size(); ++i) + m_standAloneModeTestList[i] = folderEntry.absoluteFilePath(m_standAloneModeTestList[i]); + } + connect(this, SIGNAL(ready()), this, SLOT(loadNextTestInStandAloneMode())); + + if (!m_standAloneModeTestList.isEmpty()) { + QString first = m_standAloneModeTestList.takeFirst(); + processLine(first); + } +} + +void DumpRenderTree::loadNextTestInStandAloneMode() +{ + if (m_standAloneModeTestList.isEmpty()) { + emit quit(); + return; + } + QString first = m_standAloneModeTestList.takeFirst(); + processLine(first); +} + +void DumpRenderTree::processLine(const QString &input) +{ + QString line = input; + + m_expectedHash = QString(); + if (m_dumpPixels) { + // single quote marks the pixel dump hash + int i = line.indexOf('\''); + if (i > -1) { + m_expectedHash = line.mid(i + 1, line.length()); + line.remove(i, line.length()); + } + } + + if (line.startsWith(QLatin1String("http:")) + || line.startsWith(QLatin1String("https:")) + || line.startsWith(QLatin1String("file:"))) { + open(QUrl(line)); + } else { + QFileInfo fi(line); + + if (!fi.exists()) { + QDir currentDir = QDir::currentPath(); + + // Try to be smart about where the test is located + if (currentDir.dirName() == QLatin1String("LayoutTests")) + fi = QFileInfo(currentDir, line.replace(QRegExp(".*?LayoutTests/(.*)"), "\\1")); + else if (!line.contains(QLatin1String("LayoutTests"))) + fi = QFileInfo(currentDir, line.prepend(QLatin1String("LayoutTests/"))); + + if (!fi.exists()) { + emit ready(); + return; + } + } + + open(QUrl::fromLocalFile(fi.absoluteFilePath())); + } + + fflush(stdout); +} + +void DumpRenderTree::setDumpPixels(bool dump) +{ + m_dumpPixels = dump; +} + +void DumpRenderTree::closeRemainingWindows() +{ + foreach (QObject* widget, windows) + delete widget; + windows.clear(); +} + +void DumpRenderTree::initJSObjects() +{ + QWebFrame *frame = qobject_cast<QWebFrame*>(sender()); + Q_ASSERT(frame); + frame->addToJavaScriptWindowObject(QLatin1String("layoutTestController"), m_controller); + frame->addToJavaScriptWindowObject(QLatin1String("eventSender"), m_eventSender); + frame->addToJavaScriptWindowObject(QLatin1String("textInputController"), m_textInputController); + frame->addToJavaScriptWindowObject(QLatin1String("GCController"), m_gcController); + frame->addToJavaScriptWindowObject(QLatin1String("plainText"), m_plainTextController); + DumpRenderTreeSupportQt::injectInternalsObject(frame); +} + +void DumpRenderTree::showPage() +{ + m_mainView->show(); + // we need a paint event but cannot process all the events + QPixmap pixmap(m_mainView->size()); + m_mainView->render(&pixmap); +} + +void DumpRenderTree::hidePage() +{ + m_mainView->hide(); +} + +QString DumpRenderTree::dumpFrameScrollPosition(QWebFrame* frame) +{ + if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame)) + return QString(); + + QString result; + QPoint pos = frame->scrollPosition(); + if (pos.x() > 0 || pos.y() > 0) { + QWebFrame* parent = qobject_cast<QWebFrame *>(frame->parent()); + if (parent) + result.append(QString("frame '%1' ").arg(frame->title())); + result.append(QString("scrolled to %1,%2\n").arg(pos.x()).arg(pos.y())); + } + + if (m_controller->shouldDumpChildFrameScrollPositions()) { + QList<QWebFrame*> children = frame->childFrames(); + for (int i = 0; i < children.size(); ++i) + result += dumpFrameScrollPosition(children.at(i)); + } + return result; +} + +QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame) +{ + if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame)) + return QString(); + + QString result; + QWebFrame* parent = qobject_cast<QWebFrame*>(frame->parent()); + if (parent) { + result.append(QLatin1String("\n--------\nFrame: '")); + result.append(frame->frameName()); + result.append(QLatin1String("'\n--------\n")); + } + + QString innerText = frame->toPlainText(); + result.append(innerText); + result.append(QLatin1String("\n")); + + if (m_controller->shouldDumpChildrenAsText()) { + QList<QWebFrame *> children = frame->childFrames(); + for (int i = 0; i < children.size(); ++i) + result += dumpFramesAsText(children.at(i)); + } + + return result; +} + +static QString dumpHistoryItem(const QWebHistoryItem& item, int indent, bool current) +{ + QString result; + + int start = 0; + if (current) { + result.append(QLatin1String("curr->")); + start = 6; + } + for (int i = start; i < indent; i++) + result.append(' '); + + QString url = item.url().toString(); + if (url.contains("file://")) { + static QString layoutTestsString("/LayoutTests/"); + static QString fileTestString("(file test):"); + + QString res = url.mid(url.indexOf(layoutTestsString) + layoutTestsString.length()); + if (res.isEmpty()) + return result; + + result.append(fileTestString); + result.append(res); + } else { + result.append(url); + } + + QString target = DumpRenderTreeSupportQt::historyItemTarget(item); + if (!target.isEmpty()) + result.append(QString(QLatin1String(" (in frame \"%1\")")).arg(target)); + + if (DumpRenderTreeSupportQt::isTargetItem(item)) + result.append(QLatin1String(" **nav target**")); + result.append(QLatin1String("\n")); + + QMap<QString, QWebHistoryItem> children = DumpRenderTreeSupportQt::getChildHistoryItems(item); + foreach (QWebHistoryItem item, children) + result += dumpHistoryItem(item, 12, false); + + return result; +} + +QString DumpRenderTree::dumpBackForwardList(QWebPage* page) +{ + QWebHistory* history = page->history(); + + QString result; + result.append(QLatin1String("\n============== Back Forward List ==============\n")); + + // FORMAT: + // " (file test):fast/loader/resources/click-fragment-link.html **nav target**" + // "curr-> (file test):fast/loader/resources/click-fragment-link.html#testfragment **nav target**" + + int maxItems = history->maximumItemCount(); + + foreach (const QWebHistoryItem item, history->backItems(maxItems)) { + if (!item.isValid()) + continue; + result.append(dumpHistoryItem(item, 8, false)); + } + + QWebHistoryItem item = history->currentItem(); + if (item.isValid()) + result.append(dumpHistoryItem(item, 8, true)); + + foreach (const QWebHistoryItem item, history->forwardItems(maxItems)) { + if (!item.isValid()) + continue; + result.append(dumpHistoryItem(item, 8, false)); + } + + result.append(QLatin1String("===============================================\n")); + return result; +} + +static const char *methodNameStringForFailedTest(LayoutTestController *controller) +{ + const char *errorMessage; + if (controller->shouldDumpAsText()) + errorMessage = "[documentElement innerText]"; + // FIXME: Add when we have support + //else if (controller->dumpDOMAsWebArchive()) + // errorMessage = "[[mainFrame DOMDocument] webArchive]"; + //else if (controller->dumpSourceAsWebArchive()) + // errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + + return errorMessage; +} + +void DumpRenderTree::dump() +{ + // Prevent any further frame load or resource load callbacks from appearing after we dump the result. + DumpRenderTreeSupportQt::dumpFrameLoader(false); + DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false); + + QWebFrame *mainFrame = m_page->mainFrame(); + + if (isStandAloneMode()) { + QString markup = mainFrame->toHtml(); + fprintf(stdout, "Source:\n\n%s\n", markup.toUtf8().constData()); + } + + QString mimeType = DumpRenderTreeSupportQt::responseMimeType(mainFrame); + if (mimeType == "text/plain") + m_controller->dumpAsText(); + + // Dump render text... + QString resultString; + if (m_controller->shouldDumpAsText()) + resultString = dumpFramesAsText(mainFrame); + else { + resultString = mainFrame->renderTreeDump(); + resultString += dumpFrameScrollPosition(mainFrame); + } + if (!resultString.isEmpty()) { + fprintf(stdout, "Content-Type: text/plain\n"); + fprintf(stdout, "%s", resultString.toUtf8().constData()); + + if (m_controller->shouldDumpBackForwardList()) { + fprintf(stdout, "%s", dumpBackForwardList(webPage()).toUtf8().constData()); + foreach (QObject* widget, windows) { + QWebPage* page = qobject_cast<QWebPage*>(widget->findChild<QWebPage*>()); + fprintf(stdout, "%s", dumpBackForwardList(page).toUtf8().constData()); + } + } + + } else + printf("ERROR: nil result from %s", methodNameStringForFailedTest(m_controller)); + + // signal end of text block + fputs("#EOF\n", stdout); + fputs("#EOF\n", stderr); + + // FIXME: All other ports don't dump pixels, if generatePixelResults is false. + if (m_dumpPixels) { + QImage image(m_page->viewportSize(), QImage::Format_ARGB32); + image.fill(Qt::white); + QPainter painter(&image); + mainFrame->render(&painter); + painter.end(); + + QCryptographicHash hash(QCryptographicHash::Md5); + for (int row = 0; row < image.height(); ++row) + hash.addData(reinterpret_cast<const char*>(image.scanLine(row)), image.width() * 4); + QString actualHash = hash.result().toHex(); + + fprintf(stdout, "\nActualHash: %s\n", qPrintable(actualHash)); + + bool dumpImage = true; + + if (!m_expectedHash.isEmpty()) { + Q_ASSERT(m_expectedHash.length() == 32); + fprintf(stdout, "\nExpectedHash: %s\n", qPrintable(m_expectedHash)); + + if (m_expectedHash == actualHash) + dumpImage = false; + } + + if (dumpImage) { + image.setText("checksum", actualHash); + + QBuffer buffer; + buffer.open(QBuffer::WriteOnly); + image.save(&buffer, "PNG"); + buffer.close(); + const QByteArray &data = buffer.data(); + + printf("Content-Type: %s\n", "image/png"); + printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length())); + + const quint32 bytesToWriteInOneChunk = 1 << 15; + quint32 dataRemainingToWrite = data.length(); + const char *ptr = data.data(); + while (dataRemainingToWrite) { + quint32 bytesToWriteInThisChunk = qMin(dataRemainingToWrite, bytesToWriteInOneChunk); + quint32 bytesWritten = fwrite(ptr, 1, bytesToWriteInThisChunk, stdout); + if (bytesWritten != bytesToWriteInThisChunk) + break; + dataRemainingToWrite -= bytesWritten; + ptr += bytesWritten; + } + } + + fflush(stdout); + } + + puts("#EOF"); // terminate the (possibly empty) pixels block + + fflush(stdout); + fflush(stderr); + + emit ready(); +} + +void DumpRenderTree::titleChanged(const QString &s) +{ + if (m_controller->shouldDumpTitleChanges()) + printf("TITLE CHANGED: %s\n", s.toUtf8().data()); +} + +void DumpRenderTree::connectFrame(QWebFrame *frame) +{ + connect(frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(initJSObjects())); + connect(frame, SIGNAL(provisionalLoad()), + layoutTestController(), SLOT(provisionalLoad())); +} + +void DumpRenderTree::dumpDatabaseQuota(QWebFrame* frame, const QString& dbName) +{ + if (!m_controller->shouldDumpDatabaseCallbacks()) + return; + QWebSecurityOrigin origin = frame->securityOrigin(); + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", + origin.scheme().toUtf8().data(), + origin.host().toUtf8().data(), + origin.port(), + dbName.toUtf8().data()); + origin.setDatabaseQuota(databaseDefaultQuota); +} + +void DumpRenderTree::dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded) +{ + if (m_controller->shouldDumpApplicationCacheDelegateCallbacks()) { + // For example, numbers from 30000 - 39999 will output as 30000. + // Rounding up or down not really matter for these tests. It's + // sufficient to just get a range of 10000 to determine if we were + // above or below a threshold. + quint64 truncatedSpaceNeeded = (totalSpaceNeeded / 10000) * 10000; + printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i} totalSpaceNeeded:~%llu\n", + origin->scheme().toUtf8().data(), + origin->host().toUtf8().data(), + origin->port(), + truncatedSpaceNeeded + ); + } + + if (m_controller->shouldDisallowIncreaseForApplicationCacheQuota()) + return; + + origin->setApplicationCacheQuota(defaultOriginQuota); +} + +void DumpRenderTree::statusBarMessage(const QString& message) +{ + if (!m_controller->shouldDumpStatusCallbacks()) + return; + + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message.toUtf8().constData()); +} + +QWebPage *DumpRenderTree::createWindow() +{ + if (!m_controller->canOpenWindows()) + return 0; + + // Create a dummy container object to track the page in DRT. + // QObject is used instead of QWidget to prevent DRT from + // showing the main view when deleting the container. + + QObject* container = new QObject(m_mainView); + // create a QWebPage we want to return + QWebPage* page = static_cast<QWebPage*>(new WebPage(container, this)); + // gets cleaned up in closeRemainingWindows() + windows.append(container); + + // connect the needed signals to the page + connect(page, SIGNAL(frameCreated(QWebFrame*)), this, SLOT(connectFrame(QWebFrame*))); + connectFrame(page->mainFrame()); + connect(page, SIGNAL(loadFinished(bool)), m_controller, SLOT(maybeDump(bool))); + connect(page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested())); + + // Use a frame group name for all pages created by DumpRenderTree to allow + // testing of cross-page frame lookup. + DumpRenderTreeSupportQt::webPageSetGroupName(page, "org.webkit.qt.DumpRenderTree"); + + return page; +} + +void DumpRenderTree::windowCloseRequested() +{ + QWebPage* page = qobject_cast<QWebPage*>(sender()); + QObject* container = page->parent(); + windows.removeAll(container); + container->deleteLater(); +} + +int DumpRenderTree::windowCount() const +{ +// include the main view in the count + return windows.count() + 1; +} + +void DumpRenderTree::geolocationPermissionSet() +{ + m_page->permissionSet(QWebPage::Geolocation); +} + +void DumpRenderTree::switchFocus(bool focused) +{ + QFocusEvent event((focused) ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason); + if (!isGraphicsBased()) + QApplication::sendEvent(m_mainView, &event); + else { + if (WebViewGraphicsBased* view = qobject_cast<WebViewGraphicsBased*>(m_mainView)) + view->scene()->sendEvent(view->graphicsView(), &event); + } + +} + +QList<WebPage*> DumpRenderTree::getAllPages() const +{ + QList<WebPage*> pages; + pages.append(m_page); + foreach (QObject* widget, windows) { + if (WebPage* page = widget->findChild<WebPage*>()) + pages.append(page); + } + return pages; +} + +void DumpRenderTree::initializeFonts() +{ +#if HAVE(FONTCONFIG) + static int numFonts = -1; + + FcInit(); + + // Some test cases may add or remove application fonts (via @font-face). + // Make sure to re-initialize the font set if necessary. + FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication); + if (appFontSet && numFonts >= 0 && appFontSet->nfont == numFonts) + return; + + QByteArray fontDir = getenv("WEBKIT_TESTFONTS"); + if (fontDir.isEmpty() || !QDir(fontDir).exists()) { + fprintf(stderr, + "\n\n" + "----------------------------------------------------------------------\n" + "WEBKIT_TESTFONTS environment variable is not set correctly.\n" + "This variable has to point to the directory containing the fonts\n" + "you can clone from git://gitorious.org/qtwebkit/testfonts.git\n" + "----------------------------------------------------------------------\n" + ); + exit(1); + } + char currentPath[PATH_MAX+1]; + if (!getcwd(currentPath, PATH_MAX)) + qFatal("Couldn't get current working directory"); + QByteArray configFile = currentPath; + FcConfig *config = FcConfigCreate(); + configFile += "/Tools/DumpRenderTree/qt/fonts.conf"; + if (!FcConfigParseAndLoad (config, (FcChar8*) configFile.data(), true)) + qFatal("Couldn't load font configuration file"); + if (!FcConfigAppFontAddDir (config, (FcChar8*) fontDir.data())) + qFatal("Couldn't add font dir!"); + FcConfigSetCurrent(config); + + appFontSet = FcConfigGetFonts(config, FcSetApplication); + numFonts = appFontSet->nfont; +#endif +} + +} diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h new file mode 100644 index 000000000..77b6e461f --- /dev/null +++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeQt_h +#define DumpRenderTreeQt_h + +#include <QList> +#include <QNetworkAccessManager> +#include <QObject> +#include <QTextStream> +#include <QSocketNotifier> + +#ifndef QT_NO_OPENSSL +#include <QSslError> +#endif + +#include "DumpRenderTreeSupportQt.h" +#include <qgraphicsview.h> +#include <qgraphicswebview.h> +#include <qwebframe.h> +#include <qwebinspector.h> +#include <qwebpage.h> +#include <qwebview.h> + +QT_BEGIN_NAMESPACE +class QUrl; +class QFile; +QT_END_NAMESPACE + +class QWebFrame; + +class LayoutTestController; +class DumpRenderTreeSupportQt; +class EventSender; +class TextInputController; +class GCController; +class PlainTextController; + +namespace WebCore { + +class WebPage; +class NetworkAccessManager; + +class DumpRenderTree : public QObject { +Q_OBJECT + +public: + DumpRenderTree(); + virtual ~DumpRenderTree(); + + // Initialize in single-file mode. + void open(const QUrl& url); + + void setTextOutputEnabled(bool enable) { m_enableTextOutput = enable; } + bool isTextOutputEnabled() { return m_enableTextOutput; } + + void setGraphicsBased(bool flag) { m_graphicsBased = flag; } + bool isGraphicsBased() { return m_graphicsBased; } + + void setDumpPixels(bool); + + void closeRemainingWindows(); + void resetToConsistentStateBeforeTesting(const QUrl&); + + LayoutTestController *layoutTestController() const { return m_controller; } + EventSender *eventSender() const { return m_eventSender; } + TextInputController *textInputController() const { return m_textInputController; } + QString persistentStoragePath() const { return m_persistentStoragePath; } + NetworkAccessManager *networkAccessManager() const { return m_networkAccessManager; } + + QWebPage *createWindow(); + int windowCount() const; + + void switchFocus(bool focused); + + WebPage *webPage() const { return m_page; } + QList<WebPage*> getAllPages() const; + + static void initializeFonts(); + + void processArgsLine(const QStringList&); + void setRedirectOutputFileName(const QString& fileName) { m_redirectOutputFileName = fileName; } + void setRedirectErrorFileName(const QString& fileName) { m_redirectErrorFileName = fileName; } + +public Q_SLOTS: + void initJSObjects(); + + void readLine(); + void processLine(const QString&); + + void dump(); + void titleChanged(const QString &s); + void connectFrame(QWebFrame *frame); + void dumpDatabaseQuota(QWebFrame* frame, const QString& dbName); + void dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded); + void statusBarMessage(const QString& message); + void windowCloseRequested(); + +Q_SIGNALS: + void quit(); + void ready(); + +private Q_SLOTS: + void showPage(); + void hidePage(); + void dryRunPrint(QWebFrame*); + void loadNextTestInStandAloneMode(); + void geolocationPermissionSet(); + +private: + void setStandAloneMode(bool flag) { m_standAloneMode = flag; } + bool isStandAloneMode() { return m_standAloneMode; } + + QString dumpFramesAsText(QWebFrame* frame); + QString dumpBackForwardList(QWebPage* page); + QString dumpFrameScrollPosition(QWebFrame* frame); + LayoutTestController *m_controller; + + bool m_dumpPixels; + QString m_expectedHash; + QStringList m_standAloneModeTestList; + + WebPage *m_page; + QWidget* m_mainView; + + EventSender *m_eventSender; + TextInputController *m_textInputController; + GCController* m_gcController; + PlainTextController* m_plainTextController; + NetworkAccessManager* m_networkAccessManager; + + QFile *m_stdin; + + QList<QObject*> windows; + bool m_enableTextOutput; + bool m_standAloneMode; + bool m_graphicsBased; + QString m_persistentStoragePath; + QString m_redirectOutputFileName; + QString m_redirectErrorFileName; +}; + +class NetworkAccessManager : public QNetworkAccessManager { + Q_OBJECT +public: + NetworkAccessManager(QObject* parent); + +private slots: +#ifndef QT_NO_OPENSSL + void sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&); +#endif +}; + +class WebPage : public QWebPage { + Q_OBJECT +public: + WebPage(QObject* parent, DumpRenderTree*); + virtual ~WebPage(); + QWebInspector* webInspector(); + void closeWebInspector(); + + QWebPage *createWindow(QWebPage::WebWindowType); + + void javaScriptAlert(QWebFrame *frame, const QString& message); + void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID); + bool javaScriptConfirm(QWebFrame *frame, const QString& msg); + bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result); + + void resetSettings(); + + virtual bool supportsExtension(QWebPage::Extension extension) const; + virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output); + + QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&); + + void permissionSet(QWebPage::Feature feature); + +public slots: + bool shouldInterruptJavaScript() { return false; } + void requestPermission(QWebFrame* frame, QWebPage::Feature feature); + void cancelPermission(QWebFrame* frame, QWebPage::Feature feature); + +protected: + bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); + bool isTextOutputEnabled() { return m_drt->isTextOutputEnabled(); } + +private slots: + void setViewGeometry(const QRect&); + +private: + QWebInspector* m_webInspector; + QList<QWebFrame*> m_pendingGeolocationRequests; + DumpRenderTree *m_drt; +}; + +class WebViewGraphicsBased : public QGraphicsView { + Q_OBJECT + +public: + WebViewGraphicsBased(QWidget* parent); + QGraphicsWebView* graphicsView() const { return m_item; } + void setPage(QWebPage* page) { m_item->setPage(page); } + +private: + QGraphicsWebView* m_item; +}; + +} + +#endif diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.cpp b/Tools/DumpRenderTree/qt/EventSenderQt.cpp new file mode 100644 index 000000000..3e4590e7f --- /dev/null +++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp @@ -0,0 +1,679 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EventSenderQt.h" + +#include <QGraphicsSceneMouseEvent> +#include <QtTest/QtTest> + +#define KEYCODE_DEL 127 +#define KEYCODE_BACKSPACE 8 +#define KEYCODE_LEFTARROW 0xf702 +#define KEYCODE_RIGHTARROW 0xf703 +#define KEYCODE_UPARROW 0xf700 +#define KEYCODE_DOWNARROW 0xf701 + +// Ports like Gtk and Windows expose a different approach for their zooming +// API if compared to Qt: they have specific methods for zooming in and out, +// as well as a settable zoom factor, while Qt has only a 'setZoomValue' method. +// Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility. +#define ZOOM_STEP 1.2 + +#define DRT_MESSAGE_DONE (QEvent::User + 1) + +struct DRTEventQueue { + QEvent* m_event; + int m_delay; +}; + +static DRTEventQueue eventQueue[1024]; +static unsigned endOfQueue; +static unsigned startOfQueue; + +EventSender::EventSender(QWebPage* parent) + : QObject(parent) +{ + m_page = parent; + m_mouseButtonPressed = false; + m_drag = false; + memset(eventQueue, 0, sizeof(eventQueue)); + endOfQueue = 0; + startOfQueue = 0; + m_eventLoop = 0; + m_currentButton = 0; + resetClickCount(); + m_page->view()->installEventFilter(this); + // So that we can match Scrollbar::pixelsPerLineStep() in WheelEventQt.cpp and + // pass fast/events/platform-wheelevent-in-scrolling-div.html + QApplication::setWheelScrollLines(2); +} + +static Qt::KeyboardModifiers getModifiers(const QStringList& modifiers) +{ + Qt::KeyboardModifiers modifs = 0; + for (int i = 0; i < modifiers.size(); ++i) { + const QString& m = modifiers.at(i); + if (m == "ctrlKey") + modifs |= Qt::ControlModifier; + else if (m == "shiftKey") + modifs |= Qt::ShiftModifier; + else if (m == "altKey") + modifs |= Qt::AltModifier; + else if (m == "metaKey") + modifs |= Qt::MetaModifier; + } + return modifs; +} + +void EventSender::mouseDown(int button, const QStringList& modifiers) +{ + Qt::KeyboardModifiers modifs = getModifiers(modifiers); + Qt::MouseButton mouseButton; + switch (button) { + case 0: + mouseButton = Qt::LeftButton; + break; + case 1: + mouseButton = Qt::MidButton; + break; + case 2: + mouseButton = Qt::RightButton; + break; + case 3: + // fast/events/mouse-click-events expects the 4th button to be treated as the middle button + mouseButton = Qt::MidButton; + break; + default: + mouseButton = Qt::LeftButton; + break; + } + + // only consider a click to count, an event originated by the + // same previous button and at the same position. + if (m_currentButton == button + && m_mousePos == m_clickPos + && m_clickTimer.isActive()) + m_clickCount++; + else + m_clickCount = 1; + + m_currentButton = button; + m_clickPos = m_mousePos; + m_mouseButtons |= mouseButton; + +// qDebug() << "EventSender::mouseDown" << frame; + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent((m_clickCount == 2) ? + QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, modifs); + } else { + event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick : + QEvent::MouseButtonPress, m_mousePos, m_mousePos, + mouseButton, m_mouseButtons, modifs); + } + + sendOrQueueEvent(event); + + m_clickTimer.start(QApplication::doubleClickInterval(), this); +} + +void EventSender::mouseUp(int button) +{ + Qt::MouseButton mouseButton; + switch (button) { + case 0: + mouseButton = Qt::LeftButton; + break; + case 1: + mouseButton = Qt::MidButton; + break; + case 2: + mouseButton = Qt::RightButton; + break; + case 3: + // fast/events/mouse-click-events expects the 4th button to be treated as the middle button + mouseButton = Qt::MidButton; + break; + default: + mouseButton = Qt::LeftButton; + break; + } + + m_mouseButtons &= ~mouseButton; + +// qDebug() << "EventSender::mouseUp" << frame; + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } else { + event = new QMouseEvent(QEvent::MouseButtonRelease, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } + + sendOrQueueEvent(event); +} + +void EventSender::mouseMoveTo(int x, int y) +{ +// qDebug() << "EventSender::mouseMoveTo" << x << y; + m_mousePos = QPoint(x, y); + + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove, + m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier); + } else { + event = new QMouseEvent(QEvent::MouseMove, + m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier); + } + + sendOrQueueEvent(event); +} + +#ifndef QT_NO_WHEELEVENT +void EventSender::mouseScrollBy(int x, int y) +{ + continuousMouseScrollBy((x*120), (y*120)); +} + +void EventSender::continuousMouseScrollBy(int x, int y) +{ + // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual + // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this. + if (x) { + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel, + m_mousePos, m_mousePos, x, Qt::NoModifier, Qt::Horizontal); + } else + event = new QWheelEvent(m_mousePos, m_mousePos, x, m_mouseButtons, Qt::NoModifier, Qt::Horizontal); + + sendOrQueueEvent(event); + } + if (y) { + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel, + m_mousePos, m_mousePos, y, Qt::NoModifier, Qt::Vertical); + } else + event = new QWheelEvent(m_mousePos, m_mousePos, y, m_mouseButtons, Qt::NoModifier, Qt::Vertical); + + sendOrQueueEvent(event); + } +} +#endif + +void EventSender::leapForward(int ms) +{ + eventQueue[endOfQueue].m_delay = ms; + //qDebug() << "EventSender::leapForward" << ms; +} + +void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location) +{ + QString s = string; + Qt::KeyboardModifiers modifs = getModifiers(modifiers); + if (location == 3) + modifs |= Qt::KeypadModifier; + int code = 0; + if (string.length() == 1) { + code = string.unicode()->unicode(); + //qDebug() << ">>>>>>>>> keyDown" << code << (char)code; + // map special keycodes used by the tests to something that works for Qt/X11 + if (code == '\r') { + code = Qt::Key_Return; + } else if (code == '\t') { + code = Qt::Key_Tab; + if (modifs == Qt::ShiftModifier) + code = Qt::Key_Backtab; + s = QString(); + } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) { + code = Qt::Key_Backspace; + if (modifs == Qt::AltModifier) + modifs = Qt::ControlModifier; + s = QString(); + } else if (code == 'o' && modifs == Qt::ControlModifier) { + // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph + // separator and then putting the cursor back to its original + // position. Allows us to pass emacs-ctrl-o.html + s = QLatin1String("\n"); + code = '\n'; + modifs = 0; + QKeyEvent event(QEvent::KeyPress, code, modifs, s); + sendEvent(m_page, &event); + QKeyEvent event2(QEvent::KeyRelease, code, modifs, s); + sendEvent(m_page, &event2); + s = QString(); + code = Qt::Key_Left; + } else if (code == 'y' && modifs == Qt::ControlModifier) { + s = QLatin1String("c"); + code = 'c'; + } else if (code == 'k' && modifs == Qt::ControlModifier) { + s = QLatin1String("x"); + code = 'x'; + } else if (code == 'a' && modifs == Qt::ControlModifier) { + s = QString(); + code = Qt::Key_Home; + modifs = 0; + } else if (code == KEYCODE_LEFTARROW) { + s = QString(); + code = Qt::Key_Left; + if (modifs & Qt::MetaModifier) { + code = Qt::Key_Home; + modifs &= ~Qt::MetaModifier; + } + } else if (code == KEYCODE_RIGHTARROW) { + s = QString(); + code = Qt::Key_Right; + if (modifs & Qt::MetaModifier) { + code = Qt::Key_End; + modifs &= ~Qt::MetaModifier; + } + } else if (code == KEYCODE_UPARROW) { + s = QString(); + code = Qt::Key_Up; + if (modifs & Qt::MetaModifier) { + code = Qt::Key_PageUp; + modifs &= ~Qt::MetaModifier; + } + } else if (code == KEYCODE_DOWNARROW) { + s = QString(); + code = Qt::Key_Down; + if (modifs & Qt::MetaModifier) { + code = Qt::Key_PageDown; + modifs &= ~Qt::MetaModifier; + } + } else if (code == 'a' && modifs == Qt::ControlModifier) { + s = QString(); + code = Qt::Key_Home; + modifs = 0; + } else + code = string.unicode()->toUpper().unicode(); + } else { + //qDebug() << ">>>>>>>>> keyDown" << string; + + if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) { + s = s.mid(1); + int functionKey = s.toInt(); + Q_ASSERT(functionKey >= 1 && functionKey <= 35); + code = Qt::Key_F1 + (functionKey - 1); + // map special keycode strings used by the tests to something that works for Qt/X11 + } else if (string == QLatin1String("leftArrow")) { + s = QString(); + code = Qt::Key_Left; + } else if (string == QLatin1String("rightArrow")) { + s = QString(); + code = Qt::Key_Right; + } else if (string == QLatin1String("upArrow")) { + s = QString(); + code = Qt::Key_Up; + } else if (string == QLatin1String("downArrow")) { + s = QString(); + code = Qt::Key_Down; + } else if (string == QLatin1String("pageUp")) { + s = QString(); + code = Qt::Key_PageUp; + } else if (string == QLatin1String("pageDown")) { + s = QString(); + code = Qt::Key_PageDown; + } else if (string == QLatin1String("home")) { + s = QString(); + code = Qt::Key_Home; + } else if (string == QLatin1String("end")) { + s = QString(); + code = Qt::Key_End; + } else if (string == QLatin1String("insert")) { + s = QString(); + code = Qt::Key_Insert; + } else if (string == QLatin1String("delete")) { + s = QString(); + code = Qt::Key_Delete; + } else if (string == QLatin1String("printScreen")) { + s = QString(); + code = Qt::Key_Print; + } else if (string == QLatin1String("menu")) { + s = QString(); + code = Qt::Key_Menu; + } + } + QKeyEvent event(QEvent::KeyPress, code, modifs, s); + sendEvent(m_page, &event); + QKeyEvent event2(QEvent::KeyRelease, code, modifs, s); + sendEvent(m_page, &event2); +} + +QStringList EventSender::contextClick() +{ + QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier); + sendEvent(m_page, &event); + QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier); + sendEvent(m_page, &event2); + + if (isGraphicsBased()) { + QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu); + ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse); + ctxEvent.setPos(m_mousePos); + WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view()); + if (view) + sendEvent(view->graphicsView(), &ctxEvent); + } else { + QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos); + sendEvent(m_page->view(), &ctxEvent); + } + return DumpRenderTreeSupportQt::contextMenu(m_page); +} + +void EventSender::scheduleAsynchronousClick() +{ + QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier); + postEvent(m_page, event); + QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier); + postEvent(m_page, event2); +} + +void EventSender::addTouchPoint(int x, int y) +{ + const int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1; + const QPointF pos(x, y); + QTouchEvent::TouchPoint point(id); + point.setPos(pos); + point.setStartPos(pos); + point.setState(Qt::TouchPointPressed); + m_touchPoints.append(point); +} + +void EventSender::updateTouchPoint(int index, int x, int y) +{ + if (index < 0 || index >= m_touchPoints.count()) + return; + + QTouchEvent::TouchPoint &p = m_touchPoints[index]; + p.setPos(QPointF(x, y)); + p.setState(Qt::TouchPointMoved); +} + +void EventSender::setTouchModifier(const QString &modifier, bool enable) +{ + Qt::KeyboardModifier mod = Qt::NoModifier; + if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive)) + mod = Qt::ShiftModifier; + else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive)) + mod = Qt::AltModifier; + else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive)) + mod = Qt::MetaModifier; + else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive)) + mod = Qt::ControlModifier; + + if (enable) + m_touchModifiers |= mod; + else + m_touchModifiers &= ~mod; +} + +void EventSender::touchStart() +{ + if (!m_touchActive) { + sendTouchEvent(QEvent::TouchBegin); + m_touchActive = true; + } else + sendTouchEvent(QEvent::TouchUpdate); +} + +void EventSender::touchMove() +{ + sendTouchEvent(QEvent::TouchUpdate); +} + +void EventSender::touchEnd() +{ + for (int i = 0; i < m_touchPoints.count(); ++i) + if (m_touchPoints[i].state() != Qt::TouchPointReleased) { + sendTouchEvent(QEvent::TouchUpdate); + return; + } + sendTouchEvent(QEvent::TouchEnd); + m_touchActive = false; +} + +void EventSender::clearTouchPoints() +{ + m_touchPoints.clear(); + m_touchModifiers = Qt::KeyboardModifiers(); + m_touchActive = false; +} + +void EventSender::releaseTouchPoint(int index) +{ + if (index < 0 || index >= m_touchPoints.count()) + return; + + m_touchPoints[index].setState(Qt::TouchPointReleased); +} + +void EventSender::sendTouchEvent(QEvent::Type type) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + static QTouchDevice* device = 0; + if (!device) { + device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + } + + QTouchEvent event(type, device, m_touchModifiers); +#else + QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers); +#endif + event.setTouchPoints(m_touchPoints); + sendEvent(m_page, &event); + QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin(); + while (it != m_touchPoints.end()) { + if (it->state() == Qt::TouchPointReleased) + it = m_touchPoints.erase(it); + else { + it->setState(Qt::TouchPointStationary); + ++it; + } + } +} + +void EventSender::zoomPageIn() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP); +} + +void EventSender::zoomPageOut() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP); +} + +void EventSender::textZoomIn() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP); +} + +void EventSender::textZoomOut() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP); +} + +void EventSender::scalePageBy(float scaleFactor, float x, float y) +{ + if (QWebFrame* frame = m_page->mainFrame()) + DumpRenderTreeSupportQt::scalePageBy(frame, scaleFactor, QPoint(x, y)); +} + +QWebFrame* EventSender::frameUnderMouse() const +{ + QWebFrame* frame = m_page->mainFrame(); + +redo: + QList<QWebFrame*> children = frame->childFrames(); + for (int i = 0; i < children.size(); ++i) { + if (children.at(i)->geometry().contains(m_mousePos)) { + frame = children.at(i); + goto redo; + } + } + if (frame->geometry().contains(m_mousePos)) + return frame; + return 0; +} + +void EventSender::sendOrQueueEvent(QEvent* event) +{ + // Mouse move events are queued if + // 1. A previous event was queued. + // 2. A delay was set-up by leapForward(). + // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed. + // To be safe and avoid a deadlock, this event is queued. + if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) { + sendEvent(m_page->view(), event); + delete event; + return; + } + eventQueue[endOfQueue++].m_event = event; + eventQueue[endOfQueue].m_delay = 0; + replaySavedEvents(event->type() != QEvent::MouseMove); +} + +void EventSender::replaySavedEvents(bool flush) +{ + if (startOfQueue < endOfQueue) { + // First send all the events that are ready to be sent + while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) { + QEvent* ev = eventQueue[startOfQueue++].m_event; + postEvent(m_page->view(), ev); + } + if (startOfQueue == endOfQueue) { + // Reset the queue + startOfQueue = 0; + endOfQueue = 0; + } else { + QTest::qWait(eventQueue[startOfQueue].m_delay); + eventQueue[startOfQueue].m_delay = 0; + } + } + if (!flush) + return; + + // Send a marker event, it will tell us when it is safe to exit the new event loop + QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE); + QApplication::postEvent(m_page->view(), drtEvent); + + // Start an event loop for async handling of Drag & Drop + m_eventLoop = new QEventLoop; + m_eventLoop->exec(); + delete m_eventLoop; + m_eventLoop = 0; +} + +bool EventSender::eventFilter(QObject* watched, QEvent* event) +{ + if (watched != m_page->view()) + return false; + switch (event->type()) { + case QEvent::Leave: + return true; + case QEvent::MouseButtonPress: + case QEvent::GraphicsSceneMousePress: + m_mouseButtonPressed = true; + break; + case QEvent::MouseMove: + case QEvent::GraphicsSceneMouseMove: + if (m_mouseButtonPressed) + m_drag = true; + break; + case QEvent::MouseButtonRelease: + case QEvent::GraphicsSceneMouseRelease: + m_mouseButtonPressed = false; + m_drag = false; + break; + case DRT_MESSAGE_DONE: + m_eventLoop->exit(); + return true; + } + return false; +} + +void EventSender::timerEvent(QTimerEvent* ev) +{ + m_clickTimer.stop(); +} + +QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) +{ + QGraphicsSceneMouseEvent* event; + event = new QGraphicsSceneMouseEvent(type); + event->setPos(pos); + event->setScreenPos(screenPos); + event->setButton(button); + event->setButtons(buttons); + event->setModifiers(modifiers); + + return event; +} + +QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation) +{ + QGraphicsSceneWheelEvent* event; + event = new QGraphicsSceneWheelEvent(type); + event->setPos(pos); + event->setScreenPos(screenPos); + event->setDelta(delta); + event->setModifiers(modifiers); + event->setOrientation(orientation); + + return event; +} + +void EventSender::sendEvent(QObject* receiver, QEvent* event) +{ + if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) + view->scene()->sendEvent(view->graphicsView(), event); + else + QApplication::sendEvent(receiver, event); +} + +void EventSender::postEvent(QObject* receiver, QEvent* event) +{ + // QGraphicsScene does not have a postEvent method, so send the event in this case + // and delete it after that. + if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) { + view->scene()->sendEvent(view->graphicsView(), event); + delete event; + } else + QApplication::postEvent(receiver, event); // event deleted by the system +} diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.h b/Tools/DumpRenderTree/qt/EventSenderQt.h new file mode 100644 index 000000000..736818442 --- /dev/null +++ b/Tools/DumpRenderTree/qt/EventSenderQt.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EventSenderQt_h +#define EventSenderQt_h + + +#include "DumpRenderTreeQt.h" + +#include <QApplication> +#include <QBasicTimer> +#include <QEvent> +#include <QEventLoop> +#include <QMouseEvent> +#include <QObject> +#include <QPoint> +#include <QString> +#include <QStringList> +#include <QTouchEvent> + +#include <qwebpage.h> +#include <qwebframe.h> + + +class EventSender : public QObject { + Q_OBJECT +public: + EventSender(QWebPage* parent); + virtual bool eventFilter(QObject* watched, QEvent* event); + void resetClickCount() { m_clickCount = 0; } + +public slots: + void mouseDown(int button = 0, const QStringList& modifiers = QStringList()); + void mouseUp(int button = 0); + void mouseMoveTo(int x, int y); +#ifndef QT_NO_WHEELEVENT + void mouseScrollBy(int x, int y); + void continuousMouseScrollBy(int x, int y); +#endif + void leapForward(int ms); + void keyDown(const QString& string, const QStringList& modifiers = QStringList(), unsigned int location = 0); + void clearKillRing() {} + QStringList contextClick(); + void scheduleAsynchronousClick(); + void addTouchPoint(int x, int y); + void updateTouchPoint(int index, int x, int y); + void setTouchModifier(const QString &modifier, bool enable); + void touchStart(); + void touchMove(); + void touchEnd(); + void zoomPageIn(); + void zoomPageOut(); + void textZoomIn(); + void textZoomOut(); + void scalePageBy(float scaleFactor, float x, float y); + void clearTouchPoints(); + void releaseTouchPoint(int index); + +protected: + void timerEvent(QTimerEvent*); + +private: + bool isGraphicsBased() const { return qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view()); } + QGraphicsSceneMouseEvent* createGraphicsSceneMouseEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton, Qt::MouseButtons, Qt::KeyboardModifiers); + QGraphicsSceneWheelEvent* createGraphicsSceneWheelEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers, Qt::Orientation); + void sendEvent(QObject* receiver, QEvent* event); + void postEvent(QObject* receiver, QEvent* event); + +private: + void sendTouchEvent(QEvent::Type); + void sendOrQueueEvent(QEvent*); + void replaySavedEvents(bool flush); + QPoint m_mousePos; + QPoint m_clickPos; + Qt::MouseButtons m_mouseButtons; + QWebPage* m_page; + int m_clickCount; + int m_currentButton; + bool m_mouseButtonPressed; + bool m_drag; + QEventLoop* m_eventLoop; + QWebFrame* frameUnderMouse() const; + QBasicTimer m_clickTimer; + QList<QTouchEvent::TouchPoint> m_touchPoints; + Qt::KeyboardModifiers m_touchModifiers; + bool m_touchActive; +}; +#endif // EventSenderQt_h diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.cpp b/Tools/DumpRenderTree/qt/GCControllerQt.cpp new file mode 100644 index 000000000..a2e5e0c85 --- /dev/null +++ b/Tools/DumpRenderTree/qt/GCControllerQt.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCControllerQt.h" +#include "DumpRenderTreeSupportQt.h" + +#include <qwebpage.h> + +GCController::GCController(QWebPage* parent) + : QObject(parent) +{ +} + +void GCController::collect() const +{ + DumpRenderTreeSupportQt::garbageCollectorCollect(); +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(waitUntilDone); +} + +unsigned int GCController::getJSObjectCount() const +{ + return DumpRenderTreeSupportQt::javaScriptObjectsCount(); +} diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.h b/Tools/DumpRenderTree/qt/GCControllerQt.h new file mode 100644 index 000000000..d3c83b9fe --- /dev/null +++ b/Tools/DumpRenderTree/qt/GCControllerQt.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 GCControllerQt_h +#define GCControllerQt_h + +#include <QObject> + +class QWebPage; +class DumpRenderTreeSupportQt; + +class GCController : public QObject +{ + Q_OBJECT +public: + GCController(QWebPage* parent); + +public slots: + void collect() const; + void collectOnAlternateThread(bool waitUntilDone) const; + unsigned int getJSObjectCount() const; + +}; + +#endif diff --git a/Tools/DumpRenderTree/qt/ImageDiff.cpp b/Tools/DumpRenderTree/qt/ImageDiff.cpp new file mode 100644 index 000000000..a1da2e026 --- /dev/null +++ b/Tools/DumpRenderTree/qt/ImageDiff.cpp @@ -0,0 +1,151 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QtCore/qmath.h> + +#include <QApplication> +#include <QBuffer> +#include <QByteArray> +#include <QImage> +#include <QStringList> + +#include <stdio.h> + +int main(int argc, char* argv[]) +{ + QCoreApplication app(argc, argv); + + qreal tolerance = 0; + + QStringList args = app.arguments(); + for (int i = 0; i < argc; ++i) + if (args[i] == "-t" || args[i] == "--tolerance") + tolerance = args[i + 1].toDouble(); + + char buffer[2048]; + QImage actualImage; + QImage baselineImage; + + while (fgets(buffer, sizeof(buffer), stdin)) { + // remove the CR + char* newLineCharacter = strchr(buffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strncmp("Content-Length: ", buffer, 16)) { + strtok(buffer, " "); + int imageSize = strtol(strtok(0, " "), 0, 10); + + if (imageSize <= 0) { + fputs("error, image size must be specified.\n", stdout); + } else { + unsigned char buffer[2048]; + QBuffer data; + + // Read all the incoming chunks + data.open(QBuffer::WriteOnly); + while (imageSize > 0) { + size_t bytesToRead = qMin(imageSize, 2048); + size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); + data.write(reinterpret_cast<const char*>(buffer), bytesRead); + imageSize -= static_cast<int>(bytesRead); + } + + // Convert into QImage + QImage decodedImage; + decodedImage.loadFromData(data.data(), "PNG"); + decodedImage.convertToFormat(QImage::Format_ARGB32); + + // Place it in the right place + if (actualImage.isNull()) + actualImage = decodedImage; + else + baselineImage = decodedImage; + } + } + + if (!actualImage.isNull() && !baselineImage.isNull()) { + + if (actualImage.size() != baselineImage.size()) { + fprintf(stderr, "error, test and reference image have different properties.\n"); + fflush(stderr); + } else { + + int w = actualImage.width(); + int h = actualImage.height(); + QImage diffImage(w, h, QImage::Format_ARGB32); + + int count = 0; + qreal sum = 0; + qreal maxDistance = 0; + + for (int x = 0; x < w; ++x) + for (int y = 0; y < h; ++y) { + QRgb pixel = actualImage.pixel(x, y); + QRgb basePixel = baselineImage.pixel(x, y); + qreal red = (qRed(pixel) - qRed(basePixel)) / static_cast<float>(qMax(255 - qRed(basePixel), qRed(basePixel))); + qreal green = (qGreen(pixel) - qGreen(basePixel)) / static_cast<float>(qMax(255 - qGreen(basePixel), qGreen(basePixel))); + qreal blue = (qBlue(pixel) - qBlue(basePixel)) / static_cast<float>(qMax(255 - qBlue(basePixel), qBlue(basePixel))); + qreal alpha = (qAlpha(pixel) - qAlpha(basePixel)) / static_cast<float>(qMax(255 - qAlpha(basePixel), qAlpha(basePixel))); + qreal distance = qSqrt(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; + int gray = distance * qreal(255); + diffImage.setPixel(x, y, qRgb(gray, gray, gray)); + if (distance >= 1 / qreal(255)) { + count++; + sum += distance; + maxDistance = qMax(maxDistance, distance); + } + } + + qreal difference = 0; + if (count) + difference = 100 * sum / static_cast<qreal>(w * h); + if (difference <= tolerance) { + difference = 0; + } else { + difference = qRound(difference * 100) / 100; + difference = qMax(difference, qreal(0.01)); + } + + if (!difference) + fprintf(stdout, "diff: %01.2f%% passed\n", difference); + else { + QBuffer buffer; + buffer.open(QBuffer::WriteOnly); + diffImage.save(&buffer, "PNG"); + buffer.close(); + const QByteArray &data = buffer.data(); + printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length())); + + // We have to use the return value of fwrite to avoid "ignoring return value" gcc warning + // See https://bugs.webkit.org/show_bug.cgi?id=45384 for details. + if (fwrite(data.constData(), 1, data.length(), stdout)) {} + + fprintf(stdout, "diff: %01.2f%% failed\n", difference); + } + + fflush(stdout); + } + actualImage = QImage(); + baselineImage = QImage(); + } + } + + return 0; +} diff --git a/Tools/DumpRenderTree/qt/ImageDiff.pro b/Tools/DumpRenderTree/qt/ImageDiff.pro new file mode 100644 index 000000000..729ec259a --- /dev/null +++ b/Tools/DumpRenderTree/qt/ImageDiff.pro @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------- +# Project file for the ImageDiff binary +# +# See 'Tools/qmake/README' for an overview of the build system +# ------------------------------------------------------------------- + +TEMPLATE = app + +TARGET = ImageDiff +DESTDIR = $$ROOT_BUILD_DIR/bin + +QT = core gui +haveQt(5): QT += widgets + +SOURCES = ImageDiff.cpp diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp new file mode 100644 index 000000000..b16511efb --- /dev/null +++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestControllerQt.h" +#include "DumpRenderTreeSupportQt.h" + +#include "DumpRenderTreeQt.h" +#include "WorkQueue.h" +#include "WorkQueueItemQt.h" +#include <QCoreApplication> +#include <QDir> +#include <QLocale> +#include <qwebsettings.h> + +LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt) + : QObject() + , m_drt(drt) +{ + reset(); + DumpRenderTreeSupportQt::dumpNotification(true); +} + +void LayoutTestController::reset() +{ + m_hasDumped = false; + m_loadFinished = false; + m_textDump = false; + m_dumpBackForwardList = false; + m_dumpChildrenAsText = false; + m_dumpChildFrameScrollPositions = false; + m_canOpenWindows = false; + m_waitForDone = false; + m_disallowIncreaseForApplicationCacheQuota = false; + m_dumpTitleChanges = false; + m_dumpDatabaseCallbacks = false; + m_dumpApplicationCacheDelegateCallbacks = false; + m_dumpStatusCallbacks = false; + m_timeoutTimer.stop(); + m_topLoadingFrame = 0; + m_waitForPolicy = false; + m_handleErrorPages = false; + m_webHistory = 0; + m_globalFlag = false; + m_userStyleSheetEnabled = false; + m_desktopNotificationAllowedOrigins.clear(); + m_ignoreDesktopNotification = false; + m_isGeolocationPermissionSet = false; + m_isPrinting = false; + m_geolocationPermission = false; + + DumpRenderTreeSupportQt::dumpEditingCallbacks(false); + DumpRenderTreeSupportQt::dumpFrameLoader(false); + DumpRenderTreeSupportQt::dumpProgressFinishedCallback(false); + DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(false); + DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false); + DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(false); + DumpRenderTreeSupportQt::dumpWillCacheResponseCallbacks(false); + DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(true); + DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(false); + DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(false); + DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(QStringList()); + DumpRenderTreeSupportQt::clearScriptWorlds(); + DumpRenderTreeSupportQt::setCustomPolicyDelegate(false, false); + DumpRenderTreeSupportQt::dumpHistoryCallbacks(false); + DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(false); + DumpRenderTreeSupportQt::resetGeolocationMock(m_drt->webPage()); + setIconDatabaseEnabled(false); + clearAllDatabases(); +#if QT_VERSION >= 0x040800 + // The default state for DRT is to block third-party cookies, mimicing the Mac port + setAlwaysAcceptCookies(false); +#endif + emit hidePage(); +} + +void LayoutTestController::processWork() +{ + // qDebug() << ">>>processWork"; + + // if we didn't start a new load, then we finished all the commands, so we're ready to dump state + if (WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) { + emit done(); + m_hasDumped = true; + } +} + +// Called on loadFinished on WebPage +void LayoutTestController::maybeDump(bool /*success*/) +{ + + // This can happen on any of the http/tests/security/window-events-*.html tests, where the test opens + // a new window, calls the unload and load event handlers on the window's page, and then immediately + // issues a notifyDone. Needs investigation. + if (!m_topLoadingFrame) + return; + + // It is possible that we get called by windows created from the main page that have finished + // loading, so we don't ASSERT here. At the moment we do not gather results from such windows, + // but may need to in future. + if (sender() != m_topLoadingFrame->page()) + return; + + m_loadFinished = true; + // as the function is called on loadFinished, the test might + // already have dumped and thus no longer be active, thus + // bail out here. + if (m_hasDumped) + return; + + WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test + if (WorkQueue::shared()->count()) + QTimer::singleShot(0, this, SLOT(processWork())); + else if (!shouldWaitUntilDone()) { + emit done(); + m_hasDumped = true; + } +} + +void LayoutTestController::waitUntilDone() +{ + //qDebug() << ">>>>waitForDone"; + m_waitForDone = true; + m_timeoutTimer.start(30000, this); +} + +QString LayoutTestController::counterValueForElementById(const QString& id) +{ + return DumpRenderTreeSupportQt::counterValueForElementById(m_drt->webPage()->mainFrame(), id); +} + +void LayoutTestController::setViewModeMediaFeature(const QString& mode) +{ + m_drt->webPage()->setProperty("_q_viewMode", mode); +} + +int LayoutTestController::webHistoryItemCount() +{ + if (!m_webHistory) + return -1; + + // Subtract one here as our QWebHistory::count() includes the actual page, + // which is not considered in the DRT tests. + return m_webHistory->count() - 1; +} + +void LayoutTestController::keepWebHistory() +{ + m_webHistory = m_drt->webPage()->history(); +} + +void LayoutTestController::notifyDone() +{ + qDebug() << ">>>>notifyDone"; + + if (!m_timeoutTimer.isActive()) + return; + + m_timeoutTimer.stop(); + m_waitForDone = false; + + // If the page has not finished loading (i.e. loadFinished() has not been emitted) then + // content created by the likes of document.write() JS methods will not be available yet. + // When the page has finished loading, maybeDump above will dump the results now that we have + // just set shouldWaitUntilDone to false. + if (!m_loadFinished) + return; + + emit done(); + + // FIXME: investigate why always resetting these result in timeouts + m_hasDumped = true; + m_waitForPolicy = false; +} + +int LayoutTestController::windowCount() +{ + return m_drt->windowCount(); +} + +void LayoutTestController::grantDesktopNotificationPermission(const QString& origin) +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + m_drt->webPage()->setFeaturePermission(frame, QWebPage::Notifications, QWebPage::PermissionGrantedByUser); + m_desktopNotificationAllowedOrigins.append(origin); +} + +void LayoutTestController::ignoreDesktopNotificationPermissionRequests() +{ + m_ignoreDesktopNotification = true; +} + +bool LayoutTestController::checkDesktopNotificationPermission(const QString& origin) +{ + return !m_ignoreDesktopNotification && m_desktopNotificationAllowedOrigins.contains(origin); +} + +void LayoutTestController::simulateDesktopNotificationClick(const QString& title) +{ + DumpRenderTreeSupportQt::simulateDesktopNotificationClick(title); +} + +void LayoutTestController::display() +{ + emit showPage(); +} + +void LayoutTestController::displayInvalidatedRegion() +{ + display(); +} + +void LayoutTestController::clearBackForwardList() +{ + m_drt->webPage()->history()->clear(); +} + +QString LayoutTestController::pathToLocalResource(const QString& url) +{ + QString localTmpUrl(QLatin1String("file:///tmp/LayoutTests")); + + // Translate a request for /tmp/LayoutTests to the repository LayoutTests directory. + // Do not rely on a symlink to be created via the test runner, which will not work on Windows. + if (url.startsWith(localTmpUrl)) { + // DumpRenderTree lives in WebKit/WebKitBuild/<build_mode>/bin. + // Translate from WebKit/WebKitBuild/Release/bin => WebKit/LayoutTests. + QFileInfo layoutTestsRoot(QCoreApplication::applicationDirPath() + QLatin1String("/../../../LayoutTests/")); + if (layoutTestsRoot.exists()) + return QLatin1String("file://") + layoutTestsRoot.absolutePath() + url.mid(localTmpUrl.length()); + } + + return url; +} + +void LayoutTestController::dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight) +{ + QString res = DumpRenderTreeSupportQt::viewportAsText(m_drt->webPage(), deviceDPI, QSize(deviceWidth, deviceHeight), QSize(availableWidth, availableHeight)); + fputs(qPrintable(res), stdout); +} + +void LayoutTestController::dumpEditingCallbacks() +{ + qDebug() << ">>>dumpEditingCallbacks"; + DumpRenderTreeSupportQt::dumpEditingCallbacks(true); +} + +void LayoutTestController::dumpFrameLoadCallbacks() +{ + DumpRenderTreeSupportQt::dumpFrameLoader(true); +} + +void LayoutTestController::dumpProgressFinishedCallback() +{ + DumpRenderTreeSupportQt::dumpProgressFinishedCallback(true); +} + +void LayoutTestController::dumpUserGestureInFrameLoadCallbacks() +{ + DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(true); +} + +void LayoutTestController::dumpResourceLoadCallbacks() +{ + DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(true); +} + +void LayoutTestController::dumpResourceResponseMIMETypes() +{ + DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(true); +} + +void LayoutTestController::dumpWillCacheResponse() +{ + DumpRenderTreeSupportQt::dumpWillCacheResponseCallbacks(true); +} + +void LayoutTestController::dumpHistoryCallbacks() +{ + DumpRenderTreeSupportQt::dumpHistoryCallbacks(true); +} + +void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(bool enabled) +{ + DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(enabled); +} + +void LayoutTestController::setWillSendRequestReturnsNull(bool enabled) +{ + DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(enabled); +} + +void LayoutTestController::setWillSendRequestClearHeader(const QStringList& headers) +{ + DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(headers); +} + +void LayoutTestController::setDeferMainResourceDataLoad(bool defer) +{ + DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(defer); +} + +void LayoutTestController::queueBackNavigation(int howFarBackward) +{ + //qDebug() << ">>>queueBackNavigation" << howFarBackward; + for (int i = 0; i != howFarBackward; ++i) + WorkQueue::shared()->queue(new BackItem(1, m_drt->webPage())); +} + +void LayoutTestController::queueForwardNavigation(int howFarForward) +{ + //qDebug() << ">>>queueForwardNavigation" << howFarForward; + for (int i = 0; i != howFarForward; ++i) + WorkQueue::shared()->queue(new ForwardItem(1, m_drt->webPage())); +} + +void LayoutTestController::queueLoad(const QString& url, const QString& target) +{ + //qDebug() << ">>>queueLoad" << url << target; + QUrl mainResourceUrl = m_drt->webPage()->mainFrame()->url(); + QString absoluteUrl = mainResourceUrl.resolved(QUrl(url)).toEncoded(); + WorkQueue::shared()->queue(new LoadItem(absoluteUrl, target, m_drt->webPage())); +} + +void LayoutTestController::queueLoadHTMLString(const QString& content, const QString& baseURL, const QString& failingURL) +{ + if (failingURL.isEmpty()) + WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, m_drt->webPage())); + else + WorkQueue::shared()->queue(new LoadAlternateHTMLStringItem(content, baseURL, failingURL, m_drt->webPage())); +} + +void LayoutTestController::queueReload() +{ + //qDebug() << ">>>queueReload"; + WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage())); +} + +void LayoutTestController::queueLoadingScript(const QString& script) +{ + //qDebug() << ">>>queueLoadingScript" << script; + WorkQueue::shared()->queue(new LoadingScriptItem(script, m_drt->webPage())); +} + +void LayoutTestController::queueNonLoadingScript(const QString& script) +{ + //qDebug() << ">>>queueNonLoadingScript" << script; + WorkQueue::shared()->queue(new NonLoadingScriptItem(script, m_drt->webPage())); +} + +void LayoutTestController::provisionalLoad() +{ + QWebFrame* frame = qobject_cast<QWebFrame*>(sender()); + if (!m_topLoadingFrame && !m_hasDumped) + m_topLoadingFrame = frame; +} + +void LayoutTestController::timerEvent(QTimerEvent *ev) +{ + if (ev->timerId() == m_timeoutTimer.timerId()) { + const char* message = "FAIL: Timed out waiting for notifyDone to be called\n"; + fprintf(stderr, "%s", message); + fprintf(stdout, "%s", message); + notifyDone(); + } else + QObject::timerEvent(ev); +} + +QString LayoutTestController::encodeHostName(const QString& host) +{ + QString encoded = QString::fromLatin1(QUrl::toAce(host + QLatin1String(".no"))); + encoded.truncate(encoded.length() - 3); // strip .no + return encoded; +} + +QString LayoutTestController::decodeHostName(const QString& host) +{ + QString decoded = QUrl::fromAce(host.toLatin1() + QByteArray(".no")); + decoded.truncate(decoded.length() - 3); + return decoded; +} + +void LayoutTestController::setMediaType(const QString& type) +{ + DumpRenderTreeSupportQt::setMediaType(m_drt->webPage()->mainFrame(), type); +} + +void LayoutTestController::closeWebInspector() +{ + DumpRenderTreeSupportQt::webInspectorClose(m_drt->webPage()); + m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false); +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enabled); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + // FIXME: Implement this. +} + +void LayoutTestController::showWebInspector() +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); + DumpRenderTreeSupportQt::webInspectorShow(m_drt->webPage()); +} + +void LayoutTestController::evaluateInWebInspector(long callId, const QString& script) +{ + DumpRenderTreeSupportQt::webInspectorExecuteScript(m_drt->webPage(), callId, script); +} + +void LayoutTestController::setFrameFlatteningEnabled(bool enabled) +{ + DumpRenderTreeSupportQt::setFrameFlatteningEnabled(m_drt->webPage(), enabled); +} + +void LayoutTestController::goBack() +{ + DumpRenderTreeSupportQt::goBack(m_drt->webPage()); +} + +void LayoutTestController::setDefersLoading(bool flag) +{ + DumpRenderTreeSupportQt::setDefersLoading(m_drt->webPage(), flag); +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, enabled); +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long quota) +{ + m_drt->webPage()->settings()->setOfflineWebApplicationCacheQuota(quota); +} + +void LayoutTestController::setAutofilled(const QWebElement& element, bool isAutofilled) +{ + return DumpRenderTreeSupportQt::setAutofilled(element, isAutofilled); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool enable) +{ + setDeveloperExtrasEnabled(enable); + DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(m_topLoadingFrame, enable); +} + +void LayoutTestController::setValueForUser(const QWebElement& element, const QString& value) +{ + DumpRenderTreeSupportQt::setValueForUser(element, value); +} + +void LayoutTestController::setFixedContentsSize(int width, int height) +{ + m_topLoadingFrame->page()->setPreferredContentsSize(QSize(width, height)); +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool enable) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable); +} + +void LayoutTestController::setSpatialNavigationEnabled(bool enable) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, enable); +} + +void LayoutTestController::setPopupBlockingEnabled(bool enable) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !enable); +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + // FIXME: Implement +} + +void LayoutTestController::setPOSIXLocale(const QString& locale) +{ + QLocale qlocale(locale); + QLocale::setDefault(qlocale); +} + +void LayoutTestController::setWindowIsKey(bool isKey) +{ + m_drt->switchFocus(isKey); +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst) +{ + //FIXME: only need this for the moment: https://bugs.webkit.org/show_bug.cgi?id=32990 +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool enable) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, enable); +} + +void LayoutTestController::setXSSAuditorEnabled(bool enable) +{ + // Set XSSAuditingEnabled globally so that windows created by the test inherit it too. + // resetSettings() will call this to reset the page and global setting to false again. + // Needed by http/tests/security/xssAuditor/link-opens-new-window.html + QWebSettings* globalSettings = QWebSettings::globalSettings(); + globalSettings->setAttribute(QWebSettings::XSSAuditingEnabled, enable); + m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditingEnabled, enable); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& animationName, + double time, + const QString& elementId) +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + return DumpRenderTreeSupportQt::pauseAnimation(frame, animationName, time, elementId); +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& propertyName, + double time, + const QString& elementId) +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + return DumpRenderTreeSupportQt::pauseTransitionOfProperty(frame, propertyName, time, elementId); +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId, + double time, + const QString& elementId) +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + return DumpRenderTreeSupportQt::pauseSVGAnimation(frame, animationId, time, elementId); +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame); +} + +void LayoutTestController::suspendAnimations() const +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + DumpRenderTreeSupportQt::suspendAnimations(frame); +} + +void LayoutTestController::resumeAnimations() const +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + DumpRenderTreeSupportQt::resumeAnimations(frame); +} + +void LayoutTestController::disableImageLoading() +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::AutoLoadImages, false); +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 +} + +void LayoutTestController::clearAllApplicationCaches() +{ + DumpRenderTreeSupportQt::clearAllApplicationCaches(); +} + +void LayoutTestController::clearApplicationCacheForOrigin(const QString& url) +{ + // FIXME: Implement to support deleting all application caches for an origin. +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(const QString& originIdentifier) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + return 0; +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + if (!m_topLoadingFrame) + return; + m_topLoadingFrame->securityOrigin().setApplicationCacheQuota(quota); +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(const QString& origin) +{ + // FIXME: Implement to support getting disk usage by all application caches for an origin. + return 0; +} + +QStringList LayoutTestController::originsWithApplicationCache() +{ + // FIXME: Implement to get origins that have application caches. + return QStringList(); +} + +void LayoutTestController::setCacheModel(int model) +{ + // qwebsetting doesn't have matched setting yet : + // WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER + // WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER + // WEBKIT_CACHE_MODEL_WEB_BROWSER + + // FIXME: Implement. +} + +void LayoutTestController::setDatabaseQuota(int size) +{ + if (!m_topLoadingFrame) + return; + m_topLoadingFrame->securityOrigin().setDatabaseQuota(size); +} + +void LayoutTestController::clearAllDatabases() +{ + QWebDatabase::removeAllDatabases(); +} + +void LayoutTestController::addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains) +{ + DumpRenderTreeSupportQt::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains) +{ + DumpRenderTreeSupportQt::removeWhiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); +} + +void LayoutTestController::setCustomPolicyDelegate(bool enabled, bool permissive) +{ + DumpRenderTreeSupportQt::setCustomPolicyDelegate(enabled, permissive); +} + +void LayoutTestController::waitForPolicyDelegate() +{ + setCustomPolicyDelegate(true); + m_waitForPolicy = true; + waitUntilDone(); +} + +void LayoutTestController::overridePreference(const QString& name, const QVariant& value) +{ + QWebSettings* settings = m_topLoadingFrame->page()->settings(); + + if (name == "WebKitJavaScriptEnabled") + settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool()); + else if (name == "WebKitTabToLinksPreferenceKey") + settings->setAttribute(QWebSettings::LinksIncludedInFocusChain, value.toBool()); + else if (name == "WebKitOfflineWebApplicationCacheEnabled") + settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool()); + else if (name == "WebKitDefaultFontSize") + settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt()); + else if (name == "WebKitUsesPageCachePreferenceKey") + QWebSettings::setMaximumPagesInCache(value.toInt()); + else if (name == "WebKitEnableCaretBrowsing") + setCaretBrowsingEnabled(value.toBool()); + else if (name == "WebKitPluginsEnabled") + settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool()); + else if (name == "WebKitWebGLEnabled") + settings->setAttribute(QWebSettings::WebGLEnabled, value.toBool()); + else if (name == "WebKitHyperlinkAuditingEnabled") + settings->setAttribute(QWebSettings::HyperlinkAuditingEnabled, value.toBool()); + else if (name == "WebKitHixie76WebSocketProtocolEnabled") + DumpRenderTreeSupportQt::setHixie76WebSocketProtocolEnabled(m_topLoadingFrame->page(), value.toBool()); + else + printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n", + name.toLatin1().data()); +} + +void LayoutTestController::setUserStyleSheetLocation(const QString& url) +{ + QByteArray urlData = pathToLocalResource(url).toLatin1(); + m_userStyleSheetLocation = QUrl::fromEncoded(urlData, QUrl::StrictMode); + + if (m_userStyleSheetEnabled) + setUserStyleSheetEnabled(true); +} + +void LayoutTestController::setCaretBrowsingEnabled(bool value) +{ + DumpRenderTreeSupportQt::setCaretBrowsingEnabled(m_drt->webPage(), value); +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool value) +{ + DumpRenderTreeSupportQt::setAuthorAndUserStylesEnabled(m_drt->webPage(), value); +} + +void LayoutTestController::setUserStyleSheetEnabled(bool enabled) +{ + m_userStyleSheetEnabled = enabled; + + if (enabled) + m_drt->webPage()->settings()->setUserStyleSheetUrl(m_userStyleSheetLocation); + else + m_drt->webPage()->settings()->setUserStyleSheetUrl(QUrl()); +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme) +{ + DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme); +} + +int LayoutTestController::workerThreadCount() +{ + return DumpRenderTreeSupportQt::workerThreadCount(); +} + +int LayoutTestController::pageNumberForElementById(const QString& id, float width, float height) +{ + // If no size specified, webpage viewport size is used + if (!width && !height) { + width = m_drt->webPage()->viewportSize().width(); + height = m_drt->webPage()->viewportSize().height(); + } + + return DumpRenderTreeSupportQt::pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height); +} + +int LayoutTestController::numberOfPages(float width, float height) +{ + return DumpRenderTreeSupportQt::numberOfPages(m_drt->webPage()->mainFrame(), width, height); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + return DumpRenderTreeSupportQt::shouldClose(m_drt->webPage()->mainFrame()); +} + +void LayoutTestController::setScrollbarPolicy(const QString& orientation, const QString& policy) +{ + Qt::Orientation o; + Qt::ScrollBarPolicy p; + + if (orientation == "vertical") + o = Qt::Vertical; + else if (orientation == "horizontal") + o = Qt::Horizontal; + else + return; + + if (policy == "on") + p = Qt::ScrollBarAlwaysOn; + else if (policy == "auto") + p = Qt::ScrollBarAsNeeded; + else if (policy == "off") + p = Qt::ScrollBarAlwaysOff; + else + return; + + m_drt->webPage()->mainFrame()->setScrollBarPolicy(o, p); +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool enable) +{ + DumpRenderTreeSupportQt::setSmartInsertDeleteEnabled(m_drt->webPage(), enable); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool enable) +{ + DumpRenderTreeSupportQt::setSelectTrailingWhitespaceEnabled(m_drt->webPage(), enable); +} + +void LayoutTestController::execCommand(const QString& name, const QString& value) +{ + DumpRenderTreeSupportQt::executeCoreCommandByName(m_drt->webPage(), name, value); +} + +bool LayoutTestController::isCommandEnabled(const QString& name) const +{ + return DumpRenderTreeSupportQt::isCommandEnabled(m_drt->webPage(), name); +} + +bool LayoutTestController::findString(const QString& string, const QStringList& optionArray) +{ + return DumpRenderTreeSupportQt::findString(m_drt->webPage(), string, optionArray); +} + +QString LayoutTestController::markerTextForListItem(const QWebElement& listItem) +{ + return DumpRenderTreeSupportQt::markerTextForListItem(listItem); +} + +QVariantMap LayoutTestController::computedStyleIncludingVisitedInfo(const QWebElement& element) const +{ + return DumpRenderTreeSupportQt::computedStyleIncludingVisitedInfo(element); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const QString& elementId) +{ + return DumpRenderTreeSupportQt::elementDoesAutoCompleteForElementWithId(m_drt->webPage()->mainFrame(), elementId); +} + +void LayoutTestController::authenticateSession(const QString&, const QString&, const QString&) +{ + // FIXME: If there is a concept per-session (per-process) credential storage, the credentials should be added to it for later use. +} + +void LayoutTestController::setIconDatabaseEnabled(bool enable) +{ + if (enable && !m_drt->persistentStoragePath().isEmpty()) + QWebSettings::setIconDatabasePath(m_drt->persistentStoragePath()); + else + QWebSettings::setIconDatabasePath(QString()); +} + +void LayoutTestController::setEditingBehavior(const QString& editingBehavior) +{ + DumpRenderTreeSupportQt::setEditingBehavior(m_drt->webPage(), editingBehavior); +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + DumpRenderTreeSupportQt::setMockDeviceOrientation(page, canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + setGeolocationPermissionCommon(allow); + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + DumpRenderTreeSupportQt::setMockGeolocationPermission(page, allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + int pendingPermissionCount = 0; + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + pendingPermissionCount += DumpRenderTreeSupportQt::numberOfPendingGeolocationPermissionRequests(page); + + return pendingPermissionCount; +} + +void LayoutTestController::setGeolocationPermissionCommon(bool allow) +{ + m_isGeolocationPermissionSet = true; + m_geolocationPermission = allow; +} + +void LayoutTestController::setMockGeolocationError(int code, const QString& message) +{ + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + DumpRenderTreeSupportQt::setMockGeolocationError(page, code, message); +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + DumpRenderTreeSupportQt::setMockGeolocationPosition(page, latitude, longitude, accuracy); +} + +void LayoutTestController::addMockSpeechInputResult(const QString& result, double confidence, const QString& language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::startSpeechInput(const QString& inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(int worldID, const QString& script) +{ + DumpRenderTreeSupportQt::evaluateScriptInIsolatedWorld(m_drt->webPage()->mainFrame(), worldID, script); +} + +bool LayoutTestController::isPageBoxVisible(int pageIndex) +{ + return DumpRenderTreeSupportQt::isPageBoxVisible(m_drt->webPage()->mainFrame(), pageIndex); +} + +QString LayoutTestController::pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) +{ + return DumpRenderTreeSupportQt::pageSizeAndMarginsInPixels(m_drt->webPage()->mainFrame(), pageIndex, + width, height, marginTop, marginRight, marginBottom, marginLeft); +} + +QString LayoutTestController::pageProperty(const QString& propertyName, int pageNumber) +{ + return DumpRenderTreeSupportQt::pageProperty(m_drt->webPage()->mainFrame(), propertyName, pageNumber); +} + +void LayoutTestController::addUserStyleSheet(const QString& sourceCode) +{ + DumpRenderTreeSupportQt::addUserStyleSheet(m_drt->webPage(), sourceCode); +} + +void LayoutTestController::removeAllVisitedLinks() +{ + QWebHistory* history = m_drt->webPage()->history(); + history->clear(); + DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(true); +} + +bool LayoutTestController::hasSpellingMarker(int, int) +{ + // FIXME: Implement. + return false; +} + +QVariantList LayoutTestController::nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + return DumpRenderTreeSupportQt::nodesFromRect(document, x, y, top, right, bottom, left, ignoreClipping); +} + +void LayoutTestController::addURLToRedirect(const QString& origin, const QString& destination) +{ + DumpRenderTreeSupportQt::addURLToRedirect(origin, destination); +} + +void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval) +{ + DumpRenderTreeSupportQt::setMinimumTimerInterval(m_drt->webPage(), minimumTimerInterval); +} + +void LayoutTestController::originsWithLocalStorage() +{ + // FIXME: Implement. +} + +void LayoutTestController::deleteAllLocalStorage() +{ + // FIXME: Implement. +} + +void LayoutTestController::deleteLocalStorageForOrigin(const QString& originIdentifier) +{ + // FIXME: Implement. +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned number) +{ + // FIXME: Implement. +} + +void LayoutTestController::syncLocalStorage() +{ + // FIXME: Implement. +} + +QString LayoutTestController::layerTreeAsText() +{ + return DumpRenderTreeSupportQt::layerTreeAsText(m_drt->webPage()->mainFrame()); +} + +void LayoutTestController::setTextDirection(const QString& directionName) +{ + if (directionName == "auto") + m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionDefault); + else if (directionName == "rtl") + m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionRightToLeft); + else if (directionName == "ltr") + m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionLeftToRight); +} + +#if QT_VERSION >= 0x040800 +void LayoutTestController::setAlwaysAcceptCookies(bool accept) +{ + QWebSettings* globalSettings = QWebSettings::globalSettings(); + if (accept) + globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysAllowThirdPartyCookies); + else { + // This matches the Safari third-party cookie blocking policy tested in third-party-cookie-relaxing.html + globalSettings->setThirdPartyCookiePolicy(QWebSettings::AllowThirdPartyWithExistingCookies); + } +} + +void LayoutTestController::setAlwaysBlockCookies(bool block) +{ + QWebSettings* globalSettings = QWebSettings::globalSettings(); + if (block) + globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysBlockThirdPartyCookies); + else + globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysAllowThirdPartyCookies); +} +#endif + +const unsigned LayoutTestController::maxViewWidth = 800; +const unsigned LayoutTestController::maxViewHeight = 600; diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h new file mode 100644 index 000000000..b842fe4df --- /dev/null +++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 LayoutTestControllerQt_h +#define LayoutTestControllerQt_h + +#include <QBasicTimer> +#include <QObject> +#include <QSize> +#include <QString> +#include <QtDebug> +#include <QTimer> +#include <QTimerEvent> +#include <QVariant> + +#include <qwebdatabase.h> +#include <qwebelement.h> +#include <qwebframe.h> +#include <qwebhistory.h> +#include <qwebpage.h> +#include <qwebsecurityorigin.h> + +class QWebFrame; +class DumpRenderTreeSupportQt; +namespace WebCore { + class DumpRenderTree; +} +class LayoutTestController : public QObject { + Q_OBJECT + Q_PROPERTY(int webHistoryItemCount READ webHistoryItemCount) + Q_PROPERTY(int workerThreadCount READ workerThreadCount) + Q_PROPERTY(bool globalFlag READ globalFlag WRITE setGlobalFlag) +public: + LayoutTestController(WebCore::DumpRenderTree* drt); + + bool shouldDisallowIncreaseForApplicationCacheQuota() const { return m_disallowIncreaseForApplicationCacheQuota; } + bool shouldDumpAsText() const { return m_textDump; } + bool shouldDumpBackForwardList() const { return m_dumpBackForwardList; } + bool shouldDumpChildrenAsText() const { return m_dumpChildrenAsText; } + bool shouldDumpChildFrameScrollPositions() const { return m_dumpChildFrameScrollPositions; } + bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; } + bool shouldDumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; } + bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; } + bool shouldWaitUntilDone() const { return m_waitForDone; } + bool shouldHandleErrorPages() const { return m_handleErrorPages; } + bool canOpenWindows() const { return m_canOpenWindows; } + bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; } + bool waitForPolicy() const { return m_waitForPolicy; } + bool ignoreReqestForPermission() const { return m_ignoreDesktopNotification; } + bool isPrinting() { return m_isPrinting; } + + void reset(); + + static const unsigned int maxViewWidth; + static const unsigned int maxViewHeight; + +protected: + void timerEvent(QTimerEvent*); + +signals: + void done(); + + void showPage(); + void hidePage(); + void geolocationPermissionSet(); + +public slots: + void maybeDump(bool ok); + void disallowIncreaseForApplicationCacheQuota() { m_disallowIncreaseForApplicationCacheQuota = true; } + void dumpAsText() { m_textDump = true; } + void dumpChildFramesAsText() { m_dumpChildrenAsText = true; } + void dumpChildFrameScrollPositions() { m_dumpChildFrameScrollPositions = true; } + void dumpDatabaseCallbacks() { m_dumpDatabaseCallbacks = true; } + void dumpApplicationCacheDelegateCallbacks() { m_dumpApplicationCacheDelegateCallbacks = true; } + void dumpStatusCallbacks() { m_dumpStatusCallbacks = true; } + void setCanOpenWindows() { m_canOpenWindows = true; } + void setPrinting() { m_isPrinting = true; } + void waitUntilDone(); + QString counterValueForElementById(const QString& id); + int webHistoryItemCount(); + void keepWebHistory(); + void notifyDone(); + void dumpBackForwardList() { m_dumpBackForwardList = true; } + bool globalFlag() const { return m_globalFlag; } + void setGlobalFlag(bool flag) { m_globalFlag = flag; } + void handleErrorPages() { m_handleErrorPages = true; } + void dumpEditingCallbacks(); + void dumpFrameLoadCallbacks(); + void dumpProgressFinishedCallback(); + void dumpUserGestureInFrameLoadCallbacks(); + void dumpResourceLoadCallbacks(); + void dumpResourceResponseMIMETypes(); + void dumpWillCacheResponse(); + void dumpHistoryCallbacks(); + void dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight); + void setWillSendRequestReturnsNullOnRedirect(bool enabled); + void setWillSendRequestReturnsNull(bool enabled); + void setWillSendRequestClearHeader(const QStringList& headers); + void queueBackNavigation(int howFarBackward); + void queueForwardNavigation(int howFarForward); + void queueLoad(const QString& url, const QString& target = QString()); + void queueLoadHTMLString(const QString& content, const QString& baseURL = QString(), const QString& failingURL = QString()); + void queueReload(); + void queueLoadingScript(const QString& script); + void queueNonLoadingScript(const QString& script); + void provisionalLoad(); + void setCloseRemainingWindowsWhenComplete(bool = false) {} + int windowCount(); + void grantDesktopNotificationPermission(const QString& origin); + void ignoreDesktopNotificationPermissionRequests(); + bool checkDesktopNotificationPermission(const QString& origin); + void simulateDesktopNotificationClick(const QString& title); + void display(); + void displayInvalidatedRegion(); + void clearBackForwardList(); + QString pathToLocalResource(const QString& url); + void dumpTitleChanges() { m_dumpTitleChanges = true; } + QString encodeHostName(const QString& host); + QString decodeHostName(const QString& host); + void dumpSelectionRect() const {} + void setDeveloperExtrasEnabled(bool); + void setAsynchronousSpellCheckingEnabled(bool); + void showWebInspector(); + void closeWebInspector(); + void evaluateInWebInspector(long callId, const QString& script); + void removeAllVisitedLinks(); + void setMediaType(const QString& type); + void setFrameFlatteningEnabled(bool enable); + void setAllowUniversalAccessFromFileURLs(bool enable); + void setAllowFileAccessFromFileURLs(bool enable); + void setAppCacheMaximumSize(unsigned long long quota); + void setAutofilled(const QWebElement&, bool enable); + void setJavaScriptProfilingEnabled(bool enable); + void setValueForUser(const QWebElement&, const QString& value); + void setFixedContentsSize(int width, int height); + void setPrivateBrowsingEnabled(bool enable); + void setSpatialNavigationEnabled(bool enabled); + void setPluginsEnabled(bool flag); + void setPopupBlockingEnabled(bool enable); + void setPOSIXLocale(const QString& locale); + void resetLoadFinished() { m_loadFinished = false; } + void setWindowIsKey(bool isKey); + void setMainFrameIsFirstResponder(bool isFirst); + void setDeferMainResourceDataLoad(bool); + void setJavaScriptCanAccessClipboard(bool enable); + void setXSSAuditorEnabled(bool enable); + void setCaretBrowsingEnabled(bool enable); + void setAuthorAndUserStylesEnabled(bool); + void setViewModeMediaFeature(const QString& mode); + void setSmartInsertDeleteEnabled(bool enable); + void setSelectTrailingWhitespaceEnabled(bool enable); + void execCommand(const QString& name, const QString& value = QString()); + bool isCommandEnabled(const QString& name) const; + bool findString(const QString& string, const QStringList& optionArray); + + bool pauseAnimationAtTimeOnElementWithId(const QString& animationName, double time, const QString& elementId); + bool pauseTransitionAtTimeOnElementWithId(const QString& propertyName, double time, const QString& elementId); + bool sampleSVGAnimationForElementAtTime(const QString& animationId, double time, const QString& elementId); + bool elementDoesAutoCompleteForElementWithId(const QString& elementId); + + unsigned numberOfActiveAnimations() const; + void suspendAnimations() const; + void resumeAnimations() const; + + void addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains); + void removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains); + + void dispatchPendingLoadRequests(); + void disableImageLoading(); + + void clearAllApplicationCaches(); + void clearApplicationCacheForOrigin(const QString& url); + void setApplicationCacheOriginQuota(unsigned long long quota); + QStringList originsWithApplicationCache(); + long long applicationCacheDiskUsageForOrigin(const QString&); + void setCacheModel(int); + + void setDatabaseQuota(int size); + void clearAllDatabases(); + void setIconDatabaseEnabled(bool enable); + + void setCustomPolicyDelegate(bool enabled, bool permissive = false); + void waitForPolicyDelegate(); + + void overridePreference(const QString& name, const QVariant& value); + void setUserStyleSheetLocation(const QString& url); + void setUserStyleSheetEnabled(bool enabled); + void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme); + int workerThreadCount(); + int pageNumberForElementById(const QString& id, float width = 0, float height = 0); + int numberOfPages(float width = maxViewWidth, float height = maxViewHeight); + bool callShouldCloseOnWebView(); + // For now, this is a no-op. This may change depending on outcome of + // https://bugs.webkit.org/show_bug.cgi?id=33333 + void setCallCloseOnWebViews() {} + // This is a no-op - it allows us to pass + // plugins/get-url-that-the-resource-load-delegate-will-disallow.html + // which is a Mac-specific test. + void addDisallowedURL(const QString&) {} + + void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma); + + void setMockGeolocationError(int code, const QString& message); + void setMockGeolocationPosition(double latitude, double longitude, double accuracy); + void setGeolocationPermission(bool allow); + int numberOfPendingGeolocationPermissionRequests(); + bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; } + bool geolocationPermission() const { return m_geolocationPermission; } + + void addMockSpeechInputResult(const QString& result, double confidence, const QString& language); + void startSpeechInput(const QString& inputElement); + + // Empty stub method to keep parity with object model exposed by global LayoutTestController. + void abortModal() {} + bool hasSpellingMarker(int from, int length); + + QVariantList nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping); + + void addURLToRedirect(const QString& origin, const QString& destination); + + /* + Policy values: 'on', 'auto' or 'off'. + Orientation values: 'vertical' or 'horizontal'. + */ + void setScrollbarPolicy(const QString& orientation, const QString& policy); + + QString markerTextForListItem(const QWebElement& listItem); + QVariantMap computedStyleIncludingVisitedInfo(const QWebElement& element) const; + + // Simulate a request an embedding application could make, populating per-session credential storage. + void authenticateSession(const QString& url, const QString& username, const QString& password); + + void setEditingBehavior(const QString& editingBehavior); + + void evaluateScriptInIsolatedWorld(int worldID, const QString& script); + bool isPageBoxVisible(int pageIndex); + QString pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft); + QString pageProperty(const QString& propertyName, int pageNumber); + void addUserStyleSheet(const QString& sourceCode); + + void setMinimumTimerInterval(double); + + void originsWithLocalStorage(); + void deleteAllLocalStorage(); + void deleteLocalStorageForOrigin(const QString& originIdentifier); + long long localStorageDiskUsageForOrigin(const QString& originIdentifier); + void observeStorageTrackerNotifications(unsigned number); + void syncLocalStorage(); + QString layerTreeAsText(); + void setTextDirection(const QString& directionName); + void goBack(); + void setDefersLoading(bool); +#if QT_VERSION >= 0x040800 + void setAlwaysAcceptCookies(bool); + void setAlwaysBlockCookies(bool); +#endif + +private slots: + void processWork(); + +private: + void setGeolocationPermissionCommon(bool allow); + +private: + bool m_hasDumped; + bool m_textDump; + bool m_disallowIncreaseForApplicationCacheQuota; + bool m_dumpBackForwardList; + bool m_dumpChildrenAsText; + bool m_dumpChildFrameScrollPositions; + bool m_canOpenWindows; + bool m_waitForDone; + bool m_dumpTitleChanges; + bool m_dumpDatabaseCallbacks; + bool m_dumpApplicationCacheDelegateCallbacks; + bool m_dumpStatusCallbacks; + bool m_waitForPolicy; + bool m_handleErrorPages; + bool m_loadFinished; + bool m_globalFlag; + bool m_userStyleSheetEnabled; + bool m_isGeolocationPermissionSet; + bool m_isPrinting; + bool m_geolocationPermission; + + QUrl m_userStyleSheetLocation; + QBasicTimer m_timeoutTimer; + QWebFrame* m_topLoadingFrame; + WebCore::DumpRenderTree* m_drt; + QWebHistory* m_webHistory; + QStringList m_desktopNotificationAllowedOrigins; + bool m_ignoreDesktopNotification; +}; + +#endif // LayoutTestControllerQt_h diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp new file mode 100644 index 000000000..dd63feadb --- /dev/null +++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PlainTextControllerQt.h" + +#include "DumpRenderTreeSupportQt.h" +#include <QApplication> +#include <QInputMethodEvent> +#include <QKeyEvent> + +PlainTextController::PlainTextController(QWebPage* parent) + : QObject(parent) +{ +} + +QString PlainTextController::plainText(const QVariant& range) +{ + return DumpRenderTreeSupportQt::plainText(range); +} diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.h b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h new file mode 100644 index 000000000..e78e1105a --- /dev/null +++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 PlainTextControllerQt_h +#define PlainTextControllerQt_h + +#include <QList> +#include <QObject> +#include <QString> +#include <QVariant> + +#include "qwebpage.h" + +class PlainTextController : public QObject { + Q_OBJECT +public: + PlainTextController(QWebPage* parent); + +public slots: + QString plainText(const QVariant& range); +}; + +#endif // PlainTextControllerQt_h diff --git a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro new file mode 100644 index 000000000..cbcd92198 --- /dev/null +++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------- +# Project file for the NPAPI test plugin +# +# See 'Tools/qmake/README' for an overview of the build system +# ------------------------------------------------------------------- + +TEMPLATE = lib +TARGET = TestNetscapePlugIn + +CONFIG += plugin + +SOURCES += \ + PluginObject.cpp \ + PluginTest.cpp \ + TestObject.cpp \ + main.cpp \ + Tests/DocumentOpenInDestroyStream.cpp \ + Tests/EvaluateJSAfterRemovingPluginElement.cpp \ + Tests/FormValue.cpp \ + Tests/GetURLNotifyWithURLThatFailsToLoad.cpp \ + Tests/GetURLWithJavaScriptURL.cpp \ + Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \ + Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \ + Tests/NPDeallocateCalledBeforeNPShutdown.cpp \ + Tests/NPPSetWindowCalledDuringDestruction.cpp \ + Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \ + Tests/NPRuntimeRemoveProperty.cpp \ + Tests/NullNPPGetValuePointer.cpp \ + Tests/PassDifferentNPPStruct.cpp \ + Tests/PluginScriptableNPObjectInvokeDefault.cpp \ + Tests/PrivateBrowsing.cpp + +WEBKIT += webcore # For NPAPI headers + +VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn + + +INCLUDEPATH += \ + ../../unix/TestNetscapePlugin/ForwardingHeaders \ + ../../unix/TestNetscapePlugin/ForwardingHeaders/WebKit \ + ../../TestNetscapePlugIn + +DESTDIR = $${ROOT_BUILD_DIR}/lib/plugins + +mac { + CONFIG += plugin_bundle + QMAKE_INFO_PLIST = ../../TestNetscapePlugIn/mac/Info.plist + QMAKE_PLUGIN_BUNDLE_NAME = $$TARGET + QMAKE_BUNDLE_LOCATION += "Contents/MacOS" + + !build_pass:CONFIG += build_all + + OBJECTIVE_SOURCES += PluginObjectMac.mm + LIBS += -framework Carbon -framework Cocoa -framework QuartzCore +} + +!win32:!embedded:!mac { + LIBS += -lX11 + DEFINES += XP_UNIX +} diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp new file mode 100644 index 000000000..d5645a523 --- /dev/null +++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "TextInputControllerQt.h" +#include "DumpRenderTreeSupportQt.h" + +#include <QApplication> +#include <QInputMethodEvent> +#include <QKeyEvent> + +TextInputController::TextInputController(QWebPage* parent) + : QObject(parent) +{ +} + +void TextInputController::doCommand(const QString& command) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + int keycode = 0; + if (command == "moveBackwardAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Left; + } else if (command =="moveDown:") { + keycode = Qt::Key_Down; + } else if (command =="moveDownAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Down; + } else if (command =="moveForward:") { + keycode = Qt::Key_Right; + } else if (command =="moveForwardAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Right; + } else if (command =="moveLeft:") { + keycode = Qt::Key_Left; + } else if (command =="moveLeftAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Left; + } else if (command =="moveRight:") { + keycode = Qt::Key_Right; + } else if (command =="moveRightAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Right; + } else if (command =="moveToBeginningOfDocument:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Home; + } else if (command =="moveToBeginningOfLine:") { + keycode = Qt::Key_Home; +// } else if (command =="moveToBeginningOfParagraph:") { + } else if (command =="moveToEndOfDocument:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_End; + } else if (command =="moveToEndOfLine:") { + keycode = Qt::Key_End; +// } else if (command =="moveToEndOfParagraph:") { + } else if (command =="moveUp:") { + keycode = Qt::Key_Up; + } else if (command =="moveUpAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Up; + } else if (command =="moveWordBackward:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Up; + } else if (command =="moveWordBackwardAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Left; + } else if (command =="moveWordForward:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Right; + } else if (command =="moveWordForwardAndModifySelection:") { + modifiers |= Qt::ControlModifier; + modifiers |= Qt::ShiftModifier; + keycode = Qt::Key_Right; + } else if (command =="moveWordLeft:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Left; + } else if (command =="moveWordRight:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Left; + } else if (command =="moveWordRightAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Right; + } else if (command =="moveWordLeftAndModifySelection:") { + modifiers |= Qt::ShiftModifier; + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Left; + } else if (command =="pageDown:") { + keycode = Qt::Key_PageDown; + } else if (command =="pageUp:") { + keycode = Qt::Key_PageUp; + } else if (command == "deleteWordBackward:") { + modifiers |= Qt::ControlModifier; + keycode = Qt::Key_Backspace; + } else if (command == "deleteBackward:") { + keycode = Qt::Key_Backspace; + } else if (command == "deleteForward:") { + keycode = Qt::Key_Delete; + } + + QKeyEvent event(QEvent::KeyPress, keycode, modifiers); + QApplication::sendEvent(parent(), &event); + QKeyEvent event2(QEvent::KeyRelease, keycode, modifiers); + QApplication::sendEvent(parent(), &event2); +} + +void TextInputController::setMarkedText(const QString& string, int start, int end) +{ + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute selection(QInputMethodEvent::Selection, start, end, QVariant()); + attributes << selection; + QInputMethodEvent event(string, attributes); + QApplication::sendEvent(parent(), &event); +} + +void TextInputController::insertText(const QString& string) +{ + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event(string, attributes); + event.setCommitString(string); + QApplication::sendEvent(parent(), &event); +} + +QVariantList TextInputController::selectedRange() +{ + return DumpRenderTreeSupportQt::selectedRange(qobject_cast<QWebPage*>(parent())); +} + +QVariantList TextInputController::firstRectForCharacterRange(int location, int length) +{ + return DumpRenderTreeSupportQt::firstRectForCharacterRange(qobject_cast<QWebPage*>(parent()), location, length); +} + +void TextInputController::unmarkText() +{ + DumpRenderTreeSupportQt::confirmComposition(qobject_cast<QWebPage*>(parent()), 0); +} diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.h b/Tools/DumpRenderTree/qt/TextInputControllerQt.h new file mode 100644 index 000000000..572abfd7c --- /dev/null +++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 TextInputControllerQt_h +#define TextInputControllerQt_h + +#include <QList> +#include <QObject> +#include <QVariant> +#include <QString> +#include "qwebpage.h" + +class TextInputController : public QObject { + Q_OBJECT +public: + TextInputController(QWebPage* parent); + +public slots: + void doCommand(const QString& command); + void setMarkedText(const QString& string, int start, int end); +// bool hasMarkedText(); + void unmarkText(); +// QList<int> markedRange(); + QVariantList selectedRange(); +// void validAttributesForMarkedText(); + void insertText(const QString& string); + QVariantList firstRectForCharacterRange(int location, int length); +// void characterIndexForPoint(int, int); +// void substringFromRange(int, int); +// void conversationIdentifier(); +}; +#endif // TextInputControllerQt_h diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp new file mode 100644 index 000000000..b09336667 --- /dev/null +++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItemQt.h" +#include "DumpRenderTreeSupportQt.h" + +QWebFrame* findFrameNamed(const QString& frameName, QWebFrame* frame) +{ + if (frame->frameName() == frameName) + return frame; + + foreach (QWebFrame* childFrame, frame->childFrames()) + if (QWebFrame* f = findFrameNamed(frameName, childFrame)) + return f; + + return 0; +} + +bool LoadItem::invoke() const +{ + //qDebug() << ">>>LoadItem::invoke"; + Q_ASSERT(m_webPage); + + QWebFrame* frame = 0; + const QString t = target(); + if (t.isEmpty()) + frame = m_webPage->mainFrame(); + else + frame = findFrameNamed(t, m_webPage->mainFrame()); + + if (!frame) + return false; + + frame->load(url()); + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + Q_ASSERT(m_webPage); + + QWebFrame* frame = m_webPage->mainFrame(); + if (!frame) + return false; + + frame->setHtml(m_content, QUrl(m_baseURL)); + return true; +} + +bool LoadAlternateHTMLStringItem::invoke() const +{ + Q_ASSERT(m_webPage); + + QWebFrame* frame = m_webPage->mainFrame(); + if (!frame) + return false; + + DumpRenderTreeSupportQt::setAlternateHtml(frame, m_content, QUrl(m_baseURL), QUrl(m_failingURL)); + return true; +} + +bool ReloadItem::invoke() const +{ + //qDebug() << ">>>ReloadItem::invoke"; + Q_ASSERT(m_webPage); + m_webPage->triggerAction(QWebPage::Reload); + return true; +} + +bool ScriptItem::invoke() const +{ + //qDebug() << ">>>ScriptItem::invoke"; + Q_ASSERT(m_webPage); + m_webPage->mainFrame()->evaluateJavaScript(script()); + return true; +} + +bool BackForwardItem::invoke() const +{ + //qDebug() << ">>>BackForwardItem::invoke"; + Q_ASSERT(m_webPage); + if (!m_howFar) + return false; + + if (m_howFar > 0) { + for (int i = 0; i != m_howFar; ++i) + m_webPage->triggerAction(QWebPage::Forward); + } else { + for (int i = 0; i != m_howFar; --i) + m_webPage->triggerAction(QWebPage::Back); + } + return true; +} diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.h b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h new file mode 100644 index 000000000..ac7d1b37a --- /dev/null +++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WorkQueueItemQt_h +#define WorkQueueItemQt_h + +#include <QPointer> +#include <QString> +#include <qwebframe.h> +#include <qwebpage.h> + +class WorkQueueItem { +public: + WorkQueueItem(QWebPage *page) : m_webPage(page) {} + virtual ~WorkQueueItem() { } + virtual bool invoke() const = 0; + +protected: + QPointer<QWebPage> m_webPage; +}; + +class LoadItem : public WorkQueueItem { +public: + LoadItem(const QString &url, const QString &target, QWebPage *page) + : WorkQueueItem(page) + , m_url(url) + , m_target(target) + { + } + + QString url() const { return m_url; } + QString target() const { return m_target; } + + virtual bool invoke() const; + +private: + QString m_url; + QString m_target; +}; + +class LoadHTMLStringItem : public WorkQueueItem { +public: + LoadHTMLStringItem(const QString& content, const QString &baseURL, QWebPage *page) + : WorkQueueItem(page) + , m_content(content) + , m_baseURL(baseURL) + { + } + +private: + virtual bool invoke() const; + + QString m_content; + QString m_baseURL; +}; + +class LoadAlternateHTMLStringItem : public WorkQueueItem { +public: + LoadAlternateHTMLStringItem(const QString& content, const QString& baseURL, const QString &failingURL, QWebPage *page) + : WorkQueueItem(page) + , m_content(content) + , m_baseURL(baseURL) + , m_failingURL(failingURL) + { + } + +private: + virtual bool invoke() const; + + QString m_content; + QString m_baseURL; + QString m_failingURL; +}; + +class ReloadItem : public WorkQueueItem { +public: + ReloadItem(QWebPage *page) + : WorkQueueItem(page) + { + } + virtual bool invoke() const; +}; + +class ScriptItem : public WorkQueueItem { +public: + ScriptItem(const QString &script, QWebPage *page) + : WorkQueueItem(page) + , m_script(script) + { + } + + QString script() const { return m_script; } + + virtual bool invoke() const; + +private: + QString m_script; +}; + +class LoadingScriptItem : public ScriptItem { +public: + LoadingScriptItem(const QString& script, QWebPage* page) + : ScriptItem(script, page) + { + } + + virtual bool invoke() const { return ScriptItem::invoke(); } +}; + +class NonLoadingScriptItem : public ScriptItem { +public: + NonLoadingScriptItem(const QString& script, QWebPage* page) + : ScriptItem(script, page) + { + } + + virtual bool invoke() const { ScriptItem::invoke(); return false; } +}; + + +class BackForwardItem : public WorkQueueItem { +public: + virtual bool invoke() const; + +protected: + BackForwardItem(int howFar, QWebPage *page) + : WorkQueueItem(page) + , m_howFar(howFar) + { + } + + int m_howFar; +}; + +class BackItem : public BackForwardItem { +public: + BackItem(unsigned howFar, QWebPage *page) + : BackForwardItem(-howFar, page) + { + } +}; + +class ForwardItem : public BackForwardItem { +public: + ForwardItem(unsigned howFar, QWebPage *page) + : BackForwardItem(howFar, page) + { + } +}; + +#endif // !defined(WorkQueueItemQt_h) diff --git a/Tools/DumpRenderTree/qt/fonts.conf b/Tools/DumpRenderTree/qt/fonts.conf new file mode 100644 index 000000000..3540c479f --- /dev/null +++ b/Tools/DumpRenderTree/qt/fonts.conf @@ -0,0 +1,258 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<fontconfig> + +<!-- + Accept deprecated 'mono' alias, replacing it with 'monospace' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>mono</string> + </test> + <edit name="family" mode="assign"> + <string>monospace</string> + </edit> + </match> + +<!-- + Accept alternate 'sans serif' spelling, replacing it with 'sans-serif' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans serif</string> + </test> + <edit name="family" mode="assign"> + <string>sans-serif</string> + </edit> + </match> + +<!-- + Accept deprecated 'sans' alias, replacing it with 'sans-serif' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans</string> + </test> + <edit name="family" mode="assign"> + <string>sans-serif</string> + </edit> + </match> + + + <config> +<!-- + These are the default Unicode chars that are expected to be blank + in fonts. All other blank chars are assumed to be broken and + won't appear in the resulting charsets + --> + <blank> + <int>0x0020</int> <!-- SPACE --> + <int>0x00A0</int> <!-- NO-BREAK SPACE --> + <int>0x00AD</int> <!-- SOFT HYPHEN --> + <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER --> + <int>0x0600</int> <!-- ARABIC NUMBER SIGN --> + <int>0x0601</int> <!-- ARABIC SIGN SANAH --> + <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER --> + <int>0x0603</int> <!-- ARABIC SIGN SAFHA --> + <int>0x06DD</int> <!-- ARABIC END OF AYAH --> + <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK --> + <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER --> + <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER --> + <int>0x1680</int> <!-- OGHAM SPACE MARK --> + <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ --> + <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA --> + <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR --> + <int>0x2000</int> <!-- EN QUAD --> + <int>0x2001</int> <!-- EM QUAD --> + <int>0x2002</int> <!-- EN SPACE --> + <int>0x2003</int> <!-- EM SPACE --> + <int>0x2004</int> <!-- THREE-PER-EM SPACE --> + <int>0x2005</int> <!-- FOUR-PER-EM SPACE --> + <int>0x2006</int> <!-- SIX-PER-EM SPACE --> + <int>0x2007</int> <!-- FIGURE SPACE --> + <int>0x2008</int> <!-- PUNCTUATION SPACE --> + <int>0x2009</int> <!-- THIN SPACE --> + <int>0x200A</int> <!-- HAIR SPACE --> + <int>0x200B</int> <!-- ZERO WIDTH SPACE --> + <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER --> + <int>0x200D</int> <!-- ZERO WIDTH JOINER --> + <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK --> + <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK --> + <int>0x2028</int> <!-- LINE SEPARATOR --> + <int>0x2029</int> <!-- PARAGRAPH SEPARATOR --> + <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING --> + <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING --> + <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING --> + <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE --> + <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE --> + <int>0x202F</int> <!-- NARROW NO-BREAK SPACE --> + <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE --> + <int>0x2060</int> <!-- WORD JOINER --> + <int>0x2061</int> <!-- FUNCTION APPLICATION --> + <int>0x2062</int> <!-- INVISIBLE TIMES --> + <int>0x2063</int> <!-- INVISIBLE SEPARATOR --> + <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING --> + <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING --> + <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING --> + <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING --> + <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES --> + <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES --> + <int>0x3000</int> <!-- IDEOGRAPHIC SPACE --> + <int>0x3164</int> <!-- HANGUL FILLER --> + <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE --> + <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER --> + <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR --> + <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR --> + <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR --> + </blank> +<!-- + Rescan configuration every 30 seconds when FcFontSetList is called + --> + <rescan> + <int>30</int> + </rescan> + </config> + +<!-- + URW provides metric and shape compatible fonts for these 10 Adobe families. + + However, these fonts are quite ugly and do not render well on-screen, + so we avoid matching them if the application said `anymetrics'; in that + case, a more generic font with different metrics but better appearance + will be used. + --> + <match target="pattern"> + <test name="family"> + <string>Avant Garde</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>URW Gothic L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Bookman</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>URW Bookman L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Courier</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>Nimbus Mono L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Helvetica</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>Nimbus Sans L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>New Century Schoolbook</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>Century Schoolbook L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Palatino</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>URW Palladio L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Times</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>Nimbus Roman No9 L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Zapf Chancery</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>URW Chancery L</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Zapf Dingbats</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append"> + <string>Dingbats</string> + </edit> + </match> + <match target="pattern"> + <test name="family"> + <string>Symbol</string> + </test> + <test name="anymetrics" qual="all" compare="not_eq"> + <bool>true</bool> + </test> + <edit name="family" mode="append" binding="same"> + <string>Standard Symbols L</string> + </edit> + </match> + +<!-- + Serif faces + --> + <alias> + <family>Nimbus Roman No9 L</family> + <default><family>serif</family></default> + </alias> +<!-- + Sans-serif faces + --> + <alias> + <family>Nimbus Sans L</family> + <default><family>sans-serif</family></default> + </alias> +<!-- + Monospace faces + --> + <alias> + <family>Nimbus Mono L</family> + <default><family>monospace</family></default> + </alias> + + +</fontconfig> diff --git a/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF Binary files differnew file mode 100644 index 000000000..ac81cb031 --- /dev/null +++ b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF diff --git a/Tools/DumpRenderTree/qt/main.cpp b/Tools/DumpRenderTree/qt/main.cpp new file mode 100644 index 000000000..3d9673bee --- /dev/null +++ b/Tools/DumpRenderTree/qt/main.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTreeQt.h" + +#include <wtf/AlwaysInline.h> + +#include <qstringlist.h> +#include <qapplication.h> +#include <qurl.h> +#include <qdir.h> +#include <qdebug.h> +#include <qfont.h> +#include <qwebdatabase.h> +#include <qtimer.h> +#include <qwindowsstyle.h> + +#ifdef Q_WS_X11 +#include <qx11info_x11.h> +#endif + +#ifdef Q_OS_WIN +#include <io.h> +#include <fcntl.h> +#endif + +#include <limits.h> +#include <signal.h> + +#if defined(__GLIBC__) && !defined(__UCLIBC__) +#include <execinfo.h> +#endif + +void messageHandler(QtMsgType type, const char *message) +{ + if (type == QtCriticalMsg) { + fprintf(stderr, "%s\n", message); + return; + } + // do nothing +} + +// We only support -v or --pixel-tests or --stdout or --stderr or -, all the others will be +// pass as test case name (even -abc.html is a valid test case name) +bool isOption(const QString& str) +{ + return str == QString("-v") || str == QString("--pixel-tests") + || str == QString("--stdout") || str == QString("--stderr") + || str == QString("-"); +} + +QString takeOptionValue(QStringList& arguments, int index) +{ + QString result; + + if (index + 1 < arguments.count() && !isOption(arguments.at(index + 1))) + result = arguments.takeAt(index + 1); + arguments.removeAt(index); + + return result; +} + +void printUsage() +{ + fprintf(stderr, "Usage: DumpRenderTree [-v|--pixel-tests] [--stdout output_filename] [-stderr error_filename] filename [filename2..n]\n"); + fprintf(stderr, "Or folder containing test files: DumpRenderTree [-v|--pixel-tests] dirpath\n"); + fflush(stderr); +} + +QString get_backtrace() { + QString s; + +#if defined(__GLIBC__) && !defined(__UCLIBC__) + void* array[256]; + size_t size; /* number of stack frames */ + + size = backtrace(array, 256); + + if (!size) + return s; + + char** strings = backtrace_symbols(array, size); + for (int i = 0; i < int(size); ++i) { + s += QString::number(i) + + QLatin1String(": ") + + QLatin1String(strings[i]) + QLatin1String("\n"); + } + + if (strings) + free (strings); +#endif + + return s; +} + +#if HAVE(SIGNAL_H) +static NO_RETURN void crashHandler(int sig) +{ + fprintf(stderr, "%s\n", strsignal(sig)); + fprintf(stderr, "%s\n", get_backtrace().toLatin1().constData()); + exit(128 + sig); +} +#endif + +int main(int argc, char* argv[]) +{ +#ifdef Q_OS_WIN + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); +#endif + + // Suppress debug output from Qt if not started with -v + bool suppressQtDebugOutput = true; + for (int i = 1; i < argc; ++i) { + if (!qstrcmp(argv[i], "-v")) { + suppressQtDebugOutput = false; + break; + } + } + + // Has to be done before QApplication is constructed in case + // QApplication itself produces debug output. + if (suppressQtDebugOutput) + qInstallMsgHandler(messageHandler); + + WebCore::DumpRenderTree::initializeFonts(); + + QApplication::setGraphicsSystem("raster"); + QApplication::setStyle(new QWindowsStyle); + + QApplication app(argc, argv); + +#ifdef Q_WS_X11 + QX11Info::setAppDpiY(0, 96); + QX11Info::setAppDpiX(0, 96); +#endif + + /* + * QApplication will initialize the default application font based + * on the application DPI at construction time, which might be + * different from the DPI we explicitly set using QX11Info above. + * See: https://bugreports.qt.nokia.com/browse/QTBUG-21603 + * + * To ensure that the application font DPI matches the application + * DPI, we override the application font using the font we get from + * a QWidget, which has already been resolved against the existing + * default font, but with the correct paint-device DPI. + */ + QApplication::setFont(QWidget().font()); + +#if HAVE(SIGNAL_H) + signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */ + signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */ + signal(SIGFPE, crashHandler); /* 8: floating point exception */ + signal(SIGBUS, crashHandler); /* 10: bus error */ + signal(SIGSEGV, crashHandler); /* 11: segmentation violation */ + signal(SIGSYS, crashHandler); /* 12: bad argument to system call */ + signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */ + signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */ + signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */ +#endif + + QStringList args = app.arguments(); + if (args.count() < (!suppressQtDebugOutput ? 3 : 2)) { + printUsage(); + exit(1); + } + + // Remove the first arguments, it is application name itself + args.removeAt(0); + + WebCore::DumpRenderTree dumper; + + int index = args.indexOf(QLatin1String("--pixel-tests")); + if (index != -1) { + dumper.setDumpPixels(true); + args.removeAt(index); + } + + index = args.indexOf(QLatin1String("--stdout")); + if (index != -1) { + QString fileName = takeOptionValue(args, index); + dumper.setRedirectOutputFileName(fileName); + if (fileName.isEmpty() || !freopen(qPrintable(fileName), "w", stdout)) { + fprintf(stderr, "STDOUT redirection failed."); + exit(1); + } + } + index = args.indexOf(QLatin1String("--stderr")); + if (index != -1) { + QString fileName = takeOptionValue(args, index); + dumper.setRedirectErrorFileName(fileName); + if (!freopen(qPrintable(fileName), "w", stderr)) { + fprintf(stderr, "STDERR redirection failed."); + exit(1); + } + } + QWebDatabase::removeAllDatabases(); + + index = args.indexOf(QLatin1String("-")); + if (index != -1) { + args.removeAt(index); + + // Continue waiting in STDIN for more test case after process one test case + QObject::connect(&dumper, SIGNAL(ready()), &dumper, SLOT(readLine()), Qt::QueuedConnection); + + // Read and only read the first test case, ignore the others + if (args.size() > 0) { + // Process the argument first + dumper.processLine(args[0]); + } else + QTimer::singleShot(0, &dumper, SLOT(readLine())); + } else { + // Go into standalone mode + // Standalone mode need at least one test case + if (args.count() < 1) { + printUsage(); + exit(1); + } + dumper.processArgsLine(args); + } + return app.exec(); +} diff --git a/Tools/DumpRenderTree/qt/resources/user.css b/Tools/DumpRenderTree/qt/resources/user.css new file mode 100644 index 000000000..af3981995 --- /dev/null +++ b/Tools/DumpRenderTree/qt/resources/user.css @@ -0,0 +1,4 @@ +body { + font-size: 50px; + background-color: rgb(255, 255, 0); +}
\ No newline at end of file diff --git a/Tools/DumpRenderTree/qt/testplugin.cpp b/Tools/DumpRenderTree/qt/testplugin.cpp new file mode 100644 index 000000000..d5b8bc7ee --- /dev/null +++ b/Tools/DumpRenderTree/qt/testplugin.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "testplugin.h" + +TestPlugin::TestPlugin(QObject *parent) + : QWebPluginFactory(parent) +{ +} + +TestPlugin::~TestPlugin() +{ +} + +QList<QWebPluginFactory::Plugin> TestPlugin::plugins() const +{ + QWebPluginFactory::Plugin plugin; + + plugin.name = "testplugin"; + plugin.description = "testdescription"; + MimeType mimeType; + mimeType.name = "testtype"; + mimeType.fileExtensions.append("testsuffixes"); + plugin.mimeTypes.append(mimeType); + + plugin.name = "testplugin2"; + plugin.description = "testdescription2"; + mimeType.name = "testtype2"; + mimeType.fileExtensions.append("testsuffixes2"); + mimeType.fileExtensions.append("testsuffixes3"); + plugin.mimeTypes.append(mimeType); + + return QList<QWebPluginFactory::Plugin>() << plugin; +} + +QObject *TestPlugin::create(const QString&, + const QUrl&, + const QStringList&, + const QStringList&) const +{ + return 0; +} + diff --git a/Tools/DumpRenderTree/qt/testplugin.h b/Tools/DumpRenderTree/qt/testplugin.h new file mode 100644 index 000000000..3d8a28cf3 --- /dev/null +++ b/Tools/DumpRenderTree/qt/testplugin.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <qwebpluginfactory.h> + + +class TestPlugin : public QWebPluginFactory +{ +public: + explicit TestPlugin(QObject *parent = 0); + virtual ~TestPlugin(); + + virtual QList<Plugin> plugins() const; + + virtual QObject *create(const QString &mimeType, + const QUrl &url, + const QStringList &argumentNames, + const QStringList &argumentValues) const; + +}; + diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h new file mode 100644 index 000000000..627bc97a9 --- /dev/null +++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h @@ -0,0 +1 @@ +#include <plugins/npapi.h> diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h new file mode 100644 index 000000000..54a603dbb --- /dev/null +++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h @@ -0,0 +1 @@ +#include <plugins/npfunctions.h> diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h new file mode 100644 index 000000000..e435ae2ab --- /dev/null +++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h @@ -0,0 +1 @@ +#include <plugins/npruntime.h> diff --git a/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp new file mode 100644 index 000000000..644efe5f1 --- /dev/null +++ b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityUIElement.h" +#include "DumpRenderTree.h" +#include "FrameLoadDelegate.h" +#include <JavaScriptCore/Assertions.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <oleacc.h> +#include <string> + +using namespace std; + +AccessibilityController::AccessibilityController() + : m_focusEventHook(0) + , m_scrollingStartEventHook(0) + , m_valueChangeEventHook(0) + , m_allEventsHook(0) + , m_notificationsEventHook(0) +{ +} + +AccessibilityController::~AccessibilityController() +{ + setLogFocusEvents(false); + setLogAccessibilityEvents(false); + setLogValueChangeEvents(false); + + if (m_notificationsEventHook) + UnhookWinEvent(m_notificationsEventHook); + + for (HashMap<PlatformUIElement, JSObjectRef>::iterator it = m_notificationListeners.begin(); it != m_notificationListeners.end(); ++it) + JSValueUnprotect(frame->globalContext(), it->second); +} + +AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityController::focusedElement() +{ + COMPtr<IAccessible> rootAccessible = rootElement().platformUIElement(); + + VARIANT vFocus; + if (FAILED(rootAccessible->get_accFocus(&vFocus))) + return 0; + + if (V_VT(&vFocus) == VT_I4) { + ASSERT(V_I4(&vFocus) == CHILDID_SELF); + // The root accessible object is the focused object. + return rootAccessible; + } + + ASSERT(V_VT(&vFocus) == VT_DISPATCH); + // We have an IDispatch; query for IAccessible. + return COMPtr<IAccessible>(Query, V_DISPATCH(&vFocus)); +} + +AccessibilityUIElement AccessibilityController::rootElement() +{ + COMPtr<IWebView> view; + if (FAILED(frame->webView(&view))) + return 0; + + COMPtr<IWebViewPrivate> viewPrivate(Query, view); + if (!viewPrivate) + return 0; + + HWND webViewWindow; + if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow))) + return 0; + + // Get the root accessible object by querying for the accessible object for the + // WebView's window. + COMPtr<IAccessible> rootAccessible; + if (FAILED(AccessibleObjectFromWindow(webViewWindow, static_cast<DWORD>(OBJID_CLIENT), __uuidof(IAccessible), reinterpret_cast<void**>(&rootAccessible)))) + return 0; + + return rootAccessible; +} + +static void CALLBACK logEventProc(HWINEVENTHOOK, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD, DWORD) +{ + // Get the accessible object for this event. + COMPtr<IAccessible> parentObject; + + VARIANT vChild; + VariantInit(&vChild); + + HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &parentObject, &vChild); + ASSERT(SUCCEEDED(hr)); + + // Get the name of the focused element, and log it to stdout. + BSTR nameBSTR; + hr = parentObject->get_accName(vChild, &nameBSTR); + ASSERT(SUCCEEDED(hr)); + wstring name(nameBSTR, ::SysStringLen(nameBSTR)); + SysFreeString(nameBSTR); + + switch (event) { + case EVENT_OBJECT_FOCUS: + printf("Received focus event for object '%S'.\n", name.c_str()); + break; + + case EVENT_OBJECT_SELECTION: + printf("Received selection event for object '%S'.\n", name.c_str()); + break; + + case EVENT_OBJECT_VALUECHANGE: { + BSTR valueBSTR; + hr = parentObject->get_accValue(vChild, &valueBSTR); + ASSERT(SUCCEEDED(hr)); + wstring value(valueBSTR, ::SysStringLen(valueBSTR)); + SysFreeString(valueBSTR); + + printf("Received value change event for object '%S', value '%S'.\n", name.c_str(), value.c_str()); + break; + } + + case EVENT_SYSTEM_SCROLLINGSTART: + printf("Received scrolling start event for object '%S'.\n", name.c_str()); + break; + + default: + printf("Received unknown event for object '%S'.\n", name.c_str()); + break; + } + + VariantClear(&vChild); +} + +void AccessibilityController::setLogFocusEvents(bool logFocusEvents) +{ + if (!!m_focusEventHook == logFocusEvents) + return; + + if (!logFocusEvents) { + UnhookWinEvent(m_focusEventHook); + m_focusEventHook = 0; + return; + } + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object. + rootElement(); + + m_focusEventHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + + ASSERT(m_focusEventHook); +} + +void AccessibilityController::setLogValueChangeEvents(bool logValueChangeEvents) +{ + if (!!m_valueChangeEventHook == logValueChangeEvents) + return; + + if (!logValueChangeEvents) { + UnhookWinEvent(m_valueChangeEventHook); + m_valueChangeEventHook = 0; + return; + } + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object. + rootElement(); + + m_valueChangeEventHook = SetWinEventHook(EVENT_OBJECT_VALUECHANGE, EVENT_OBJECT_VALUECHANGE, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + + ASSERT(m_valueChangeEventHook); +} + +void AccessibilityController::setLogScrollingStartEvents(bool logScrollingStartEvents) +{ + if (!!m_scrollingStartEventHook == logScrollingStartEvents) + return; + + if (!logScrollingStartEvents) { + UnhookWinEvent(m_scrollingStartEventHook); + m_scrollingStartEventHook = 0; + return; + } + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object. + rootElement(); + + m_scrollingStartEventHook = SetWinEventHook(EVENT_SYSTEM_SCROLLINGSTART, EVENT_SYSTEM_SCROLLINGSTART, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + + ASSERT(m_scrollingStartEventHook); +} + +void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents) +{ + if (!!m_allEventsHook == logAccessibilityEvents) + return; + + if (!logAccessibilityEvents) { + UnhookWinEvent(m_allEventsHook); + m_allEventsHook = 0; + return; + } + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object. + rootElement(); + + m_allEventsHook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + + ASSERT(m_allEventsHook); +} + +static string stringEvent(DWORD event) +{ + switch(event) { + case EVENT_OBJECT_VALUECHANGE: + return "value change event"; + default: + return "unknown event"; + } +} + +static void CALLBACK notificationListenerProc(HWINEVENTHOOK, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD, DWORD) +{ + // Get the accessible object for this event. + COMPtr<IAccessible> parentObject; + + VARIANT vChild; + VariantInit(&vChild); + + HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &parentObject, &vChild); + if (FAILED(hr) || !parentObject) + return; + + COMPtr<IDispatch> childDispatch; + if (FAILED(parentObject->get_accChild(vChild, &childDispatch))) { + VariantClear(&vChild); + return; + } + + COMPtr<IAccessible> childAccessible(Query, childDispatch); + + sharedFrameLoadDelegate->accessibilityController()->winNotificationReceived(childAccessible, stringEvent(event)); + + VariantClear(&vChild); +} + +static COMPtr<IAccessibleComparable> comparableObject(const COMPtr<IServiceProvider>& serviceProvider) +{ + COMPtr<IAccessibleComparable> comparable; + serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable)); + return comparable; +} + +bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback) +{ + return false; +} + +void AccessibilityController::removeNotificationListener() +{ +} + +void AccessibilityController::winNotificationReceived(PlatformUIElement element, const string& eventName) +{ + for (HashMap<PlatformUIElement, JSObjectRef>::iterator it = m_notificationListeners.begin(); it != m_notificationListeners.end(); ++it) { + COMPtr<IServiceProvider> thisServiceProvider(Query, it->first); + if (!thisServiceProvider) + continue; + + COMPtr<IAccessibleComparable> thisComparable = comparableObject(thisServiceProvider); + if (!thisComparable) + continue; + + COMPtr<IServiceProvider> elementServiceProvider(Query, element); + if (!elementServiceProvider) + continue; + + COMPtr<IAccessibleComparable> elementComparable = comparableObject(elementServiceProvider); + if (!elementComparable) + continue; + + BOOL isSame = FALSE; + thisComparable->isSameObject(elementComparable.get(), &isSame); + if (!isSame) + continue; + + JSRetainPtr<JSStringRef> jsNotification(Adopt, JSStringCreateWithUTF8CString(eventName.c_str())); + JSValueRef argument = JSValueMakeString(frame->globalContext(), jsNotification.get()); + JSObjectCallAsFunction(frame->globalContext(), it->second, NULL, 1, &argument, NULL); + } +} + +void AccessibilityController::winAddNotificationListener(PlatformUIElement element, JSObjectRef functionCallback) +{ + if (!m_notificationsEventHook) + m_notificationsEventHook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandle(0), notificationListenerProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + + JSValueProtect(frame->globalContext(), functionCallback); + m_notificationListeners.add(element, functionCallback); +} diff --git a/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp b/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp new file mode 100644 index 000000000..2863b5cfd --- /dev/null +++ b/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp @@ -0,0 +1,698 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "AccessibilityController.h" +#include "DumpRenderTree.h" +#include "FrameLoadDelegate.h" +#include <JavaScriptCore/JSStringRef.h> +#include <tchar.h> +#include <string> + +using std::wstring; + +static COMPtr<IAccessibleComparable> comparableObject(IAccessible* accessible) +{ + COMPtr<IServiceProvider> serviceProvider(Query, accessible); + if (!serviceProvider) + return 0; + COMPtr<IAccessibleComparable> comparable; + serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable)); + return comparable; +} + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) +{ +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) +{ +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ +} + +bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) +{ + COMPtr<IAccessibleComparable> comparable = comparableObject(m_element.get()); + COMPtr<IAccessibleComparable> otherComparable = comparableObject(otherElement->m_element.get()); + if (!comparable || !otherComparable) + return false; + BOOL isSame = FALSE; + if (FAILED(comparable->isSameObject(otherComparable.get(), &isSame))) + return false; + return isSame; +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&) +{ +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) +{ +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) +{ + long childCount; + if (FAILED(m_element->get_accChildCount(&childCount))) + return; + for (long i = 0; i < childCount; ++i) + children.append(getChildAtIndex(i)); +} + +void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length) +{ + long childCount; + unsigned appendedCount = 0; + if (FAILED(m_element->get_accChildCount(&childCount))) + return; + for (long i = location; i < childCount && appendedCount < length; ++i, ++appendedCount) + elementVector.append(getChildAtIndex(i)); +} + +int AccessibilityUIElement::childrenCount() +{ + long childCount; + m_element->get_accChildCount(&childCount); + return childCount; +} + +int AccessibilityUIElement::rowCount() +{ + // FIXME: implement + return 0; +} + +int AccessibilityUIElement::columnCount() +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + COMPtr<IDispatch> child; + VARIANT vChild; + ::VariantInit(&vChild); + V_VT(&vChild) = VT_I4; + // In MSAA, index 0 is the object itself. + V_I4(&vChild) = index + 1; + if (FAILED(m_element->get_accChild(vChild, &child))) + return 0; + return COMPtr<IAccessible>(Query, child); +} + +unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) +{ + // FIXME: implement + return 0; +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + return JSStringCreateWithCharacters(0, 0); +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::parentElement() +{ + COMPtr<IDispatch> parent; + m_element->get_accParent(&parent); + + COMPtr<IAccessible> parentAccessible(Query, parent); + return parentAccessible; +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + return JSStringCreateWithCharacters(0, 0); +} + +static VARIANT& self() +{ + static VARIANT vSelf; + static bool haveInitialized; + + if (!haveInitialized) { + ::VariantInit(&vSelf); + V_VT(&vSelf) = VT_I4; + V_I4(&vSelf) = CHILDID_SELF; + } + return vSelf; +} + +JSStringRef AccessibilityUIElement::role() +{ + VARIANT vRole; + if (FAILED(m_element->get_accRole(self(), &vRole))) + return JSStringCreateWithCharacters(0, 0); + + ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR); + + wstring result; + if (V_VT(&vRole) == VT_I4) { + unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), 0, 0) + 1; + + Vector<TCHAR> roleText(roleTextLength); + + ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength); + + result = roleText.data(); + } else if (V_VT(&vRole) == VT_BSTR) + result = wstring(V_BSTR(&vRole), ::SysStringLen(V_BSTR(&vRole))); + + ::VariantClear(&vRole); + + return JSStringCreateWithCharacters(result.data(), result.length()); +} + +JSStringRef AccessibilityUIElement::subrole() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::roleDescription() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::title() +{ + BSTR titleBSTR; + if (FAILED(m_element->get_accName(self(), &titleBSTR)) || !titleBSTR) + return JSStringCreateWithCharacters(0, 0); + wstring title(titleBSTR, SysStringLen(titleBSTR)); + ::SysFreeString(titleBSTR); + return JSStringCreateWithCharacters(title.data(), title.length()); +} + +JSStringRef AccessibilityUIElement::description() +{ + BSTR descriptionBSTR; + if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR)) || !descriptionBSTR) + return JSStringCreateWithCharacters(0, 0); + wstring description(descriptionBSTR, SysStringLen(descriptionBSTR)); + ::SysFreeString(descriptionBSTR); + return JSStringCreateWithCharacters(description.data(), description.length()); +} + +JSStringRef AccessibilityUIElement::stringValue() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::language() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::helpText() const +{ + return 0; +} + +double AccessibilityUIElement::x() +{ + long x, y, width, height; + if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) + return 0; + return x; +} + +double AccessibilityUIElement::y() +{ + long x, y, width, height; + if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) + return 0; + return y; +} + +double AccessibilityUIElement::width() +{ + long x, y, width, height; + if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) + return 0; + return width; +} + +double AccessibilityUIElement::height() +{ + long x, y, width, height; + if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) + return 0; + return height; +} + +double AccessibilityUIElement::clickPointX() +{ + return 0; +} + +double AccessibilityUIElement::clickPointY() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::valueDescription() +{ + return 0; +} + +static DWORD accessibilityState(COMPtr<IAccessible> element) +{ + VARIANT state; + element->get_accState(self(), &state); + + ASSERT(V_VT(&state) == VT_I4); + + DWORD result = state.lVal; + VariantClear(&state); + + return result; +} + +bool AccessibilityUIElement::isFocused() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelected() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED; +} + +int AccessibilityUIElement::hierarchicalLevel() const +{ + return 0; +} + +bool AccessibilityUIElement::ariaIsGrabbed() const +{ + return false; +} + +JSStringRef AccessibilityUIElement::ariaDropEffects() const +{ + return 0; +} + +bool AccessibilityUIElement::isExpanded() const +{ + return false; +} + +bool AccessibilityUIElement::isChecked() const +{ + VARIANT vState; + if (FAILED(m_element->get_accState(self(), &vState))) + return false; + + return vState.lVal & STATE_SYSTEM_CHECKED; +} + +JSStringRef AccessibilityUIElement::orientation() const +{ + return 0; +} + +double AccessibilityUIElement::intValue() const +{ + BSTR valueBSTR; + if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR) + return 0; + wstring value(valueBSTR, SysStringLen(valueBSTR)); + ::SysFreeString(valueBSTR); + TCHAR* ignored; + return _tcstod(value.data(), &ignored); +} + +double AccessibilityUIElement::minValue() +{ + return 0; +} + +double AccessibilityUIElement::maxValue() +{ + return 0; +} + +bool AccessibilityUIElement::isActionSupported(JSStringRef action) +{ + return false; +} + +bool AccessibilityUIElement::isEnabled() +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE; +} + +bool AccessibilityUIElement::isRequired() const +{ + return false; +} + + +int AccessibilityUIElement::insertionPointLineNumber() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + return JSStringCreateWithCharacters(0, 0); +} + +int AccessibilityUIElement::indexInTable() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::rowIndexRange() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::columnIndexRange() +{ + return JSStringCreateWithCharacters(0, 0); +} + +int AccessibilityUIElement::lineForIndex(int) +{ + return 0; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) +{ + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) +{ + return false; +} + +AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) +{ + return 0; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + return JSStringCreateWithCharacters(0, 0); +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ +} + +JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return 0; +} + +bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) +{ + return false; +} + +bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) +{ + return false; +} + +void AccessibilityUIElement::increment() +{ +} + +void AccessibilityUIElement::decrement() +{ +} + +void AccessibilityUIElement::showMenu() +{ + ASSERT(hasPopup()); + m_element->accDoDefaultAction(self()); +} + +void AccessibilityUIElement::press() +{ + // FIXME: implement +} + +AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) +{ + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedByRow() +{ + return 0; +} + +JSStringRef AccessibilityUIElement::accessibilityValue() const +{ + BSTR valueBSTR; + if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR) + return JSStringCreateWithCharacters(0, 0); + + wstring value(valueBSTR, SysStringLen(valueBSTR)); + ::SysFreeString(valueBSTR); + + return JSStringCreateWithCharacters(value.data(), value.length()); +} + + +JSStringRef AccessibilityUIElement::documentEncoding() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentURI() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::url() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + sharedFrameLoadDelegate->accessibilityController()->winAddNotificationListener(m_element, functionCallback); + return true; +} + +void AccessibilityUIElement::removeNotificationListener() +{ + // FIXME: implement +} + +bool AccessibilityUIElement::isFocusable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelectable() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE; +} + +bool AccessibilityUIElement::isMultiSelectable() const +{ + DWORD multiSelectable = STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE; + DWORD state = accessibilityState(m_element); + return (state & multiSelectable) == multiSelectable; +} + +bool AccessibilityUIElement::isSelectedOptionActive() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isVisible() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE; +} + +bool AccessibilityUIElement::isOffScreen() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN; +} + +bool AccessibilityUIElement::isCollapsed() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED; +} + +bool AccessibilityUIElement::isIgnored() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::hasPopup() const +{ + DWORD state = accessibilityState(m_element); + return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP; +} + +void AccessibilityUIElement::takeFocus() +{ + m_element->accSelect(SELFLAG_TAKEFOCUS, self()); +} + +void AccessibilityUIElement::takeSelection() +{ + m_element->accSelect(SELFLAG_TAKESELECTION, self()); +} + +void AccessibilityUIElement::addSelection() +{ + m_element->accSelect(SELFLAG_ADDSELECTION, self()); +} + +void AccessibilityUIElement::removeSelection() +{ + m_element->accSelect(SELFLAG_REMOVESELECTION, self()); +} diff --git a/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp new file mode 100644 index 000000000..1bc4678b1 --- /dev/null +++ b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009 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 "DRTDesktopNotificationPresenter.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/JSStringRefBSTR.h> +#include <WebCore/NotificationPresenter.h> + +DRTDesktopNotificationPresenter::DRTDesktopNotificationPresenter() + : m_refCount(1) {} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<DRTDesktopNotificationPresenter*>(this); + else if (IsEqualGUID(riid, IID_IWebDesktopNotificationsDelegate)) + *ppvObject = static_cast<DRTDesktopNotificationPresenter*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE DRTDesktopNotificationPresenter::AddRef() +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE DRTDesktopNotificationPresenter::Release() +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::showDesktopNotification( + /* [in] */ IWebDesktopNotification* notification) +{ + BSTR title, text, url; + BOOL html; + + if (!notification->isHTML(&html) && html) { + notification->contentsURL(&url); + printf("DESKTOP NOTIFICATION: contents at %S\n", url ? url : L""); + } else { + notification->iconURL(&url); + notification->title(&title); + notification->text(&text); + printf("DESKTOP NOTIFICATION: icon %S, title %S, text %S\n", + url ? url : L"", + title ? title : L"", + text ? text : L""); + } + + // In this stub implementation, the notification is displayed immediately; + // we dispatch the display event to mimic that. + notification->notifyDisplay(); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::cancelDesktopNotification( + /* [in] */ IWebDesktopNotification* notification) +{ + BSTR identifier; + BOOL html; + notification->isHTML(&html); + if (html) + notification->contentsURL(&identifier); + else + notification->title(&identifier); + + printf("DESKTOP NOTIFICATION CLOSED: %S\n", identifier ? identifier : L""); + notification->notifyClose(false); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::notificationDestroyed( + /* [in] */ IWebDesktopNotification* notification) +{ + // Since in these tests events happen immediately, we don't hold on to + // Notification pointers. So there's no cleanup to do. + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::checkNotificationPermission( + /* [in] */ BSTR origin, + /* [out, retval] */ int* result) +{ +#if ENABLE(NOTIFICATIONS) + JSStringRef jsOrigin = JSStringCreateWithBSTR(origin); + bool allowed = ::gLayoutTestController->checkDesktopNotificationPermission(jsOrigin); + + if (allowed) + *result = WebCore::NotificationPresenter::PermissionAllowed; + else + *result = WebCore::NotificationPresenter::PermissionDenied; + + JSStringRelease(jsOrigin); +#endif + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::requestNotificationPermission( + /* [in] */ BSTR origin) +{ + printf("DESKTOP NOTIFICATION PERMISSION REQUESTED: %S\n", origin ? origin : L""); + return S_OK; +} diff --git a/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h new file mode 100644 index 000000000..567984503 --- /dev/null +++ b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DRTDesktopNotificationPresenter_h +#define DRTDesktopNotificationPresenter_h + +#include <WebKit/WebKit.h> +#include <wtf/OwnPtr.h> +#include <windef.h> + +class DRTDesktopNotificationPresenter : public IWebDesktopNotificationsDelegate { +public: + DRTDesktopNotificationPresenter(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebDesktopNotificationsDelegate + virtual HRESULT STDMETHODCALLTYPE showDesktopNotification( + /* [in] */ IWebDesktopNotification* notification); + + virtual HRESULT STDMETHODCALLTYPE cancelDesktopNotification( + /* [in] */ IWebDesktopNotification* notification); + + virtual HRESULT STDMETHODCALLTYPE notificationDestroyed( + /* [in] */ IWebDesktopNotification* notification); + + virtual HRESULT STDMETHODCALLTYPE checkNotificationPermission( + /* [in] */ BSTR origin, + /* [out, retval] */ int* result); + + virtual HRESULT STDMETHODCALLTYPE requestNotificationPermission( + /* [in] */ BSTR origin); + +private: + ULONG m_refCount; +}; + +#endif diff --git a/Tools/DumpRenderTree/win/DraggingInfo.h b/Tools/DumpRenderTree/win/DraggingInfo.h new file mode 100644 index 000000000..98982bc16 --- /dev/null +++ b/Tools/DumpRenderTree/win/DraggingInfo.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DraggingInfo_h +#define DraggingInfo_h + +#include <objidl.h> + +class DraggingInfo { +public: + DraggingInfo(IDataObject* object, IDropSource* source) + : m_object(object) + , m_source(source) + , m_performedDropEffect(DROPEFFECT_NONE) + { + m_object->AddRef(); + m_source->AddRef(); + } + + ~DraggingInfo() + { + if (m_object) + m_object->Release(); + m_object = 0; + if (m_source) + m_source->Release(); + m_source = 0; + } + + IDataObject* dataObject() const { return m_object; } + IDropSource* dropSource() const { return m_source; } + + DWORD performedDropEffect() const { return m_performedDropEffect; } + void setPerformedDropEffect(DWORD effect) { m_performedDropEffect = effect; } + +private: + IDataObject* m_object; + IDropSource* m_source; + DWORD m_performedDropEffect; +}; + +#endif // !defined(DraggingInfo_h) diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.cpp b/Tools/DumpRenderTree/win/DumpRenderTree.cpp new file mode 100644 index 000000000..1ec5c5e60 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTree.cpp @@ -0,0 +1,1459 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" + +#include "EditingDelegate.h" +#include "FrameLoadDelegate.h" +#include "HistoryDelegate.h" +#include "LayoutTestController.h" +#include "PixelDumpSupport.h" +#include "PolicyDelegate.h" +#include "ResourceLoadDelegate.h" +#include "UIDelegate.h" +#include "WorkQueueItem.h" +#include "WorkQueue.h" + +#include <comutil.h> +#include <fcntl.h> +#include <io.h> +#include <math.h> +#include <pthread.h> +#include <shlwapi.h> +#include <stdio.h> +#include <string.h> +#include <tchar.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <windows.h> +#include <CoreFoundation/CoreFoundation.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <WebKit/WebKit.h> +#include <WebKit/WebKitCOMAPI.h> + +#if USE(CFNETWORK) +#include <CFNetwork/CFURLCachePriv.h> +#endif + +#if USE(CFNETWORK) +#include <CFNetwork/CFHTTPCookiesPriv.h> +#endif + +using namespace std; + +#ifdef DEBUG_ALL +const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug"; +#else +const LPWSTR TestPluginDir = L"TestNetscapePlugin"; +#endif + +static LPCWSTR fontsEnvironmentVariable = L"WEBKIT_TESTFONTS"; +#define USE_MAC_FONTS + +const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow"; + +static bool dumpTree = true; +static bool dumpPixels; +static bool dumpAllPixels; +static bool printSeparators; +static bool leakChecking = false; +static bool threaded = false; +static bool forceComplexText = false; +static bool printSupportedFeatures = false; +static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; + +volatile bool done; +// This is the topmost frame that is loading, during a given load, or nil when no load is +// in progress. Usually this is the same as the main frame, but not always. In the case +// where a frameset is loaded, and then new content is loaded into one of the child frames, +// that child frame is the "topmost frame that is loading". +IWebFrame* topLoadingFrame; // !nil iff a load is in progress +static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test +PolicyDelegate* policyDelegate; +COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate; +COMPtr<UIDelegate> sharedUIDelegate; +COMPtr<EditingDelegate> sharedEditingDelegate; +COMPtr<HistoryDelegate> sharedHistoryDelegate; + +IWebFrame* frame; +HWND webViewWindow; + +RefPtr<LayoutTestController> gLayoutTestController; + +UINT_PTR waitToDumpWatchdog = 0; + +void setPersistentUserStyleSheetLocation(CFStringRef url) +{ + persistentUserStyleSheetLocation = url; +} + +bool setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ +#if USE(CFNETWORK) + COMPtr<IWebCookieManager> cookieManager; + if (FAILED(WebKitCreateInstance(CLSID_WebCookieManager, 0, IID_IWebCookieManager, reinterpret_cast<void**>(&cookieManager)))) + return false; + CFHTTPCookieStorageRef cookieStorage = 0; + if (FAILED(cookieManager->cookieStorage(&cookieStorage)) || !cookieStorage) + return false; + + WebKitCookieStorageAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? WebKitCookieStorageAcceptPolicyAlways : WebKitCookieStorageAcceptPolicyOnlyFromMainDocumentDomain; + CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, cookieAcceptPolicy); + return true; +#else + // FIXME: Implement! + return false; +#endif +} + +static RetainPtr<CFStringRef> substringFromIndex(CFStringRef string, CFIndex index) +{ + return RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithSubstring(kCFAllocatorDefault, string, CFRangeMake(index, CFStringGetLength(string) - index))); +} + +wstring urlSuitableForTestResult(const wstring& urlString) +{ + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0)); + + RetainPtr<CFStringRef> scheme(AdoptCF, CFURLCopyScheme(url.get())); + if (scheme && CFStringCompare(scheme.get(), CFSTR("file"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) + return urlString; + + COMPtr<IWebDataSource> dataSource; + if (FAILED(frame->dataSource(&dataSource))) { + if (FAILED(frame->provisionalDataSource(&dataSource))) + return urlString; + } + + COMPtr<IWebMutableURLRequest> request; + if (FAILED(dataSource->request(&request))) + return urlString; + + _bstr_t requestURLString; + if (FAILED(request->URL(requestURLString.GetAddress()))) + return urlString; + + RetainPtr<CFURLRef> requestURL(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(requestURLString.GetBSTR()), requestURLString.length() * sizeof(OLECHAR), kCFStringEncodingUTF16, 0)); + RetainPtr<CFURLRef> baseURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, requestURL.get())); + + RetainPtr<CFStringRef> basePath(AdoptCF, CFURLCopyPath(baseURL.get())); + RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyPath(url.get())); + + return cfStringRefToWString(substringFromIndex(path.get(), CFStringGetLength(basePath.get())).get()); +} + +wstring lastPathComponent(const wstring& urlString) +{ + if (urlString.empty()) + return urlString; + + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0)); + RetainPtr<CFStringRef> lastPathComponent(CFURLCopyLastPathComponent(url.get())); + + return cfStringRefToWString(lastPathComponent.get()); +} + +static string toUTF8(const wchar_t* wideString, size_t length) +{ + int result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, 0, 0, 0, 0); + Vector<char> utf8Vector(result); + result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, utf8Vector.data(), result, 0, 0); + if (!result) + return string(); + + return string(utf8Vector.data(), utf8Vector.size() - 1); +} + +string toUTF8(BSTR bstr) +{ + return toUTF8(bstr, SysStringLen(bstr)); +} + +string toUTF8(const wstring& wideString) +{ + return toUTF8(wideString.c_str(), wideString.length()); +} + +wstring cfStringRefToWString(CFStringRef cfStr) +{ + Vector<wchar_t> v(CFStringGetLength(cfStr)); + CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), (UniChar *)v.data()); + + return wstring(v.data(), v.size()); +} + +static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_DESTROY: + for (unsigned i = openWindows().size() - 1; i >= 0; --i) { + if (openWindows()[i] == hWnd) { + openWindows().remove(i); + windowToWebViewMap().remove(hWnd); + break; + } + } + return 0; + break; + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } +} + +static const wstring& exePath() +{ + static wstring path; + static bool initialized; + + if (initialized) + return path; + initialized = true; + + TCHAR buffer[MAX_PATH]; + GetModuleFileName(GetModuleHandle(0), buffer, ARRAYSIZE(buffer)); + path = buffer; + int lastSlash = path.rfind('\\'); + if (lastSlash != -1 && lastSlash + 1 < path.length()) + path = path.substr(0, lastSlash + 1); + + return path; +} + +static const wstring& fontsPath() +{ + static wstring path; + static bool initialized; + + if (initialized) + return path; + initialized = true; + + DWORD size = GetEnvironmentVariable(fontsEnvironmentVariable, 0, 0); + Vector<TCHAR> buffer(size); + if (GetEnvironmentVariable(fontsEnvironmentVariable, buffer.data(), buffer.size())) { + path = buffer.data(); + if (path[path.length() - 1] != '\\') + path.append(L"\\"); + return path; + } + + path = exePath() + TEXT("DumpRenderTree.resources\\"); + return path; +} + +static void addQTDirToPATH() +{ + static LPCWSTR pathEnvironmentVariable = L"PATH"; + static LPCWSTR quickTimeKeyName = L"Software\\Apple Computer, Inc.\\QuickTime"; + static LPCWSTR quickTimeSysDir = L"QTSysDir"; + static bool initialized; + + if (initialized) + return; + initialized = true; + + // Get the QuickTime dll directory from the registry. The key can be in either HKLM or HKCU. + WCHAR qtPath[MAX_PATH]; + DWORD qtPathBufferLen = sizeof(qtPath); + DWORD keyType; + HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen); + if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) { + qtPathBufferLen = sizeof(qtPath); + result = SHGetValue(HKEY_CURRENT_USER, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen); + if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) + return; + } + + // Read the current PATH. + DWORD pathSize = GetEnvironmentVariableW(pathEnvironmentVariable, 0, 0); + Vector<WCHAR> oldPath(pathSize); + if (!GetEnvironmentVariableW(pathEnvironmentVariable, oldPath.data(), oldPath.size())) + return; + + // And add the QuickTime dll. + wstring newPath; + newPath.append(qtPath); + newPath.append(L";"); + newPath.append(oldPath.data(), oldPath.size()); + SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data()); +} + +#ifdef DEBUG_ALL +#define WEBKITDLL TEXT("WebKit_debug.dll") +#else +#define WEBKITDLL TEXT("WebKit.dll") +#endif + +static void initialize() +{ + if (HMODULE webKitModule = LoadLibrary(WEBKITDLL)) + if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer")) + dllRegisterServer(); + + // Init COM + OleInitialize(0); + + static LPCTSTR fontsToInstall[] = { + TEXT("AHEM____.ttf"), + TEXT("Apple Chancery.ttf"), + TEXT("Courier Bold.ttf"), + TEXT("Courier.ttf"), + TEXT("Helvetica Bold Oblique.ttf"), + TEXT("Helvetica Bold.ttf"), + TEXT("Helvetica Oblique.ttf"), + TEXT("Helvetica.ttf"), + TEXT("Helvetica Neue Bold Italic.ttf"), + TEXT("Helvetica Neue Bold.ttf"), + TEXT("Helvetica Neue Condensed Black.ttf"), + TEXT("Helvetica Neue Condensed Bold.ttf"), + TEXT("Helvetica Neue Italic.ttf"), + TEXT("Helvetica Neue Light Italic.ttf"), + TEXT("Helvetica Neue Light.ttf"), + TEXT("Helvetica Neue UltraLight Italic.ttf"), + TEXT("Helvetica Neue UltraLight.ttf"), + TEXT("Helvetica Neue.ttf"), + TEXT("Lucida Grande.ttf"), + TEXT("Lucida Grande Bold.ttf"), + TEXT("Monaco.ttf"), + TEXT("Papyrus.ttf"), + TEXT("Times Bold Italic.ttf"), + TEXT("Times Bold.ttf"), + TEXT("Times Italic.ttf"), + TEXT("Times Roman.ttf"), + TEXT("WebKit Layout Tests 2.ttf"), + TEXT("WebKit Layout Tests.ttf"), + TEXT("WebKitWeightWatcher100.ttf"), + TEXT("WebKitWeightWatcher200.ttf"), + TEXT("WebKitWeightWatcher300.ttf"), + TEXT("WebKitWeightWatcher400.ttf"), + TEXT("WebKitWeightWatcher500.ttf"), + TEXT("WebKitWeightWatcher600.ttf"), + TEXT("WebKitWeightWatcher700.ttf"), + TEXT("WebKitWeightWatcher800.ttf"), + TEXT("WebKitWeightWatcher900.ttf") + }; + + wstring resourcesPath = fontsPath(); + + COMPtr<IWebTextRenderer> textRenderer; + if (SUCCEEDED(WebKitCreateInstance(CLSID_WebTextRenderer, 0, IID_IWebTextRenderer, (void**)&textRenderer))) + for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i) + textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str()); + + // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems + // linked with older versions of qtmlclientlib.dll. + addQTDirToPATH(); + + // Register a host window + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = DumpRenderTreeWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(0); + wcex.hIcon = 0; + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = 0; + wcex.lpszMenuName = 0; + wcex.lpszClassName = kDumpRenderTreeClassName; + wcex.hIconSm = 0; + + RegisterClassEx(&wcex); +} + +void displayWebView() +{ + ::InvalidateRect(webViewWindow, 0, TRUE); + ::SendMessage(webViewWindow, WM_PAINT, 0, 0); +} + +void dumpFrameScrollPosition(IWebFrame* frame) +{ + if (!frame) + return; + + COMPtr<IWebFramePrivate> framePrivate; + if (FAILED(frame->QueryInterface(&framePrivate))) + return; + + SIZE scrollPosition; + if (FAILED(framePrivate->scrollOffset(&scrollPosition))) + return; + + if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) { + COMPtr<IWebFrame> parent; + if (FAILED(frame->parentFrame(&parent))) + return; + if (parent) { + BSTR name; + if (FAILED(frame->name(&name))) + return; + printf("frame '%S' ", name ? name : L""); + SysFreeString(name); + } + printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy); + } + + if (::gLayoutTestController->dumpChildFrameScrollPositions()) { + COMPtr<IEnumVARIANT> enumKids; + if (FAILED(frame->childFrames(&enumKids))) + return; + VARIANT var; + VariantInit(&var); + while (enumKids->Next(1, &var, 0) == S_OK) { + ASSERT(V_VT(&var) == VT_UNKNOWN); + COMPtr<IWebFrame> framePtr; + V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr); + dumpFrameScrollPosition(framePtr.get()); + VariantClear(&var); + } + } +} + +static wstring dumpFramesAsText(IWebFrame* frame) +{ + if (!frame) + return L""; + + COMPtr<IDOMDocument> document; + if (FAILED(frame->DOMDocument(&document))) + return L""; + + COMPtr<IDOMElement> documentElement; + if (FAILED(document->documentElement(&documentElement))) + return L""; + + wstring result; + + // Add header for all but the main frame. + COMPtr<IWebFrame> parent; + if (FAILED(frame->parentFrame(&parent))) + return L""; + if (parent) { + BSTR name = L""; + if (FAILED(frame->name(&name))) + return L""; + + result.append(L"\n--------\nFrame: '"); + result.append(name ? name : L"", SysStringLen(name)); + result.append(L"'\n--------\n"); + + SysFreeString(name); + } + + BSTR innerText = 0; + COMPtr<IDOMElementPrivate> docPrivate; + if (SUCCEEDED(documentElement->QueryInterface(&docPrivate))) + docPrivate->innerText(&innerText); + + result.append(innerText ? innerText : L"", SysStringLen(innerText)); + result.append(L"\n"); + + SysFreeString(innerText); + + if (::gLayoutTestController->dumpChildFramesAsText()) { + COMPtr<IEnumVARIANT> enumKids; + if (FAILED(frame->childFrames(&enumKids))) + return L""; + VARIANT var; + VariantInit(&var); + while (enumKids->Next(1, &var, 0) == S_OK) { + ASSERT(V_VT(&var) == VT_UNKNOWN); + COMPtr<IWebFrame> framePtr; + V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr); + result.append(dumpFramesAsText(framePtr.get())); + VariantClear(&var); + } + } + + return result; +} + +static int compareHistoryItems(const void* item1, const void* item2) +{ + COMPtr<IWebHistoryItemPrivate> itemA; + if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA))) + return 0; + + COMPtr<IWebHistoryItemPrivate> itemB; + if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB))) + return 0; + + BSTR targetA; + if (FAILED(itemA->target(&targetA))) + return 0; + + BSTR targetB; + if (FAILED(itemB->target(&targetB))) { + SysFreeString(targetA); + return 0; + } + + int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str()); + SysFreeString(targetA); + SysFreeString(targetB); + return result; +} + +static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current) +{ + assert(item); + + int start = 0; + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + BSTR url; + if (FAILED(item->URLString(&url))) + return; + + if (wcsstr(url, L"file:/") == url) { + static wchar_t* layoutTestsString = L"/LayoutTests/"; + static wchar_t* fileTestString = L"(file test):"; + + wchar_t* result = wcsstr(url, layoutTestsString); + if (result == NULL) + return; + wchar_t* start = result + wcslen(layoutTestsString); + + BSTR newURL = SysAllocStringLen(NULL, SysStringLen(url)); + wcscpy(newURL, fileTestString); + wcscpy(newURL + wcslen(fileTestString), start); + + SysFreeString(url); + url = newURL; + } + + printf("%S", url ? url : L""); + SysFreeString(url); + + COMPtr<IWebHistoryItemPrivate> itemPrivate; + if (FAILED(item->QueryInterface(&itemPrivate))) + return; + + BSTR target; + if (FAILED(itemPrivate->target(&target))) + return; + if (SysStringLen(target)) + printf(" (in frame \"%S\")", target); + SysFreeString(target); + BOOL isTargetItem = FALSE; + if (FAILED(itemPrivate->isTargetItem(&isTargetItem))) + return; + if (isTargetItem) + printf(" **nav target**"); + putchar('\n'); + + unsigned kidsCount; + SAFEARRAY* arrPtr; + if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount) + return; + + Vector<COMPtr<IUnknown> > kidsVector; + + LONG lowerBound; + if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound))) + goto exit; + + LONG upperBound; + if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound))) + goto exit; + + LONG length = upperBound - lowerBound + 1; + if (!length) + goto exit; + ASSERT(length == kidsCount); + + IUnknown** safeArrayData; + if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData))) + goto exit; + + for (int i = 0; i < length; ++i) + kidsVector.append(safeArrayData[i]); + ::SafeArrayUnaccessData(arrPtr); + + // must sort to eliminate arbitrary result ordering which defeats reproducible testing + qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems); + + for (unsigned i = 0; i < kidsCount; ++i) { + COMPtr<IWebHistoryItem> item; + kidsVector[i]->QueryInterface(&item); + dumpHistoryItem(item.get(), indent + 4, false); + } + +exit: + if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr))) + ::SafeArrayDestroy(arrPtr); +} + +static void dumpBackForwardList(IWebView* webView) +{ + ASSERT(webView); + + printf("\n============== Back Forward List ==============\n"); + + COMPtr<IWebBackForwardList> bfList; + if (FAILED(webView->backForwardList(&bfList))) + return; + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + + Vector<COMPtr<IUnknown> > itemsToPrint; + + int forwardListCount; + if (FAILED(bfList->forwardListCount(&forwardListCount))) + return; + + for (int i = forwardListCount; i > 0; --i) { + COMPtr<IWebHistoryItem> item; + if (FAILED(bfList->itemAtIndex(i, &item))) + return; + // something is wrong if the item from the last test is in the forward part of the b/f list + assert(item != prevTestBFItem); + COMPtr<IUnknown> itemUnknown; + item->QueryInterface(&itemUnknown); + itemsToPrint.append(itemUnknown); + } + + COMPtr<IWebHistoryItem> currentItem; + if (FAILED(bfList->currentItem(¤tItem))) + return; + + assert(currentItem != prevTestBFItem); + COMPtr<IUnknown> currentItemUnknown; + currentItem->QueryInterface(¤tItemUnknown); + itemsToPrint.append(currentItemUnknown); + int currentItemIndex = itemsToPrint.size() - 1; + + int backListCount; + if (FAILED(bfList->backListCount(&backListCount))) + return; + + for (int i = -1; i >= -backListCount; --i) { + COMPtr<IWebHistoryItem> item; + if (FAILED(bfList->itemAtIndex(i, &item))) + return; + if (item == prevTestBFItem) + break; + COMPtr<IUnknown> itemUnknown; + item->QueryInterface(&itemUnknown); + itemsToPrint.append(itemUnknown); + } + + for (int i = itemsToPrint.size() - 1; i >= 0; --i) { + COMPtr<IWebHistoryItem> historyItemToPrint; + itemsToPrint[i]->QueryInterface(&historyItemToPrint); + dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex); + } + + printf("===============================================\n"); +} + +static void dumpBackForwardListForAllWindows() +{ + unsigned count = openWindows().size(); + for (unsigned i = 0; i < count; i++) { + HWND window = openWindows()[i]; + IWebView* webView = windowToWebViewMap().get(window).get(); + dumpBackForwardList(webView); + } +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (!waitToDumpWatchdog) + return; + + KillTimer(0, waitToDumpWatchdog); + waitToDumpWatchdog = 0; +} + +void dump() +{ + invalidateAnyPreviousWaitToDumpWatchdog(); + + COMPtr<IWebDataSource> dataSource; + if (SUCCEEDED(frame->dataSource(&dataSource))) { + COMPtr<IWebURLResponse> response; + if (SUCCEEDED(dataSource->response(&response)) && response) { + BSTR mimeType; + if (SUCCEEDED(response->MIMEType(&mimeType)) && !_tcscmp(mimeType, TEXT("text/plain"))) { + ::gLayoutTestController->setDumpAsText(true); + ::gLayoutTestController->setGeneratePixelResults(false); + } + SysFreeString(mimeType); + } + } + + BSTR resultString = 0; + + if (dumpTree) { + if (::gLayoutTestController->dumpAsText()) { + ::InvalidateRect(webViewWindow, 0, TRUE); + ::SendMessage(webViewWindow, WM_PAINT, 0, 0); + wstring result = dumpFramesAsText(frame); + resultString = SysAllocStringLen(result.data(), result.size()); + } else { + bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos); + unsigned width; + unsigned height; + if (isSVGW3CTest) { + width = 480; + height = 360; + } else { + width = LayoutTestController::maxViewWidth; + height = LayoutTestController::maxViewHeight; + } + + ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE); + ::InvalidateRect(webViewWindow, 0, TRUE); + ::SendMessage(webViewWindow, WM_PAINT, 0, 0); + + COMPtr<IWebFramePrivate> framePrivate; + if (FAILED(frame->QueryInterface(&framePrivate))) + goto fail; + framePrivate->renderTreeAsExternalRepresentation(gLayoutTestController->isPrinting(), &resultString); + } + + if (!resultString) + printf("ERROR: nil result from %s", ::gLayoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation"); + else { + unsigned stringLength = SysStringLen(resultString); + int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0); + char* buffer = (char*)malloc(bufferSize + 1); + ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0); + fwrite(buffer, 1, bufferSize, stdout); + free(buffer); + if (!::gLayoutTestController->dumpAsText()) + dumpFrameScrollPosition(frame); + } + if (::gLayoutTestController->dumpBackForwardList()) + dumpBackForwardListForAllWindows(); + } + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + + if (dumpPixels + && gLayoutTestController->generatePixelResults() + && !gLayoutTestController->dumpDOMAsWebArchive() + && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + printf("#EOF\n"); // terminate the (possibly empty) pixels block + fflush(stdout); + +fail: + SysFreeString(resultString); + // This will exit from our message loop. + PostQuitMessage(0); + done = true; +} + +static bool shouldLogFrameLoadDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "/loading/") || strstr(pathOrURL, "\\loading\\"); +} + +static bool shouldLogHistoryDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\"); +} + +static bool shouldOpenWebInspector(const char* pathOrURL) +{ + return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\"); +} + +static bool shouldDumpAsText(const char* pathOrURL) +{ + return strstr(pathOrURL, "/dumpAsText/") || strstr(pathOrURL, "\\dumpAsText\\"); +} + +static bool shouldEnableDeveloperExtras(const char* pathOrURL) +{ + return true; +} + +static void resetDefaultsToConsistentValues(IWebPreferences* preferences) +{ +#ifdef USE_MAC_FONTS + static BSTR standardFamily = SysAllocString(TEXT("Times")); + static BSTR fixedFamily = SysAllocString(TEXT("Courier")); + static BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica")); + static BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery")); + static BSTR fantasyFamily = SysAllocString(TEXT("Papyrus")); + static BSTR pictographFamily = SysAllocString(TEXT("Apple Color Emoji")); +#else + static BSTR standardFamily = SysAllocString(TEXT("Times New Roman")); + static BSTR fixedFamily = SysAllocString(TEXT("Courier New")); + static BSTR sansSerifFamily = SysAllocString(TEXT("Arial")); + static BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use. + static BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman")); + static BSTR pictographFamily = SysAllocString(TEXT("Times New Roman")); +#endif + + preferences->setStandardFontFamily(standardFamily); + preferences->setFixedFontFamily(fixedFamily); + preferences->setSerifFontFamily(standardFamily); + preferences->setSansSerifFontFamily(sansSerifFamily); + preferences->setCursiveFontFamily(cursiveFamily); + preferences->setFantasyFontFamily(fantasyFamily); + preferences->setPictographFontFamily(pictographFamily); + + preferences->setAutosaves(FALSE); + preferences->setDefaultFontSize(16); + preferences->setDefaultFixedFontSize(13); + preferences->setMinimumFontSize(0); + preferences->setJavaEnabled(FALSE); + preferences->setPlugInsEnabled(TRUE); + preferences->setDOMPasteAllowed(TRUE); + preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey); + preferences->setFontSmoothing(FontSmoothingTypeStandard); + preferences->setUsesPageCache(FALSE); + preferences->setPrivateBrowsingEnabled(FALSE); + preferences->setJavaScriptCanOpenWindowsAutomatically(TRUE); + preferences->setJavaScriptEnabled(TRUE); + preferences->setTabsToLinks(FALSE); + preferences->setShouldPrintBackgrounds(TRUE); + preferences->setLoadsImagesAutomatically(TRUE); + preferences->setEditingBehavior(WebKitEditingWinBehavior); + + if (persistentUserStyleSheetLocation) { + Vector<wchar_t> urlCharacters(CFStringGetLength(persistentUserStyleSheetLocation.get())); + CFStringGetCharacters(persistentUserStyleSheetLocation.get(), CFRangeMake(0, CFStringGetLength(persistentUserStyleSheetLocation.get())), (UniChar *)urlCharacters.data()); + BSTR url = SysAllocStringLen(urlCharacters.data(), urlCharacters.size()); + preferences->setUserStyleSheetLocation(url); + SysFreeString(url); + preferences->setUserStyleSheetEnabled(TRUE); + } else + preferences->setUserStyleSheetEnabled(FALSE); + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (prefsPrivate) { + prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE); + prefsPrivate->setAllowFileAccessFromFileURLs(TRUE); + prefsPrivate->setAuthorAndUserStylesEnabled(TRUE); + prefsPrivate->setDeveloperExtrasEnabled(FALSE); + prefsPrivate->setExperimentalNotificationsEnabled(TRUE); + prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592> + prefsPrivate->setJavaScriptCanAccessClipboard(TRUE); + prefsPrivate->setXSSAuditorEnabled(FALSE); + prefsPrivate->setFrameFlatteningEnabled(FALSE); + prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE); + prefsPrivate->setLoadsSiteIconsIgnoringImageLoadingPreference(FALSE); + prefsPrivate->setHixie76WebSocketProtocolEnabled(TRUE); + } + setAlwaysAcceptCookies(false); + + setlocale(LC_ALL, ""); +} + +static void resetWebViewToConsistentStateBeforeTesting() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + webView->setPolicyDelegate(0); + policyDelegate->setPermissive(false); + policyDelegate->setControllerToNotifyDone(0); + + COMPtr<IWebIBActions> webIBActions(Query, webView); + if (webIBActions) { + webIBActions->makeTextStandardSize(0); + webIBActions->resetPageZoom(0); + } + + + COMPtr<IWebPreferences> preferences; + if (SUCCEEDED(webView->preferences(&preferences))) + resetDefaultsToConsistentValues(preferences.get()); + + COMPtr<IWebViewEditing> viewEditing; + if (SUCCEEDED(webView->QueryInterface(&viewEditing))) + viewEditing->setSmartInsertDeleteEnabled(TRUE); + + COMPtr<IWebViewPrivate> webViewPrivate(Query, webView); + if (!webViewPrivate) + return; + + double minimumInterval = 0; + if (SUCCEEDED(webViewPrivate->defaultMinimumTimerInterval(&minimumInterval))) + webViewPrivate->setMinimumTimerInterval(minimumInterval); + + COMPtr<IWebInspector> inspector; + if (SUCCEEDED(webViewPrivate->inspector(&inspector))) + inspector->setJavaScriptProfilingEnabled(FALSE); + + HWND viewWindow; + if (SUCCEEDED(webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))) && viewWindow) + SetFocus(viewWindow); + + webViewPrivate->clearMainFrameName(); + webViewPrivate->resetOriginAccessWhitelists(); + + BSTR groupName; + if (SUCCEEDED(webView->groupName(&groupName))) { + webViewPrivate->removeAllUserContentFromGroup(groupName); + SysFreeString(groupName); + } + + sharedUIDelegate->resetUndoManager(); + + sharedFrameLoadDelegate->resetToConsistentState(); + + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->clearOpener(); +} + +static void runTest(const string& testPathOrURL) +{ + static BSTR methodBStr = SysAllocString(TEXT("GET")); + + // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. + string pathOrURL(testPathOrURL); + string expectedPixelHash; + + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != string::npos) { + pathOrURL = string(testPathOrURL, 0, separatorPos); + expectedPixelHash = string(testPathOrURL, separatorPos + 1); + } + + BSTR urlBStr; + + CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1); + CFURLRef url = CFURLCreateWithString(0, str, 0); + + if (!url) + url = CFURLCreateWithFileSystemPath(0, str, kCFURLWindowsPathStyle, false); + + CFRelease(str); + + str = CFURLGetString(url); + + CFIndex length = CFStringGetLength(str); + UniChar* buffer = new UniChar[length]; + + CFStringGetCharacters(str, CFRangeMake(0, length), buffer); + urlBStr = SysAllocStringLen((OLECHAR*)buffer, length); + delete[] buffer; + + CFRelease(url); + + ::gLayoutTestController = LayoutTestController::create(pathOrURL, expectedPixelHash); + done = false; + topLoadingFrame = 0; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + COMPtr<IWebView> webView; + if (SUCCEEDED(frame->webView(&webView))) { + COMPtr<IWebViewPrivate> viewPrivate; + if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) { + if (shouldLogHistoryDelegates(pathOrURL.c_str())) { + gLayoutTestController->setDumpHistoryDelegateCallbacks(true); + viewPrivate->setHistoryDelegate(sharedHistoryDelegate.get()); + } else + viewPrivate->setHistoryDelegate(0); + } + } + COMPtr<IWebHistory> history; + if (SUCCEEDED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history)))) + history->setOptionalSharedHistory(0); + + resetWebViewToConsistentStateBeforeTesting(); + + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->setDeveloperExtrasEnabled(true); + if (shouldOpenWebInspector(pathOrURL.c_str())) + gLayoutTestController->showWebInspector(); + } + if (shouldDumpAsText(pathOrURL.c_str())) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + + prevTestBFItem = 0; + if (webView) { + COMPtr<IWebBackForwardList> bfList; + if (SUCCEEDED(webView->backForwardList(&bfList))) + bfList->currentItem(&prevTestBFItem); + } + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + HWND hostWindow; + webView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); + + COMPtr<IWebMutableURLRequest> request; + HRESULT hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request); + if (FAILED(hr)) + goto exit; + + request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60); + + request->setHTTPMethod(methodBStr); + frame->loadRequest(request.get()); + + MSG msg; + while (GetMessage(&msg, 0, 0, 0)) { + // We get spurious WM_MOUSELEAVE events which make event handling machinery think that mouse button + // is released during dragging (see e.g. fast\dynamic\layer-hit-test-crash.html). + // Mouse can never leave WebView during normal DumpRenderTree operation, so we just ignore all such events. + if (msg.message == WM_MOUSELEAVE) + continue; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } + + resetWebViewToConsistentStateBeforeTesting(); + + frame->stopLoading(); + + if (::gLayoutTestController->closeRemainingWindowsWhenComplete()) { + Vector<HWND> windows = openWindows(); + unsigned size = windows.size(); + for (unsigned i = 0; i < size; i++) { + HWND window = windows[i]; + + // Don't try to close the main window + if (window == hostWindow) + continue; + + DestroyWindow(window); + } + } + +exit: + SysFreeString(urlBStr); + ::gLayoutTestController.clear(); + + return; +} + +static Boolean pthreadEqualCallback(const void* value1, const void* value2) +{ + return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2); +} + +static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 }; + +static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER; +static bool javaScriptThreadsShouldTerminate; + +static const int javaScriptThreadsCount = 4; +static CFMutableDictionaryRef javaScriptThreads() +{ + assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY); + static CFMutableDictionaryRef staticJavaScriptThreads; + if (!staticJavaScriptThreads) + staticJavaScriptThreads = CFDictionaryCreateMutable(0, 0, &pthreadKeyCallbacks, 0); + return staticJavaScriptThreads; +} + +// Loops forever, running a script and randomly respawning, until +// javaScriptThreadsShouldTerminate becomes true. +void* runJavaScriptThread(void* arg) +{ + const char* const script = + " \ + var array = []; \ + for (var i = 0; i < 10; i++) { \ + array.push(String(i)); \ + } \ + "; + + while (true) { + JSGlobalContextRef ctx = JSGlobalContextCreate(0); + JSStringRef scriptRef = JSStringCreateWithUTF8CString(script); + + JSValueRef exception = 0; + JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); + assert(!exception); + + JSGlobalContextRelease(ctx); + JSStringRelease(scriptRef); + + JSGarbageCollect(ctx); + + pthread_mutex_lock(&javaScriptThreadsMutex); + + // Check for cancellation. + if (javaScriptThreadsShouldTerminate) { + pthread_mutex_unlock(&javaScriptThreadsMutex); + return 0; + } + + // Respawn probabilistically. + if (rand() % 5 == 0) { + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_detach(pthread); + + pthread_t self = pthread_self(); + CFDictionaryRemoveValue(javaScriptThreads(), self.p); + CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0); + + pthread_mutex_unlock(&javaScriptThreadsMutex); + return 0; + } + + pthread_mutex_unlock(&javaScriptThreadsMutex); + } +} + +static void startJavaScriptThreads(void) +{ + pthread_mutex_lock(&javaScriptThreadsMutex); + + for (int i = 0; i < javaScriptThreadsCount; i++) { + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_detach(pthread); + CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0); + } + + pthread_mutex_unlock(&javaScriptThreadsMutex); +} + +static void stopJavaScriptThreads(void) +{ + pthread_mutex_lock(&javaScriptThreadsMutex); + + javaScriptThreadsShouldTerminate = true; + + pthread_t* pthreads[javaScriptThreadsCount] = {0}; + int threadDictCount = CFDictionaryGetCount(javaScriptThreads()); + assert(threadDictCount == javaScriptThreadsCount); + CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0); + + pthread_mutex_unlock(&javaScriptThreadsMutex); + + for (int i = 0; i < javaScriptThreadsCount; i++) { + pthread_t* pthread = pthreads[i]; + pthread_join(*pthread, 0); + free(pthread); + } +} + +Vector<HWND>& openWindows() +{ + static Vector<HWND> vector; + return vector; +} + +WindowToWebViewMap& windowToWebViewMap() +{ + static WindowToWebViewMap map; + return map; +} + +IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow) +{ + unsigned maxViewWidth = LayoutTestController::maxViewWidth; + unsigned maxViewHeight = LayoutTestController::maxViewHeight; + HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP, + -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0); + + IWebView* webView; + + HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&webView); + if (FAILED(hr)) { + fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr); + return 0; + } + + if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow))) + return 0; + + RECT clientRect; + clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0; + BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree"); + bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName)); + SysFreeString(groupName); + if (failed) + return 0; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return 0; + + viewPrivate->setShouldApplyMacFontAscentHack(TRUE); + viewPrivate->setAlwaysUsesComplexTextCodePath(forceComplexText); + + BSTR pluginPath = SysAllocStringLen(0, exePath().length() + _tcslen(TestPluginDir)); + _tcscpy(pluginPath, exePath().c_str()); + _tcscat(pluginPath, TestPluginDir); + failed = FAILED(viewPrivate->addAdditionalPluginDirectory(pluginPath)); + SysFreeString(pluginPath); + if (failed) + return 0; + + HWND viewWindow; + if (FAILED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) + return 0; + if (webViewWindow) + *webViewWindow = viewWindow; + + SetWindowPos(viewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0); + ShowWindow(hostWindow, SW_SHOW); + + if (FAILED(webView->setFrameLoadDelegate(sharedFrameLoadDelegate.get()))) + return 0; + + if (FAILED(viewPrivate->setFrameLoadDelegatePrivate(sharedFrameLoadDelegate.get()))) + return 0; + + if (FAILED(webView->setUIDelegate(sharedUIDelegate.get()))) + return 0; + + COMPtr<IWebViewEditing> viewEditing; + if (FAILED(webView->QueryInterface(&viewEditing))) + return 0; + + if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get()))) + return 0; + + ResourceLoadDelegate* resourceLoadDelegate = new ResourceLoadDelegate(); + HRESULT result = webView->setResourceLoadDelegate(resourceLoadDelegate); + resourceLoadDelegate->Release(); // The delegate is owned by the WebView, so release our reference to it. + if (FAILED(result)) + return 0; + + openWindows().append(hostWindow); + windowToWebViewMap().set(hostWindow, webView); + return webView; +} + +#if USE(CFNETWORK) +RetainPtr<CFURLCacheRef> sharedCFURLCache() +{ +#ifndef DEBUG_ALL + HMODULE module = GetModuleHandle(TEXT("CFNetwork.dll")); +#else + HMODULE module = GetModuleHandle(TEXT("CFNetwork_debug.dll")); +#endif + if (!module) + return 0; + + typedef CFURLCacheRef (*CFURLCacheCopySharedURLCacheProcPtr)(void); + if (CFURLCacheCopySharedURLCacheProcPtr copyCache = reinterpret_cast<CFURLCacheCopySharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheCopySharedURLCache"))) + return RetainPtr<CFURLCacheRef>(AdoptCF, copyCache()); + + typedef CFURLCacheRef (*CFURLCacheSharedURLCacheProcPtr)(void); + if (CFURLCacheSharedURLCacheProcPtr sharedCache = reinterpret_cast<CFURLCacheSharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheSharedURLCache"))) + return sharedCache(); + + return 0; +} +#endif + +static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*) +{ + fputs("#CRASHED\n", stderr); + fflush(stderr); + return EXCEPTION_CONTINUE_SEARCH; +} + +extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) +{ + // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for + // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the + // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. + ::SetErrorMode(0); + + ::SetUnhandledExceptionFilter(exceptionFilter); + + leakChecking = false; + + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); + + initialize(); + + Vector<const char*> tests; + + for (int i = 1; i < argc; ++i) { + if (!stricmp(argv[i], "--threaded")) { + threaded = true; + continue; + } + + if (!stricmp(argv[i], "--dump-all-pixels")) { + dumpAllPixels = true; + continue; + } + + if (!stricmp(argv[i], "--pixel-tests")) { + dumpPixels = true; + continue; + } + + if (!stricmp(argv[i], "--complex-text")) { + forceComplexText = true; + continue; + } + + if (!stricmp(argv[i], "--print-supported-features")) { + printSupportedFeatures = true; + continue; + } + + tests.append(argv[i]); + } + + policyDelegate = new PolicyDelegate(); + sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate); + sharedUIDelegate.adoptRef(new UIDelegate); + sharedEditingDelegate.adoptRef(new EditingDelegate); + sharedHistoryDelegate.adoptRef(new HistoryDelegate); + + // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592> + COMPtr<IWebPreferences> tmpPreferences; + if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences)))) + return -1; + COMPtr<IWebPreferences> standardPreferences; + if (FAILED(tmpPreferences->standardPreferences(&standardPreferences))) + return -1; + COMPtr<IWebPreferencesPrivate> standardPreferencesPrivate; + if (FAILED(standardPreferences->QueryInterface(&standardPreferencesPrivate))) + return -1; + standardPreferencesPrivate->setShouldPaintNativeControls(FALSE); + standardPreferences->setJavaScriptEnabled(TRUE); + standardPreferences->setDefaultFontSize(16); + standardPreferences->setAcceleratedCompositingEnabled(true); + standardPreferences->setContinuousSpellCheckingEnabled(TRUE); + + if (printSupportedFeatures) { + BOOL acceleratedCompositingAvailable; + standardPreferences->acceleratedCompositingEnabled(&acceleratedCompositingAvailable); + +#if ENABLE(3D_RENDERING) + // In theory, we could have a software-based 3D rendering implementation that we use when + // hardware-acceleration is not available. But we don't have any such software + // implementation, so 3D rendering is only available when hardware-acceleration is. + BOOL threeDRenderingAvailable = acceleratedCompositingAvailable; +#else + BOOL threeDRenderingAvailable = FALSE; +#endif + + printf("SupportedFeatures:%s %s\n", acceleratedCompositingAvailable ? "AcceleratedCompositing" : "", threeDRenderingAvailable ? "3DRendering" : ""); + return 0; + } + + COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow)); + if (!webView) + return -1; + + COMPtr<IWebIconDatabase> iconDatabase; + COMPtr<IWebIconDatabase> tmpIconDatabase; + if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase))) + return -1; + if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase))) + return -1; + + if (FAILED(webView->mainFrame(&frame))) + return -1; + +#if USE(CFNETWORK) + RetainPtr<CFURLCacheRef> urlCache = sharedCFURLCache(); + CFURLCacheRemoveAllCachedResponses(urlCache.get()); +#endif + +#ifdef _DEBUG + _CrtMemState entryToMainMemCheckpoint; + if (leakChecking) + _CrtMemCheckpoint(&entryToMainMemCheckpoint); +#endif + + if (threaded) + startJavaScriptThreads(); + + if (tests.size() == 1 && !strcmp(tests[0], "-")) { + char filenameBuffer[2048]; + printSeparators = true; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + char* newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (strlen(filenameBuffer) == 0) + continue; + + runTest(filenameBuffer); + } + } else { + printSeparators = tests.size() > 1; + for (int i = 0; i < tests.size(); i++) + runTest(tests[i]); + } + + if (threaded) + stopJavaScriptThreads(); + + delete policyDelegate; + frame->Release(); + +#ifdef _DEBUG + if (leakChecking) { + // dump leaks to stderr + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint); + } +#endif + + shutDownWebKit(); + + return 0; +} diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj new file mode 100644 index 000000000..d22ddfa7d --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj @@ -0,0 +1,728 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTree" + ProjectGUID="{6567DFD4-D6DE-4CD5-825D-17E353D160E1}" + RootNamespace="DumpRenderTree" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeDebug.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeRelease.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Cairo_CFLite|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeDebugCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Cairo_CFLite|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeReleaseCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_All|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeDebugAll.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Production|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\DumpRenderTreeProduction.vsprops" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Controllers" + > + <File + RelativePath="..\AccessibilityController.cpp" + > + </File> + <File + RelativePath="..\AccessibilityController.h" + > + </File> + <File + RelativePath=".\AccessibilityControllerWin.cpp" + > + </File> + <File + RelativePath=".\EventSender.cpp" + > + </File> + <File + RelativePath=".\EventSender.h" + > + </File> + <File + RelativePath="..\GCController.cpp" + > + </File> + <File + RelativePath="..\GCController.h" + > + </File> + <File + RelativePath=".\GCControllerWin.cpp" + > + </File> + <File + RelativePath="..\LayoutTestController.cpp" + > + </File> + <File + RelativePath="..\LayoutTestController.h" + > + </File> + <File + RelativePath=".\LayoutTestControllerWin.cpp" + > + </File> + </Filter> + <Filter + Name="Delegates" + > + <File + RelativePath=".\DRTDesktopNotificationPresenter.cpp" + > + </File> + <File + RelativePath=".\DRTDesktopNotificationPresenter.h" + > + </File> + <File + RelativePath=".\EditingDelegate.cpp" + > + </File> + <File + RelativePath=".\EditingDelegate.h" + > + </File> + <File + RelativePath=".\FrameLoadDelegate.cpp" + > + </File> + <File + RelativePath=".\FrameLoadDelegate.h" + > + </File> + <File + RelativePath=".\HistoryDelegate.cpp" + > + </File> + <File + RelativePath=".\HistoryDelegate.h" + > + </File> + <File + RelativePath=".\PolicyDelegate.cpp" + > + </File> + <File + RelativePath=".\PolicyDelegate.h" + > + </File> + <File + RelativePath=".\ResourceLoadDelegate.cpp" + > + </File> + <File + RelativePath=".\ResourceLoadDelegate.h" + > + </File> + <File + RelativePath=".\UIDelegate.cpp" + > + </File> + <File + RelativePath=".\UIDelegate.h" + > + </File> + </Filter> + <File + RelativePath="..\AccessibilityTextMarker.cpp" + > + </File> + <File + RelativePath="..\AccessibilityTextMarker.h" + > + </File> + <File + RelativePath="..\AccessibilityUIElement.cpp" + > + </File> + <File + RelativePath="..\AccessibilityUIElement.h" + > + </File> + <File + RelativePath=".\AccessibilityUIElementWin.cpp" + > + </File> + <File + RelativePath="..\CyclicRedundancyCheck.cpp" + > + </File> + <File + RelativePath="..\CyclicRedundancyCheck.h" + > + </File> + <File + RelativePath=".\DraggingInfo.h" + > + </File> + <File + RelativePath=".\DumpRenderTree.cpp" + > + </File> + <File + RelativePath="..\DumpRenderTree.h" + > + </File> + <File + RelativePath="..\DumpRenderTreePrefix.h" + > + </File> + <File + RelativePath=".\DumpRenderTreeWin.h" + > + </File> + <File + RelativePath=".\MD5.cpp" + > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\MD5.h" + > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\PixelDumpSupport.cpp" + > + </File> + <File + RelativePath="..\PixelDumpSupport.h" + > + </File> + <File + RelativePath="..\cairo\PixelDumpSupportCairo.cpp" + > + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_All|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Production|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\cairo\PixelDumpSupportCairo.h" + > + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_All|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Production|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\cg\PixelDumpSupportCG.cpp" + > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\cg\PixelDumpSupportCG.h" + > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\PixelDumpSupportWin.cpp" + > + </File> + <File + RelativePath="..\WorkQueue.cpp" + > + </File> + <File + RelativePath="..\WorkQueue.h" + > + </File> + <File + RelativePath="..\WorkQueueItem.h" + > + </File> + <File + RelativePath=".\WorkQueueItemWin.cpp" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops new file mode 100644 index 000000000..f126689e1 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeApple" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ProjectDir)\..\cg";" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="CoreGraphics$(LibraryConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib CFNetwork$(LibraryConfigSuffix).lib" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops new file mode 100644 index 000000000..209b3ea06 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeCFLite" + > + <Tool + Name="VCLinkerTool" + AdditionalDependencies="CFLite$(LibraryConfigSuffix).lib" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops new file mode 100644 index 000000000..6d44dec4a --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeCairo" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ProjectDir)\..\cairo";" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="cairo.lib" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops new file mode 100644 index 000000000..ac5003cba --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeCommon" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ProjectDir)\.";"$(ProjectDir)\..";"$(ConfigurationBuildDir)\Include";"$(ConfigurationBuildDir)\Include\private";"$(ConfigurationBuildDir)\Include\DumpRenderTree\ForwardingHeaders";"$(ConfigurationBuildDir)\Include\JavaScriptCore";"$(ConfigurationBuildDir)\Include\private\JavaScriptCore";"$(ConfigurationBuildDir)\Include\WebCoreTestSupport";"$(WebKitLibrariesDir)\Include";"$(WebKitLibrariesDir)\Include\private";"$(WebKitLibrariesDir)\include\pthreads";"$(ConfigurationBuildDir)\Include\WebCore";"$(WebKitLibrariesDir)\Include\WebCore"" + PreprocessorDefinitions="_CONSOLE" + DisableSpecificWarnings="4146" + ForcedIncludeFiles="DumpRenderTreePrefix.h" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT" + AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKitGUID$(WebKitConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib WebCoreTestSupport$(WebKitConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib gdi32.lib ole32.lib oleaut32.lib user32.lib shlwapi.lib oleacc.lib comsuppw.lib" + OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops new file mode 100644 index 000000000..11db1cd97 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeDebug" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops new file mode 100644 index 000000000..38327ed12 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeDebugAll" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops new file mode 100644 index 000000000..ea3a15c49 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeDebugCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\cURL.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeCairo.vsprops;.\DumpRenderTreeCFLite.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj b/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj new file mode 100644 index 000000000..72050b14b --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj @@ -0,0 +1,396 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncher" + ProjectGUID="{2974EA02-840B-4995-8719-8920A61006F1}" + RootNamespace="DumpRenderTreeLauncher" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherDebug.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherRelease.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Cairo_CFLite|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherDebugCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_All|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherDebugAll.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Production|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherProduction.vsprops" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Cairo_CFLite|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\DumpRenderTreeLauncherReleaseCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\..\win\DLLLauncher\DLLLauncherMain.cpp" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops new file mode 100644 index 000000000..033665aec --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherCommon" + > + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="USE_CONSOLE_ENTRY_POINT" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="shlwapi.lib" + OutputFile="$(OutDir)\DumpRenderTree$(WebKitConfigSuffix).exe" + ProgramDatabaseFile="$(TargetDir)$(TargetName)Launcher.pdb" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops new file mode 100644 index 000000000..3ec09ffbe --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherDebug" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\DumpRenderTreeLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops new file mode 100644 index 000000000..d1c2cb5d4 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherDebugAll" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\DumpRenderTreeLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops new file mode 100644 index 000000000..e70732efd --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeDebugCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops new file mode 100644 index 000000000..bf3360136 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherProduction" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\DumpRenderTreeLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops new file mode 100644 index 000000000..535e18fb3 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherRelease" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops new file mode 100644 index 000000000..cf2a0db5b --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeLauncherReleaseCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd new file mode 100644 index 000000000..464502c21 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd @@ -0,0 +1,62 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" + +if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b) + +mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\bin" + +if not exist "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" GOTO:CFLITE + +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFNetwork.resources" "%CONFIGURATIONBUILDDIR%\bin\CFNetwork.resources" +xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CoreFoundation.resources" "%CONFIGURATIONBUILDDIR%\bin\CoreFoundation.resources" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +exit /b + +:CFLITE +if not exist "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.dll" exit /b + +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFLite.resources" "%CONFIGURATIONBUILDDIR%\bin\CFLite.resources" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libcurl.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libeay32.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\ssleay32.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\cairo.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt46.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libicuuc.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libicuin.dll" "%CONFIGURATIONBUILDDIR%\bin" + +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" +xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin" +if exist "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin" diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd new file mode 100644 index 000000000..c2f85c790 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd @@ -0,0 +1,20 @@ +%SystemDrive%\cygwin\bin\which.exe bash +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" + +mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree" +mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders" +mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\runtime" +mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf" + +xcopy /y /d "%PROJECTDIR%\..\ForwardingHeaders\wtf\*.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf" +xcopy /y /d "%PROJECTDIR%\..\ForwardingHeaders\runtime\*.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\runtime" + +if "%CONFIGURATIONNAME%"=="Debug_Cairo_CFLite" xcopy /y /d "%CONFIGURATIONBUILDDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf" +if "%CONFIGURATIONNAME%"=="Release_Cairo_CFLite" xcopy /y /d "%CONFIGURATIONBUILDDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf" + +if "%CONFIGURATIONNAME%"=="Debug_Cairo" xcopy /y /d "%TARGETDIR%\..\include\WebCore\ForwardingHeaders\wtf\MD5.h" +if "%CONFIGURATIONNAME%"=="Release_Cairo" xcopy /y /d "%TARGETDIR%\..\include\WebCore\ForwardingHeaders\wtf\MD5.h" diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops new file mode 100644 index 000000000..ee29e00e2 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeProduction" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops new file mode 100644 index 000000000..3e8e857d8 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeRelease" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops new file mode 100644 index 000000000..aef8e0d9a --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="DumpRenderTreeReleaseCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\cURL.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeCairo.vsprops;.\DumpRenderTreeCFLite.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeWin.h b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h new file mode 100644 index 000000000..c64c3bf50 --- /dev/null +++ b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeWin_h +#define DumpRenderTreeWin_h + +struct IWebFrame; +struct IWebScriptWorld; +struct IWebView; +struct FrameLoadDelegate; +struct PolicyDelegate; +typedef const struct __CFString* CFStringRef; +typedef struct HWND__* HWND; + +extern IWebFrame* topLoadingFrame; +extern IWebFrame* frame; +extern PolicyDelegate* policyDelegate; + +extern HWND webViewWindow; + +#include <WebCore/COMPtr.h> +#include <string> +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +std::wstring urlSuitableForTestResult(const std::wstring& url); +std::wstring lastPathComponent(const std::wstring&); +std::string toUTF8(BSTR); +std::string toUTF8(const std::wstring&); +std::wstring cfStringRefToWString(CFStringRef); + +IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow = 0); +Vector<HWND>& openWindows(); +typedef HashMap<HWND, COMPtr<IWebView> > WindowToWebViewMap; +WindowToWebViewMap& windowToWebViewMap(); + +void setPersistentUserStyleSheetLocation(CFStringRef); +bool setAlwaysAcceptCookies(bool alwaysAcceptCookies); + +unsigned worldIDForWorld(IWebScriptWorld*); + +extern UINT_PTR waitToDumpWatchdog; + +extern COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate; + +#endif // DumpRenderTreeWin_h diff --git a/Tools/DumpRenderTree/win/EditingDelegate.cpp b/Tools/DumpRenderTree/win/EditingDelegate.cpp new file mode 100644 index 000000000..3552ecd17 --- /dev/null +++ b/Tools/DumpRenderTree/win/EditingDelegate.cpp @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EditingDelegate.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <WebCore/COMPtr.h> +#include <wtf/Platform.h> +#include <JavaScriptCore/Assertions.h> +#include <string> +#include <tchar.h> + +using std::wstring; + +EditingDelegate::EditingDelegate() + : m_refCount(1) + , m_acceptsEditing(true) +{ +} + +// IUnknown +HRESULT STDMETHODCALLTYPE EditingDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebEditingDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebEditingDelegate)) + *ppvObject = static_cast<IWebEditingDelegate*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE EditingDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE EditingDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete this; + + return newRef; +} + +static wstring dumpPath(IDOMNode* node) +{ + ASSERT(node); + + wstring result; + + BSTR name; + if (FAILED(node->nodeName(&name))) + return result; + result.assign(name, SysStringLen(name)); + SysFreeString(name); + + COMPtr<IDOMNode> parent; + if (SUCCEEDED(node->parentNode(&parent))) + result += TEXT(" > ") + dumpPath(parent.get()); + + return result; +} + +static wstring dump(IDOMRange* range) +{ + ASSERT(range); + + int startOffset; + if (FAILED(range->startOffset(&startOffset))) + return 0; + + int endOffset; + if (FAILED(range->endOffset(&endOffset))) + return 0; + + COMPtr<IDOMNode> startContainer; + if (FAILED(range->startContainer(&startContainer))) + return 0; + + COMPtr<IDOMNode> endContainer; + if (FAILED(range->endContainer(&endContainer))) + return 0; + + wchar_t buffer[1024]; + _snwprintf(buffer, ARRAYSIZE(buffer), L"range from %ld of %s to %ld of %s", startOffset, dumpPath(startContainer.get()), endOffset, dumpPath(endContainer.get())); + return buffer; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldBeginEditingInDOMRange( + /* [in] */ IWebView* webView, + /* [in] */ IDOMRange* range, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n"), dump(range)); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldEndEditingInDOMRange( + /* [in] */ IWebView* webView, + /* [in] */ IDOMRange* range, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n"), dump(range)); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertNode( + /* [in] */ IWebView* webView, + /* [in] */ IDOMNode* node, + /* [in] */ IDOMRange* range, + /* [in] */ WebViewInsertAction action) +{ + static LPCTSTR insertactionstring[] = { + TEXT("WebViewInsertActionTyped"), + TEXT("WebViewInsertActionPasted"), + TEXT("WebViewInsertActionDropped"), + }; + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n"), dumpPath(node), dump(range), insertactionstring[action]); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertText( + /* [in] */ IWebView* webView, + /* [in] */ BSTR text, + /* [in] */ IDOMRange* range, + /* [in] */ WebViewInsertAction action, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + static LPCTSTR insertactionstring[] = { + TEXT("WebViewInsertActionTyped"), + TEXT("WebViewInsertActionPasted"), + TEXT("WebViewInsertActionDropped"), + }; + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n"), text ? text : TEXT(""), dump(range), insertactionstring[action]); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldDeleteDOMRange( + /* [in] */ IWebView* webView, + /* [in] */ IDOMRange* range, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldDeleteDOMRange:%s\n"), dump(range)); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeSelectedDOMRange( + /* [in] */ IWebView* webView, + /* [in] */ IDOMRange* currentRange, + /* [in] */ IDOMRange* proposedRange, + /* [in] */ WebSelectionAffinity selectionAffinity, + /* [in] */ BOOL stillSelecting, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + static LPCTSTR affinitystring[] = { + TEXT("NSSelectionAffinityUpstream"), + TEXT("NSSelectionAffinityDownstream") + }; + static LPCTSTR boolstring[] = { + TEXT("FALSE"), + TEXT("TRUE") + }; + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n"), dump(currentRange), dump(proposedRange), affinitystring[selectionAffinity], boolstring[stillSelecting]); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldApplyStyle( + /* [in] */ IWebView* webView, + /* [in] */ IDOMCSSStyleDeclaration* style, + /* [in] */ IDOMRange* range, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n"), TEXT("'style description'")/*[[style description] UTF8String]*/, dump(range)); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeTypingStyle( + /* [in] */ IWebView* webView, + /* [in] */ IDOMCSSStyleDeclaration* currentStyle, + /* [in] */ IDOMCSSStyleDeclaration* proposedStyle, + /* [retval][out] */ BOOL* result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n"), TEXT("'currentStyle description'"), TEXT("'proposedStyle description'")); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::doPlatformCommand( + /* [in] */ IWebView *webView, + /* [in] */ BSTR command, + /* [retval][out] */ BOOL *result) +{ + if (!result) { + ASSERT_NOT_REACHED(); + return E_POINTER; + } + + if (::gLayoutTestController->dumpEditingCallbacks() && !done) + _tprintf(TEXT("EDITING DELEGATE: doPlatformCommand:%s\n"), command ? command : TEXT("")); + + *result = m_acceptsEditing; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidBeginEditing( + /* [in] */ IWebNotification* notification) +{ + if (::gLayoutTestController->dumpEditingCallbacks() && !done) { + BSTR name; + notification->name(&name); + _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT("")); + SysFreeString(name); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChange( + /* [in] */ IWebNotification *notification) +{ + if (::gLayoutTestController->dumpEditingCallbacks() && !done) { + BSTR name; + notification->name(&name); + _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT("")); + SysFreeString(name); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidEndEditing( + /* [in] */ IWebNotification *notification) +{ + if (::gLayoutTestController->dumpEditingCallbacks() && !done) { + BSTR name; + notification->name(&name); + _tprintf(TEXT("EDITING DELEGATE: webViewDidEndEditing:%s\n"), name ? name : TEXT("")); + SysFreeString(name); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeTypingStyle( + /* [in] */ IWebNotification *notification) +{ + if (::gLayoutTestController->dumpEditingCallbacks() && !done) { + BSTR name; + notification->name(&name); + _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n"), name ? name : TEXT("")); + SysFreeString(name); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeSelection( + /* [in] */ IWebNotification *notification) +{ + if (::gLayoutTestController->dumpEditingCallbacks() && !done) { + BSTR name; + notification->name(&name); + _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeSelection:%s\n"), name ? name : TEXT("")); + SysFreeString(name); + } + return S_OK; +} + +static int indexOfFirstWordCharacter(const TCHAR* text) +{ + const TCHAR* cursor = text; + while (*cursor && !iswalpha(*cursor)) + ++cursor; + return *cursor ? (cursor - text) : -1; +}; + +static int wordLength(const TCHAR* text) +{ + const TCHAR* cursor = text; + while (*cursor && iswalpha(*cursor)) + ++cursor; + return cursor - text; +}; + +HRESULT STDMETHODCALLTYPE EditingDelegate::checkSpellingOfString( + /* [in] */ IWebView* view, + /* [in] */ LPCTSTR text, + /* [in] */ int length, + /* [out] */ int* misspellingLocation, + /* [out] */ int* misspellingLength) +{ + static const TCHAR* 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. + TEXT("foo"), + TEXT("Foo"), + TEXT("baz"), + TEXT("fo"), + TEXT("LibertyF"), + TEXT("chello"), + TEXT("xxxtestxxx"), + TEXT("XXxxx"), + TEXT("Textx"), + TEXT("blockquoted"), + TEXT("asd"), + TEXT("Lorem"), + TEXT("Nunc"), + TEXT("Curabitur"), + TEXT("eu"), + TEXT("adlj"), + TEXT("adaasj"), + TEXT("sdklj"), + TEXT("jlkds"), + TEXT("jsaada"), + TEXT("jlda"), + TEXT("zz"), + TEXT("contentEditable"), + 0, + }; + + wstring textString(text, length); + int wordStart = indexOfFirstWordCharacter(textString.c_str()); + if (-1 == wordStart) + return S_OK; + wstring word = textString.substr(wordStart, wordLength(textString.c_str() + wordStart)); + for (size_t i = 0; misspelledWords[i]; ++i) { + if (word == misspelledWords[i]) { + *misspellingLocation = wordStart; + *misspellingLength = word.size(); + break; + } + } + + return S_OK; +} diff --git a/Tools/DumpRenderTree/win/EditingDelegate.h b/Tools/DumpRenderTree/win/EditingDelegate.h new file mode 100644 index 000000000..7b7f418aa --- /dev/null +++ b/Tools/DumpRenderTree/win/EditingDelegate.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EditingDelegate_h +#define EditingDelegate_h + +#include <WebKit/WebKit.h> + +class __declspec(uuid("265DCD4B-79C3-44a2-84BC-511C3EDABD6F")) EditingDelegate : public IWebEditingDelegate { +public: + EditingDelegate(); + + void setAcceptsEditing(bool b) { m_acceptsEditing = b; } + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebEditingDelegate + virtual HRESULT STDMETHODCALLTYPE shouldBeginEditingInDOMRange( + /* [in] */ IWebView *webView, + /* [in] */ IDOMRange *range, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldEndEditingInDOMRange( + /* [in] */ IWebView *webView, + /* [in] */ IDOMRange *range, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldInsertNode( + /* [in] */ IWebView *webView, + /* [in] */ IDOMNode *node, + /* [in] */ IDOMRange *range, + /* [in] */ WebViewInsertAction action); + + virtual HRESULT STDMETHODCALLTYPE shouldInsertText( + /* [in] */ IWebView *webView, + /* [in] */ BSTR text, + /* [in] */ IDOMRange *range, + /* [in] */ WebViewInsertAction action, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldDeleteDOMRange( + /* [in] */ IWebView *webView, + /* [in] */ IDOMRange *range, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldChangeSelectedDOMRange( + /* [in] */ IWebView *webView, + /* [in] */ IDOMRange *currentRange, + /* [in] */ IDOMRange *proposedRange, + /* [in] */ WebSelectionAffinity selectionAffinity, + /* [in] */ BOOL stillSelecting, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldApplyStyle( + /* [in] */ IWebView *webView, + /* [in] */ IDOMCSSStyleDeclaration *style, + /* [in] */ IDOMRange *range, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE shouldChangeTypingStyle( + /* [in] */ IWebView *webView, + /* [in] */ IDOMCSSStyleDeclaration *currentStyle, + /* [in] */ IDOMCSSStyleDeclaration *proposedStyle, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE doPlatformCommand( + /* [in] */ IWebView *webView, + /* [in] */ BSTR command, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE webViewDidBeginEditing( + /* [in] */ IWebNotification *notification); + + virtual HRESULT STDMETHODCALLTYPE webViewDidChange( + /* [in] */ IWebNotification *notification); + + virtual HRESULT STDMETHODCALLTYPE webViewDidEndEditing( + /* [in] */ IWebNotification *notification); + + virtual HRESULT STDMETHODCALLTYPE webViewDidChangeTypingStyle( + /* [in] */ IWebNotification *notification); + + virtual HRESULT STDMETHODCALLTYPE webViewDidChangeSelection( + /* [in] */ IWebNotification *notification); + + virtual HRESULT STDMETHODCALLTYPE undoManagerForWebView( + /* [in] */ IWebView *webView, + /* [retval][out] */ IWebUndoManager **undoManager) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE ignoreWordInSpellDocument( + /* [in] */ IWebView *view, + /* [in] */ BSTR word) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE learnWord( + /* [in] */ BSTR word) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE checkSpellingOfString( + /* [in] */ IWebView *view, + /* [in] */ LPCTSTR text, + /* [in] */ int length, + /* [out] */ int *misspellingLocation, + /* [out] */ int *misspellingLength); + + virtual HRESULT STDMETHODCALLTYPE checkGrammarOfString( + /* [in] */ IWebView *view, + /* [in] */ LPCTSTR text, + /* [in] */ int length, + /* [out] */ IEnumWebGrammarDetails **grammarDetails, + /* [out] */ int *badGrammarLocation, + /* [out] */ int *badGrammarLength) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE updateSpellingUIWithGrammarString( + /* [in] */ BSTR string, + /* [in] */ int location, + /* [in] */ int length, + /* [in] */ BSTR userDescription, + /* [in] */ BSTR *guesses, + /* [in] */ int guessesCount) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE updateSpellingUIWithMisspelledWord( + /* [in] */ BSTR word) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE showSpellingUI( + /* [in] */ BOOL show) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE spellingUIIsShowing( + /* [retval][out] */ BOOL *result) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE guessesForWord( + /* [in] */ BSTR word, + /* [retval][out] */ IEnumSpellingGuesses **guesses) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE closeSpellDocument( + /* [in] */ IWebView *view) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE sharedSpellCheckerExists( + /* [retval][out] */ BOOL *exists) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE preflightChosenSpellServer( void) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE updateGrammar( void) { return E_NOTIMPL; } + +private: + bool m_acceptsEditing; + ULONG m_refCount; +}; + +#endif // !defined(EditingDelegate_h) diff --git a/Tools/DumpRenderTree/win/EventSender.cpp b/Tools/DumpRenderTree/win/EventSender.cpp new file mode 100644 index 000000000..e1c5cd502 --- /dev/null +++ b/Tools/DumpRenderTree/win/EventSender.cpp @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h" + +#include "DraggingInfo.h" +#include "DumpRenderTree.h" + +#include <WebCore/COMPtr.h> +#include <wtf/ASCIICType.h> +#include <wtf/Platform.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <JavaScriptCore/Assertions.h> +#include <WebKit/WebKit.h> +#include <windows.h> + +#define WM_DRT_SEND_QUEUED_EVENT (WM_APP+1) + +static bool down; +static bool dragMode = true; +static bool replayingSavedEvents; +static int timeOffset; +static POINT lastMousePosition; + +struct DelayedMessage { + MSG msg; + unsigned delay; +}; + +static DelayedMessage msgQueue[1024]; +static unsigned endOfQueue; +static unsigned startOfQueue; + +static bool didDragEnter; +DraggingInfo* draggingInfo = 0; + +static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + return JSValueMakeBoolean(context, dragMode); +} + +static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + dragMode = JSValueToBoolean(context, value); + return true; +} + +static JSValueRef getConstantCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYDOWN")) + return JSValueMakeNumber(context, WM_KEYDOWN); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYUP")) + return JSValueMakeNumber(context, WM_KEYUP); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_CHAR")) + return JSValueMakeNumber(context, WM_CHAR); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR")) + return JSValueMakeNumber(context, WM_DEADCHAR); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYDOWN")) + return JSValueMakeNumber(context, WM_SYSKEYDOWN); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYUP")) + return JSValueMakeNumber(context, WM_SYSKEYUP); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSCHAR")) + return JSValueMakeNumber(context, WM_SYSCHAR); + if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSDEADCHAR")) + return JSValueMakeNumber(context, WM_SYSDEADCHAR); + ASSERT_NOT_REACHED(); + return JSValueMakeUndefined(context); +} + +static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount > 0) { + msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception); + ASSERT(!exception || !*exception); + } + + return JSValueMakeUndefined(context); +} + +static DWORD currentEventTime() +{ + return ::GetTickCount() + timeOffset; +} + +static MSG makeMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + MSG result = {0}; + result.hwnd = hwnd; + result.message = message; + result.wParam = wParam; + result.lParam = lParam; + result.time = currentEventTime(); + result.pt = lastMousePosition; + + return result; +} + +static LRESULT dispatchMessage(const MSG* msg) +{ + ASSERT(msg); + ::TranslateMessage(msg); + return ::DispatchMessage(msg); +} + +static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + down = true; + MSG msg = makeMsg(webViewWindow, WM_RBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); + dispatchMessage(&msg); + down = false; + msg = makeMsg(webViewWindow, WM_RBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); + dispatchMessage(&msg); + + return JSValueMakeUndefined(context); +} + +static WPARAM buildModifierFlags(JSContextRef context, const JSValueRef modifiers) +{ + JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0); + if (!modifiersArray) + return 0; + + WPARAM flags = 0; + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0); + for (int i = 0; i < modifiersCount; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0); + JSStringRef string = JSValueToStringCopy(context, value, 0); + if (JSStringIsEqualToUTF8CString(string, "ctrlKey") + || JSStringIsEqualToUTF8CString(string, "addSelectionKey")) + flags |= MK_CONTROL; + else if (JSStringIsEqualToUTF8CString(string, "shiftKey") + || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey")) + flags |= MK_SHIFT; + // No way to specifiy altKey in a MSG. + + JSStringRelease(string); + } + return flags; +} + +static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + down = true; + int mouseType = WM_LBUTTONDOWN; + if (argumentCount >= 1) { + int mouseNumber = JSValueToNumber(context, arguments[0], exception); + switch (mouseNumber) { + case 0: + mouseType = WM_LBUTTONDOWN; + break; + case 1: + mouseType = WM_MBUTTONDOWN; + break; + case 2: + mouseType = WM_RBUTTONDOWN; + break; + case 3: + // fast/events/mouse-click-events expects the 4th button has event.button = 1, so send an WM_BUTTONDOWN + mouseType = WM_MBUTTONDOWN; + break; + default: + mouseType = WM_LBUTTONDOWN; + break; + } + } + + WPARAM wparam = 0; + if (argumentCount >= 2) + wparam |= buildModifierFlags(context, arguments[1]); + + MSG msg = makeMsg(webViewWindow, mouseType, wparam, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); + if (!msgQueue[endOfQueue].delay) + dispatchMessage(&msg); + else { + // replaySavedEvents has the required logic to make leapForward delays work + msgQueue[endOfQueue++].msg = msg; + replaySavedEvents(); + } + + return JSValueMakeUndefined(context); +} + +static inline POINTL pointl(const POINT& point) +{ + POINTL result; + result.x = point.x; + result.y = point.y; + return result; +} + +static void doMouseUp(MSG msg, HRESULT* oleDragAndDropReturnValue = 0) +{ + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + dispatchMessage(&msg); + down = false; + + if (draggingInfo) { + COMPtr<IWebView> webView; + COMPtr<IDropTarget> webViewDropTarget; + if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) { + POINT screenPoint = msg.pt; + DWORD effect = 0; + ::ClientToScreen(webViewWindow, &screenPoint); + if (!didDragEnter) { + webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); + didDragEnter = true; + } + HRESULT hr = draggingInfo->dropSource()->QueryContinueDrag(0, 0); + if (oleDragAndDropReturnValue) + *oleDragAndDropReturnValue = hr; + webViewDropTarget->DragOver(0, pointl(screenPoint), &effect); + if (hr == DRAGDROP_S_DROP && effect != DROPEFFECT_NONE) { + DWORD effect = 0; + webViewDropTarget->Drop(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); + draggingInfo->setPerformedDropEffect(effect); + } else + webViewDropTarget->DragLeave(); + + // Reset didDragEnter so that another drag started within the same frame works properly. + didDragEnter = false; + } + } +} + +static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int mouseType = WM_LBUTTONUP; + if (argumentCount >= 1) { + int mouseNumber = JSValueToNumber(context, arguments[0], exception); + switch (mouseNumber) { + case 0: + mouseType = WM_LBUTTONUP; + break; + case 1: + mouseType = WM_MBUTTONUP; + break; + case 2: + mouseType = WM_RBUTTONUP; + break; + case 3: + // fast/events/mouse-click-events expects the 4th button has event.button = 1, so send an WM_MBUTTONUP + mouseType = WM_MBUTTONUP; + break; + default: + mouseType = WM_LBUTTONUP; + break; + } + } + + WPARAM wparam = 0; + if (argumentCount >= 2) + wparam |= buildModifierFlags(context, arguments[1]); + + MSG msg = makeMsg(webViewWindow, mouseType, wparam, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); + + if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) { + msgQueue[endOfQueue++].msg = msg; + replaySavedEvents(); + } else + doMouseUp(msg); + + return JSValueMakeUndefined(context); +} + +static void doMouseMove(MSG msg) +{ + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + dispatchMessage(&msg); + + if (down && draggingInfo) { + POINT screenPoint = msg.pt; + ::ClientToScreen(webViewWindow, &screenPoint); + + IWebView* webView; + COMPtr<IDropTarget> webViewDropTarget; + if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) { + DWORD effect = 0; + if (didDragEnter) + webViewDropTarget->DragOver(MK_LBUTTON, pointl(screenPoint), &effect); + else { + webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); + didDragEnter = true; + } + draggingInfo->dropSource()->GiveFeedback(effect); + } + } +} + +static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + lastMousePosition.x = (int)JSValueToNumber(context, arguments[0], exception); + ASSERT(!exception || !*exception); + lastMousePosition.y = (int)JSValueToNumber(context, arguments[1], exception); + ASSERT(!exception || !*exception); + + MSG msg = makeMsg(webViewWindow, WM_MOUSEMOVE, down ? MK_LBUTTON : 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); + + if (dragMode && down && !replayingSavedEvents) { + msgQueue[endOfQueue++].msg = msg; + return JSValueMakeUndefined(context); + } + + doMouseMove(msg); + + return JSValueMakeUndefined(context); +} + +void replaySavedEvents(HRESULT* oleDragAndDropReturnValue) +{ + replayingSavedEvents = true; + + MSG msg = { 0 }; + + while (startOfQueue < endOfQueue && !msgQueue[startOfQueue].delay) { + msg = msgQueue[startOfQueue++].msg; + switch (msg.message) { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + doMouseUp(msg, oleDragAndDropReturnValue); + break; + case WM_MOUSEMOVE: + doMouseMove(msg); + break; + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + dispatchMessage(&msg); + break; + default: + // Not reached + break; + } + } + + int numQueuedMessages = endOfQueue - startOfQueue; + if (!numQueuedMessages) { + startOfQueue = 0; + endOfQueue = 0; + replayingSavedEvents = false; + ASSERT(!down); + return; + } + + if (msgQueue[startOfQueue].delay) { + ::Sleep(msgQueue[startOfQueue].delay); + msgQueue[startOfQueue].delay = 0; + } + + ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0); + while (::GetMessage(&msg, webViewWindow, 0, 0)) { + // FIXME: Why do we get a WM_MOUSELEAVE? it breaks tests + if (msg.message == WM_MOUSELEAVE) + continue; + if (msg.message != WM_DRT_SEND_QUEUED_EVENT) { + dispatchMessage(&msg); + continue; + } + msg = msgQueue[startOfQueue++].msg; + switch (msg.message) { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + doMouseUp(msg, oleDragAndDropReturnValue); + break; + case WM_MOUSEMOVE: + doMouseMove(msg); + break; + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + dispatchMessage(&msg); + break; + default: + // Not reached + break; + } + if (startOfQueue >= endOfQueue) + break; + ::Sleep(msgQueue[startOfQueue].delay); + msgQueue[startOfQueue].delay = 0; + ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0); + } + startOfQueue = 0; + endOfQueue = 0; + + replayingSavedEvents = false; +} + +static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + static const JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length"); + + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + JSStringRef character = JSValueToStringCopy(context, arguments[0], exception); + ASSERT(!*exception); + int virtualKeyCode; + int charCode = 0; + int keyData = 1; + bool needsShiftKeyModifier = false; + if (JSStringIsEqualToUTF8CString(character, "leftArrow")) { + virtualKeyCode = VK_LEFT; + keyData += KF_EXTENDED << 16; // In this case, extended means "not keypad". + } else if (JSStringIsEqualToUTF8CString(character, "rightArrow")) { + virtualKeyCode = VK_RIGHT; + keyData += KF_EXTENDED << 16; + } else if (JSStringIsEqualToUTF8CString(character, "upArrow")) { + virtualKeyCode = VK_UP; + keyData += KF_EXTENDED << 16; + } else if (JSStringIsEqualToUTF8CString(character, "downArrow")) { + virtualKeyCode = VK_DOWN; + keyData += KF_EXTENDED << 16; + } else if (JSStringIsEqualToUTF8CString(character, "pageUp")) + virtualKeyCode = VK_PRIOR; + else if (JSStringIsEqualToUTF8CString(character, "pageDown")) + virtualKeyCode = VK_NEXT; + else if (JSStringIsEqualToUTF8CString(character, "home")) + virtualKeyCode = VK_HOME; + else if (JSStringIsEqualToUTF8CString(character, "end")) + virtualKeyCode = VK_END; + else if (JSStringIsEqualToUTF8CString(character, "insert")) + virtualKeyCode = VK_INSERT; + else if (JSStringIsEqualToUTF8CString(character, "delete")) + virtualKeyCode = VK_DELETE; + else if (JSStringIsEqualToUTF8CString(character, "printScreen")) + virtualKeyCode = VK_SNAPSHOT; + else if (JSStringIsEqualToUTF8CString(character, "menu")) + virtualKeyCode = VK_APPS; + else { + charCode = JSStringGetCharactersPtr(character)[0]; + virtualKeyCode = LOBYTE(VkKeyScan(charCode)); + if (WTF::isASCIIUpper(charCode)) + needsShiftKeyModifier = true; + } + JSStringRelease(character); + + BYTE keyState[256]; + if (argumentCount > 1 || needsShiftKeyModifier) { + ::GetKeyboardState(keyState); + + BYTE newKeyState[256]; + memcpy(newKeyState, keyState, sizeof(keyState)); + + if (needsShiftKeyModifier) + newKeyState[VK_SHIFT] = 0x80; + + if (argumentCount > 1) { + JSObjectRef modifiersArray = JSValueToObject(context, arguments[1], 0); + if (modifiersArray) { + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty, 0), 0); + for (int i = 0; i < modifiersCount; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0); + JSStringRef string = JSValueToStringCopy(context, value, 0); + if (JSStringIsEqualToUTF8CString(string, "ctrlKey") || JSStringIsEqualToUTF8CString(string, "addSelectionKey")) + newKeyState[VK_CONTROL] = 0x80; + else if (JSStringIsEqualToUTF8CString(string, "shiftKey") || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey")) + newKeyState[VK_SHIFT] = 0x80; + else if (JSStringIsEqualToUTF8CString(string, "altKey")) + newKeyState[VK_MENU] = 0x80; + + JSStringRelease(string); + } + } + } + + ::SetKeyboardState(newKeyState); + } + + MSG msg = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYDOWN : WM_KEYDOWN, virtualKeyCode, keyData); + if (virtualKeyCode != 255) + dispatchMessage(&msg); + else { + // For characters that do not exist in the active keyboard layout, + // ::Translate will not work, so we post an WM_CHAR event ourselves. + ::PostMessage(webViewWindow, WM_CHAR, charCode, 0); + } + + // Tests expect that all messages are processed by the time keyDown() returns. + if (::PeekMessage(&msg, webViewWindow, WM_CHAR, WM_CHAR, PM_REMOVE) || ::PeekMessage(&msg, webViewWindow, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) + ::DispatchMessage(&msg); + + MSG msgUp = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYUP : WM_KEYUP, virtualKeyCode, keyData); + ::DispatchMessage(&msgUp); + + if (argumentCount > 1 || needsShiftKeyModifier) + ::SetKeyboardState(keyState); + + return JSValueMakeUndefined(context); +} + +// eventSender.dispatchMessage(message, wParam, lParam, time = currentEventTime(), x = lastMousePosition.x, y = lastMousePosition.y) +static JSValueRef dispatchMessageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + COMPtr<IWebFramePrivate> framePrivate; + if (SUCCEEDED(frame->QueryInterface(&framePrivate))) + framePrivate->layout(); + + MSG msg = {}; + msg.hwnd = webViewWindow; + msg.message = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + msg.wParam = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + msg.lParam = static_cast<ULONG_PTR>(JSValueToNumber(context, arguments[2], exception)); + ASSERT(!*exception); + if (argumentCount >= 4) { + msg.time = JSValueToNumber(context, arguments[3], exception); + ASSERT(!*exception); + } + if (!msg.time) + msg.time = currentEventTime(); + if (argumentCount >= 6) { + msg.pt.x = JSValueToNumber(context, arguments[4], exception); + ASSERT(!*exception); + msg.pt.y = JSValueToNumber(context, arguments[5], exception); + ASSERT(!*exception); + } else + msg.pt = lastMousePosition; + + ::DispatchMessage(&msg); + + return JSValueMakeUndefined(context); +} + +static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return JSValueMakeUndefined(context); + + COMPtr<IWebIBActions> webIBActions(Query, webView); + if (!webIBActions) + return JSValueMakeUndefined(context); + + webIBActions->makeTextLarger(0); + return JSValueMakeUndefined(context); +} + +static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return JSValueMakeUndefined(context); + + COMPtr<IWebIBActions> webIBActions(Query, webView); + if (!webIBActions) + return JSValueMakeUndefined(context); + + webIBActions->makeTextSmaller(0); + return JSValueMakeUndefined(context); +} + +static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return JSValueMakeUndefined(context); + + COMPtr<IWebIBActions> webIBActions(Query, webView); + if (!webIBActions) + return JSValueMakeUndefined(context); + + webIBActions->zoomPageIn(0); + return JSValueMakeUndefined(context); +} + +static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return JSValueMakeUndefined(context); + + COMPtr<IWebIBActions> webIBActions(Query, webView); + if (!webIBActions) + return JSValueMakeUndefined(context); + + webIBActions->zoomPageOut(0); + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticFunctions[] = { + { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "dispatchMessage", dispatchMessageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSStaticValue staticValues[] = { + { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone }, + { "WM_KEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_KEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_CHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_DEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_SYSKEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_SYSKEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_SYSCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { "WM_SYSDEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static JSClassRef getClass(JSContextRef context) +{ + static JSClassRef eventSenderClass = 0; + + if (!eventSenderClass) { + JSClassDefinition classDefinition = {0}; + classDefinition.staticFunctions = staticFunctions; + classDefinition.staticValues = staticValues; + + eventSenderClass = JSClassCreate(&classDefinition); + } + + return eventSenderClass; +} + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame) +{ + if (isTopFrame) { + down = false; + dragMode = true; + replayingSavedEvents = false; + timeOffset = 0; + lastMousePosition.x = 0; + lastMousePosition.y = 0; + + endOfQueue = 0; + startOfQueue = 0; + + didDragEnter = false; + draggingInfo = 0; + } + return JSObjectMake(context, getClass(context), 0); +} diff --git a/Tools/DumpRenderTree/win/EventSender.h b/Tools/DumpRenderTree/win/EventSender.h new file mode 100644 index 000000000..a0add85eb --- /dev/null +++ b/Tools/DumpRenderTree/win/EventSender.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h +#define EventSender_h + +class DraggingInfo; + +typedef long HRESULT; +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame); +void replaySavedEvents(HRESULT* oleDragAndDropReturnValue = 0); + +extern DraggingInfo* draggingInfo; + +#endif diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp new file mode 100644 index 000000000..c5b9e3396 --- /dev/null +++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "FrameLoadDelegate.h" + +#include "AccessibilityController.h" +#include "DumpRenderTree.h" +#include "EventSender.h" +#include "GCController.h" +#include "LayoutTestController.h" +#include "WebCoreTestSupport.h" +#include "WorkQueueItem.h" +#include "WorkQueue.h" +#include <WebCore/COMPtr.h> +#include <JavaScriptCore/Assertions.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <WebKit/WebKit.h> +#include <stdio.h> +#include <string> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +using std::string; + +static FrameLoadDelegate* g_delegateWaitingOnTimer; + +string descriptionSuitableForTestResult(IWebFrame* webFrame) +{ + COMPtr<IWebView> webView; + if (FAILED(webFrame->webView(&webView))) + return string(); + + COMPtr<IWebFrame> mainFrame; + if (FAILED(webView->mainFrame(&mainFrame))) + return string(); + + BSTR frameNameBSTR; + if (FAILED(webFrame->name(&frameNameBSTR)) || toUTF8(frameNameBSTR).empty()) + return (webFrame == mainFrame) ? "main frame" : string(); + + string frameName = (webFrame == mainFrame) ? "main frame" : "frame"; + frameName += " \"" + toUTF8(frameNameBSTR) + "\""; + + SysFreeString(frameNameBSTR); + return frameName; +} + +FrameLoadDelegate::FrameLoadDelegate() + : m_refCount(1) + , m_gcController(adoptPtr(new GCController)) + , m_accessibilityController(adoptPtr(new AccessibilityController)) +{ +} + +FrameLoadDelegate::~FrameLoadDelegate() +{ +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebFrameLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate)) + *ppvObject = static_cast<IWebFrameLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate)) + *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this); + else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate2)) + *ppvObject = static_cast<IWebFrameLoadDelegatePrivate2*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame( + /* [in] */ IWebView* webView, + /* [in] */ IWebFrame* frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didStartProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str()); + + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError( + /* [in] */ IWebView *webView, + /* [in] */ IWebError *error, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str()); + + locationChangeDone(error, frame); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str()); + + COMPtr<IWebViewPrivate> webViewPrivate; + HRESULT hr = webView->QueryInterface(&webViewPrivate); + if (FAILED(hr)) + return hr; + webViewPrivate->updateFocusedAndActiveState(); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle( + /* [in] */ IWebView *webView, + /* [in] */ BSTR title, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title); + + if (::gLayoutTestController->dumpTitleChanges() && !done) + printf("TITLE CHANGED: %S\n", title ? title : L""); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didChangeIcons( + /* [in] */ IWebView* webView, + /* [in] */ IWebFrame* frame) +{ + if (!done && gLayoutTestController->dumpIconChanges()) + printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str()); + + return S_OK; +} + +void FrameLoadDelegate::processWork() +{ + // if another load started, then wait for it to complete. + if (topLoadingFrame) + return; + + // if we finish all the commands, we're ready to dump state + if (WorkQueue::shared()->processWork() && !::gLayoutTestController->waitToDump()) + dump(); +} + +void FrameLoadDelegate::resetToConsistentState() +{ + m_accessibilityController->resetToConsistentState(); +} + +typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector; +static DelegateVector& delegatesWithDelayedWork() +{ + DEFINE_STATIC_LOCAL(DelegateVector, delegates, ()); + return delegates; +} + +static UINT_PTR processWorkTimerID; + +static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD) +{ + ASSERT_ARG(id, id == processWorkTimerID); + ::KillTimer(hwnd, id); + processWorkTimerID = 0; + + DelegateVector delegates; + delegates.swap(delegatesWithDelayedWork()); + + for (size_t i = 0; i < delegates.size(); ++i) + delegates[i]->processWork(); +} + +void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame) +{ + if (frame != topLoadingFrame) + return; + + topLoadingFrame = 0; + WorkQueue::shared()->setFrozen(true); + + if (::gLayoutTestController->waitToDump()) + return; + + if (WorkQueue::shared()->count()) { + if (!processWorkTimerID) + processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer); + delegatesWithDelayedWork().append(this); + return; + } + + dump(); +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame( + /* [in] */ IWebView* webView, + /* [in] */ IWebFrame* frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str()); + + locationChangeDone(0, frame); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError( + /* [in] */ IWebView* webView, + /* [in] */ IWebError* error, + /* [in] */ IWebFrame* frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str()); + + locationChangeDone(error, frame); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willPerformClientRedirectToURL( + /* [in] */ IWebView *webView, + /* [in] */ BSTR url, + /* [in] */ double delaySeconds, + /* [in] */ DATE fireDate, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(), + urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCancelClientRedirectForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str()); + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) +{ + return E_NOTIMPL; +} + +HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*) +{ + return E_NOTIMPL; +} + +HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world) +{ + ASSERT_ARG(webView, webView); + ASSERT_ARG(frame, frame); + ASSERT_ARG(world, world); + if (!webView || !frame || !world) + return E_POINTER; + + COMPtr<IWebScriptWorld> standardWorld; + if (FAILED(world->standardWorld(&standardWorld))) + return S_OK; + + if (world == standardWorld) + didClearWindowObjectForFrameInStandardWorld(frame); + else + didClearWindowObjectForFrameInIsolatedWorld(frame, world); + return S_OK; +} + +void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world); + if (!ctx) + return; + + JSObjectRef globalObject = JSContextGetGlobalObject(ctx); + if (!globalObject) + return; + + JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); + return; +} + +void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame) +{ + JSGlobalContextRef context = frame->globalContext(); + JSObjectRef windowObject = JSContextGetGlobalObject(context); + + IWebFrame* parentFrame = 0; + frame->parentFrame(&parentFrame); + + JSValueRef exception = 0; + + ::gLayoutTestController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + m_gcController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + m_accessibilityController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender"); + JSValueRef eventSender = makeEventSender(context, !parentFrame); + JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); + JSStringRelease(eventSenderStr); + + WebCoreTestSupport::injectInternalsObject(context); +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didFinishDocumentLoadForFrame\n", + descriptionSuitableForTestResult(frame).c_str()); + if (!done) { + COMPtr<IWebFramePrivate> webFramePrivate; + HRESULT hr = frame->QueryInterface(&webFramePrivate); + if (FAILED(hr)) + return hr; + unsigned pendingFrameUnloadEvents; + hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents); + if (FAILED(hr)) + return hr; + if (pendingFrameUnloadEvents) + printf("%s - has %u onunload handler(s)\n", + descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents); + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("%s - didHandleOnloadEventsForFrame\n", + descriptionSuitableForTestResult(frame).c_str()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didDisplayInsecureContent( + /* [in] */ IWebView *sender) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("didDisplayInsecureContent\n"); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didRunInsecureContent( + /* [in] */ IWebView *sender, + /* [in] */ IWebSecurityOrigin *origin) +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf("didRunInsecureContent\n"); + + return S_OK; +} + diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.h b/Tools/DumpRenderTree/win/FrameLoadDelegate.h new file mode 100644 index 000000000..4cd5e1148 --- /dev/null +++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 FrameLoadDelegate_h +#define FrameLoadDelegate_h + +#include <WebKit/WebKit.h> +#include <wtf/OwnPtr.h> + +class AccessibilityController; +class GCController; + +class FrameLoadDelegate : public IWebFrameLoadDelegate, public IWebFrameLoadDelegatePrivate2 { +public: + FrameLoadDelegate(); + virtual ~FrameLoadDelegate(); + + void processWork(); + + void resetToConsistentState(); + + AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); } + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebFrameLoadDelegate + virtual HRESULT STDMETHODCALLTYPE didStartProvisionalLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didReceiveServerRedirectForProvisionalLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didFailProvisionalLoadWithError( + /* [in] */ IWebView *webView, + /* [in] */ IWebError *error, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didCommitLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didReceiveTitle( + /* [in] */ IWebView *webView, + /* [in] */ BSTR title, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didChangeIcons( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didReceiveIcon( + /* [in] */ IWebView *webView, + /* [in] */ OLE_HANDLE image, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didFinishLoadForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didFailLoadWithError( + /* [in] */ IWebView *webView, + /* [in] */ IWebError *error, + /* [in] */ IWebFrame *forFrame); + + virtual HRESULT STDMETHODCALLTYPE didChangeLocationWithinPageForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE willPerformClientRedirectToURL( + /* [in] */ IWebView *webView, + /* [in] */ BSTR url, + /* [in] */ double delaySeconds, + /* [in] */ DATE fireDate, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didCancelClientRedirectForFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE willCloseFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE windowScriptObjectAvailable( + /* [in] */ IWebView *sender, + /* [in] */ JSContextRef context, + /* [in] */ JSObjectRef windowObject) { return E_NOTIMPL; } + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE didClearWindowObject( + /* [in] */ IWebView* webView, + /* [in] */ JSContextRef context, + /* [in] */ JSObjectRef windowObject, + /* [in] */ IWebFrame* frame); + + // IWebFrameLoadDelegatePrivate + virtual HRESULT STDMETHODCALLTYPE didFinishDocumentLoadForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didFirstLayoutInFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didHandleOnloadEventsForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE didFirstVisuallyNonEmptyLayoutInFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame); + + // IWebFrameLoadDelegatePrivate2 + virtual HRESULT STDMETHODCALLTYPE didDisplayInsecureContent( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE didRunInsecureContent( + /* [in] */ IWebView *sender, + /* [in] */ IWebSecurityOrigin *origin); + + virtual HRESULT STDMETHODCALLTYPE didClearWindowObjectForFrameInScriptWorld(IWebView*, IWebFrame*, IWebScriptWorld*); + + virtual HRESULT STDMETHODCALLTYPE didPushStateWithinPageForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didReplaceStateWithinPageForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didPopStateWithinPageForFrame( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } + +private: + void didClearWindowObjectForFrameInIsolatedWorld(IWebFrame*, IWebScriptWorld*); + void didClearWindowObjectForFrameInStandardWorld(IWebFrame*); + + void locationChangeDone(IWebError*, IWebFrame*); + + ULONG m_refCount; + OwnPtr<GCController> m_gcController; + OwnPtr<AccessibilityController> m_accessibilityController; +}; + +#endif // FrameLoadDelegate_h diff --git a/Tools/DumpRenderTree/win/GCControllerWin.cpp b/Tools/DumpRenderTree/win/GCControllerWin.cpp new file mode 100644 index 000000000..b86725086 --- /dev/null +++ b/Tools/DumpRenderTree/win/GCControllerWin.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h" + +#include "DumpRenderTree.h" +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <WebKit/WebKitCOMAPI.h> + +void GCController::collect() const +{ + COMPtr<IWebJavaScriptCollector> collector; + if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector))) + return; + collector->collect(); +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + COMPtr<IWebJavaScriptCollector> collector; + if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector))) + return; + collector->collectOnAlternateThread(waitUntilDone ? TRUE : FALSE); +} + +size_t GCController::getJSObjectCount() const +{ + COMPtr<IWebJavaScriptCollector> collector; + if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector))) + return 0; + UINT objects = 0; + collector->objectCount(&objects); + return objects; +} diff --git a/Tools/DumpRenderTree/win/HistoryDelegate.cpp b/Tools/DumpRenderTree/win/HistoryDelegate.cpp new file mode 100644 index 000000000..8a41facfc --- /dev/null +++ b/Tools/DumpRenderTree/win/HistoryDelegate.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "HistoryDelegate.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeWin.h" +#include "LayoutTestController.h" +#include <string> +#include <WebKit/WebKit.h> + +using std::wstring; + +static inline wstring wstringFromBSTR(BSTR str) +{ + return wstring(str, ::SysStringLen(str)); +} + +HistoryDelegate::HistoryDelegate() + : m_refCount(1) +{ +} + +HistoryDelegate::~HistoryDelegate() +{ +} + + // IUnknown +HRESULT HistoryDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebHistoryDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebHistoryDelegate)) + *ppvObject = static_cast<IWebHistoryDelegate*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG HistoryDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG HistoryDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + +// IWebHistoryDelegate +HRESULT HistoryDelegate::didNavigateWithNavigationData(IWebView* webView, IWebNavigationData* navigationData, IWebFrame* webFrame) +{ + if (!gLayoutTestController->dumpHistoryDelegateCallbacks()) + return S_OK; + + BSTR urlBSTR; + if (FAILED(navigationData->url(&urlBSTR))) + return E_FAIL; + wstring url; + if (urlBSTR) + url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + SysFreeString(urlBSTR); + + BSTR titleBSTR; + if (FAILED(navigationData->title(&titleBSTR))) + return E_FAIL; + wstring title; + if (titleBSTR) + title = wstringFromBSTR(titleBSTR); + SysFreeString(titleBSTR); + + COMPtr<IWebURLRequest> request; + if (FAILED(navigationData->originalRequest(&request))) + return E_FAIL; + + BSTR httpMethodBSTR; + if (FAILED(request->HTTPMethod(&httpMethodBSTR))) + return E_FAIL; + wstring httpMethod; + if (httpMethodBSTR) + httpMethod = wstringFromBSTR(httpMethodBSTR); + SysFreeString(httpMethodBSTR); + + COMPtr<IWebURLResponse> response; + if (FAILED(navigationData->response(&response))) + return E_FAIL; + + COMPtr<IWebHTTPURLResponse> httpResponse; + if (FAILED(response->QueryInterface(&httpResponse))) + return E_FAIL; + + int statusCode = 0; + if (FAILED(httpResponse->statusCode(&statusCode))) + return E_FAIL; + + BOOL hasSubstituteData; + if (FAILED(navigationData->hasSubstituteData(&hasSubstituteData))) + return E_FAIL; + + BSTR clientRedirectSourceBSTR; + if (FAILED(navigationData->clientRedirectSource(&clientRedirectSourceBSTR))) + return E_FAIL; + bool hasClientRedirect = clientRedirectSourceBSTR && SysStringLen(clientRedirectSourceBSTR); + wstring redirectSource; + if (clientRedirectSourceBSTR) + redirectSource = urlSuitableForTestResult(wstringFromBSTR(clientRedirectSourceBSTR)); + SysFreeString(clientRedirectSourceBSTR); + + bool wasFailure = hasSubstituteData || (httpResponse && statusCode >= 400); + + printf("WebView navigated to url \"%S\" with title \"%S\" with HTTP equivalent method \"%S\". The navigation was %s and was %s%S.\n", + url.c_str(), + title.c_str(), + httpMethod.c_str(), + wasFailure ? "a failure" : "successful", + hasClientRedirect ? "a client redirect from " : "not a client redirect", + redirectSource.c_str()); + + return S_OK; +} + +HRESULT HistoryDelegate::didPerformClientRedirectFromURL(IWebView*, BSTR sourceURL, BSTR destinationURL, IWebFrame*) +{ + if (!gLayoutTestController->dumpHistoryDelegateCallbacks()) + return S_OK; + + wstring source; + if (sourceURL) + source = urlSuitableForTestResult(wstringFromBSTR(sourceURL)); + + wstring destination; + if (destinationURL) + destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL)); + + printf("WebView performed a client redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str()); + return S_OK; +} + +HRESULT HistoryDelegate::didPerformServerRedirectFromURL(IWebView* webView, BSTR sourceURL, BSTR destinationURL, IWebFrame* webFrame) +{ + if (!gLayoutTestController->dumpHistoryDelegateCallbacks()) + return S_OK; + + wstring source; + if (sourceURL) + source = urlSuitableForTestResult(wstringFromBSTR(sourceURL)); + + wstring destination; + if (destinationURL) + destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL)); + + printf("WebView performed a server redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str()); + return S_OK; +} + +HRESULT HistoryDelegate::updateHistoryTitle(IWebView* webView, BSTR titleBSTR, BSTR urlBSTR) +{ + if (!gLayoutTestController->dumpHistoryDelegateCallbacks()) + return S_OK; + + wstring url; + if (urlBSTR) + url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + + wstring title; + if (titleBSTR) + title = wstringFromBSTR(titleBSTR); + + printf("WebView updated the title for history URL \"%S\" to \"%S\".\n", url.c_str(), title.c_str()); + return S_OK; +} + +HRESULT HistoryDelegate::populateVisitedLinksForWebView(IWebView* webView) +{ + if (!gLayoutTestController->dumpHistoryDelegateCallbacks()) + return S_OK; + + BSTR urlBSTR; + if (FAILED(webView->mainFrameURL(&urlBSTR))) + return E_FAIL; + + wstring url; + if (urlBSTR) + url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + SysFreeString(urlBSTR); + + if (gLayoutTestController->dumpVisitedLinksCallback()) + printf("Asked to populate visited links for WebView \"%S\"\n", url.c_str()); + + return S_OK; +} diff --git a/Tools/DumpRenderTree/win/HistoryDelegate.h b/Tools/DumpRenderTree/win/HistoryDelegate.h new file mode 100644 index 000000000..41be670db --- /dev/null +++ b/Tools/DumpRenderTree/win/HistoryDelegate.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 HistoryDelegate_h +#define HistoryDelegate_h + +#include <WebKit/WebKit.h> +#include <wtf/OwnPtr.h> + +class HistoryDelegate : public IWebHistoryDelegate { +public: + HistoryDelegate(); + virtual ~HistoryDelegate(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebHistoryDelegate + virtual HRESULT STDMETHODCALLTYPE didNavigateWithNavigationData( + /* [in] */ IWebView* webView, + /* [in] */ IWebNavigationData* navigationData, + /* [in] */ IWebFrame* webFrame); + + virtual HRESULT STDMETHODCALLTYPE didPerformClientRedirectFromURL( + /* [in] */ IWebView* webView, + /* [in] */ BSTR sourceURL, + /* [in] */ BSTR destinationURL, + /* [in] */ IWebFrame* webFrame); + + virtual HRESULT STDMETHODCALLTYPE didPerformServerRedirectFromURL( + /* [in] */ IWebView* webView, + /* [in] */ BSTR sourceURL, + /* [in] */ BSTR destinationURL, + /* [in] */ IWebFrame* webFrame); + + virtual HRESULT STDMETHODCALLTYPE updateHistoryTitle( + /* [in] */ IWebView* webView, + /* [in] */ BSTR title, + /* [in] */ BSTR url); + + virtual HRESULT STDMETHODCALLTYPE populateVisitedLinksForWebView( + /* [in] */ IWebView* webView); + +private: + ULONG m_refCount; +}; + +#endif // HistoryDelegate_h diff --git a/Tools/DumpRenderTree/win/ImageDiff.vcproj b/Tools/DumpRenderTree/win/ImageDiff.vcproj new file mode 100644 index 000000000..c3201bf21 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiff.vcproj @@ -0,0 +1,452 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiff" + ProjectGUID="{59CC0547-70AC-499C-9B19-EC01C6F61137}" + RootNamespace="ImageDiff" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffDebug.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffRelease.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_All|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffDebugAll.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Cairo_CFLite|Win32" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffDebugCairoCFLite.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Production|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffProduction.vsprops" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Cairo_CFLite|Win32" + ConfigurationType="2" + InheritedPropertySheets=".\ImageDiffReleaseCairoCFLite.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\win\ImageDiffCairo.cpp" + > + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_All|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Production|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\cg\ImageDiffCG.cpp" + > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\ImageDiffWin.cpp" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Tools/DumpRenderTree/win/ImageDiffCairo.cpp b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp new file mode 100644 index 000000000..d10cc14c6 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved. + * Copyright (C) 2011 Brent Fulgham. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +// FIXME: We need to be able to include these defines from a config.h somewhere. +#define JS_EXPORT_PRIVATE +#define WTF_EXPORT_PRIVATE + +#include <cairo.h> +#include <stdio.h> +#include <wtf/Platform.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +#if PLATFORM(WIN) +#include <fcntl.h> +#include <io.h> +#include <windows.h> +#include <wtf/MathExtras.h> +#endif + +using namespace std; + +static const int s_bufferSize = 2048; +static const int s_bytesPerPixel = 4; +static cairo_user_data_key_t s_imageDataKey; + + +#if PLATFORM(WIN) +#undef min +#undef max + +static inline float strtof(const char* inputString, char** endptr) +{ + return strtod(inputString, endptr); +} +#endif + +static cairo_status_t readFromData(void* closure, unsigned char* data, unsigned int length) +{ + CFMutableDataRef dataSource = reinterpret_cast<CFMutableDataRef>(closure); + + CFRange range = CFRangeMake(0, length); + CFDataGetBytes(dataSource, range, data); + CFDataDeleteBytes(dataSource, range); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t* createImageFromStdin(int bytesRemaining) +{ + unsigned char buffer[s_bufferSize]; + RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining)); + + while (bytesRemaining > 0) { + size_t bytesToRead = min(bytesRemaining, s_bufferSize); + size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); + CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead)); + bytesRemaining -= static_cast<int>(bytesRead); + } + + return cairo_image_surface_create_from_png_stream (static_cast<cairo_read_func_t>(readFromData), data.get()); +} + +static void releaseMallocBuffer(void* data) +{ + free(data); +} + +static inline float pixelDifference(float expected, float actual) +{ + return (actual - expected) / max<float>(255 - expected, expected); +} + +static inline void normalizeBuffer(float maxDistance, unsigned char* buffer, size_t length) +{ + if (maxDistance >= 1) + return; + + for (size_t p = 0; p < length; ++p) + buffer[p] /= maxDistance; +} + +static cairo_surface_t* createDifferenceImage(cairo_surface_t* baselineImage, cairo_surface_t* actualImage, float& difference) +{ + size_t width = cairo_image_surface_get_width(baselineImage); + size_t height = cairo_image_surface_get_height(baselineImage); + + unsigned char* baselinePixel = cairo_image_surface_get_data(baselineImage); + unsigned char* actualPixel = cairo_image_surface_get_data(actualImage); + + // Compare the content of the 2 bitmaps + void* diffBuffer = malloc(width * height); + unsigned char* diffPixel = reinterpret_cast<unsigned char*>(diffBuffer); + + float count = 0; + float sum = 0; + float maxDistance = 0; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + float red = pixelDifference(baselinePixel[0], actualPixel[0]); + float green = pixelDifference(baselinePixel[1], actualPixel[1]); + float blue = pixelDifference(baselinePixel[2], actualPixel[2]); + float alpha = pixelDifference(baselinePixel[3], actualPixel[3]); + + float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0; + + *diffPixel++ = static_cast<unsigned char>(distance * 255); + + if (distance >= 1.0 / 255.0) { + ++count; + sum += distance; + if (distance > maxDistance) + maxDistance = distance; + } + + baselinePixel += s_bytesPerPixel; + actualPixel += s_bytesPerPixel; + } + } + + // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image + if (count > 0) + difference = 100.0f * sum / (height * width); + else + difference = 0; + + if (!difference) { + free(diffBuffer); + return 0; + } + + // Generate a normalized diff image + normalizeBuffer(maxDistance, reinterpret_cast<unsigned char*>(diffBuffer), height * width); + + cairo_surface_t* diffImage = cairo_image_surface_create_for_data(diffPixel, CAIRO_FORMAT_ARGB32, width, height, width * s_bytesPerPixel); + cairo_surface_set_user_data(diffImage, &s_imageDataKey, diffBuffer, releaseMallocBuffer); + + return diffImage; +} + +static inline bool imageHasAlpha(cairo_surface_t* image) +{ + return (cairo_image_surface_get_format(image) == CAIRO_FORMAT_ARGB32); +} + +static cairo_status_t writeToData(void* closure, unsigned char* data, unsigned int length) +{ + CFMutableDataRef dataTarget = reinterpret_cast<CFMutableDataRef>(closure); + + CFDataAppendBytes(dataTarget, data, length); + + return CAIRO_STATUS_SUCCESS; +} + +int main(int argc, const char* argv[]) +{ +#if PLATFORM(WIN) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + + float tolerance = 0; + + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { + if (i >= argc - 1) + exit(1); + tolerance = strtof(argv[i + 1], 0); + ++i; + continue; + } + } + + char buffer[s_bufferSize]; + cairo_surface_t* actualImage = 0; + cairo_surface_t* baselineImage = 0; + + while (fgets(buffer, sizeof(buffer), stdin)) { + char* newLineCharacter = strchr(buffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strncmp("Content-Length: ", buffer, 16)) { + strtok(buffer, " "); + int imageSize = strtol(strtok(0, " "), 0, 10); + + if (imageSize > 0 && !actualImage) + actualImage = createImageFromStdin(imageSize); + else if (imageSize > 0 && !baselineImage) + baselineImage = createImageFromStdin(imageSize); + else + fputs("error, image size must be specified.\n", stdout); + } + + if (actualImage && baselineImage) { + cairo_surface_t* diffImage = 0; + float difference = 100.0; + + if ((cairo_image_surface_get_width(actualImage) == cairo_image_surface_get_width(baselineImage)) + && (cairo_image_surface_get_height(actualImage) == cairo_image_surface_get_height(baselineImage)) + && (imageHasAlpha(actualImage) == imageHasAlpha(baselineImage))) { + diffImage = createDifferenceImage(actualImage, baselineImage, difference); // difference is passed by reference + if (difference <= tolerance) + difference = 0; + else { + difference = roundf(difference * 100.0) / 100.0; + difference = max<float>(difference, 0.01); // round to 2 decimal places + } + } else + fputs("error, test and reference image have different properties.\n", stderr); + + if (difference > 0.0) { + if (diffImage) { + RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); + cairo_surface_write_to_png_stream(diffImage, (cairo_write_func_t)writeToData, imageData.get()); + printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); + fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); + cairo_surface_destroy(diffImage); + diffImage = 0; + } + + fprintf(stdout, "diff: %01.2f%% failed\n", difference); + } else + fprintf(stdout, "diff: %01.2f%% passed\n", difference); + + cairo_surface_destroy(actualImage); + cairo_surface_destroy(baselineImage); + actualImage = 0; + baselineImage = 0; + } + + fflush(stdout); + } + + return 0; +} diff --git a/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops new file mode 100644 index 000000000..c94645956 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffCommon" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\private";"$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private"" + PreprocessorDefinitions="NOMINMAX" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT" + AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib CoreGraphics$(LibraryConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib" + OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops new file mode 100644 index 000000000..5b31049bc --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffDebug" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\ImageDiffCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops new file mode 100644 index 000000000..5a201cd6f --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffDebugAll" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\ImageDiffCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops new file mode 100644 index 000000000..ae54939a9 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffDebugCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\ImageDiffWinCairoCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj b/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj new file mode 100644 index 000000000..8ea7edf3c --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj @@ -0,0 +1,396 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncher" + ProjectGUID="{DD7949B6-F2B4-47C2-9C42-E21E84CB1017}" + RootNamespace="ImageDiffLauncher" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherDebug.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherRelease.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Cairo_CFLite|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherDebugCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_All|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherDebugAll.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Production|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherProduction.vsprops" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Cairo_CFLite|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ImageDiffLauncherReleaseCairoCFLite.vsprops" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\..\win\DLLLauncher\DLLLauncherMain.cpp" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops new file mode 100644 index 000000000..bf1c4169d --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherCommon" + > + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="USE_CONSOLE_ENTRY_POINT" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="shlwapi.lib" + OutputFile="$(OutDir)\ImageDiff$(WebKitConfigSuffix).exe" + ProgramDatabaseFile="$(TargetDir)$(TargetName)Launcher.pdb" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops new file mode 100644 index 000000000..aa8654551 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherDebug" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\ImageDiffLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops new file mode 100644 index 000000000..685f356fe --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherDebugAll" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\ImageDiffLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops new file mode 100644 index 000000000..3f5dc5442 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffDebugCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops new file mode 100644 index 000000000..457551023 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherProduction" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\ImageDiffLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops new file mode 100644 index 000000000..57fb84732 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherRelease" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops new file mode 100644 index 000000000..d5002e6d7 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffLauncherReleaseCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffLauncherCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd new file mode 100644 index 000000000..26707cac6 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd @@ -0,0 +1 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd new file mode 100644 index 000000000..a77077674 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd @@ -0,0 +1,6 @@ +%SystemDrive%\cygwin\bin\which.exe bash +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops new file mode 100644 index 000000000..8e758b5cb --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffProduction" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\ImageDiffCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops new file mode 100644 index 000000000..acf3e525b --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffRelease" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops new file mode 100644 index 000000000..4125ff119 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffReleaseCairoCFLite" + InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\ImageDiffWinCairoCommon.vsprops" + > +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffWin.cpp b/Tools/DumpRenderTree/win/ImageDiffWin.cpp new file mode 100644 index 000000000..01dfc0b99 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffWin.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 <windows.h> + +int main(int argc, const char* argv[]); + +extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) +{ + return main(argc, argv); +} diff --git a/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops new file mode 100644 index 000000000..5fa982a27 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffCommon" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\private";"$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private"" + PreprocessorDefinitions="NOMINMAX" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT" + AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib cairo$(LibraryConfigSuffix).lib libjpeg.lib libpng$(LibraryConfigSuffix).lib zdll.lib Msimg32.lib CFLite$(LibraryConfigSuffix).lib" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp new file mode 100644 index 000000000..38c987760 --- /dev/null +++ b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp @@ -0,0 +1,1563 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "EditingDelegate.h" +#include "PolicyDelegate.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include <CoreFoundation/CoreFoundation.h> +#include <JavaScriptCore/Assertions.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRefBSTR.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <WebKit/WebKitCOMAPI.h> +#include <comutil.h> +#include <shlwapi.h> +#include <shlguid.h> +#include <shobjidl.h> +#include <string> +#include <wtf/Platform.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +using std::string; +using std::wstring; + +static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath); + +LayoutTestController::~LayoutTestController() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + // reset webview-related states back to default values in preparation for next test + + COMPtr<IWebViewPrivate> viewPrivate; + if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) + viewPrivate->setTabKeyCyclesThroughElements(TRUE); + + COMPtr<IWebViewEditing> viewEditing; + if (FAILED(webView->QueryInterface(&viewEditing))) + return; + COMPtr<IWebEditingDelegate> delegate; + if (FAILED(viewEditing->editingDelegate(&delegate))) + return; + COMPtr<EditingDelegate> editingDelegate(Query, viewEditing.get()); + if (editingDelegate) + editingDelegate->setAcceptsEditing(TRUE); +} + +void LayoutTestController::addDisallowedURL(JSStringRef url) +{ + // FIXME: Implement! +} + +void LayoutTestController::clearBackForwardList() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebBackForwardList> backForwardList; + if (FAILED(webView->backForwardList(&backForwardList))) + return; + + COMPtr<IWebHistoryItem> item; + if (FAILED(backForwardList->currentItem(&item))) + return; + + // We clear the history by setting the back/forward list's capacity to 0 + // then restoring it back and adding back the current item. + int capacity; + if (FAILED(backForwardList->capacity(&capacity))) + return; + + backForwardList->setCapacity(0); + backForwardList->setCapacity(capacity); + backForwardList->addItem(item.get()); + backForwardList->goToItem(item.get()); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return false; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return false; + + BOOL result; + viewPrivate->shouldClose(&result); + return result; +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name) +{ + // FIXME: Implement! + return 0; +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name) +{ + // FIXME: Implement! + return 0; +} + +void LayoutTestController::disableImageLoading() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + preferences->setLoadsImagesAutomatically(FALSE); +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +void LayoutTestController::keepWebHistory() +{ + COMPtr<IWebHistory> history; + if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history)))) + return; + + COMPtr<IWebHistory> sharedHistory; + if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory)))) + return; + + history->setOptionalSharedHistory(sharedHistory.get()); +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value) +{ + // FIXME: Implement this. + return JSValueMakeUndefined(context); +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + // FIXME: Implement this. + return JSValueMakeUndefined(context); +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + + BSTR textBSTR = 0; + HRESULT hr = framePrivate->layerTreeAsText(&textBSTR); + + wstring text(textBSTR, SysStringLen(textBSTR)); + SysFreeString(textBSTR); + JSRetainPtr<JSStringRef> textValueJS(Adopt, JSStringCreateWithCharacters(text.data(), text.length())); + return textValueJS; +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return 0; + + COMPtr<IWebViewPrivate> webViewPrivate(Query, webView); + if (!webViewPrivate) + return 0; + + COMPtr<IDOMElement> element; + if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element))) + return 0; + + COMPtr<IDOMElementPrivate> elementPrivate(Query, element); + if (!elementPrivate) + return 0; + + BSTR textBSTR = 0; + if (FAILED(elementPrivate->markerTextForListItem(&textBSTR))) + return 0; + + JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithBSTR(textBSTR)); + SysFreeString(textBSTR); + return markerText; +} + +void LayoutTestController::waitForPolicyDelegate() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + setWaitToDump(true); + policyDelegate->setControllerToNotifyDone(this); + webView->setPolicyDelegate(policyDelegate); +} + +size_t LayoutTestController::webHistoryItemCount() +{ + COMPtr<IWebHistory> history; + if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history)))) + return 0; + + COMPtr<IWebHistory> sharedHistory; + if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory) + return 0; + + COMPtr<IWebHistoryPrivate> sharedHistoryPrivate; + if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate))) + return 0; + + int count; + if (FAILED(sharedHistoryPrivate->allItems(&count, 0))) + return 0; + + return count; +} + +unsigned LayoutTestController::workerThreadCount() const +{ + COMPtr<IWebWorkersPrivate> workers; + if (FAILED(WebKitCreateInstance(CLSID_WebWorkersPrivate, 0, __uuidof(workers), reinterpret_cast<void**>(&workers)))) + return 0; + unsigned count; + if (FAILED(workers->workerThreadCount(&count))) + return 0; + return count; +} + +JSRetainPtr<JSStringRef> LayoutTestController::platformName() const +{ + JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("win")); + return platformName; +} + +void LayoutTestController::notifyDone() +{ + // Same as on mac. This can be shared. + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url)); + + wstring localPath; + if (!resolveCygwinPath(input, localPath)) { + printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str()); + return 0; + } + + return JSStringCreateWithCharacters(localPath.c_str(), localPath.length()); +} + +static wstring jsStringRefToWString(JSStringRef jsStr) +{ + size_t length = JSStringGetLength(jsStr); + Vector<WCHAR> buffer(length + 1); + memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR)); + buffer[length] = '\0'; + + return buffer.data(); +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + COMPtr<IWebDataSource> dataSource; + if (FAILED(frame->dataSource(&dataSource))) + return; + + COMPtr<IWebURLResponse> response; + if (FAILED(dataSource->response(&response)) || !response) + return; + + BSTR responseURLBSTR; + if (FAILED(response->URL(&responseURLBSTR))) + return; + wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR)); + SysFreeString(responseURLBSTR); + + // FIXME: We should do real relative URL resolution here. + int lastSlash = responseURL.rfind('/'); + if (lastSlash != -1) + responseURL = responseURL.substr(0, lastSlash); + + wstring wURL = jsStringRefToWString(url); + wstring wAbsoluteURL = responseURL + TEXT("/") + wURL; + JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length())); + + WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool acceptsEditing) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewEditing> viewEditing; + if (FAILED(webView->QueryInterface(&viewEditing))) + return; + + COMPtr<IWebEditingDelegate> delegate; + if (FAILED(viewEditing->editingDelegate(&delegate))) + return; + + EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get(); + editingDelegate->setAcceptsEditing(acceptsEditing); +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + if (alwaysAcceptCookies == m_alwaysAcceptCookies) + return; + + if (!::setAlwaysAcceptCookies(alwaysAcceptCookies)) + return; + m_alwaysAcceptCookies = alwaysAcceptCookies; +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setAuthorAndUserStylesEnabled(flag); +} + +void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> webViewPrivate(Query, webView); + if (!webViewPrivate) + return; + + COMPtr<IDOMElement> element; + if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element))) + return; + + COMPtr<IFormsAutoFillTransition> autofillElement(Query, element); + if (!autofillElement) + return; + + autofillElement->setAutofilled(autofilled); +} + +void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + if (setDelegate) { + policyDelegate->setPermissive(permissive); + webView->setPolicyDelegate(policyDelegate); + } else + webView->setPolicyDelegate(0); +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + // FIXME: Implement for DeviceOrientation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=30335. +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. +} + +void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + // FIXME: Implement for Geolocation layout tests. + setGeolocationPermissionCommon(allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + // FIXME: Implement for Geolocation layout tests. + return -1; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled) +{ + // See also <rdar://problem/6480108> + COMPtr<IWebIconDatabase> iconDatabase; + COMPtr<IWebIconDatabase> tmpIconDatabase; + if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase))) + return; + if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase))) + return; + + iconDatabase->setEnabled(iconDatabaseEnabled); +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + // FIXME: Implement! +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled); +} + +void LayoutTestController::setXSSAuditorEnabled(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setXSSAuditorEnabled(enabled); +} + +void LayoutTestController::setFrameFlatteningEnabled(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setFrameFlatteningEnabled(enabled); +} + +void LayoutTestController::setSpatialNavigationEnabled(bool enabled) +{ + // FIXME: Implement for SpatialNavigation layout tests. +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setAllowFileAccessFromFileURLs(enabled); +} + +void LayoutTestController::setPopupBlockingEnabled(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled); +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + // FIXME: Implement +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setJavaScriptCanAccessClipboard(enabled); +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE); +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + // FIXME: Implement! +} + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + preferences->setUserStyleSheetEnabled(flag); +} + +bool appendComponentToPath(wstring& path, const wstring& component) +{ + WCHAR buffer[MAX_PATH]; + + if (path.size() + 1 > MAX_PATH) + return false; + + memcpy(buffer, path.data(), path.size() * sizeof(WCHAR)); + buffer[path.size()] = '\0'; + + if (!PathAppendW(buffer, component.c_str())) + return false; + + path = wstring(buffer); + return true; +} + +static bool followShortcuts(wstring& path) +{ + if (PathFileExists(path.c_str())) + return true; + + // Do we have a shortcut? + wstring linkPath = path; + linkPath.append(TEXT(".lnk")); + if (!PathFileExists(linkPath.c_str())) + return true; + + // We have a shortcut, find its target. + COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink); + if (!shortcut) + return false; + COMPtr<IPersistFile> persistFile(Query, shortcut); + if (!shortcut) + return false; + if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ))) + return false; + if (FAILED(shortcut->Resolve(0, 0))) + return false; + WCHAR targetPath[MAX_PATH]; + DWORD targetPathLen = _countof(targetPath); + if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0))) + return false; + if (!PathFileExists(targetPath)) + return false; + // Use the target path as the result path instead. + path = wstring(targetPath); + + return true; +} + +static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath) +{ + wstring fileProtocol = L"file://"; + bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos; + if (cygwinPath[isFileProtocol ? 7 : 0] != '/') // ensure path is absolute + return false; + + // Get the Root path. + WCHAR rootPath[MAX_PATH]; + DWORD rootPathSize = _countof(rootPath); + DWORD keyType; + DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize); + + if (result != ERROR_SUCCESS || keyType != REG_SZ) { + // Cygwin 1.7 doesn't store Cygwin's root as a mount point anymore, because mount points are now stored in /etc/fstab. + // However, /etc/fstab doesn't contain any information about where / is located as a Windows path, so we need to use Cygwin's + // new registry key that has the root. + result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygwin\\setup"), TEXT("rootdir"), &keyType, &rootPath, &rootPathSize); + if (result != ERROR_SUCCESS || keyType != REG_SZ) + return false; + } + + windowsPath = wstring(rootPath, rootPathSize); + + int oldPos = isFileProtocol ? 8 : 1; + while (1) { + int newPos = cygwinPath.find('/', oldPos); + + if (newPos == -1) { + wstring pathComponent = cygwinPath.substr(oldPos); + + if (!appendComponentToPath(windowsPath, pathComponent)) + return false; + + if (!followShortcuts(windowsPath)) + return false; + + break; + } + + wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos); + if (!appendComponentToPath(windowsPath, pathComponent)) + return false; + + if (!followShortcuts(windowsPath)) + return false; + + oldPos = newPos + 1; + } + + if (isFileProtocol) + windowsPath = fileProtocol + windowsPath; + + return true; +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef jsURL) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL)); + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(0, urlString.get(), 0)); + if (!url) + return; + + // Now copy the file system path, POSIX style. + RetainPtr<CFStringRef> pathCF(AdoptCF, CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle)); + if (!pathCF) + return; + + wstring path = cfStringRefToWString(pathCF.get()); + + wstring resultPath; + if (!resolveCygwinPath(path, resultPath)) + return; + + // The path has been resolved, now convert it back to a CFURL. + int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0); + Vector<char> utf8Vector(result); + result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0); + if (!result) + return; + + url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false); + if (!url) + return; + + resultPath = cfStringRefToWString(CFURLGetString(url.get())); + + BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size()); + preferences->setUserStyleSheetLocation(resultPathBSTR); + SysFreeString(resultPathBSTR); +} + +void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value) +{ + // FIXME: implement +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef mode) +{ + // FIXME: implement +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL)); + ::setPersistentUserStyleSheetLocation(urlString.get()); +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + ::setPersistentUserStyleSheetLocation(0); +} + +void LayoutTestController::setWindowIsKey(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + HWND webViewWindow; + if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow))) + return; + + ::SendMessage(webViewWindow, flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0); +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewEditing> viewEditing; + if (FAILED(webView->QueryInterface(&viewEditing))) + return; + + viewEditing->setSmartInsertDeleteEnabled(flag ? TRUE : FALSE); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + COMPtr<IWebInspector> inspector; + if (FAILED(viewPrivate->inspector(&inspector))) + return; + + setDeveloperExtrasEnabled(flag); + inspector->setJavaScriptProfilingEnabled(flag); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewEditing> viewEditing; + if (FAILED(webView->QueryInterface(&viewEditing))) + return; + + viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE); +} + +static const CFTimeInterval waitToDumpWatchdogInterval = 30.0; + +static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD) +{ + gLayoutTestController->waitToDumpWatchdogTimerFired(); +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) + waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired); +} + +int LayoutTestController::windowCount() +{ + return openWindows().size(); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id) +{ + COMPtr<IDOMDocument> document; + if (FAILED(frame->DOMDocument(&document))) + return false; + + wstring idWstring = jsStringRefToWString(id); + BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length()); + COMPtr<IDOMElement> element; + HRESULT result = document->getElementById(idBSTR, &element); + SysFreeString(idBSTR); + + if (FAILED(result)) + return false; + + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + + BOOL autoCompletes; + if (FAILED(framePrivate->elementDoesAutoComplete(element.get(), &autoCompletes))) + return false; + + return autoCompletes; +} + +void LayoutTestController::execCommand(JSStringRef name, JSStringRef value) +{ + wstring wName = jsStringRefToWString(name); + wstring wValue = jsStringRefToWString(value); + + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length()); + BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length()); + viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR); + + SysFreeString(nameBSTR); + SysFreeString(valueBSTR); +} + +bool LayoutTestController::findString(JSContextRef /* context */, JSStringRef /* target */, JSObjectRef /* optionsArray */) +{ + // FIXME: Implement + return false; +} + +void LayoutTestController::setCacheModel(int) +{ + // FIXME: Implement +} + +bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/) +{ + printf("ERROR: LayoutTestController::isCommandEnabled() not implemented\n"); + return false; +} + +void LayoutTestController::clearAllApplicationCaches() +{ + // FIXME: Implement to support application cache quotas. +} + +void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef origin) +{ + // FIXME: Implement to support deleting all application cache for an origin. +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + // FIXME: Implement to support application cache quotas. +} + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that have application caches. + return JSValueMakeUndefined(context); +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef name) +{ + // FIXME: Implement to get disk usage by all application caches for an origin. + return 0; +} + +void LayoutTestController::clearAllDatabases() +{ + COMPtr<IWebDatabaseManager> databaseManager; + COMPtr<IWebDatabaseManager> tmpDatabaseManager; + if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager))) + return; + if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager))) + return; + + databaseManager->deleteAllDatabases(); +} + +void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + BSTR keyBSTR = JSStringCopyBSTR(key); + BSTR valueBSTR = JSStringCopyBSTR(value); + prefsPrivate->setPreferenceForTest(keyBSTR, valueBSTR); + SysFreeString(keyBSTR); + SysFreeString(valueBSTR); +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + COMPtr<IWebDatabaseManager> databaseManager; + COMPtr<IWebDatabaseManager> tmpDatabaseManager; + + if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager))) + return; + if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager))) + return; + + databaseManager->setQuota(TEXT("file:///"), quota); +} + +void LayoutTestController::goBack() +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setDefersLoading(bool) +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme) +{ + COMPtr<IWebViewPrivate> webView; + if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView)))) + return; + + BSTR schemeBSTR = JSStringCopyBSTR(scheme); + webView->setDomainRelaxationForbiddenForURLScheme(forbidden, schemeBSTR); + SysFreeString(schemeBSTR); +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + printf("ERROR: LayoutTestController::setAppCacheMaximumSize() not implemented\n"); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + COMPtr<IDOMDocument> document; + if (FAILED(frame->DOMDocument(&document))) + return false; + + BSTR idBSTR = JSStringCopyBSTR(elementId); + COMPtr<IDOMElement> element; + HRESULT hr = document->getElementById(idBSTR, &element); + SysFreeString(idBSTR); + if (FAILED(hr)) + return false; + + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + + BSTR nameBSTR = JSStringCopyBSTR(animationName); + BOOL wasRunning = FALSE; + hr = framePrivate->pauseAnimation(nameBSTR, element.get(), time, &wasRunning); + SysFreeString(nameBSTR); + + return SUCCEEDED(hr) && wasRunning; +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + COMPtr<IDOMDocument> document; + if (FAILED(frame->DOMDocument(&document))) + return false; + + BSTR idBSTR = JSStringCopyBSTR(elementId); + COMPtr<IDOMElement> element; + HRESULT hr = document->getElementById(idBSTR, &element); + SysFreeString(idBSTR); + if (FAILED(hr)) + return false; + + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + + BSTR nameBSTR = JSStringCopyBSTR(propertyName); + BOOL wasRunning = FALSE; + hr = framePrivate->pauseTransition(nameBSTR, element.get(), time, &wasRunning); + SysFreeString(nameBSTR); + + return SUCCEEDED(hr) && wasRunning; +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + COMPtr<IDOMDocument> document; + if (FAILED(frame->DOMDocument(&document))) + return false; + + BSTR idBSTR = JSStringCopyBSTR(animationId); + COMPtr<IDOMElement> element; + HRESULT hr = document->getElementById(idBSTR, &element); + SysFreeString(idBSTR); + if (FAILED(hr)) + return false; + + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + + BSTR elementIdBSTR = JSStringCopyBSTR(elementId); + BOOL wasRunning = FALSE; + hr = framePrivate->pauseSVGAnimation(elementIdBSTR, element.get(), time, &wasRunning); + SysFreeString(elementIdBSTR); + + return SUCCEEDED(hr) && wasRunning; +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + UINT number = 0; + if (FAILED(framePrivate->numberOfActiveAnimations(&number))) + return 0; + + return number; +} + +void LayoutTestController::suspendAnimations() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + framePrivate->suspendAnimations(); +} + +void LayoutTestController::resumeAnimations() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + framePrivate->resumeAnimations(); +} + +static _bstr_t bstrT(JSStringRef jsString) +{ + // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it. + return _bstr_t(JSStringCopyBSTR(jsString), false); +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + COMPtr<IWebViewPrivate> webView; + if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView)))) + return; + + webView->addOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + COMPtr<IWebViewPrivate> webView; + if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView)))) + return; + + webView->removeOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains); +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + COMPtr<IWebViewPrivate> webView; + if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView)))) + return; + + COMPtr<IWebScriptWorld> world; + if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world)))) + return; + + webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd); +} + + +void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + COMPtr<IWebViewPrivate> webView; + if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView)))) + return; + + COMPtr<IWebScriptWorld> world; + if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world)))) + return; + + webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0); +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setDeveloperExtrasEnabled(enabled); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + // FIXME: Implement this. +} + +void LayoutTestController::showWebInspector() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate(Query, webView); + if (!viewPrivate) + return; + + COMPtr<IWebInspector> inspector; + if (SUCCEEDED(viewPrivate->inspector(&inspector))) + inspector->show(); +} + +void LayoutTestController::closeWebInspector() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate(Query, webView); + if (!viewPrivate) + return; + + COMPtr<IWebInspector> inspector; + if (FAILED(viewPrivate->inspector(&inspector))) + return; + + inspector->close(); +} + +void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate(Query, webView); + if (!viewPrivate) + return; + + COMPtr<IWebInspector> inspector; + if (FAILED(viewPrivate->inspector(&inspector))) + return; + + COMPtr<IWebInspectorPrivate> inspectorPrivate(Query, inspector); + if (!inspectorPrivate) + return; + + inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR()); +} + +typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap; +static WorldMap& worldMap() +{ + static WorldMap& map = *new WorldMap; + return map; +} + +unsigned worldIDForWorld(IWebScriptWorld* world) +{ + WorldMap::const_iterator end = worldMap().end(); + for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) { + if (it->second == world) + return it->first; + } + + return 0; +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world + // that is created once and cached forever. + COMPtr<IWebScriptWorld> world; + if (!worldID) { + if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world)))) + return; + } else { + COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second; + if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot)))) + return; + world = worldSlot; + } + + BSTR result; + if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result))) + return; + SysFreeString(result); +} + +void LayoutTestController::removeAllVisitedLinks() +{ + COMPtr<IWebHistory> history; + if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history)))) + return; + + COMPtr<IWebHistory> sharedHistory; + if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory) + return; + + COMPtr<IWebHistoryPrivate> sharedHistoryPrivate; + if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate))) + return; + + sharedHistoryPrivate->removeAllVisitedLinks(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + wstring idWstring = jsStringRefToWString(id); + BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length()); + BSTR counterValueBSTR; + if (FAILED(framePrivate->counterValueForElementById(idBSTR, &counterValueBSTR))) + return 0; + + wstring counterValue(counterValueBSTR, SysStringLen(counterValueBSTR)); + SysFreeString(idBSTR); + SysFreeString(counterValueBSTR); + JSRetainPtr<JSStringRef> counterValueJS(Adopt, JSStringCreateWithCharacters(counterValue.data(), counterValue.length())); + return counterValueJS; +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + wstring idWstring = jsStringRefToWString(id); + BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length()); + int pageNumber = -1; + if (FAILED(framePrivate->pageNumberForElementById(idBSTR, pageWidthInPixels, pageHeightInPixels, &pageNumber))) + pageNumber = -1; + SysFreeString(idBSTR); + return pageNumber; +} + +int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + int pageNumber = -1; + if (FAILED(framePrivate->numberOfPages(pageWidthInPixels, pageHeightInPixels, &pageNumber))) + pageNumber = -1; + return pageNumber; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const +{ + // FIXME: Implement this. + return JSRetainPtr<JSStringRef>(); +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} + +bool LayoutTestController::isPageBoxVisible(int pageNumber) const +{ + // FIXME: implement + return false; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const +{ + // FIXME: implement + return JSRetainPtr<JSStringRef>(); +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebBackForwardList> backForwardList; + if (FAILED(webView->backForwardList(&backForwardList))) + return; + + COMPtr<IWebHistoryItem> item; + if (FAILED(backForwardList->currentItem(&item))) + return; + + BOOL success; + webView->goToBackForwardItem(item.get(), &success); +} + +void LayoutTestController::setWebViewEditable(bool) +{ +} + +void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ +} + +void LayoutTestController::setEditingBehavior(const char* editingBehavior) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + string behaviorString(editingBehavior); + if (behaviorString == "mac") + preferences->setEditingBehavior(WebKitEditingMacBehavior); + else if (behaviorString == "win") + preferences->setEditingBehavior(WebKitEditingWinBehavior); + else if (behaviorString == "unix") + preferences->setEditingBehavior(WebKitEditingUnixBehavior); +} + +void LayoutTestController::abortModal() +{ +} + +bool LayoutTestController::hasSpellingMarker(int from, int length) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return false; + BOOL ret = FALSE; + if (FAILED(framePrivate->hasSpellingMarker(from, length, &ret))) + return false; + return ret; +} + +bool LayoutTestController::hasGrammarMarker(int from, int length) +{ + // FIXME: Implement this. + return false; +} + +void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/) +{ + // FIXME: Implement this. +} + +void LayoutTestController::setSerializeHTTPLoads(bool) +{ + // FIXME: Implement. +} + +void LayoutTestController::syncLocalStorage() +{ + // FIXME: Implement. +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned number) +{ + // FIXME: Implement. +} + +void LayoutTestController::deleteAllLocalStorage() +{ + // FIXME: Implement. +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + // FIXME: Implement. + return JSValueMakeUndefined(context); +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: Implement to support getting local storage disk usage for an origin. + return 0; +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL) +{ + // FIXME: Implement. +} + +void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate(Query, webView); + if (!viewPrivate) + return; + + viewPrivate->setMinimumTimerInterval(minimumTimerInterval); +} + +void LayoutTestController::setTextDirection(JSStringRef direction) +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + framePrivate->setTextDirection(bstrT(direction).GetBSTR()); +} + +void LayoutTestController::allowRoundingHacks() +{ +} + +void LayoutTestController::addChromeInputField() +{ +} + +void LayoutTestController::removeChromeInputField() +{ +} + +void LayoutTestController::focusWebView() +{ +} + +void LayoutTestController::setBackingScaleFactor(double) +{ +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ + // FIXME: Implement. +} diff --git a/Tools/DumpRenderTree/win/MD5.cpp b/Tools/DumpRenderTree/win/MD5.cpp new file mode 100644 index 000000000..1bfc9c75f --- /dev/null +++ b/Tools/DumpRenderTree/win/MD5.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "MD5.h" + +#include <windows.h> + +typedef void (WINAPI*initPtr)(MD5_CTX*); +typedef void (WINAPI*updatePtr)(MD5_CTX*, unsigned char*, unsigned); +typedef void (WINAPI*finalPtr)(MD5_CTX*); + +static HMODULE cryptDLL() +{ + static HMODULE module = LoadLibraryW(L"Cryptdll.dll"); + return module; +} + +static initPtr init() +{ + static initPtr ptr = reinterpret_cast<initPtr>(GetProcAddress(cryptDLL(), "MD5Init")); + return ptr; +} + +static updatePtr update() +{ + static updatePtr ptr = reinterpret_cast<updatePtr>(GetProcAddress(cryptDLL(), "MD5Update")); + return ptr; +} + +static finalPtr final() +{ + static finalPtr ptr = reinterpret_cast<finalPtr>(GetProcAddress(cryptDLL(), "MD5Final")); + return ptr; +} + +void MD5_Init(MD5_CTX* context) +{ + init()(context); +} + +void MD5_Update(MD5_CTX* context, unsigned char* input, unsigned length) +{ + update()(context, input, length); +} + +void MD5_Final(unsigned char hash[16], MD5_CTX* context) +{ + final()(context); + + for (int i = 0; i < 16; ++i) + hash[i] = context->digest[i]; +} diff --git a/Tools/DumpRenderTree/win/MD5.h b/Tools/DumpRenderTree/win/MD5.h new file mode 100644 index 000000000..326e21d3e --- /dev/null +++ b/Tools/DumpRenderTree/win/MD5.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 MD5_h +#define MD5_h + +typedef unsigned long ULONG; + +struct MD5_CTX { + ULONG i[2]; + ULONG buf[4]; + unsigned char in[64]; + unsigned char digest[16]; +}; + +void MD5_Init(MD5_CTX*); +void MD5_Update(MD5_CTX*, unsigned char* input, unsigned length); +void MD5_Final(unsigned char hash[16], MD5_CTX*); + +#endif // MD5_h diff --git a/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp new file mode 100644 index 000000000..10ca5163f --- /dev/null +++ b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2007 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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" + +#if USE(CG) +#include "PixelDumpSupportCG.h" +#elif USE(CAIRO) +#include "PixelDumpSupportCairo.h" +#endif + +#include "DumpRenderTree.h" + +#if USE(CG) +// Note: Must be included *after* DumpRenderTree.h to avoid compile error. +#include <CoreGraphics/CGBitmapContext.h> +#endif + +#include <wtf/Assertions.h> +#include <wtf/RetainPtr.h> + +static void makeAlphaChannelOpaque(void* argbBits, LONG width, LONG height) +{ + unsigned* pixel = static_cast<unsigned*>(argbBits); + for (LONG row = 0; row < height; ++row) { + for (LONG column = 0; column < width; ++column) + *pixel++ |= 0xff000000; + } +} + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) +{ + RECT frame; + if (!GetWindowRect(webViewWindow, &frame)) + return 0; + + BITMAPINFO bmp = {0}; + bmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmp.bmiHeader.biWidth = frame.right - frame.left; + bmp.bmiHeader.biHeight = -(frame.bottom - frame.top); + bmp.bmiHeader.biPlanes = 1; + bmp.bmiHeader.biBitCount = 32; + bmp.bmiHeader.biCompression = BI_RGB; + + void* bits = 0; + HBITMAP bitmap = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0); + + HDC memoryDC = CreateCompatibleDC(0); + SelectObject(memoryDC, bitmap); + SendMessage(webViewWindow, WM_PRINT, reinterpret_cast<WPARAM>(memoryDC), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); + DeleteDC(memoryDC); + + BITMAP info = {0}; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + // We create a context that has an alpha channel below so that the PNGs we generate will also + // have an alpha channel. But WM_PRINT doesn't necessarily write anything into the alpha + // channel, so we set the alpha channel to constant full opacity to make sure the resulting image is opaque. + makeAlphaChannelOpaque(info.bmBits, info.bmWidth, info.bmHeight); + +#if USE(CG) + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, + info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); +#elif USE(CAIRO) + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, CAIRO_FORMAT_ARGB32, + info.bmWidth, info.bmHeight, info.bmWidthBytes); + cairo_t* context = cairo_create(image); + cairo_surface_destroy(image); +#endif + + return BitmapContext::createByAdoptingBitmapAndContext(bitmap, context); +} diff --git a/Tools/DumpRenderTree/win/PolicyDelegate.cpp b/Tools/DumpRenderTree/win/PolicyDelegate.cpp new file mode 100644 index 000000000..7d87c4539 --- /dev/null +++ b/Tools/DumpRenderTree/win/PolicyDelegate.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "PolicyDelegate.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <string> + +using std::wstring; + +static wstring dumpPath(IDOMNode* node) +{ + ASSERT(node); + + wstring result; + + BSTR name; + if (FAILED(node->nodeName(&name))) + return result; + result.assign(name, SysStringLen(name)); + SysFreeString(name); + + COMPtr<IDOMNode> parent; + if (SUCCEEDED(node->parentNode(&parent))) + result += TEXT(" > ") + dumpPath(parent.get()); + + return result; +} + +PolicyDelegate::PolicyDelegate() + : m_refCount(1) + , m_permissiveDelegate(false) + , m_controllerToNotifyDone(0) +{ +} + +// IUnknown +HRESULT STDMETHODCALLTYPE PolicyDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebPolicyDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebPolicyDelegate)) + *ppvObject = static_cast<IWebPolicyDelegate*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE PolicyDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE PolicyDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete this; + + return newRef; +} + +HRESULT STDMETHODCALLTYPE PolicyDelegate::decidePolicyForNavigationAction( + /*[in]*/ IWebView* /*webView*/, + /*[in]*/ IPropertyBag* actionInformation, + /*[in]*/ IWebURLRequest* request, + /*[in]*/ IWebFrame* frame, + /*[in]*/ IWebPolicyDecisionListener* listener) +{ + BSTR url; + request->URL(&url); + wstring wurl = urlSuitableForTestResult(wstring(url, SysStringLen(url))); + + int navType = 0; + VARIANT var; + if (SUCCEEDED(actionInformation->Read(WebActionNavigationTypeKey, &var, 0))) { + V_VT(&var) = VT_I4; + navType = V_I4(&var); + } + + LPCTSTR typeDescription; + switch (navType) { + case WebNavigationTypeLinkClicked: + typeDescription = TEXT("link clicked"); + break; + case WebNavigationTypeFormSubmitted: + typeDescription = TEXT("form submitted"); + break; + case WebNavigationTypeBackForward: + typeDescription = TEXT("back/forward"); + break; + case WebNavigationTypeReload: + typeDescription = TEXT("reload"); + break; + case WebNavigationTypeFormResubmitted: + typeDescription = TEXT("form resubmitted"); + break; + case WebNavigationTypeOther: + typeDescription = TEXT("other"); + break; + default: + typeDescription = TEXT("illegal value"); + } + + wstring message = TEXT("Policy delegate: attempt to load ") + wurl + TEXT(" with navigation type '") + typeDescription + TEXT("'"); + + VARIANT actionElementVar; + if (SUCCEEDED(actionInformation->Read(WebActionElementKey, &actionElementVar, 0))) { + COMPtr<IPropertyBag> actionElement(Query, V_UNKNOWN(&actionElementVar)); + VARIANT originatingNodeVar; + if (SUCCEEDED(actionElement->Read(WebElementDOMNodeKey, &originatingNodeVar, 0))) { + COMPtr<IDOMNode> originatingNode(Query, V_UNKNOWN(&originatingNodeVar)); + message += TEXT(" originating from ") + dumpPath(originatingNode.get()); + } + } + + printf("%S\n", message.c_str()); + + SysFreeString(url); + + if (m_permissiveDelegate) + listener->use(); + else + listener->ignore(); + + if (m_controllerToNotifyDone) { + m_controllerToNotifyDone->notifyDone(); + m_controllerToNotifyDone = 0; + } + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE PolicyDelegate::unableToImplementPolicyWithError( + /*[in]*/ IWebView* /*webView*/, + /*[in]*/ IWebError* error, + /*[in]*/ IWebFrame* frame) +{ + BSTR domainStr; + error->domain(&domainStr); + wstring domainMessage = domainStr; + + int code; + error->code(&code); + + BSTR frameName; + frame->name(&frameName); + wstring frameNameMessage = frameName; + + printf("Policy delegate: unable to implement policy with error domain '%S', error code %d, in frame '%S'", domainMessage.c_str(), code, frameNameMessage.c_str()); + + SysFreeString(domainStr); + SysFreeString(frameName); + + return S_OK; +} diff --git a/Tools/DumpRenderTree/win/PolicyDelegate.h b/Tools/DumpRenderTree/win/PolicyDelegate.h new file mode 100644 index 000000000..c808dc9c4 --- /dev/null +++ b/Tools/DumpRenderTree/win/PolicyDelegate.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 PolicyDelegate_h +#define PolicyDelegate_h + +#include <WebKit/WebKit.h> + +class LayoutTestController; + +class PolicyDelegate : public IWebPolicyDelegate { +public: + PolicyDelegate(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebPolicyDelegate + virtual HRESULT STDMETHODCALLTYPE decidePolicyForNavigationAction( + /* [in] */ IWebView *webView, + /* [in] */ IPropertyBag *actionInformation, + /* [in] */ IWebURLRequest *request, + /* [in] */ IWebFrame *frame, + /* [in] */ IWebPolicyDecisionListener *listener); + + virtual HRESULT STDMETHODCALLTYPE decidePolicyForNewWindowAction( + /* [in] */ IWebView *webView, + /* [in] */ IPropertyBag *actionInformation, + /* [in] */ IWebURLRequest *request, + /* [in] */ BSTR frameName, + /* [in] */ IWebPolicyDecisionListener *listener){ return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE decidePolicyForMIMEType( + /* [in] */ IWebView *webView, + /* [in] */ BSTR type, + /* [in] */ IWebURLRequest *request, + /* [in] */ IWebFrame *frame, + /* [in] */ IWebPolicyDecisionListener *listener){ return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE unableToImplementPolicyWithError( + /* [in] */ IWebView *webView, + /* [in] */ IWebError *error, + /* [in] */ IWebFrame *frame); + + // PolicyDelegate + void setPermissive(bool permissive) { m_permissiveDelegate = permissive; } + void setControllerToNotifyDone(LayoutTestController* controller) { m_controllerToNotifyDone = controller; } + +private: + ULONG m_refCount; + bool m_permissiveDelegate; + LayoutTestController* m_controllerToNotifyDone; +}; + +#endif // PolicyDelegate_h diff --git a/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp new file mode 100644 index 000000000..26b722a4e --- /dev/null +++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "ResourceLoadDelegate.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <WebKit/WebKitCOMAPI.h> +#include <comutil.h> +#include <sstream> +#include <tchar.h> +#include <wtf/Vector.h> + +using namespace std; + +static inline wstring wstringFromBSTR(BSTR str) +{ + return wstring(str, ::SysStringLen(str)); +} + +static inline wstring wstringFromInt(int i) +{ + wostringstream ss; + ss << i; + return ss.str(); +} + +static inline BSTR BSTRFromString(const string& str) +{ + int length = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), 0, 0); + BSTR result = ::SysAllocStringLen(0, length); + ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), result, length); + return result; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(unsigned long identifier) const +{ + IdentifierMap::const_iterator it = m_urlMap.find(identifier); + + if (it == m_urlMap.end()) + return L"<unknown>"; + + return urlSuitableForTestResult(it->second); +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLRequest* request) +{ + if (!request) + return L"(null)"; + + BSTR urlBSTR; + if (FAILED(request->URL(&urlBSTR))) + return wstring(); + + wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + ::SysFreeString(urlBSTR); + + BSTR mainDocumentURLBSTR; + if (FAILED(request->mainDocumentURL(&mainDocumentURLBSTR))) + return wstring(); + + wstring mainDocumentURL = urlSuitableForTestResult(wstringFromBSTR(mainDocumentURLBSTR)); + ::SysFreeString(mainDocumentURLBSTR); + + BSTR httpMethodBSTR; + if (FAILED(request->HTTPMethod(&httpMethodBSTR))) + return wstring(); + + wstring httpMethod = wstringFromBSTR(httpMethodBSTR); + ::SysFreeString(httpMethodBSTR); + + return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + httpMethod + L">"; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response) +{ + if (!response) + return L"(null)"; + + BSTR urlBSTR; + if (FAILED(response->URL(&urlBSTR))) + return wstring(); + + wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR)); + ::SysFreeString(urlBSTR); + + int statusCode = 0; + COMPtr<IWebHTTPURLResponse> httpResponse; + if (response && SUCCEEDED(response->QueryInterface(&httpResponse))) + httpResponse->statusCode(&statusCode); + + return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">"; +} + +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const +{ + wstring result = L"<NSError "; + + BSTR domainSTR; + if (FAILED(error->domain(&domainSTR))) + return wstring(); + + wstring domain = wstringFromBSTR(domainSTR); + ::SysFreeString(domainSTR); + + int code; + if (FAILED(error->code(&code))) + return wstring(); + + if (domain == L"CFURLErrorDomain") { + domain = L"NSURLErrorDomain"; + + // Convert kCFURLErrorUnknown to NSURLErrorUnknown + if (code == -998) + code = -1; + } else if (domain == L"kCFErrorDomainWinSock") { + domain = L"NSURLErrorDomain"; + + // Convert the winsock error code to an NSURLError code. + if (code == WSAEADDRNOTAVAIL) + code = -1004; // NSURLErrorCannotConnectToHose; + } + + result += L"domain " + domain; + result += L", code " + wstringFromInt(code); + + BSTR failingURLSTR; + if (FAILED(error->failingURL(&failingURLSTR))) + return wstring(); + + if (failingURLSTR) { + result += L", failing URL \"" + urlSuitableForTestResult(wstringFromBSTR(failingURLSTR)) + L"\""; + ::SysFreeString(failingURLSTR); + } + + result += L">"; + + return result; +} + +ResourceLoadDelegate::ResourceLoadDelegate() + : m_refCount(1) +{ +} + +ResourceLoadDelegate::~ResourceLoadDelegate() +{ +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate)) + *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2)) + *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void) +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void) +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( + /* [in] */ IWebView* webView, + /* [in] */ IWebURLRequest* request, + /* [in] */ IWebDataSource* dataSource, + /* [in] */ unsigned long identifier) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + BSTR urlStr; + if (FAILED(request->URL(&urlStr))) + return E_FAIL; + + ASSERT(!urlMap().contains(identifier)); + urlMap().set(identifier, wstringFromBSTR(urlStr)); + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::removeIdentifierForRequest( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier) +{ + urlMap().remove(identifier); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLRequest* request, + /* [in] */ IWebURLResponse* redirectResponse, + /* [in] */ IWebDataSource* dataSource, + /* [retval][out] */ IWebURLRequest **newRequest) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - willSendRequest %S redirectResponse %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(request).c_str(), + descriptionSuitableForTestResult(redirectResponse).c_str()); + } + + if (!done && !gLayoutTestController->deferMainResourceDataLoad()) { + COMPtr<IWebDataSourcePrivate> dataSourcePrivate(Query, dataSource); + if (!dataSourcePrivate) + return E_FAIL; + dataSourcePrivate->setDeferMainResourceDataLoad(FALSE); + } + + if (!done && gLayoutTestController->willSendRequestReturnsNull()) { + *newRequest = 0; + return S_OK; + } + + if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) { + printf("Returning null for this redirect\n"); + *newRequest = 0; + return S_OK; + } + + IWebMutableURLRequest* requestCopy = 0; + request->mutableCopy(&requestCopy); + const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) { + BSTR bstrHeader = BSTRFromString(*header); + requestCopy->setValue(0, bstrHeader); + SysFreeString(bstrHeader); + } + + *newRequest = requestCopy; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveAuthenticationChallenge( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLAuthenticationChallenge *challenge, + /* [in] */ IWebDataSource *dataSource) +{ + COMPtr<IWebURLAuthenticationChallengeSender> sender; + if (!challenge || FAILED(challenge->sender(&sender))) + return E_FAIL; + + if (!gLayoutTestController->handlesAuthenticationChallenges()) { + printf("%S - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", descriptionSuitableForTestResult(identifier).c_str()); + sender->continueWithoutCredentialForAuthenticationChallenge(challenge); + return S_OK; + } + + const char* user = gLayoutTestController->authenticationUsername().c_str(); + const char* password = gLayoutTestController->authenticationPassword().c_str(); + + printf("%S - didReceiveAuthenticationChallenge - Responding with %s:%s\n", descriptionSuitableForTestResult(identifier).c_str(), user, password); + + COMPtr<IWebURLCredential> credential; + if (FAILED(WebKitCreateInstance(CLSID_WebURLCredential, 0, IID_IWebURLCredential, (void**)&credential))) + return E_FAIL; + credential->initWithUser(_bstr_t(user), _bstr_t(password), WebURLCredentialPersistenceForSession); + + sender->useCredential(credential.get(), challenge); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveResponse( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLResponse* response, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didReceiveResponse %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(response).c_str()); + } + if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) { + BSTR mimeTypeBSTR; + if (FAILED(response->MIMEType(&mimeTypeBSTR))) + E_FAIL; + + wstring mimeType = wstringFromBSTR(mimeTypeBSTR); + ::SysFreeString(mimeTypeBSTR); + + BSTR urlBSTR; + if (FAILED(response->URL(&urlBSTR))) + E_FAIL; + + wstring url = wstringFromBSTR(urlBSTR); + ::SysFreeString(urlBSTR); + + printf("%S has MIME type %S\n", lastPathComponent(url).c_str(), mimeType.c_str()); + } + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didFinishLoading\n", + descriptionSuitableForTestResult(identifier).c_str()); + } + + removeIdentifierForRequest(webView, identifier); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebError* error, + /* [in] */ IWebDataSource* dataSource) +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + printf("%S - didFailLoadingWithError: %S\n", + descriptionSuitableForTestResult(identifier).c_str(), + descriptionSuitableForTestResult(error, identifier).c_str()); + } + + removeIdentifierForRequest(webView, identifier); + + return S_OK; +} diff --git a/Tools/DumpRenderTree/win/ResourceLoadDelegate.h b/Tools/DumpRenderTree/win/ResourceLoadDelegate.h new file mode 100644 index 000000000..3f20f47c9 --- /dev/null +++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ResourceLoadDelegate_h +#define ResourceLoadDelegate_h + +#include <WebKit/WebKit.h> +#include <string> +#include <wtf/HashMap.h> + +class ResourceLoadDelegate : public IWebResourceLoadDelegate, public IWebResourceLoadDelegatePrivate2 { +public: + ResourceLoadDelegate(); + virtual ~ResourceLoadDelegate(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebResourceLoadDelegate + virtual HRESULT STDMETHODCALLTYPE identifierForInitialRequest( + /* [in] */ IWebView *webView, + /* [in] */ IWebURLRequest *request, + /* [in] */ IWebDataSource *dataSource, + /* [in] */ unsigned long identifier); + + virtual HRESULT STDMETHODCALLTYPE willSendRequest( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLRequest *request, + /* [in] */ IWebURLResponse *redirectResponse, + /* [in] */ IWebDataSource *dataSource, + /* [retval][out] */ IWebURLRequest **newRequest); + + virtual HRESULT STDMETHODCALLTYPE didReceiveAuthenticationChallenge( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLAuthenticationChallenge *challenge, + /* [in] */ IWebDataSource *dataSource); + + virtual HRESULT STDMETHODCALLTYPE didCancelAuthenticationChallenge( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLAuthenticationChallenge *challenge, + /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didReceiveResponse( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebURLResponse *response, + /* [in] */ IWebDataSource *dataSource); + + virtual HRESULT STDMETHODCALLTYPE didReceiveContentLength( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ UINT length, + /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE didFinishLoadingFromDataSource( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebDataSource *dataSource); + + virtual HRESULT STDMETHODCALLTYPE didFailLoadingWithError( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier, + /* [in] */ IWebError *error, + /* [in] */ IWebDataSource *dataSource); + + virtual HRESULT STDMETHODCALLTYPE plugInFailedWithError( + /* [in] */ IWebView *webView, + /* [in] */ IWebError *error, + /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; } + + // IWebResourceLoadDelegatePrivate2 + virtual HRESULT STDMETHODCALLTYPE removeIdentifierForRequest( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier); + +private: + static std::wstring descriptionSuitableForTestResult(IWebURLRequest*); + static std::wstring descriptionSuitableForTestResult(IWebURLResponse*); + std::wstring descriptionSuitableForTestResult(unsigned long) const; + std::wstring descriptionSuitableForTestResult(IWebError*, unsigned long) const; + + typedef HashMap<unsigned long, std::wstring> IdentifierMap; + IdentifierMap& urlMap() { return m_urlMap; } + IdentifierMap m_urlMap; + + ULONG m_refCount; +}; + +#endif // ResourceLoadDelegate_h diff --git a/Tools/DumpRenderTree/win/UIDelegate.cpp b/Tools/DumpRenderTree/win/UIDelegate.cpp new file mode 100644 index 000000000..729e3378d --- /dev/null +++ b/Tools/DumpRenderTree/win/UIDelegate.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "UIDelegate.h" + +#include "DumpRenderTree.h" +#include "DraggingInfo.h" +#include "EventSender.h" +#include "LayoutTestController.h" +#include "DRTDesktopNotificationPresenter.h" + +#include <WebCore/COMPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Platform.h> +#include <wtf/Vector.h> +#include <JavaScriptCore/Assertions.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <WebKit/WebKit.h> +#include <stdio.h> + +using std::wstring; + +class DRTUndoObject { +public: + DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) + : m_target(target) + , m_actionName(SysAllocString(actionName)) + , m_obj(obj) + { + } + + ~DRTUndoObject() + { + SysFreeString(m_actionName); + } + + void invoke() + { + m_target->invoke(m_actionName, m_obj.get()); + } + +private: + IWebUndoTarget* m_target; + BSTR m_actionName; + COMPtr<IUnknown> m_obj; +}; + +class DRTUndoStack { +public: + ~DRTUndoStack() { deleteAllValues(m_undoVector); } + + bool isEmpty() const { return m_undoVector.isEmpty(); } + void clear() { deleteAllValues(m_undoVector); m_undoVector.clear(); } + + void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); } + DRTUndoObject* pop() { DRTUndoObject* top = m_undoVector.last(); m_undoVector.removeLast(); return top; } + +private: + Vector<DRTUndoObject*> m_undoVector; +}; + +class DRTUndoManager { +public: + DRTUndoManager(); + + void removeAllActions(); + void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj); + void redo(); + void undo(); + bool canRedo() { return !m_redoStack->isEmpty(); } + bool canUndo() { return !m_undoStack->isEmpty(); } + +private: + OwnPtr<DRTUndoStack> m_redoStack; + OwnPtr<DRTUndoStack> m_undoStack; + bool m_isRedoing; + bool m_isUndoing; +}; + +DRTUndoManager::DRTUndoManager() + : m_redoStack(adoptPtr(new DRTUndoStack)) + , m_undoStack(adoptPtr(new DRTUndoStack)) + , m_isRedoing(false) + , m_isUndoing(false) +{ +} + +void DRTUndoManager::removeAllActions() +{ + m_redoStack->clear(); + m_undoStack->clear(); +} + +void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) +{ + if (!m_isUndoing && !m_isRedoing) + m_redoStack->clear(); + + DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get(); + stack->push(new DRTUndoObject(target, actionName, obj)); +} + +void DRTUndoManager::redo() +{ + if (!canRedo()) + return; + + m_isRedoing = true; + + DRTUndoObject* redoObject = m_redoStack->pop(); + redoObject->invoke(); + delete redoObject; + + m_isRedoing = false; +} + +void DRTUndoManager::undo() +{ + if (!canUndo()) + return; + + m_isUndoing = true; + + DRTUndoObject* undoObject = m_undoStack->pop(); + undoObject->invoke(); + delete undoObject; + + m_isUndoing = false; +} + +UIDelegate::UIDelegate() + : m_refCount(1) + , m_undoManager(adoptPtr(new DRTUndoManager)) + , m_desktopNotifications(new DRTDesktopNotificationPresenter) +{ + m_frame.bottom = 0; + m_frame.top = 0; + m_frame.left = 0; + m_frame.right = 0; +} + +void UIDelegate::resetUndoManager() +{ + m_undoManager = adoptPtr(new DRTUndoManager); +} + +HRESULT STDMETHODCALLTYPE UIDelegate::QueryInterface(REFIID riid, void** ppvObject) +{ + *ppvObject = 0; + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = static_cast<IWebUIDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebUIDelegate)) + *ppvObject = static_cast<IWebUIDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebUIDelegate2)) + *ppvObject = static_cast<IWebUIDelegate2*>(this); + else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate)) + *ppvObject = static_cast<IWebUIDelegatePrivate*>(this); + else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate2)) + *ppvObject = static_cast<IWebUIDelegatePrivate2*>(this); + else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate3)) + *ppvObject = static_cast<IWebUIDelegatePrivate3*>(this); + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE UIDelegate::AddRef() +{ + return ++m_refCount; +} + +ULONG STDMETHODCALLTYPE UIDelegate::Release() +{ + ULONG newRef = --m_refCount; + if (!newRef) + delete(this); + + return newRef; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation( + /* [retval][out] */ BOOL *hasCustomMenus) +{ + *hasCustomMenus = TRUE; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE menu, + /* [in] */ LPPOINT point) +{ + // Do nothing + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget( + /* [in] */ IWebUndoTarget* target, + /* [in] */ BSTR actionName, + /* [in] */ IUnknown* actionArg) +{ + m_undoManager->registerUndoWithTarget(target, actionName, actionArg); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget( + /* [in] */ IWebUndoTarget*) +{ + m_undoManager->removeAllActions(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle( + /* [in] */ BSTR actionTitle) +{ + // It is not neccessary to implement this for DRT because there is + // menu to write out the title to. + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::undo() +{ + m_undoManager->undo(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::redo() +{ + m_undoManager->redo(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::canUndo( + /* [retval][out] */ BOOL* result) +{ + if (!result) + return E_POINTER; + + *result = m_undoManager->canUndo(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::canRedo( + /* [retval][out] */ BOOL* result) +{ + if (!result) + return E_POINTER; + + *result = m_undoManager->canRedo(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::printFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::ftpDirectoryTemplatePath( + /* [in] */ IWebView *webView, + /* [retval][out] */ BSTR *path) +{ + if (!path) + return E_POINTER; + *path = 0; + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewHeaderHeight( + /* [in] */ IWebView *webView, + /* [retval][out] */ float *result) +{ + if (!result) + return E_POINTER; + *result = 0; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewFooterHeight( + /* [in] */ IWebView *webView, + /* [retval][out] */ float *result) +{ + if (!result) + return E_POINTER; + *result = 0; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::drawHeaderInRect( + /* [in] */ IWebView *webView, + /* [in] */ RECT *rect, + /* [in] */ OLE_HANDLE drawingContext) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::drawFooterInRect( + /* [in] */ IWebView *webView, + /* [in] */ RECT *rect, + /* [in] */ OLE_HANDLE drawingContext, + /* [in] */ UINT pageIndex, + /* [in] */ UINT pageCount) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewPrintingMarginRect( + /* [in] */ IWebView *webView, + /* [retval][out] */ RECT *rect) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::canRunModal( + /* [in] */ IWebView *webView, + /* [retval][out] */ BOOL *canRunBoolean) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::createModalDialog( + /* [in] */ IWebView *sender, + /* [in] */ IWebURLRequest *request, + /* [retval][out] */ IWebView **newWebView) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runModal( + /* [in] */ IWebView *webView) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::isMenuBarVisible( + /* [in] */ IWebView *webView, + /* [retval][out] */ BOOL *visible) +{ + if (!visible) + return E_POINTER; + *visible = false; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::setMenuBarVisible( + /* [in] */ IWebView *webView, + /* [in] */ BOOL visible) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runDatabaseSizeLimitPrompt( + /* [in] */ IWebView *webView, + /* [in] */ BSTR displayName, + /* [in] */ IWebFrame *initiatedByFrame, + /* [retval][out] */ BOOL *allowed) +{ + if (!allowed) + return E_POINTER; + *allowed = false; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollbar( + /* [in] */ IWebView *webView, + /* [in] */ HDC hDC, + /* [in] */ RECT rect, + /* [in] */ WebScrollBarControlSize size, + /* [in] */ WebScrollbarControlState state, + /* [in] */ WebScrollbarControlPart pressedPart, + /* [in] */ BOOL vertical, + /* [in] */ float value, + /* [in] */ float proportion, + /* [in] */ WebScrollbarControlPartMask parts) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollCorner( + /* [in] */ IWebView *webView, + /* [in] */ HDC hDC, + /* [in] */ RECT rect) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::setFrame( + /* [in] */ IWebView* /*sender*/, + /* [in] */ RECT* frame) +{ + m_frame = *frame; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame( + /* [in] */ IWebView* /*sender*/, + /* [retval][out] */ RECT* frame) +{ + *frame = m_frame; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage( + /* [in] */ IWebView* /*sender*/, + /* [in] */ BSTR message) +{ + printf("ALERT: %S\n", message ? message : L""); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage( + /* [in] */ IWebView* sender, + /* [in] */ BSTR message, + /* [retval][out] */ BOOL* result) +{ + printf("CONFIRM: %S\n", message ? message : L""); + *result = TRUE; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message, + /* [in] */ BSTR defaultText, + /* [retval][out] */ BSTR *result) +{ + printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L""); + *result = SysAllocString(defaultText); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage( + /* [in] */ IWebView* /*sender*/, + /* [in] */ BSTR message, + /* [in] */ IWebFrame* /*initiatedByFrame*/, + /* [retval][out] */ BOOL* result) +{ + if (!result) + return E_POINTER; + printf("CONFIRM NAVIGATION: %S\n", message ? message : L""); + *result = !gLayoutTestController->shouldStayOnPageAfterHandlingBeforeUnload(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole( + /* [in] */ IWebView* sender, + /* [in] */ BSTR message, + /* [in] */ int lineNumber, + /* [in] */ BSTR url, + /* [in] */ BOOL isError) +{ + wstring newMessage; + if (message) { + newMessage = message; + size_t fileProtocol = newMessage.find(L"file://"); + if (fileProtocol != wstring::npos) + newMessage = newMessage.substr(0, fileProtocol) + lastPathComponent(newMessage.substr(fileProtocol)); + } + + printf("CONSOLE MESSAGE: line %d: %s\n", lineNumber, toUTF8(newMessage).c_str()); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop( + /* [in] */ IWebView* sender, + /* [in] */ IDataObject* object, + /* [in] */ IDropSource* source, + /* [in] */ DWORD okEffect, + /* [retval][out] */ DWORD* performedEffect) +{ + if (!performedEffect) + return E_POINTER; + + *performedEffect = 0; + + draggingInfo = new DraggingInfo(object, source); + HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL; + replaySavedEvents(&oleDragAndDropReturnValue); + if (draggingInfo) { + *performedEffect = draggingInfo->performedDropEffect(); + delete draggingInfo; + draggingInfo = 0; + } + return oleDragAndDropReturnValue; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode( + /* [in] */ IWebView* /*sender*/, + /* [in] */ UINT /*keyCode*/, + /* [retval][out] */ LONG_PTR *code) +{ + if (!code) + return E_POINTER; + *code = 0; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest( + /* [in] */ IWebView *sender, + /* [in] */ IWebURLRequest *request, + /* [retval][out] */ IWebView **newWebView) +{ + if (!::gLayoutTestController->canOpenWindows()) + return E_FAIL; + *newWebView = createWebViewAndOffscreenWindow(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose( + /* [in] */ IWebView *sender) +{ + HWND hostWindow; + sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); + DestroyWindow(hostWindow); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus( + /* [in] */ IWebView *sender) +{ + HWND hostWindow; + sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); + SetForegroundWindow(hostWindow); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus( + /* [in] */ IWebView *sender) +{ + SetForegroundWindow(GetDesktopWindow()); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted( + /* [in] */ IWebView *sender) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame, + /* [in] */ IWebSecurityOrigin *origin, + /* [in] */ BSTR databaseIdentifier) +{ + BSTR protocol; + BSTR host; + unsigned short port; + + origin->protocol(&protocol); + origin->host(&host); + origin->port(&port); + + if (!done && gLayoutTestController->dumpDatabaseCallbacks()) + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier); + + SysFreeString(protocol); + SysFreeString(host); + + static const unsigned long long defaultQuota = 5 * 1024 * 1024; + origin->setQuota(defaultQuota); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::embeddedViewWithArguments( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame, + /* [in] */ IPropertyBag *arguments, + /* [retval][out] */ IWebEmbeddedView **view) +{ + if (!view) + return E_POINTER; + *view = 0; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewClosing( + /* [in] */ IWebView *sender) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewSetCursor( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE cursor) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::webViewDidInvalidate( + /* [in] */ IWebView *sender) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text) +{ + if (gLayoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text ? toUTF8(text).c_str() : ""); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result) +{ + m_desktopNotifications.copyRefTo(result); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest(IWebView* sender, IWebURLRequest* request, IPropertyBag* windowFeatures, IWebView** newWebView) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::drawBackground(IWebView* sender, OLE_HANDLE hdc, const RECT* dirtyRect) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::decidePolicyForGeolocationRequest(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, IWebGeolocationPolicyListener* listener) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE UIDelegate::didPressMissingPluginButton(IDOMElement* element) +{ + printf("MISSING PLUGIN BUTTON PRESSED\n"); + return S_OK; +} + diff --git a/Tools/DumpRenderTree/win/UIDelegate.h b/Tools/DumpRenderTree/win/UIDelegate.h new file mode 100644 index 000000000..0c9fdaf63 --- /dev/null +++ b/Tools/DumpRenderTree/win/UIDelegate.h @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 UIDelegate_h +#define UIDelegate_h + +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <wtf/OwnPtr.h> +#include <windef.h> + +class DRTUndoManager; +class DRTDesktopNotificationPresenter; + +class UIDelegate : public IWebUIDelegate2, IWebUIDelegatePrivate3 { +public: + UIDelegate(); + + void resetUndoManager(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IWebUIDelegate + virtual HRESULT STDMETHODCALLTYPE createWebViewWithRequest( + /* [in] */ IWebView *sender, + /* [in] */ IWebURLRequest *request, + /* [retval][out] */ IWebView **newWebView); + + virtual HRESULT STDMETHODCALLTYPE webViewShow( + /* [in] */ IWebView *sender) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewClose( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE webViewFocus( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE webViewUnfocus( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE webViewFirstResponder( + /* [in] */ IWebView *sender, + /* [retval][out] */ OLE_HANDLE *responder) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE makeFirstResponder( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE responder) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE setStatusText( + /* [in] */ IWebView *sender, + /* [in] */ BSTR text); + + virtual HRESULT STDMETHODCALLTYPE webViewStatusText( + /* [in] */ IWebView *sender, + /* [retval][out] */ BSTR *text) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewAreToolbarsVisible( + /* [in] */ IWebView *sender, + /* [retval][out] */ BOOL *visible) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE setToolbarsVisible( + /* [in] */ IWebView *sender, + /* [in] */ BOOL visible) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewIsStatusBarVisible( + /* [in] */ IWebView *sender, + /* [retval][out] */ BOOL *visible) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE setStatusBarVisible( + /* [in] */ IWebView *sender, + /* [in] */ BOOL visible) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewIsResizable( + /* [in] */ IWebView *sender, + /* [retval][out] */ BOOL *resizable) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE setResizable( + /* [in] */ IWebView *sender, + /* [in] */ BOOL resizable) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE setFrame( + /* [in] */ IWebView *sender, + /* [in] */ RECT *frame); + + virtual HRESULT STDMETHODCALLTYPE webViewFrame( + /* [in] */ IWebView *sender, + /* [retval][out] */ RECT *frame); + + virtual HRESULT STDMETHODCALLTYPE setContentRect( + /* [in] */ IWebView *sender, + /* [in] */ RECT *contentRect) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewContentRect( + /* [in] */ IWebView *sender, + /* [retval][out] */ RECT *contentRect) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE runJavaScriptAlertPanelWithMessage( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message); + + virtual HRESULT STDMETHODCALLTYPE runJavaScriptConfirmPanelWithMessage( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE runJavaScriptTextInputPanelWithPrompt( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message, + /* [in] */ BSTR defaultText, + /* [retval][out] */ BSTR *result); + + virtual HRESULT STDMETHODCALLTYPE runBeforeUnloadConfirmPanelWithMessage( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message, + /* [in] */ IWebFrame *initiatedByFrame, + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE runOpenPanelForFileButtonWithResultListener( + /* [in] */ IWebView *sender, + /* [in] */ IWebOpenPanelResultListener *resultListener) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE mouseDidMoveOverElement( + /* [in] */ IWebView *sender, + /* [in] */ IPropertyBag *elementInformation, + /* [in] */ UINT modifierFlags) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE contextMenuItemsForElement( + /* [in] */ IWebView *sender, + /* [in] */ IPropertyBag *element, + /* [in] */ OLE_HANDLE defaultItems, + /* [retval][out] */ OLE_HANDLE *resultMenu) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE validateUserInterfaceItem( + /* [in] */ IWebView *webView, + /* [in] */ UINT itemCommandID, + /* [in] */ BOOL defaultValidation, + /* [retval][out] */ BOOL *isValid) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE shouldPerformAction( + /* [in] */ IWebView *webView, + /* [in] */ UINT itemCommandID, + /* [in] */ UINT sender) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE dragDestinationActionMaskForDraggingInfo( + /* [in] */ IWebView *webView, + /* [in] */ IDataObject *draggingInfo, + /* [retval][out] */ WebDragDestinationAction *action) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE willPerformDragDestinationAction( + /* [in] */ IWebView *webView, + /* [in] */ WebDragDestinationAction action, + /* [in] */ IDataObject *draggingInfo) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE dragSourceActionMaskForPoint( + /* [in] */ IWebView *webView, + /* [in] */ LPPOINT point, + /* [retval][out] */ WebDragSourceAction *action) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE willPerformDragSourceAction( + /* [in] */ IWebView *webView, + /* [in] */ WebDragSourceAction action, + /* [in] */ LPPOINT point, + /* [in] */ IDataObject *pasteboard, + /* [retval][out] */ IDataObject **newPasteboard) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE contextMenuItemSelected( + /* [in] */ IWebView *sender, + /* [in] */ void *item, + /* [in] */ IPropertyBag *element) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE hasCustomMenuImplementation( + /* [retval][out] */ BOOL *hasCustomMenus); + + virtual HRESULT STDMETHODCALLTYPE trackCustomPopupMenu( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE menu, + /* [in] */ LPPOINT point); + + virtual HRESULT STDMETHODCALLTYPE measureCustomMenuItem( + /* [in] */ IWebView *sender, + /* [in] */ void *measureItem) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE drawCustomMenuItem( + /* [in] */ IWebView *sender, + /* [in] */ void *drawItem) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE addCustomMenuDrawingData( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE menu) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE cleanUpCustomMenuDrawingData( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE menu) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE canTakeFocus( + /* [in] */ IWebView *sender, + /* [in] */ BOOL forward, + /* [out] */ BOOL *result) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE takeFocus( + /* [in] */ IWebView *sender, + /* [in] */ BOOL forward) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE registerUndoWithTarget( + /* [in] */ IWebUndoTarget *target, + /* [in] */ BSTR actionName, + /* [in] */ IUnknown *actionArg); + + virtual HRESULT STDMETHODCALLTYPE removeAllActionsWithTarget( + /* [in] */ IWebUndoTarget *target); + + virtual HRESULT STDMETHODCALLTYPE setActionTitle( + /* [in] */ BSTR actionTitle); + + virtual HRESULT STDMETHODCALLTYPE undo(); + + virtual HRESULT STDMETHODCALLTYPE redo(); + + virtual HRESULT STDMETHODCALLTYPE canUndo( + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE canRedo( + /* [retval][out] */ BOOL *result); + + virtual HRESULT STDMETHODCALLTYPE printFrame( + /* [in] */ IWebView *webView, + /* [in] */ IWebFrame *frame); + + virtual HRESULT STDMETHODCALLTYPE ftpDirectoryTemplatePath( + /* [in] */ IWebView *webView, + /* [retval][out] */ BSTR *path); + + virtual HRESULT STDMETHODCALLTYPE webViewHeaderHeight( + /* [in] */ IWebView *webView, + /* [retval][out] */ float *result); + + virtual HRESULT STDMETHODCALLTYPE webViewFooterHeight( + /* [in] */ IWebView *webView, + /* [retval][out] */ float *result); + + virtual HRESULT STDMETHODCALLTYPE drawHeaderInRect( + /* [in] */ IWebView *webView, + /* [in] */ RECT *rect, + /* [in] */ OLE_HANDLE drawingContext); + + virtual HRESULT STDMETHODCALLTYPE drawFooterInRect( + /* [in] */ IWebView *webView, + /* [in] */ RECT *rect, + /* [in] */ OLE_HANDLE drawingContext, + /* [in] */ UINT pageIndex, + /* [in] */ UINT pageCount); + + virtual HRESULT STDMETHODCALLTYPE webViewPrintingMarginRect( + /* [in] */ IWebView *webView, + /* [retval][out] */ RECT *rect); + + virtual HRESULT STDMETHODCALLTYPE canRunModal( + /* [in] */ IWebView *webView, + /* [retval][out] */ BOOL *canRunBoolean); + + virtual HRESULT STDMETHODCALLTYPE createModalDialog( + /* [in] */ IWebView *sender, + /* [in] */ IWebURLRequest *request, + /* [retval][out] */ IWebView **newWebView); + + virtual HRESULT STDMETHODCALLTYPE runModal( + /* [in] */ IWebView *webView); + + virtual HRESULT STDMETHODCALLTYPE isMenuBarVisible( + /* [in] */ IWebView *webView, + /* [retval][out] */ BOOL *visible); + + virtual HRESULT STDMETHODCALLTYPE setMenuBarVisible( + /* [in] */ IWebView *webView, + /* [in] */ BOOL visible); + + virtual HRESULT STDMETHODCALLTYPE runDatabaseSizeLimitPrompt( + /* [in] */ IWebView *webView, + /* [in] */ BSTR displayName, + /* [in] */ IWebFrame *initiatedByFrame, + /* [retval][out] */ BOOL *allowed); + + virtual HRESULT STDMETHODCALLTYPE paintCustomScrollbar( + /* [in] */ IWebView *webView, + /* [in] */ HDC hDC, + /* [in] */ RECT rect, + /* [in] */ WebScrollBarControlSize size, + /* [in] */ WebScrollbarControlState state, + /* [in] */ WebScrollbarControlPart pressedPart, + /* [in] */ BOOL vertical, + /* [in] */ float value, + /* [in] */ float proportion, + /* [in] */ WebScrollbarControlPartMask parts); + + virtual HRESULT STDMETHODCALLTYPE paintCustomScrollCorner( + /* [in] */ IWebView *webView, + /* [in] */ HDC hDC, + /* [in] */ RECT rect); + + virtual HRESULT STDMETHODCALLTYPE createWebViewWithRequest(IWebView* sender, IWebURLRequest* request, IPropertyBag* windowFeatures, IWebView** newWebView); + + virtual HRESULT STDMETHODCALLTYPE drawBackground(IWebView* sender, OLE_HANDLE hdc, const RECT* dirtyRect); + + virtual HRESULT STDMETHODCALLTYPE decidePolicyForGeolocationRequest(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, IWebGeolocationPolicyListener* listener); + + virtual HRESULT STDMETHODCALLTYPE didPressMissingPluginButton(IDOMElement*); + +protected: + // IWebUIDelegatePrivate + + virtual HRESULT STDMETHODCALLTYPE unused1() { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE unused2() { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE unused3() { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewScrolled( + /* [in] */ IWebView *sender) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewAddMessageToConsole( + /* [in] */ IWebView *sender, + /* [in] */ BSTR message, + /* [in] */ int lineNumber, + /* [in] */ BSTR url, + /* [in] */ BOOL isError); + + virtual HRESULT STDMETHODCALLTYPE webViewShouldInterruptJavaScript( + /* [in] */ IWebView *sender, + /* [retval][out] */ BOOL *result) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewReceivedFocus( + /* [in] */ IWebView *sender) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE webViewLostFocus( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE loseFocusTo) { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE doDragDrop( + /* [in] */ IWebView *sender, + /* [in] */ IDataObject *dataObject, + /* [in] */ IDropSource *dropSource, + /* [in] */ DWORD okEffect, + /* [retval][out] */ DWORD *performedEffect); + + virtual HRESULT STDMETHODCALLTYPE webViewGetDlgCode( + /* [in] */ IWebView *sender, + /* [in] */ UINT keyCode, + /* [retval][out] */ LONG_PTR *code); + + virtual HRESULT STDMETHODCALLTYPE webViewPainted( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE exceededDatabaseQuota( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame, + /* [in] */ IWebSecurityOrigin *origin, + /* [in] */ BSTR databaseIdentifier); + + virtual HRESULT STDMETHODCALLTYPE embeddedViewWithArguments( + /* [in] */ IWebView *sender, + /* [in] */ IWebFrame *frame, + /* [in] */ IPropertyBag *arguments, + /* [retval][out] */ IWebEmbeddedView **view); + + virtual HRESULT STDMETHODCALLTYPE webViewClosing( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE webViewSetCursor( + /* [in] */ IWebView *sender, + /* [in] */ OLE_HANDLE cursor); + + virtual HRESULT STDMETHODCALLTYPE webViewDidInvalidate( + /* [in] */ IWebView *sender); + + virtual HRESULT STDMETHODCALLTYPE desktopNotificationsDelegate( + /* [out] */ IWebDesktopNotificationsDelegate** result); + + ULONG m_refCount; + +private: + RECT m_frame; + OwnPtr<DRTUndoManager> m_undoManager; + + COMPtr<IWebDesktopNotificationsDelegate> m_desktopNotifications; +}; + +#endif diff --git a/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp b/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp new file mode 100644 index 000000000..49f0667d2 --- /dev/null +++ b/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItem.h" + +#include "DumpRenderTree.h" +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <WebKit/WebKitCOMAPI.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/JSStringRefCF.h> +#include <JavaScriptCore/RetainPtr.h> +#include <wtf/Vector.h> +#include <string> + +using std::wstring; + +static wstring jsStringRefToWString(JSStringRef jsStr) +{ + size_t length = JSStringGetLength(jsStr); + Vector<WCHAR> buffer(length + 1); + memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR)); + buffer[length] = '\0'; + + return buffer.data(); +} + +bool LoadItem::invoke() const +{ + wstring targetString = jsStringRefToWString(m_target.get()); + + COMPtr<IWebFrame> targetFrame; + if (targetString.empty()) + targetFrame = frame; + else { + BSTR targetBSTR = SysAllocString(targetString.c_str()); + bool failed = FAILED(frame->findFrameNamed(targetBSTR, &targetFrame)); + SysFreeString(targetBSTR); + if (failed) + return false; + } + + COMPtr<IWebURLRequest> request; + if (FAILED(WebKitCreateInstance(CLSID_WebURLRequest, 0, IID_IWebURLRequest, (void**)&request))) + return false; + + wstring urlString = jsStringRefToWString(m_url.get()); + BSTR urlBSTR = SysAllocString(urlString.c_str()); + bool failed = FAILED(request->initWithURL(urlBSTR, WebURLRequestUseProtocolCachePolicy, 60)); + SysFreeString(urlBSTR); + if (failed) + return false; + + targetFrame->loadRequest(request.get()); + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + wstring content = jsStringRefToWString(m_content.get()); + wstring baseURL = jsStringRefToWString(m_baseURL.get()); + + BSTR contentBSTR = SysAllocString(content.c_str()); + BSTR baseURLBSTR = SysAllocString(baseURL.c_str()); + + if (m_unreachableURL) { + wstring unreachableURL = jsStringRefToWString(m_unreachableURL.get()); + BSTR unreachableURLBSTR = SysAllocString(unreachableURL.c_str()); + frame->loadAlternateHTMLString(contentBSTR, baseURLBSTR, unreachableURLBSTR); + SysFreeString(contentBSTR); + SysFreeString(baseURLBSTR); + SysFreeString(unreachableURLBSTR); + return true; + } + + frame->loadHTMLString(contentBSTR, baseURLBSTR); + + SysFreeString(contentBSTR); + SysFreeString(baseURLBSTR); + + return true; +} + +bool ReloadItem::invoke() const +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return false; + + COMPtr<IWebIBActions> webActions; + if (FAILED(webView->QueryInterface(&webActions))) + return false; + + webActions->reload(0); + return true; +} + +bool ScriptItem::invoke() const +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return false; + + wstring scriptString = jsStringRefToWString(m_script.get()); + + BSTR result; + BSTR scriptBSTR = SysAllocString(scriptString.c_str()); + webView->stringByEvaluatingJavaScriptFromString(scriptBSTR, &result); + SysFreeString(result); + SysFreeString(scriptBSTR); + + return true; +} + +bool BackForwardItem::invoke() const +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return false; + + BOOL result; + if (m_howFar == 1) { + webView->goForward(&result); + return true; + } + + if (m_howFar == -1) { + webView->goBack(&result); + return true; + } + + COMPtr<IWebBackForwardList> bfList; + if (FAILED(webView->backForwardList(&bfList))) + return false; + + COMPtr<IWebHistoryItem> item; + if (FAILED(bfList->itemAtIndex(m_howFar, &item))) + return false; + + webView->goToBackForwardItem(item.get(), &result); + return true; +} diff --git a/Tools/DumpRenderTree/wscript b/Tools/DumpRenderTree/wscript new file mode 100644 index 000000000..67efe9f0b --- /dev/null +++ b/Tools/DumpRenderTree/wscript @@ -0,0 +1,65 @@ +#! /usr/bin/env python + +# Copyright (C) 2009 Kevin Ollivier All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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. +# +# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. +# +# wxBrowser sample app build script for the waf build system + +import sys + +from settings import * + +include_paths = [ + os.path.join(output_dir), + os.path.join(wk_root, 'Source', 'JavaScriptCore'), + os.path.join(wk_root, 'Source', 'WebCore'), + os.path.join(wk_root, 'Source', 'WebCore', 'bindings', 'wx'), + os.path.join(wk_root, 'Source', 'WebKit', 'wx'), + '.', + 'wx' + ] +sources = [ + 'LayoutTestController.cpp', + 'WorkQueue.cpp', + 'wx/DumpRenderTreeWx.cpp', + 'wx/LayoutTestControllerWx.cpp', + 'wx/WorkQueueItemWx.cpp' + ] + +def set_options(opt): + common_set_options(opt) + +def configure(conf): + common_configure(conf) + +def build(bld): + obj = bld.new_task_gen( + features = 'cxx cprogram', + includes = ' '.join(include_paths), + source = sources, + target = 'DumpRenderTree', + uselib = 'ICU WX ' + get_config(), + libpath = [output_dir], + uselib_local = 'jscore wxwebkit', + install_path = output_dir) + diff --git a/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp new file mode 100644 index 000000000..92840d3cf --- /dev/null +++ b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" + +#include "LayoutTestController.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" + +#include <JavaScriptCore/JavaScript.h> + +#include <wx/wx.h> +#include "WebView.h" +#include "WebFrame.h" +#include "WebBrowserShell.h" + +#include <wtf/Assertions.h> + +#include <cassert> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +volatile bool done = true; +volatile bool notified = false; +static bool printSeparators = true; +static int dumpPixels; +static int dumpTree = 1; +time_t startTime; // to detect timeouts / failed tests + +using namespace std; + +FILE* logOutput; + +RefPtr<LayoutTestController> gLayoutTestController; +static wxWebView* webView; +static wxTimer* idleTimer; + +const unsigned timeOut = 10; +const unsigned maxViewHeight = 600; +const unsigned maxViewWidth = 800; + +class LayoutWebViewEventHandler : public wxEvtHandler { + +public: + LayoutWebViewEventHandler(wxWebView* webView) + : m_webView(webView) + { + } + + void bindEvents() + { + m_webView->Connect(wxEVT_WEBVIEW_LOAD, wxWebViewLoadEventHandler(LayoutWebViewEventHandler::OnLoadEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_JS_ALERT, wxWebViewAlertEventHandler(LayoutWebViewEventHandler::OnAlertEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_JS_CONFIRM, wxWebViewConfirmEventHandler(LayoutWebViewEventHandler::OnConfirmEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_JS_PROMPT, wxWebViewPromptEventHandler(LayoutWebViewEventHandler::OnPromptEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_CONSOLE_MESSAGE, wxWebViewConsoleMessageEventHandler(LayoutWebViewEventHandler::OnConsoleMessageEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_RECEIVED_TITLE, wxWebViewReceivedTitleEventHandler(LayoutWebViewEventHandler::OnReceivedTitleEvent), NULL, this); + m_webView->Connect(wxEVT_WEBVIEW_WINDOW_OBJECT_CLEARED, wxWebViewWindowObjectClearedEventHandler(LayoutWebViewEventHandler::OnWindowObjectClearedEvent), NULL, this); + } + + void OnLoadEvent(wxWebViewLoadEvent& event) + { + + if (event.GetState() == wxWEBVIEW_LOAD_FAILED || event.GetState() == wxWEBVIEW_LOAD_STOPPED) + done = true; + + if (event.GetState() == wxWEBVIEW_LOAD_ONLOAD_HANDLED) { + done = true; + + if (!gLayoutTestController->waitToDump() || notified) { + dump(); + } + } + } + + void OnAlertEvent(wxWebViewAlertEvent& event) + { + fprintf(stdout, "ALERT: %S\n", event.GetMessage().c_str()); + } + + void OnConfirmEvent(wxWebViewConfirmEvent& event) + { + fprintf(stdout, "CONFIRM: %S\n", event.GetMessage().c_str()); + event.SetReturnCode(1); + } + + void OnPromptEvent(wxWebViewPromptEvent& event) + { + fprintf(stdout, "PROMPT: %S, default text: %S\n", event.GetMessage().c_str(), event.GetResponse().c_str()); + event.SetReturnCode(1); + } + + void OnConsoleMessageEvent(wxWebViewConsoleMessageEvent& event) + { + fprintf(stdout, "CONSOLE MESSAGE: line %d: %S\n", event.GetLineNumber(), event.GetMessage().c_str()); + } + + void OnReceivedTitleEvent(wxWebViewReceivedTitleEvent& event) + { + if (gLayoutTestController->dumpTitleChanges() && !done) { + const char* title = event.GetTitle().mb_str(wxConvUTF8); + printf("TITLE CHANGED: %S\n", title ? title : ""); + } + } + + void OnWindowObjectClearedEvent(wxWebViewWindowObjectClearedEvent& event) + { + JSValueRef exception = 0; + gLayoutTestController->makeWindowObject(event.GetJSContext(), event.GetWindowObject(), &exception); + } + +private: + wxWebView* m_webView; + +}; + +void notifyDoneFired() +{ + notified = true; + if (done) + dump(); +} + +LayoutWebViewEventHandler* eventHandler = NULL; + +static wxString dumpFramesAsText(wxWebFrame* frame) +{ + // TODO: implement this. leaving this here so we don't forget this case. + if (gLayoutTestController->dumpChildFramesAsText()) { + } + + return frame->GetInnerText(); +} + +void dump() +{ + if (!done) + return; + + if (gLayoutTestController->waitToDump() && !notified) + return; + + if (dumpTree) { + const char* result = 0; + + bool dumpAsText = gLayoutTestController->dumpAsText(); + wxString str; + if (gLayoutTestController->dumpAsText()) + str = dumpFramesAsText(webView->GetMainFrame()); + else + str = webView->GetMainFrame()->GetExternalRepresentation(); + + result = str.ToUTF8(); + if (!result) { + const char* errorMessage; + if (gLayoutTestController->dumpAsText()) + errorMessage = "WebFrame::GetInnerText"; + else + errorMessage = "WebFrame::GetExternalRepresentation"; + printf("ERROR: NULL result from %s", errorMessage); + } else { + printf("%s\n", result); + } + + if (gLayoutTestController->dumpBackForwardList()) { + // FIXME: not implemented + } + + if (printSeparators) { + puts("#EOF"); + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (dumpPixels + && gLayoutTestController->generatePixelResults() + && !gLayoutTestController->dumpDOMAsWebArchive() + && !gLayoutTestController->dumpSourceAsWebArchive()) { + // FIXME: Add support for dumping pixels + fflush(stdout); + } + + puts("#EOF"); + fflush(stdout); + fflush(stderr); + + gLayoutTestController.clear(); +} + +static void runTest(const wxString testPathOrURL) +{ + done = false; + time(&startTime); + string pathOrURLString(testPathOrURL.char_str()); + string pathOrURL(pathOrURLString); + string expectedPixelHash; + + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != string::npos) { + pathOrURL = string(pathOrURLString, 0, separatorPos); + expectedPixelHash = string(pathOrURLString, separatorPos + 1); + } + + // CURL isn't happy if we don't have a protocol. + size_t http = pathOrURL.find("http://"); + if (http == string::npos) + pathOrURL.insert(0, "file://"); + + gLayoutTestController = LayoutTestController::create(pathOrURL, expectedPixelHash); + if (!gLayoutTestController) { + wxTheApp->ExitMainLoop(); + } + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + webView->LoadURL(wxString(pathOrURL.c_str(), wxConvUTF8)); + + // wait until load completes and the results are dumped + while (!done) + wxSafeYield(); +} + +class MyApp : public wxApp +{ +public: + + virtual bool OnInit(); + +private: + wxLog* logger; +}; + + +IMPLEMENT_APP(MyApp) + +bool MyApp::OnInit() +{ + logOutput = fopen("output.txt", "ab"); + if (logOutput) { + logger = new wxLogStderr(logOutput); + wxLog::SetActiveTarget(logger); + } + + wxLogMessage(wxT("Starting DumpRenderTool, %d args.\n"), argc); + + for (int i = 1; i < argc; ++i) { + wxString option = wxString(argv[i]); + if (!option.CmpNoCase(_T("--notree"))) { + dumpTree = false; + continue; + } + + if (!option.CmpNoCase(_T("--pixel-tests"))) { + dumpPixels = true; + continue; + } + + if (!option.CmpNoCase(_T("--tree"))) { + dumpTree = true; + continue; + } + } + wxInitAllImageHandlers(); + + // create the main application window + wxWebBrowserShell* webFrame = new wxWebBrowserShell(_T("wxWebKit DumpRenderTree App"), "about:blank"); + SetTopWindow(webFrame); + webView = webFrame->webview; + webView->SetSize(wxSize(maxViewWidth, maxViewHeight)); + + if (!eventHandler) { + eventHandler = new LayoutWebViewEventHandler(webView); + eventHandler->bindEvents(); + } + + int optind = 1; + time(&startTime); + wxString option_str = wxString(argv[optind]); + if (argc == optind+1 && option_str.Find(_T("-")) == 0) { + char filenameBuffer[2048]; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + wxString filename = wxString::FromUTF8(filenameBuffer); + char* newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (strlen(filenameBuffer) == 0) + return 0; + wxLogMessage(wxT("Running test %S.\n"), filenameBuffer); + runTest(filename); + } + + } else { + printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) { + runTest(wxTheApp->argv[1]); + } + } + + webFrame->Close(); + delete eventHandler; + + wxLog::SetActiveTarget(NULL); + delete logger; + fclose(logOutput); + + // returning false shuts the app down + return false; +} diff --git a/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h new file mode 100644 index 000000000..99092b845 --- /dev/null +++ b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeWx_h +#define DumpRenderTreeWx_h + +extern void notifyDoneFired(); + +#endif // DumpRenderTreeWx_h diff --git a/Tools/DumpRenderTree/wx/GCControllerWx.cpp b/Tools/DumpRenderTree/wx/GCControllerWx.cpp new file mode 100644 index 000000000..bddf62ffb --- /dev/null +++ b/Tools/DumpRenderTree/wx/GCControllerWx.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h" + +void GCController::collect() const +{ +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ +} + +size_t GCController::getJSObjectCount() const +{ + return 0; +} diff --git a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp new file mode 100644 index 000000000..cfd1f6dd6 --- /dev/null +++ b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> + +#include <stdio.h> + + + +LayoutTestController::~LayoutTestController() +{ + // FIXME: implement +} + +void LayoutTestController::addDisallowedURL(JSStringRef url) +{ + // FIXME: implement +} + +void LayoutTestController::clearBackForwardList() +{ +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 +} + +void LayoutTestController::display() +{ +} + +void LayoutTestController::keepWebHistory() +{ + // FIXME: implement +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !WorkQueue::shared()->count()) + notifyDoneFired(); + m_waitToDump = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + // Function introduced in r28690. This may need special-casing on Windows. + return JSStringRetain(url); // Do nothing on Unix. +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + // FIXME: We need to resolve relative URLs here + WorkQueue::shared()->queue(new LoadItem(url, target)); +} + +void LayoutTestController::setAcceptsEditing(bool acceptsEditing) +{ +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + // FIXME: Implement this (and restore the default value before running each test in DumpRenderTree.cpp). +} + +void LayoutTestController::setCustomPolicyDelegate(bool, bool) +{ + // FIXME: implement +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles) +{ + // FIXME: implement +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ +} + +void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value) +{ + // FIXME: implement +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef mode) +{ + // FIXME: implement +} + +void LayoutTestController::setWindowIsKey(bool windowIsKey) +{ + // FIXME: implement +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool flag) +{ +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + static const int timeoutSeconds = 10; + + m_waitToDump = waitUntilDone; +} + +int LayoutTestController::windowCount() +{ + // FIXME: implement + return 1; +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + // FIXME: implement +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled) +{ + // FIXME: implement +} + +void LayoutTestController::setXSSAuditorEnabled(bool enabled) +{ + // FIXME: implement +} + +void LayoutTestController::setFrameFlatteningEnabled(bool enabled) +{ + // FIXME: implement +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) +{ + // FIXME: implement +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + // FIXME: implement +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + // FIXME: implement +} + +void LayoutTestController::setAutofilled(JSContextRef, JSValueRef element, bool isAutofilled) +{ + // FIXME: implement +} + +void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled) +{ + // FIXME: implement +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + // FIXME: Implement +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id) +{ + // FIXME: implement + return false; +} + +void LayoutTestController::execCommand(JSStringRef name, JSStringRef value) +{ + // FIXME: implement +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + // FIXME: implement +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + // FIXME: implement +} + +void LayoutTestController::clearAllApplicationCaches() +{ + // FIXME: Implement to support application cache quotas. +} + +void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef url) +{ + // FIXME: Implement to support deleting all application cache for an origin. +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + return 0; +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + // FIXME: Implement to support application cache quotas. +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef origin) +{ + // FIXME: Implement to support getting disk usage by all application caches for an origin. + return 0; +} + + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that have application caches. + return 0; +} + +void LayoutTestController::clearAllDatabases() +{ + // FIXME: implement +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + // FIXME: implement +} + +void LayoutTestController::goBack() +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setDefersLoading(bool) +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef) +{ + // FIXME: implement +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + // FIXME: implement +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::suspendAnimations() const +{ + // FIXME: implement +} + +void LayoutTestController::resumeAnimations() const +{ + // FIXME: implement +} + +unsigned LayoutTestController::workerThreadCount() const +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag) +{ + // FIXME: implement +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + // FIXME: implement + return false; +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + // FIXME: Implement for DeviceOrientation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=30335. +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. +} + +void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + // FIXME: Implement for Geolocation layout tests. + setGeolocationPermissionCommon(allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + // FIXME: Implement for Geolocation layout tests. + return -1; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled) +{ + // FIXME: implement +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + // FIXME: implement + return false; +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + // FIXME: implement + return false; +} + +void LayoutTestController::setCacheModel(int) +{ + // FIXME: implement +} + +bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/) +{ + // FIXME: implement + return false; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + // FIXME: implement + return 0; +} + +void LayoutTestController::waitForPolicyDelegate() +{ + // FIXME: Implement this. +} + +void LayoutTestController::overridePreference(JSStringRef /* key */, JSStringRef /* value */) +{ + // FIXME: implement +} + +void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + printf("LayoutTestController::addUserScript not implemented.\n"); +} + +void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + printf("LayoutTestController::addUserStyleSheet not implemented.\n"); +} + +void LayoutTestController::showWebInspector() +{ + // FIXME: Implement this. +} + +void LayoutTestController::closeWebInspector() +{ + // FIXME: Implement this. +} + +void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script) +{ + // FIXME: Implement this. +} + +void LayoutTestController::removeAllVisitedLinks() +{ + // FIXME: Implement this. +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + +} + +void LayoutTestController::disableImageLoading() +{ + +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + // FIXME: implement +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + // FIXME: implement +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + return 0; +} + +int LayoutTestController::pageNumberForElementById(JSStringRef, float, float) +{ + // FIXME: implement + return -1; +} + +int LayoutTestController::numberOfPages(float, float) +{ + // FIXME: implement + return -1; +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + +} + +void LayoutTestController::setSpatialNavigationEnabled(bool) +{ + +} + +void LayoutTestController::setWebViewEditable(bool) +{ +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + return false; +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + return 0; +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const +{ + return 0; +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef) +{ + return 0; +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + // FIXME: Implement this. + return 0; +} + +void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ +} + +void LayoutTestController::setEditingBehavior(const char* editingBehavior) +{ + // FIXME: Implement +} + +void LayoutTestController::abortModal() +{ +} + +bool LayoutTestController::hasSpellingMarker(int, int) +{ + // FIXME: Implement + return false; +} + +bool LayoutTestController::hasGrammarMarker(int, int) +{ + // FIXME: Implement + return false; +} + +void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/) +{ + // FIXME: Implement +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const +{ + // FIXME: Implement + return 0; +} + +bool LayoutTestController::isPageBoxVisible(int pageNumber) const +{ + // FIXME: Implement + return true; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const +{ + // FIXME: Implement + return 0; +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + // FIXME: Implement this. +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + // FIXME: Implement + return false; +} + +void LayoutTestController::setSerializeHTTPLoads(bool) +{ + // FIXME: Implement. +} + +void LayoutTestController::setMinimumTimerInterval(double interval) { + +} + +void LayoutTestController::syncLocalStorage() +{ + // FIXME: Implement. +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned number) +{ + // FIXME: Implement. +} + +void LayoutTestController::deleteAllLocalStorage() +{ + // FIXME: Implement. +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + // FIXME: Implement. + return 0; +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL) +{ + // FIXME: Implement. +} + +void LayoutTestController::setTextDirection(JSStringRef direction) +{ + // FIXME: Implement. +} + +void LayoutTestController::allowRoundingHacks() +{ +} + +void LayoutTestController::addChromeInputField() +{ +} + +void LayoutTestController::removeChromeInputField() +{ +} + +void LayoutTestController::focusWebView() +{ +} + +void LayoutTestController::setBackingScaleFactor(double) +{ +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ + // FIXME: Implement. +} diff --git a/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp b/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp new file mode 100644 index 000000000..e6ecb752b --- /dev/null +++ b/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItem.h" + +#include "DumpRenderTree.h" + +bool LoadItem::invoke() const +{ + return false; +} + +bool LoadHTMLStringItem::invoke() const +{ + return false; +} + +bool ReloadItem::invoke() const +{ + return false; +} + +bool ScriptItem::invoke() const +{ + return false; +} + +bool BackForwardItem::invoke() const +{ + return false; +} |
