diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Tools/DumpRenderTree | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Tools/DumpRenderTree')
63 files changed, 7029 insertions, 1625 deletions
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp index d035dea99..dd9996be8 100644 --- a/Tools/DumpRenderTree/AccessibilityController.cpp +++ b/Tools/DumpRenderTree/AccessibilityController.cpp @@ -130,20 +130,6 @@ static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObj return JSValueMakeUndefined(context); } -static JSValueRef enableEnhancedAccessibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); - if (argumentCount == 1) - controller->enableEnhancedAccessibility(JSValueToBoolean(context, arguments[0])); - return JSValueMakeUndefined(context); -} - -static JSValueRef getEnhancedAccessibilityEnabledCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) -{ - AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); - return JSValueMakeBoolean(context, controller->enhancedAccessibilityEnabled()); -} - static JSValueRef getPlatformNameCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject)); @@ -164,14 +150,12 @@ JSClassRef AccessibilityController::getJSClass() { "accessibleElementById", getAccessibleElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "enableEnhancedAccessibility", enableEnhancedAccessibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { 0, 0, 0 } }; static JSStaticValue staticValues[] = { { "focusedElement", getFocusedElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "rootElement", getRootElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "enhancedAccessibilityEnabled", getEnhancedAccessibilityEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "platformName", getPlatformNameCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { 0, 0, 0, 0 } }; diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h index 9f66dd6ee..2f4f6ae9e 100644 --- a/Tools/DumpRenderTree/AccessibilityController.h +++ b/Tools/DumpRenderTree/AccessibilityController.h @@ -64,10 +64,6 @@ public: bool addNotificationListener(JSObjectRef functionCallback); void removeNotificationListener(); - // Enhanced accessibility. - void enableEnhancedAccessibility(bool); - bool enhancedAccessibilityEnabled(); - JSRetainPtr<JSStringRef> platformName() const; #if PLATFORM(WIN) @@ -93,7 +89,7 @@ private: HashMap<PlatformUIElement, JSObjectRef> m_notificationListeners; #endif -#if PLATFORM(COCOA) || PLATFORM(IOS) +#if PLATFORM(MAC) RetainPtr<NotificationHandler> m_globalNotificationHandler; #endif diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.h b/Tools/DumpRenderTree/AccessibilityTextMarker.h index 7809ea459..b890e28a9 100644 --- a/Tools/DumpRenderTree/AccessibilityTextMarker.h +++ b/Tools/DumpRenderTree/AccessibilityTextMarker.h @@ -28,13 +28,13 @@ #include <JavaScriptCore/JSObjectRef.h> -#if PLATFORM(MAC) || PLATFORM(IOS) +#if PLATFORM(MAC) && !PLATFORM(IOS) #define SUPPORTS_AX_TEXTMARKERS 1 #else #define SUPPORTS_AX_TEXTMARKERS 0 #endif -#if PLATFORM(COCOA) +#if PLATFORM(MAC) #include <wtf/RetainPtr.h> typedef CFTypeRef PlatformTextMarker; typedef CFTypeRef PlatformTextMarkerRange; @@ -58,7 +58,7 @@ public: private: static JSClassRef getJSClass(); -#if SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC) +#if SUPPORTS_AX_TEXTMARKERS RetainPtr<PlatformTextMarker> m_textMarker; #else PlatformTextMarker m_textMarker; @@ -78,7 +78,7 @@ public: private: static JSClassRef getJSClass(); -#if SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC) +#if SUPPORTS_AX_TEXTMARKERS RetainPtr<PlatformTextMarkerRange> m_textMarkerRange; #else PlatformTextMarkerRange m_textMarkerRange; diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/AccessibilityUIElement.cpp index 1d77d7717..793b3103d 100644 --- a/Tools/DumpRenderTree/AccessibilityUIElement.cpp +++ b/Tools/DumpRenderTree/AccessibilityUIElement.cpp @@ -209,8 +209,7 @@ static JSValueRef uiElementCountForSearchPredicateCallback(JSContextRef context, JSValueRef searchKey = nullptr; JSRetainPtr<JSStringRef> searchText = nullptr; bool visibleOnly = false; - bool immediateDescendantsOnly = false; - if (argumentCount >= 5 && argumentCount <= 6) { + if (argumentCount == 5) { if (JSValueIsObject(context, arguments[0])) startElement = toAXElement(JSValueToObject(context, arguments[0], exception)); @@ -222,12 +221,9 @@ static JSValueRef uiElementCountForSearchPredicateCallback(JSContextRef context, searchText.adopt(JSValueToStringCopy(context, arguments[3], exception)); visibleOnly = JSValueToBoolean(context, arguments[4]); - - if (argumentCount == 6) - immediateDescendantsOnly = JSValueToBoolean(context, arguments[5]); } - return JSValueMakeNumber(context, toAXElement(thisObject)->uiElementCountForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly, immediateDescendantsOnly)); + return JSValueMakeNumber(context, toAXElement(thisObject)->uiElementCountForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly)); } static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -237,8 +233,7 @@ static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSOb JSValueRef searchKey = nullptr; JSRetainPtr<JSStringRef> searchText = nullptr; bool visibleOnly = false; - bool immediateDescendantsOnly = false; - if (argumentCount >= 5 && argumentCount <= 6) { + if (argumentCount == 5) { if (JSValueIsObject(context, arguments[0])) startElement = toAXElement(JSValueToObject(context, arguments[0], exception)); @@ -250,34 +245,9 @@ static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSOb searchText.adopt(JSValueToStringCopy(context, arguments[3], exception)); visibleOnly = JSValueToBoolean(context, arguments[4]); - - if (argumentCount == 6) - immediateDescendantsOnly = JSValueToBoolean(context, arguments[5]); } - return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly, immediateDescendantsOnly)); -} - -static JSValueRef selectTextWithCriteriaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - if (argumentCount < 2 || argumentCount > 4) - return JSValueMakeUndefined(context); - - JSRetainPtr<JSStringRef> ambiguityResolution(Adopt, JSValueToStringCopy(context, arguments[0], exception)); - JSValueRef searchStrings = arguments[1]; - JSStringRef replacementString = nullptr; - if (argumentCount == 3) - replacementString = JSValueToStringCopy(context, arguments[2], exception); - JSStringRef activityString = nullptr; - if (argumentCount == 4) - activityString = JSValueToStringCopy(context, arguments[3], exception); - - JSRetainPtr<JSStringRef> result(Adopt, toAXElement(thisObject)->selectTextWithCriteria(context, ambiguityResolution.get(), searchStrings, replacementString, activityString)); - if (replacementString) - JSStringRelease(replacementString); - if (activityString) - JSStringRelease(activityString); - return JSValueMakeString(context, result.get()); + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly)); } static JSValueRef indexOfChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -317,13 +287,12 @@ static JSValueRef elementsForRangeCallback(JSContextRef context, JSObjectRef fun Vector<AccessibilityUIElement> elements; toAXElement(thisObject)->elementsForRange(location, length, elements); - JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0); - JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0); unsigned elementsSize = elements.size(); + JSValueRef valueElements[elementsSize]; for (unsigned k = 0; k < elementsSize; ++k) - JSObjectSetPropertyAtIndex(context, arrayObj, k, AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[k]), 0); + valueElements[k] = AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[k]); - return arrayResult; + return JSObjectMakeArray(context, elementsSize, valueElements, 0); } static JSValueRef increaseTextSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -332,26 +301,6 @@ static JSValueRef increaseTextSelectionCallback(JSContextRef context, JSObjectRe return JSValueMakeUndefined(context); } -static JSValueRef scrollPageUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageUp()); -} - -static JSValueRef scrollPageDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageDown()); -} - -static JSValueRef scrollPageLeftCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageLeft()); -} - -static JSValueRef scrollPageRightCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageRight()); -} - static JSValueRef decreaseTextSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { toAXElement(thisObject)->decreaseTextSelection(); @@ -364,11 +313,6 @@ static JSValueRef assistiveTechnologySimulatedFocusCallback(JSContextRef context return JSValueMakeUndefined(context); } -static JSValueRef fieldsetAncestorElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->fieldsetAncestorElement()); -} - #endif static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -425,15 +369,6 @@ static JSValueRef ariaFlowToElementAtIndexCallback(JSContextRef context, JSObjec return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaFlowToElementAtIndex(indexNumber)); } -static JSValueRef ariaControlsElementAtIndexCallback(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)->ariaControlsElementAtIndex(indexNumber)); -} - static JSValueRef selectedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { int indexNumber = 0; @@ -463,19 +398,6 @@ static JSValueRef isEqualCallback(JSContextRef context, JSObjectRef function, JS return JSValueMakeBoolean(context, toAXElement(thisObject)->isEqual(toAXElement(otherElement))); } -static JSValueRef setValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSRetainPtr<JSStringRef> valueText = 0; - if (argumentCount == 1) { - if (JSValueIsString(context, arguments[0])) - valueText.adopt(JSValueToStringCopy(context, arguments[0], exception)); - } - - toAXElement(thisObject)->setValue(valueText.get()); - - return JSValueMakeUndefined(context); -} - static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { JSObjectRef element = 0; @@ -487,24 +409,6 @@ static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef fun return JSValueMakeUndefined(context); } -static JSValueRef setSelectedChildAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - if (argumentCount == 1) { - unsigned indexNumber = JSValueToNumber(context, arguments[0], exception); - toAXElement(thisObject)->setSelectedChildAtIndex(indexNumber); - } - return JSValueMakeUndefined(context); -} - -static JSValueRef removeSelectionAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - if (argumentCount == 1) { - unsigned indexNumber = JSValueToNumber(context, arguments[0], exception); - toAXElement(thisObject)->removeSelectionAtIndex(indexNumber); - } - return JSValueMakeUndefined(context); -} - static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { int x = 0; @@ -566,20 +470,6 @@ static JSValueRef boolAttributeValueCallback(JSContextRef context, JSObjectRef f return result; } -static JSValueRef setBoolAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSStringRef attribute = nullptr; - bool value = false; - if (argumentCount == 2) { - attribute = JSValueToStringCopy(context, arguments[0], exception); - value = JSValueToBoolean(context, arguments[1]); - } - toAXElement(thisObject)->setBoolAttributeValue(attribute, value); - if (attribute) - JSStringRelease(attribute); - return JSValueMakeUndefined(context); -} - static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { JSStringRef attribute = 0; @@ -594,14 +484,12 @@ static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef static JSValueRef convertElementsToObjectArray(JSContextRef context, Vector<AccessibilityUIElement>& elements, JSValueRef* exception) { - JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0); - JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0); - size_t elementCount = elements.size(); + auto valueElements = std::make_unique<JSValueRef[]>(elementCount); for (size_t i = 0; i < elementCount; ++i) - JSObjectSetPropertyAtIndex(context, arrayObj, i, AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[i]), 0); - - return arrayResult; + valueElements[i] = AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[i]); + + return JSObjectMakeArray(context, elementCount, valueElements.get(), exception); } static JSValueRef columnHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -713,36 +601,6 @@ static JSValueRef pressCallback(JSContextRef context, JSObjectRef function, JSOb return JSValueMakeUndefined(context); } -static JSValueRef scrollToMakeVisibleWithSubFocusCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - unsigned x = 0; - unsigned y = 0; - unsigned width = 0; - unsigned height = 0; - if (argumentCount == 4) { - x = JSValueToNumber(context, arguments[0], exception); - y = JSValueToNumber(context, arguments[1], exception); - width = JSValueToNumber(context, arguments[2], exception); - height = JSValueToNumber(context, arguments[3], exception); - } - - toAXElement(thisObject)->scrollToMakeVisibleWithSubFocus(x, y, width, height); - return JSValueMakeUndefined(context); -} - -static JSValueRef scrollToGlobalPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - unsigned x = 0; - unsigned y = 0; - if (argumentCount == 2) { - x = JSValueToNumber(context, arguments[0], exception); - y = JSValueToNumber(context, arguments[1], exception); - } - - toAXElement(thisObject)->scrollToGlobalPoint(x, y); - return JSValueMakeUndefined(context); -} - static JSValueRef scrollToMakeVisibleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { toAXElement(thisObject)->scrollToMakeVisible(); @@ -773,14 +631,6 @@ static JSValueRef removeSelectionCallback(JSContextRef context, JSObjectRef func return JSValueMakeUndefined(context); } -static JSValueRef lineTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* textMarker = nullptr; - if (argumentCount == 1) - textMarker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->lineTextMarkerRangeForTextMarker(textMarker)); -} - static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { AccessibilityUIElement* uiElement = 0; @@ -790,17 +640,6 @@ static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObje return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForElement(uiElement)); } -static JSValueRef selectedTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->selectedTextMarkerRange()); -} - -static JSValueRef resetSelectedTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - toAXElement(thisObject)->resetSelectedTextMarkerRange(); - return JSValueMakeUndefined(context); -} - static JSValueRef attributedStringForTextMarkerRangeContainsAttributeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { AccessibilityTextMarkerRange* markerRange = 0; @@ -974,109 +813,6 @@ static JSValueRef endTextMarkerCallback(JSContextRef context, JSObjectRef thisOb return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarker()); } -static JSValueRef leftWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->leftWordTextMarkerRangeForTextMarker(marker)); -} - -static JSValueRef rightWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->rightWordTextMarkerRangeForTextMarker(marker)); -} - -static JSValueRef previousWordStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousWordStartTextMarkerForTextMarker(marker)); -} - -static JSValueRef nextWordEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextWordEndTextMarkerForTextMarker(marker)); -} - -static JSValueRef paragraphTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->paragraphTextMarkerRangeForTextMarker(marker)); -} - -static JSValueRef previousParagraphStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousParagraphStartTextMarkerForTextMarker(marker)); -} - -static JSValueRef nextParagraphEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextParagraphEndTextMarkerForTextMarker(marker)); -} - -static JSValueRef sentenceTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->sentenceTextMarkerRangeForTextMarker(marker)); -} - -static JSValueRef previousSentenceStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousSentenceStartTextMarkerForTextMarker(marker)); -} - -static JSValueRef nextSentenceEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityTextMarker* marker = nullptr; - if (argumentCount == 1) - marker = toTextMarker(JSValueToObject(context, arguments[0], exception)); - - return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextSentenceEndTextMarkerForTextMarker(marker)); -} - -static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - AccessibilityUIElement* uiElement = toAXElement(thisObject); - AccessibilityTextMarkerRange* textMarkerRange = nullptr; - if (argumentCount == 1) - textMarkerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception)); - - if (uiElement) - return JSValueMakeBoolean(context, uiElement->setSelectedVisibleTextRange(textMarkerRange)); - - return JSValueMakeBoolean(context, false); -} - // Static Value Getters static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) @@ -1125,12 +861,6 @@ static JSValueRef getRoleDescriptionCallback(JSContextRef context, JSObjectRef t return JSValueMakeString(context, roleDesc.get()); } -static JSValueRef getComputedRoleStringCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) -{ - JSRetainPtr<JSStringRef> compRole(Adopt, toAXElement(thisObject)->computedRoleString()); - return JSValueMakeString(context, compRole.get()); -} - static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { JSRetainPtr<JSStringRef> title(Adopt, toAXElement(thisObject)->title()); @@ -1439,48 +1169,56 @@ static JSValueRef sentenceAtOffsetCallback(JSContextRef context, JSObjectRef fun #elif PLATFORM(IOS) -static JSValueRef getIsSearchFieldCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef stringForSelectionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - return JSValueMakeBoolean(context, toAXElement(thisObject)->isSearchField()); + JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->stringForSelection()); + return JSValueMakeString(context, labelString.get()); } -static JSValueRef getIsTextAreaCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneLabelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - return JSValueMakeBoolean(context, toAXElement(thisObject)->isTextArea()); + JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->iphoneLabel()); + return JSValueMakeString(context, labelString.get()); } -static JSValueRef stringForSelectionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneHintCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->stringForSelection()); - return JSValueMakeString(context, labelString.get()); + JSRetainPtr<JSStringRef> hintString(Adopt, toAXElement(thisObject)->iphoneHint()); + return JSValueMakeString(context, hintString.get()); } -static JSValueRef getIdentifierCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->identifier()); + JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneValue()); + return JSValueMakeString(context, valueString.get()); +} + +static JSValueRef getIPhoneIdentifierCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneIdentifier()); return JSValueMakeString(context, valueString.get()); } -static JSValueRef getTraitsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneTraitsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->traits()); + JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneTraits()); return JSValueMakeString(context, valueString.get()); } -static JSValueRef getElementTextPositionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneIsElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - return JSValueMakeNumber(context, toAXElement(thisObject)->elementTextPosition()); + return JSValueMakeBoolean(context, toAXElement(thisObject)->iphoneIsElement()); } -static JSValueRef getElementTextLengthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +static JSValueRef getIPhoneElementTextPositionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - return JSValueMakeNumber(context, toAXElement(thisObject)->elementTextLength()); + return JSValueMakeNumber(context, toAXElement(thisObject)->iphoneElementTextPosition()); } -static JSValueRef hasContainedByFieldsetTraitCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*) +static JSValueRef getIPhoneElementTextLengthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { - return JSValueMakeBoolean(context, toAXElement(thisObject)->hasContainedByFieldsetTrait()); + return JSValueMakeNumber(context, toAXElement(thisObject)->iphoneElementTextLength()); } #endif // PLATFORM(IOS) @@ -1514,8 +1252,8 @@ JSStringRef AccessibilityUIElement::speak() { return 0; } JSStringRef AccessibilityUIElement::rangeForLine(int line) { return 0; } JSStringRef AccessibilityUIElement::rangeForPosition(int, int) { return 0; } void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { } -void AccessibilityUIElement::setSelectedChildAtIndex(unsigned) const { } -void AccessibilityUIElement::removeSelectionAtIndex(unsigned) 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; } @@ -1523,11 +1261,12 @@ AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringR #if !PLATFORM(MAC) && !PLATFORM(IOS) JSStringRef AccessibilityUIElement::pathDescription() const { return 0; } -void AccessibilityUIElement::setValue(JSStringRef) { } #endif -#if !PLATFORM(COCOA) +#if !PLATFORM(MAC) void AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef, Vector<AccessibilityUIElement>&) const { } +void AccessibilityUIElement::columnHeaders(Vector<AccessibilityUIElement>&) const { } +void AccessibilityUIElement::rowHeaders(Vector<AccessibilityUIElement>&) const { } #endif #if !PLATFORM(WIN) @@ -1539,31 +1278,13 @@ bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) } #endif -#if !PLATFORM(MAC) -void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { } -#endif - #if !SUPPORTS_AX_TEXTMARKERS -AccessibilityTextMarkerRange AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*) { return 0; } -AccessibilityTextMarkerRange AccessibilityUIElement::selectedTextMarkerRange() -{ - return nullptr; -} - -void AccessibilityUIElement::resetSelectedTextMarkerRange() -{ -} - int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*) { return 0; @@ -1649,61 +1370,6 @@ AccessibilityTextMarker AccessibilityUIElement::endTextMarker() return nullptr; } -bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*) -{ - return false; -} - -AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarkerRange AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - -AccessibilityTextMarker AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*) -{ - return nullptr; -} - #endif // Destruction @@ -1730,7 +1396,6 @@ JSClassRef AccessibilityUIElement::getJSClass() { "role", getRoleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "subrole", getSubroleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "roleDescription", getRoleDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "computedRoleString", getComputedRoleStringCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1784,14 +1449,15 @@ JSClassRef AccessibilityUIElement::getJSClass() { "startTextMarker", startTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "endTextMarker", endTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, #if PLATFORM(IOS) - { "identifier", getIdentifierCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "traits", getTraitsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "elementTextPosition", getElementTextPositionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "elementTextLength", getElementTextLengthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneLabel", getIPhoneLabelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneHint", getIPhoneHintCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneValue", getIPhoneValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneIdentifier", getIPhoneIdentifierCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneTraits", getIPhoneTraitsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneIsElement", getIPhoneIsElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneElementTextPosition", getIPhoneElementTextPositionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "iphoneElementTextLength", getIPhoneElementTextLengthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "stringForSelection", stringForSelectionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "hasContainedByFieldsetTrait", hasContainedByFieldsetTraitCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "isSearchField", getIsSearchFieldCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "isTextArea", getIsTextAreaCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, #endif // PLATFORM(IOS) #if PLATFORM(MAC) && !PLATFORM(IOS) { "supportedActions", supportedActionsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1814,9 +1480,8 @@ JSClassRef AccessibilityUIElement::getJSClass() { "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "attributedStringForRange", attributedStringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "attributedStringRangeIsMisspelled", attributedStringRangeIsMisspelledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "uiElementCountForSearchPredicate", uiElementCountForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "uiElementCountForSearchPredicate", uiElementCountForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeReadOnly }, { "uiElementForSearchPredicate", uiElementForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "selectTextWithCriteria", selectTextWithCriteriaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "indexOfChild", indexOfChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1840,7 +1505,6 @@ JSClassRef AccessibilityUIElement::getJSClass() { "uiElementAttributeValue", uiElementAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "numberAttributeValue", numberAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "boolAttributeValue", boolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "setBoolAttributeValue", setBoolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isAttributeSupported", isAttributeSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isAttributeSettable", isAttributeSettableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isPressActionSupported", isPressActionSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1855,7 +1519,6 @@ JSClassRef AccessibilityUIElement::getJSClass() { "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "ariaControlsElementAtIndex", ariaControlsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "rowAtIndex", rowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1865,10 +1528,7 @@ JSClassRef AccessibilityUIElement::getJSClass() { "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "removeSelection", removeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "lineTextMarkerRangeForTextMarker", lineTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "textMarkerRangeForElement", textMarkerRangeForElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "selectedTextMarkerRange", selectedTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "resetSelectedTextMarkerRange", resetSelectedTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "attributedStringForTextMarkerRangeContainsAttribute", attributedStringForTextMarkerRangeContainsAttributeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "indexForTextMarker", indexForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isTextMarkerValid", isTextMarkerValidCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1884,25 +1544,9 @@ JSClassRef AccessibilityUIElement::getJSClass() { "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "paragraphTextMarkerRangeForTextMarker", paragraphTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "previousParagraphStartTextMarkerForTextMarker", previousParagraphStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "nextParagraphEndTextMarkerForTextMarker", nextParagraphEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "sentenceTextMarkerRangeForTextMarker", sentenceTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "previousSentenceStartTextMarkerForTextMarker", previousSentenceStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "nextSentenceEndTextMarkerForTextMarker", nextSentenceEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "removeSelectionAtIndex", removeSelectionAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "setValue", setValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "setSelectedVisibleTextRange", setSelectedVisibleTextRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "selectedChildAtIndex", selectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "scrollToMakeVisible", scrollToMakeVisibleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollToGlobalPoint", scrollToGlobalPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollToMakeVisibleWithSubFocus", scrollToMakeVisibleWithSubFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, #if PLATFORM(GTK) || PLATFORM(EFL) { "characterAtOffset", characterAtOffsetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "wordAtOffset", wordAtOffsetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1914,12 +1558,8 @@ JSClassRef AccessibilityUIElement::getJSClass() { "elementsForRange", elementsForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "increaseTextSelection", increaseTextSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "decreaseTextSelection", decreaseTextSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollPageUp", scrollPageUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollPageDown", scrollPageDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollPageLeft", scrollPageLeftCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "scrollPageRight", scrollPageRightCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "assistiveTechnologySimulatedFocus", assistiveTechnologySimulatedFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "fieldsetAncestorElement", fieldsetAncestorElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + #endif { 0, 0, 0 } }; diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.h b/Tools/DumpRenderTree/AccessibilityUIElement.h index 4abf9e9aa..f1f21b69b 100644 --- a/Tools/DumpRenderTree/AccessibilityUIElement.h +++ b/Tools/DumpRenderTree/AccessibilityUIElement.h @@ -31,7 +31,7 @@ #include <wtf/Platform.h> #include <wtf/Vector.h> -#if PLATFORM(COCOA) +#if PLATFORM(MAC) #ifdef __OBJC__ typedef id PlatformUIElement; #else @@ -53,7 +53,7 @@ typedef AtkObject* PlatformUIElement; typedef void* PlatformUIElement; #endif -#if PLATFORM(COCOA) +#if PLATFORM(MAC) #ifdef __OBJC__ typedef id NotificationHandler; #else @@ -109,7 +109,6 @@ public: void uiElementArrayAttributeValue(JSStringRef attribute, Vector<AccessibilityUIElement>& elements) const; AccessibilityUIElement uiElementAttributeValue(JSStringRef attribute) const; bool boolAttributeValue(JSStringRef attribute); - void setBoolAttributeValue(JSStringRef attribute, bool value); bool isAttributeSupported(JSStringRef attribute); bool isAttributeSettable(JSStringRef attribute); bool isPressActionSupported(); @@ -118,13 +117,11 @@ public: JSStringRef role(); JSStringRef subrole(); JSStringRef roleDescription(); - JSStringRef computedRoleString(); JSStringRef title(); JSStringRef description(); JSStringRef language(); JSStringRef stringValue(); JSStringRef accessibilityValue() const; - void setValue(JSStringRef); JSStringRef helpText() const; JSStringRef orientation() const; double x(); @@ -150,8 +147,6 @@ public: void setSelectedChild(AccessibilityUIElement*) const; unsigned selectedChildrenCount() const; AccessibilityUIElement selectedChildAtIndex(unsigned) const; - void setSelectedChildAtIndex(unsigned) const; - void removeSelectionAtIndex(unsigned) const; bool isExpanded() const; bool isChecked() const; @@ -196,7 +191,6 @@ public: // ARIA specific AccessibilityUIElement ariaOwnsElementAtIndex(unsigned); AccessibilityUIElement ariaFlowToElementAtIndex(unsigned); - AccessibilityUIElement ariaControlsElementAtIndex(unsigned); // ARIA Drag and Drop bool ariaIsGrabbed() const; @@ -212,23 +206,14 @@ public: JSStringRef stringForRange(unsigned location, unsigned length); JSStringRef attributedStringForRange(unsigned location, unsigned length); bool attributedStringRangeIsMisspelled(unsigned location, unsigned length); - unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly); - AccessibilityUIElement uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly); - JSStringRef selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity); + unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly); + AccessibilityUIElement uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly); #if PLATFORM(IOS) void elementsForRange(unsigned location, unsigned length, Vector<AccessibilityUIElement>& elements); JSStringRef stringForSelection(); void increaseTextSelection(); void decreaseTextSelection(); AccessibilityUIElement linkedElement(); - - bool scrollPageUp(); - bool scrollPageDown(); - bool scrollPageLeft(); - bool scrollPageRight(); - - bool hasContainedByFieldsetTrait(); - AccessibilityUIElement fieldsetAncestorElement(); #endif #if PLATFORM(GTK) || PLATFORM(EFL) @@ -247,7 +232,6 @@ public: AccessibilityUIElement verticalScrollbar() const; // Text markers. - AccessibilityTextMarkerRange lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*); AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement*); AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker); AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); @@ -260,19 +244,6 @@ public: AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*); AccessibilityTextMarker startTextMarker(); AccessibilityTextMarker endTextMarker(); - AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarkerRange sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarker nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*); - AccessibilityTextMarkerRange selectedTextMarkerRange(); - void resetSelectedTextMarkerRange(); - bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*); JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*); int textMarkerRangeLength(AccessibilityTextMarkerRange*); @@ -292,17 +263,17 @@ public: void removeNotificationListener(); #if PLATFORM(IOS) - JSStringRef traits(); - JSStringRef identifier(); - int elementTextPosition(); - int elementTextLength(); + JSStringRef iphoneLabel(); + JSStringRef iphoneValue(); + JSStringRef iphoneTraits(); + JSStringRef iphoneHint(); + JSStringRef iphoneIdentifier(); + bool iphoneIsElement(); + int iphoneElementTextPosition(); + int iphoneElementTextLength(); AccessibilityUIElement headerElementAtIndex(unsigned); // This will simulate the accessibilityDidBecomeFocused API in UIKit. void assistiveTechnologySimulatedFocus(); - - bool isTextArea() const; - bool isSearchField() const; - #endif // PLATFORM(IOS) #if PLATFORM(MAC) && !PLATFORM(IOS) @@ -318,7 +289,9 @@ private: static JSClassRef getJSClass(); PlatformUIElement m_element; -#if PLATFORM(COCOA) +#if PLATFORM(IOS) + JSObjectRef m_notificationFunctionCallback; +#elif PLATFORM(MAC) // A retained, platform specific object used to help manage notifications for this object. NotificationHandler m_notificationHandler; #endif diff --git a/Tools/DumpRenderTree/CMakeLists.txt b/Tools/DumpRenderTree/CMakeLists.txt deleted file mode 100644 index 1baa510fb..000000000 --- a/Tools/DumpRenderTree/CMakeLists.txt +++ /dev/null @@ -1,127 +0,0 @@ -set(DumpRenderTree_SOURCES - AccessibilityController.cpp - AccessibilityTextMarker.cpp - AccessibilityUIElement.cpp - CyclicRedundancyCheck.cpp - DumpRenderTreeCommon.cpp - GCController.cpp - JavaScriptThreading.cpp - PixelDumpSupport.cpp - TestRunner.cpp - WorkQueue.cpp -) - -set(DumpRenderTree_LIBRARIES - JavaScriptCore - WTF - WebCoreTestSupport - WebKit -) - -set(DumpRenderTree_INCLUDE_DIRECTORIES - ${WEBCORE_DIR} - ${WEBCORE_DIR}/bindings - ${WEBCORE_DIR}/bridge - ${WEBCORE_DIR}/bridge/jsc - ${WEBCORE_DIR}/css - ${WEBCORE_DIR}/dom - ${WEBCORE_DIR}/editing - ${WEBCORE_DIR}/history - ${WEBCORE_DIR}/html - ${WEBCORE_DIR}/inspector - ${WEBCORE_DIR}/loader - ${WEBCORE_DIR}/loader/cache - ${WEBCORE_DIR}/loader/icon - ${WEBCORE_DIR}/page - ${WEBCORE_DIR}/page/animation - ${WEBCORE_DIR}/platform - ${WEBCORE_DIR}/platform/animation - ${WEBCORE_DIR}/platform/graphics - ${WEBCORE_DIR}/platform/graphics/transforms - ${WEBCORE_DIR}/platform/network - ${WEBCORE_DIR}/platform/text - ${WEBCORE_DIR}/plugins - ${WEBCORE_DIR}/rendering - ${WEBCORE_DIR}/rendering/shapes - ${WEBCORE_DIR}/rendering/style - ${JAVASCRIPTCORE_DIR} - ${JAVASCRIPTCORE_DIR}/API - ${JAVASCRIPTCORE_DIR}/assembler - ${JAVASCRIPTCORE_DIR}/bytecode - ${JAVASCRIPTCORE_DIR}/dfg - ${JAVASCRIPTCORE_DIR}/disassembler - ${JAVASCRIPTCORE_DIR}/heap - ${JAVASCRIPTCORE_DIR}/interpreter - ${JAVASCRIPTCORE_DIR}/jit - ${JAVASCRIPTCORE_DIR}/llint - ${JAVASCRIPTCORE_DIR}/parser - ${JAVASCRIPTCORE_DIR}/profiler - ${JAVASCRIPTCORE_DIR}/runtime - ${JAVASCRIPTCORE_DIR}/ForwardingHeaders - ${DERIVED_SOURCES_DIR}/ForwardingHeaders - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR} - ${TOOLS_DIR}/DumpRenderTree - ${WTF_DIR} - ${CMAKE_SOURCE_DIR}/Source - ${CMAKE_BINARY_DIR} - ${DERIVED_SOURCES_DIR} - ${DERIVED_SOURCES_WEBCORE_DIR} - ${WEBCORE_DIR}/bindings/js - ${WEBCORE_DIR}/testing/js -) - -set(TestNetscapePlugin_SOURCES - TestNetscapePlugin/PluginObject.cpp - TestNetscapePlugin/PluginTest.cpp - TestNetscapePlugin/TestObject.cpp - TestNetscapePlugin/main.cpp - - 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/LogNPPSetWindow.cpp - TestNetscapePlugin/Tests/NPDeallocateCalledBeforeNPShutdown.cpp - TestNetscapePlugin/Tests/NPPNewFails.cpp - TestNetscapePlugin/Tests/NPPSetWindowCalledDuringDestruction.cpp - TestNetscapePlugin/Tests/NPRuntimeCallsWithNullNPP.cpp - TestNetscapePlugin/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp - TestNetscapePlugin/Tests/NPRuntimeRemoveProperty.cpp - TestNetscapePlugin/Tests/NullNPPGetValuePointer.cpp - TestNetscapePlugin/Tests/PassDifferentNPPStruct.cpp - TestNetscapePlugin/Tests/PluginScriptableNPObjectInvokeDefault.cpp - TestNetscapePlugin/Tests/PluginScriptableObjectOverridesAllProperties.cpp - TestNetscapePlugin/Tests/PrivateBrowsing.cpp - TestNetscapePlugin/Tests/ToStringAndValueOfObject.cpp - TestNetscapePlugin/Tests/URLRedirect.cpp -) - -set(TestNetscapePlugin_LIBRARIES - JavaScriptCore - WTF - WebCoreTestSupport - WebKit -) - -list(APPEND TestNetscapePlugin_LIBRARIES - WebKit -) - -WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() - -include_directories(${DumpRenderTree_INCLUDE_DIRECTORIES}) - -add_executable(DumpRenderTree ${DumpRenderTree_SOURCES}) -target_link_libraries(DumpRenderTree ${DumpRenderTree_LIBRARIES}) -set_target_properties(DumpRenderTree PROPERTIES FOLDER "Tools") - -add_library(TestNetscapePlugin SHARED ${TestNetscapePlugin_SOURCES}) -target_link_libraries(TestNetscapePlugin ${TestNetscapePlugin_LIBRARIES}) -set_target_properties(TestNetscapePlugin PROPERTIES FOLDER "Tools") - -if (WIN32) - add_dependencies(DumpRenderTree DumpRenderTreeLib) -endif () diff --git a/Tools/DumpRenderTree/DefaultPolicyDelegate.h b/Tools/DumpRenderTree/DefaultPolicyDelegate.h deleted file mode 100644 index 6ff5becca..000000000 --- a/Tools/DumpRenderTree/DefaultPolicyDelegate.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// DefaultPolicyDelegate.h -// DumpRenderTree -// -// Created by Anders Carlsson on 7/9/13. -// -// - -#import <WebKit/WebDefaultPolicyDelegate.h> - -@interface DefaultPolicyDelegate : WebDefaultPolicyDelegate - -@end diff --git a/Tools/DumpRenderTree/DumpRenderTree.h b/Tools/DumpRenderTree/DumpRenderTree.h index 2a2ea1467..3e6323525 100644 --- a/Tools/DumpRenderTree/DumpRenderTree.h +++ b/Tools/DumpRenderTree/DumpRenderTree.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -34,7 +34,7 @@ #include <wtf/Platform.h> #endif -#if PLATFORM(COCOA) +#if PLATFORM(MAC) #include "DumpRenderTreeMac.h" #elif PLATFORM(WIN) #include "DumpRenderTreeWin.h" diff --git a/Tools/DumpRenderTree/DumpRenderTree.sln b/Tools/DumpRenderTree/DumpRenderTree.sln deleted file mode 100644 index 7cce30330..000000000 --- a/Tools/DumpRenderTree/DumpRenderTree.sln +++ /dev/null @@ -1,100 +0,0 @@ -
-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/DumpRenderTreeFileDraggingSource.h b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h deleted file mode 100644 index 1d42a474c..000000000 --- a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -#if !PLATFORM(IOS) - -#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 - -#endif diff --git a/Tools/DumpRenderTree/DumpRenderTreePrefix.h b/Tools/DumpRenderTree/DumpRenderTreePrefix.h index 105b54356..64eae0704 100644 --- a/Tools/DumpRenderTree/DumpRenderTreePrefix.h +++ b/Tools/DumpRenderTree/DumpRenderTreePrefix.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -26,17 +26,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE) -#include "cmakeconfig.h" -#endif - #include <wtf/Platform.h> #ifdef __OBJC__ #import <Foundation/Foundation.h> #endif - -#if OS(WINDOWS) -#undef WEBCORE_EXPORT -#define WEBCORE_EXPORT WTF_IMPORT_DECLARATION -#endif diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h deleted file mode 100644 index 7731671c8..000000000 --- a/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h +++ /dev/null @@ -1 +0,0 @@ -#include <JavaScriptCore/ArrayBufferView.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h deleted file mode 100644 index e38a8040f..000000000 --- a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h +++ /dev/null @@ -1 +0,0 @@ -#include <JavaScriptCore/JSArrayBufferView.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h deleted file mode 100644 index 4c5dcb983..000000000 --- a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h +++ /dev/null @@ -1 +0,0 @@ -#include <JavaScriptCore/JSExportMacros.h>
\ No newline at end of file diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h deleted file mode 100644 index 6a61945ea..000000000 --- a/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h +++ /dev/null @@ -1 +0,0 @@ -#include <JavaScriptCore/TypedArrayInlines.h> diff --git a/Tools/DumpRenderTree/GCController.cpp b/Tools/DumpRenderTree/GCController.cpp index 781a828eb..06a04fbca 100644 --- a/Tools/DumpRenderTree/GCController.cpp +++ b/Tools/DumpRenderTree/GCController.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/GCController.h b/Tools/DumpRenderTree/GCController.h index 79ceafc9f..afc1de087 100644 --- a/Tools/DumpRenderTree/GCController.h +++ b/Tools/DumpRenderTree/GCController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/JavaScriptThreading.cpp b/Tools/DumpRenderTree/JavaScriptThreading.cpp deleted file mode 100644 index e2f9bade6..000000000 --- a/Tools/DumpRenderTree/JavaScriptThreading.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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> - * (C) 2012 Patrick Ganstere <paroga@paroga.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 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 <JavaScriptCore/JavaScriptCore.h> -#include <stdlib.h> -#include <wtf/Assertions.h> -#include <wtf/HashSet.h> -#include <wtf/Lock.h> -#include <wtf/Threading.h> -#include <wtf/ThreadingPrimitives.h> -#include <wtf/Vector.h> - -static const size_t javaScriptThreadsCount = 4; -static bool javaScriptThreadsShouldTerminate; -static JSContextGroupRef javaScriptThreadsGroup; - -static Lock& javaScriptThreadsMutex() -{ - DEPRECATED_DEFINE_STATIC_LOCAL(Lock, staticMutex, ()); - return staticMutex; -} - -typedef HashSet<ThreadIdentifier> ThreadSet; -static ThreadSet& javaScriptThreads() -{ - DEPRECATED_DEFINE_STATIC_LOCAL(ThreadSet, staticJavaScriptThreads, ()); - ASSERT(!javaScriptThreadsMutex().tryLock()); - 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*) -{ - static const char* const script = - "var array = [];" - "for (var i = 0; i < 1024; i++) {" - " array.push(String(i));" - "}"; - - JSGlobalContextRef ctx; - { - LockHolder locker(javaScriptThreadsMutex()); - ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0); - } - - JSStringRef scriptRef; - { - LockHolder locker(javaScriptThreadsMutex()); - scriptRef = JSStringCreateWithUTF8CString(script); - } - - while (true) { - { - LockHolder locker(javaScriptThreadsMutex()); - JSValueRef exception = 0; - JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); - ASSERT(!exception); - } - - { - LockHolder locker(javaScriptThreadsMutex()); - const size_t valuesCount = 1024; - JSValueRef values[valuesCount]; - for (size_t i = 0; i < valuesCount; ++i) - values[i] = JSObjectMake(ctx, 0, 0); - } - - { - LockHolder locker(javaScriptThreadsMutex()); - if (javaScriptThreadsShouldTerminate) - break; - } - - // Respawn probabilistically. - if (rand() % 5) - continue; - - LockHolder locker(javaScriptThreadsMutex()); - ThreadIdentifier thread = currentThread(); - detachThread(thread); - javaScriptThreads().remove(thread); - javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0)); - break; - } - - LockHolder locker(javaScriptThreadsMutex()); - JSStringRelease(scriptRef); - JSGarbageCollect(ctx); - JSGlobalContextRelease(ctx); -} - -void startJavaScriptThreads() -{ - javaScriptThreadsGroup = JSContextGroupCreate(); - - LockHolder locker(javaScriptThreadsMutex()); - - for (size_t i = 0; i < javaScriptThreadsCount; ++i) - javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0)); -} - -void stopJavaScriptThreads() -{ - { - LockHolder locker(javaScriptThreadsMutex()); - javaScriptThreadsShouldTerminate = true; - } - - Vector<ThreadIdentifier, javaScriptThreadsCount> threads; - { - LockHolder locker(javaScriptThreadsMutex()); - copyToVector(javaScriptThreads(), threads); - ASSERT(threads.size() == javaScriptThreadsCount); - } - - for (size_t i = 0; i < javaScriptThreadsCount; ++i) - waitForThreadCompletion(threads[i]); - - { - LockHolder locker(javaScriptThreadsMutex()); - javaScriptThreads().clear(); - } - - JSContextGroupRelease(javaScriptThreadsGroup); -} diff --git a/Tools/DumpRenderTree/JavaScriptThreading.h b/Tools/DumpRenderTree/JavaScriptThreading.h index 5bbe9cafe..43795a1a2 100644 --- a/Tools/DumpRenderTree/JavaScriptThreading.h +++ b/Tools/DumpRenderTree/JavaScriptThreading.h @@ -12,7 +12,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/PixelDumpSupport.cpp b/Tools/DumpRenderTree/PixelDumpSupport.cpp index aeb902ceb..ba619bbea 100644 --- a/Tools/DumpRenderTree/PixelDumpSupport.cpp +++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -43,6 +43,7 @@ #include "PixelDumpSupportCairo.h" #endif +#if !PLATFORM(IOS) void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash) { RefPtr<BitmapContext> context; @@ -73,6 +74,7 @@ void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash) if (dumpImage) dumpBitmap(context.get(), actualHash); } +#endif static void appendIntToVector(unsigned number, Vector<unsigned char>& vector) { diff --git a/Tools/DumpRenderTree/PixelDumpSupport.h b/Tools/DumpRenderTree/PixelDumpSupport.h index a0ec1e1c7..3bd8820c7 100644 --- a/Tools/DumpRenderTree/PixelDumpSupport.h +++ b/Tools/DumpRenderTree/PixelDumpSupport.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt b/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt deleted file mode 100644 index c431667b2..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -set(WEBKIT_TESTNETSCAPEPLUGIN_DIR "${TOOLS_DIR}/DumpRenderTree/TestNetscapePlugIn") - -set(WebKitTestNetscapePlugin_SOURCES - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/PluginObject.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/PluginTest.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/TestObject.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/main.cpp - - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/DocumentOpenInDestroyStream.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/EvaluateJSAfterRemovingPluginElement.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/FormValue.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLWithJavaScriptURL.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/LogNPPSetWindow.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPDeallocateCalledBeforeNPShutdown.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPPNewFails.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPPSetWindowCalledDuringDestruction.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeCallsWithNullNPP.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeRemoveProperty.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NullNPPGetValuePointer.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PassDifferentNPPStruct.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PluginScriptableNPObjectInvokeDefault.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PluginScriptableObjectOverridesAllProperties.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PrivateBrowsing.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/ToStringAndValueOfObject.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/URLRedirect.cpp - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp -) - -set(WebKitTestNetscapePlugin_INCLUDE_DIRECTORIES - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR} - ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/ForwardingHeaders - ${WEBCORE_DIR} - ${WTF_DIR} -) - -set(WebKitTestNetscapePlugin_SYSTEM_INCLUDE_DIRECTORIES - ${X11_INCLUDE_DIR} -) - -include_directories(${WebKitTestNetscapePlugin_INCLUDE_DIRECTORIES}) -include_directories(SYSTEM ${WebKitTestNetscapePlugin_SYSTEM_INCLUDE_DIRECTORIES}) - -set(WebKitTestNetscapePlugin_LIBRARIES - ${X11_LIBRARIES} -) - -if (WTF_OS_UNIX) - add_definitions(-DXP_UNIX) -endif () - -add_library(TestNetscapePlugin SHARED ${WebKitTestNetscapePlugin_SOURCES}) -target_link_libraries(TestNetscapePlugin ${WebKitTestNetscapePlugin_LIBRARIES}) -set_target_properties(TestNetscapePlugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins) -WEBKIT_SET_EXTRA_COMPILER_FLAGS(TestNetscapePlugin) - -# Suppress unused parameter warnings for sources in WebKit2. -ADD_TARGET_PROPERTIES(TestNetscapePlugin COMPILE_FLAGS "-Wno-unused-parameter") diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp index 982452b68..75631842f 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp @@ -30,14 +30,10 @@ #include "PluginTest.h" #include "TestObject.h" #include <assert.h> -#include <memory> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <wtf/Platform.h> -#include <wtf/ExportMacros.h> -#include <wtf/Assertions.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) @@ -64,7 +60,6 @@ static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, cons browser->releaseobject(consoleObject); } -WTF_ATTRIBUTE_PRINTF(2, 0) void pluginLogWithArguments(NPP instance, const char* format, va_list args) { const size_t messageBufferSize = 2048; @@ -85,7 +80,6 @@ void pluginLogWithArguments(NPP instance, const char* format, va_list args) } // Helper function to log to the console object. -WTF_ATTRIBUTE_PRINTF(2, 3) void pluginLog(NPP instance, const char* format, ...) { va_list args; @@ -776,15 +770,11 @@ static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, return true; } -static std::unique_ptr<char[]> toCString(const NPString& string) +static char* toCString(const NPString& string) { - size_t length = string.UTF8Length; - std::unique_ptr<char[]> result(new char[length + 1]); - if (!result) - return result; - - memcpy(result.get(), string.UTF8Characters, length); - result[length] = '\0'; + char* result = static_cast<char*>(malloc(string.UTF8Length + 1)); + memcpy(result, string.UTF8Characters, string.UTF8Length); + result[string.UTF8Length] = '\0'; return result; } @@ -795,27 +785,30 @@ static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t a return false; NPString urlString = NPVARIANT_TO_STRING(args[0]); - auto url = toCString(urlString); + char* url = toCString(urlString); NPString targetString = NPVARIANT_TO_STRING(args[1]); - auto target = toCString(targetString); + char* target = toCString(targetString); NPString pathString = NPVARIANT_TO_STRING(args[2]); - auto path = toCString(pathString); + char* path = toCString(pathString); NPString contentsString = NPVARIANT_TO_STRING(args[3]); - FILE* tempFile = fopen(path.get(), "w"); + FILE* tempFile = fopen(path, "w"); if (!tempFile) return false; - size_t count = fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile); + if (!fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile)) + return false; + fclose(tempFile); - if (!count) - return false; + NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE); - NPError error = browser->posturl(obj->npp, url.get(), target.get(), pathString.UTF8Length, path.get(), TRUE); + free(path); + free(target); + free(url); BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result); return true; @@ -974,14 +967,15 @@ bool testWindowOpen(NPP npp) static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) { - std::unique_ptr<char[]> message; + 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); - browser->status(obj->npp, message.get()); - + free(message); return true; } diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp index da78148d4..c2195c5b1 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp @@ -28,9 +28,6 @@ #include "PluginObject.h" #include <assert.h> #include <string.h> -#include <wtf/Platform.h> -#include <wtf/ExportMacros.h> -#include <wtf/Assertions.h> #if defined(XP_UNIX) || defined(ANDROID) #include <unistd.h> @@ -136,11 +133,6 @@ bool PluginTest::NPP_URLNotify(const char* url, NPReason, void* notifyData) return false; } -void PluginTest::NPP_URLRedirectNotify(const char*, int32_t, void* notifyData) -{ - NPN_URLRedirectResponse(notifyData, true); -} - NPError PluginTest::NPP_GetValue(NPPVariable variable, void *value) { // We don't know anything about plug-in values so just return NPERR_GENERIC_ERROR. @@ -164,11 +156,6 @@ NPError PluginTest::NPN_GetURLNotify(const char *url, const char *target, void * return browser->geturlnotify(m_npp, url, target, notifyData); } -NPError PluginTest::NPN_PostURLNotify(const char *url, const char *target, uint32_t len, const char* buf, NPBool file, void *notifyData) -{ - return browser->posturlnotify(m_npp, url, target, len, buf, file, notifyData); -} - NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value) { return browser->getvalue(m_npp, variable, value); @@ -241,11 +228,6 @@ void PluginTest::NPN_ReleaseVariantValue(NPVariant* variant) browser->releasevariantvalue(variant); } -void PluginTest::NPN_URLRedirectResponse(void* notifyData, NPBool allow) -{ - browser->urlredirectresponse(m_npp, notifyData, allow); -} - #ifdef XP_MACOSX bool PluginTest::NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace) { @@ -272,7 +254,6 @@ void PluginTest::executeScript(const char* script) browser->releasevariantvalue(&browserResult); } -WTF_ATTRIBUTE_PRINTF(2, 3) void PluginTest::log(const char* format, ...) { va_list args; diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h index d7a5163ff..f8a9aaee3 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h @@ -31,10 +31,6 @@ #include <map> #include <string> -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - // Helper classes for implementing has_member typedef char (&no_tag)[1]; typedef char (&yes_tag)[2]; @@ -72,14 +68,12 @@ public: virtual int16_t NPP_HandleEvent(void* event); virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData); - virtual void NPP_URLRedirectNotify(const char* url, int32_t status, 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_PostURLNotify(const char *url, const char *target, uint32_t len, const char* buf, NPBool file, void *notifyData); NPError NPN_GetValue(NPNVariable, void* value); void NPN_InvalidateRect(NPRect* invalidRect); bool NPN_Invoke(NPObject *, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); @@ -97,7 +91,6 @@ public: void NPN_ReleaseObject(NPObject*); bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName); void NPN_ReleaseVariantValue(NPVariant*); - void NPN_URLRedirectResponse(void* notifyData, NPBool allow); #ifdef XP_MACOSX bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp deleted file mode 100644 index c066db59f..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 "PluginTest.h" - -#include "PluginObject.h" - -using namespace std; - -// Executing JS within NPP_New when initializing asynchronously should not be able to deadlock with the WebProcess - -class EvaluteJSWithinNPP_New : public PluginTest { -public: - EvaluteJSWithinNPP_New(NPP, const string& identifier); - -private: - virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *); - -}; - -EvaluteJSWithinNPP_New::EvaluteJSWithinNPP_New(NPP npp, const string& identifier) - : PluginTest(npp, identifier) -{ -} - -NPError EvaluteJSWithinNPP_New::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved) -{ - // Give the WebProcess enough time to be deadlocked waiting for the PluginProcess. - usleep(15000); - executeScript("var theLocation = window.location;"); - return NPERR_NO_ERROR; -} - -static PluginTest::Register<EvaluteJSWithinNPP_New> registrar("evalute-js-within-npp-new"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp deleted file mode 100644 index 0e2dbdce7..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 "PluginTest.h" - -#include "PluginObject.h" - -using namespace std; - -// Executing JS within NPP_New when initializing asynchronously should not be able to deadlock with the WebProcess - -class InvokeDestroysPluginWithinNPP_New : public PluginTest { -public: - InvokeDestroysPluginWithinNPP_New(NPP, const string& identifier); - -private: - virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *); - -}; - -InvokeDestroysPluginWithinNPP_New::InvokeDestroysPluginWithinNPP_New(NPP npp, const string& identifier) - : PluginTest(npp, identifier) -{ -} - -NPError InvokeDestroysPluginWithinNPP_New::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved) -{ - // Give the WebProcess enough time to be deadlocked waiting for the PluginProcess if things aren't working correctly. - usleep(15000); - - NPObject* windowObject = 0; - if (NPN_GetValue(NPNVWindowNPObject, &windowObject) != NPERR_NO_ERROR) - return NPERR_GENERIC_ERROR; - - if (!windowObject) - return NPERR_GENERIC_ERROR; - - NPVariant result; - if (!NPN_Invoke(windowObject, NPN_GetStringIdentifier("removePluginElement"), 0, 0, &result)) - return NPERR_GENERIC_ERROR; - - return NPERR_NO_ERROR; -} - -static PluginTest::Register<InvokeDestroysPluginWithinNPP_New> registrar("invoke-destroys-plugin-within-npp-new"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp deleted file mode 100644 index ca399a816..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 "PluginTest.h" - -#include <string.h> - -using namespace std; - -class PluginScriptableObjectOverridesAllProperties : public PluginTest { -public: - PluginScriptableObjectOverridesAllProperties(NPP npp, const string& identifier) - : PluginTest(npp, identifier) - { - } - -private: - class PluginObject : public Object<PluginObject> { - public: - PluginObject() - { - } - - ~PluginObject() - { - } - - bool hasProperty(NPIdentifier propertyName) - { - return true; - } - - bool getProperty(NPIdentifier propertyName, NPVariant* result) - { - static const char* message = "My name is "; - char* propertyString = pluginTest()->NPN_UTF8FromIdentifier(propertyName); - - int bufferLength = strlen(propertyString) + strlen(message) + 1; - char* resultBuffer = static_cast<char*>(pluginTest()->NPN_MemAlloc(bufferLength)); - snprintf(resultBuffer, bufferLength, "%s%s", message, propertyString); - - STRINGZ_TO_NPVARIANT(resultBuffer, *result); - - return true; - } - }; - - 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<PluginScriptableObjectOverridesAllProperties> pluginScriptableObjectOverridesAllProperties("plugin-scriptable-object-overrides-all-properties"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp deleted file mode 100644 index 8c80d55a5..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 "PluginTest.h" - -#include <string.h> - -using namespace std; - -class SlowNPPNew : public PluginTest { -public: - SlowNPPNew(NPP npp, const string& identifier) - : PluginTest(npp, identifier) - { - } - -private: - class PluginObject : public Object<PluginObject> { - public: - PluginObject() - { - } - - ~PluginObject() - { - } - - bool hasProperty(NPIdentifier propertyName) - { - return true; - } - - bool getProperty(NPIdentifier propertyName, NPVariant* result) - { - static const char* message = "My name is "; - char* propertyString = pluginTest()->NPN_UTF8FromIdentifier(propertyName); - - int bufferLength = strlen(propertyString) + strlen(message) + 1; - char* resultBuffer = static_cast<char*>(pluginTest()->NPN_MemAlloc(bufferLength)); - snprintf(resultBuffer, bufferLength, "%s%s", message, propertyString); - - STRINGZ_TO_NPVARIANT(resultBuffer, *result); - - return true; - } - }; - - virtual NPError NPP_GetValue(NPPVariable variable, void *value) - { - if (variable != NPPVpluginScriptableNPObject) - return NPERR_GENERIC_ERROR; - - *(NPObject**)value = PluginObject::create(this); - - return NPERR_NO_ERROR; - } - - virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved) - { - usleep(550000); - return NPERR_NO_ERROR; - } -}; - -static PluginTest::Register<SlowNPPNew> slowNPPNew("slow-npp-new"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp deleted file mode 100644 index b834703da..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2014 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 URLRedirect : public PluginTest { -public: - URLRedirect(NPP npp, const string& identifier) - : PluginTest(npp, identifier) - { - } - - struct Redirect { - int redirectsRemaining; - bool async; - bool hasFired; - }; - - std::map<void*, Redirect> redirects; - -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, "get") || identifierIs(methodName, "getAsync") || identifierIs(methodName, "serviceAsync"); - } - - bool get(const NPVariant* args, uint32_t argCount, NPVariant* result, bool async) - { - if (argCount != 3 || !NPVARIANT_IS_STRING(args[0]) || !(NPVARIANT_IS_BOOLEAN(args[1]) || NPVARIANT_IS_DOUBLE(args[1]) || NPVARIANT_IS_INT32(args[1])) || !NPVARIANT_IS_STRING(args[2])) - return false; - - const NPString* notifyString = &NPVARIANT_TO_STRING(args[2]); - basic_string<NPUTF8> notify(notifyString->UTF8Characters, notifyString->UTF8Length); - NPIdentifier notifyMethod = pluginTest()->NPN_GetStringIdentifier(notify.c_str()); - - Redirect& redirect = static_cast<URLRedirect*>(pluginTest())->redirects[reinterpret_cast<void*>(notifyMethod)]; - if (NPVARIANT_IS_DOUBLE(args[1])) - redirect.redirectsRemaining = NPVARIANT_TO_DOUBLE(args[1]); - else if (NPVARIANT_IS_INT32(args[1])) - redirect.redirectsRemaining = NPVARIANT_TO_INT32(args[1]); - else if (NPVARIANT_IS_BOOLEAN(args[1])) - redirect.redirectsRemaining = NPVARIANT_TO_BOOLEAN(args[1]); - redirect.async = async; - redirect.hasFired = true; - - const NPString* urlString = &NPVARIANT_TO_STRING(args[0]); - basic_string<NPUTF8> url(urlString->UTF8Characters, urlString->UTF8Length); - - pluginTest()->NPN_GetURLNotify(url.c_str(), 0, reinterpret_cast<void*>(notifyMethod)); - - VOID_TO_NPVARIANT(*result); - return true; - } - - bool serviceAsync(const NPVariant* args, uint32_t argCount, NPVariant* result) - { - if (argCount) - return false; - - NPBool seen = 0; - URLRedirect* plugin = static_cast<URLRedirect*>(pluginTest()); - for (auto& redirect : plugin->redirects) { - if (redirect.second.hasFired) - continue; - redirect.second.hasFired = true; - plugin->NPN_URLRedirectResponse(redirect.first, redirect.second.redirectsRemaining); - if (redirect.second.redirectsRemaining) - --redirect.second.redirectsRemaining; - seen = 1; - } - - BOOLEAN_TO_NPVARIANT(seen, *result); - return true; - } - - bool invoke(NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) - { - if (identifierIs(methodName, "get")) - return get(args, argCount, result, false); - - if (identifierIs(methodName, "getAsync")) - return get(args, argCount, result, true); - - if (identifierIs(methodName, "serviceAsync")) - return serviceAsync(args, argCount, result); - - return false; - } - }; - - 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 bool NPP_URLNotify(const char* url, NPReason reason, void* notifyData) - { - NPVariant args[2]; - - NPObject* windowScriptObject; - NPN_GetValue(NPNVWindowNPObject, &windowScriptObject); - - NPIdentifier callbackIdentifier = notifyData; - - INT32_TO_NPVARIANT(reason, args[0]); - STRINGZ_TO_NPVARIANT(url, args[1]); - - NPVariant browserResult; - if (NPN_Invoke(windowScriptObject, callbackIdentifier, args, 2, &browserResult)) - NPN_ReleaseVariantValue(&browserResult); - - return true; - } - - virtual void NPP_URLRedirectNotify(const char*, int32_t, void* notifyData) - { - Redirect& redirect = redirects[notifyData]; - if (redirect.async) { - redirect.hasFired = false; - return; - } - - NPN_URLRedirectResponse(notifyData, redirect.redirectsRemaining); - if (redirect.redirectsRemaining) - --redirect.redirectsRemaining; - } -}; - -static PluginTest::Register<URLRedirect> urlRedirect("url-redirect"); - diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp index 6a7303f13..85cd41d2c 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp @@ -41,17 +41,10 @@ extern "C" void GlobalToLocal(Point*); using namespace std; -#if defined(__GNUC__) -#define CRASH() do { \ - *(int *)(uintptr_t)0xbbadbeef = 0; \ - __builtin_trap(); /* More reliable, but doesn't say BBADBEEF. */ \ -} while (false) -#else #define CRASH() do { \ *(int *)(uintptr_t)0xbbadbeef = 0; \ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ -} while (false) -#endif +} while(false) static bool getEntryPointsWasCalled; static bool initializeWasCalled; @@ -123,7 +116,6 @@ NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) pluginFuncs->print = NPP_Print; pluginFuncs->event = NPP_HandleEvent; pluginFuncs->urlnotify = NPP_URLNotify; - pluginFuncs->urlredirectnotify = NPP_URLRedirectNotify; pluginFuncs->getvalue = NPP_GetValue; pluginFuncs->setvalue = NPP_SetValue; @@ -356,30 +348,29 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); - if (!obj) - return NPERR_GENERIC_ERROR; - - obj->lastWindow = *window; + if (obj) { + obj->lastWindow = *window; - if (obj->logSetWindow) { - pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height); - obj->logSetWindow = FALSE; - executeScript(obj, "testRunner.notifyDone();"); - } + if (obj->logSetWindow) { + pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height); + obj->logSetWindow = FALSE; + executeScript(obj, "testRunner.notifyDone();"); + } - if (obj->onSetWindow) - executeScript(obj, obj->onSetWindow); + if (obj->onSetWindow) + executeScript(obj, obj->onSetWindow); - if (obj->testWindowOpen) { - testWindowOpen(instance); - obj->testWindowOpen = FALSE; - } + if (obj->testWindowOpen) { + testWindowOpen(instance); + obj->testWindowOpen = FALSE; + } - if (obj->testKeyboardFocusForPlugins) { - obj->eventLogging = true; - executeScript(obj, "eventSender.keyDown('A');"); + if (obj->testKeyboardFocusForPlugins) { + obj->eventLogging = true; + executeScript(obj, "eventSender.keyDown('A');"); + } } - + return obj->pluginTest->NPP_SetWindow(window); } @@ -808,12 +799,6 @@ void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyD handleCallback(obj, url, reason, notifyData); } -void NPP_URLRedirectNotify(NPP instance, const char *url, int32_t status, void *notifyData) -{ - PluginObject* obj = static_cast<PluginObject*>(instance->pdata); - obj->pluginTest->NPP_URLRedirectNotify(url, status, notifyData); -} - NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) { #ifdef XP_UNIX diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h index 627bc97a9..627bc97a9 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h index 54a603dbb..54a603dbb 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h index e435ae2ab..e435ae2ab 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h diff --git a/Tools/DumpRenderTree/TestRunner.cpp b/Tools/DumpRenderTree/TestRunner.cpp index b5270dc46..7b249770e 100644 --- a/Tools/DumpRenderTree/TestRunner.cpp +++ b/Tools/DumpRenderTree/TestRunner.cpp @@ -11,7 +11,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -59,7 +59,7 @@ const unsigned TestRunner::viewHeight = 600; const unsigned TestRunner::w3cSVGViewWidth = 480; const unsigned TestRunner::w3cSVGViewHeight = 360; -TestRunner::TestRunner(const std::string& testURL, const std::string& expectedPixelHash) +TestRunner::TestRunner(const std::string& testPathOrURL, const std::string& expectedPixelHash) : m_disallowIncreaseForApplicationCacheQuota(false) , m_dumpApplicationCacheDelegateCallbacks(false) , m_dumpAsAudio(false) @@ -112,16 +112,15 @@ TestRunner::TestRunner(const std::string& testURL, const std::string& expectedPi , m_hasPendingWebNotificationClick(false) , m_databaseDefaultQuota(-1) , m_databaseMaxQuota(-1) - , m_testURL(testURL) + , m_testPathOrURL(testPathOrURL) , m_expectedPixelHash(expectedPixelHash) , m_titleTextDirection("ltr") - , m_timeout(0) { } -PassRefPtr<TestRunner> TestRunner::create(const std::string& testURL, const std::string& expectedPixelHash) +PassRefPtr<TestRunner> TestRunner::create(const std::string& testPathOrURL, const std::string& expectedPixelHash) { - return adoptRef(new TestRunner(testURL, expectedPixelHash)); + return adoptRef(new TestRunner(testPathOrURL, expectedPixelHash)); } // Static Functions @@ -467,6 +466,73 @@ static JSValueRef clearAllDatabasesCallback(JSContextRef context, JSObjectRef fu return JSValueMakeUndefined(context); } +static JSValueRef syncLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); + + controller->syncLocalStorage(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef observeStorageTrackerNotificationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TestRunner* controller = static_cast<TestRunner*>(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) +{ + TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); + controller->deleteAllLocalStorage(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef deleteLocalStorageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TestRunner* controller = static_cast<TestRunner*>(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) +{ + TestRunner* controller = static_cast<TestRunner*>(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) +{ + TestRunner* controller = static_cast<TestRunner*>(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 @@ -646,12 +712,6 @@ static JSValueRef numberOfPendingGeolocationPermissionRequestsCallback(JSContext return JSValueMakeNumber(context, controller->numberOfPendingGeolocationPermissionRequests()); } -static JSValueRef isGeolocationProviderActiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); - return JSValueMakeBoolean(context, controller->isGeolocationProviderActive()); -} - static JSValueRef queueBackNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { // Has mac & windows implementation @@ -1044,6 +1104,38 @@ static JSValueRef setMockGeolocationPositionUnavailableErrorCallback(JSContextRe 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); + + TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); + controller->addMockSpeechInputResult(result.get(), confidence, language.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef setMockSpeechInputDumpRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + bool dumpRect = JSValueToBoolean(context, arguments[0]); + + TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); + controller->setMockSpeechInputDumpRect(dumpRect); + + return JSValueMakeUndefined(context); +} + static JSValueRef setNewWindowsCopyBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { // Has mac implementation @@ -1487,10 +1579,12 @@ static JSValueRef closeWebInspectorCallback(JSContextRef context, JSObjectRef fu static JSValueRef evaluateInWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); - JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + double callId = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception)); ASSERT(!*exception); - controller->evaluateInWebInspector(script.get()); + controller->evaluateInWebInspector(static_cast<long>(callId), script.get()); return JSValueMakeUndefined(context); } @@ -1790,13 +1884,6 @@ static JSValueRef getTitleTextDirectionCallback(JSContextRef context, JSObjectRe return JSValueMakeString(context, titleDirection.get()); } -static JSValueRef getInspectorTestStubURLCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) -{ - TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); - JSRetainPtr<JSStringRef> url(Adopt, controller->inspectorTestStubURL()); - return JSValueMakeString(context, url.get()); -} - static bool setGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) { TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject)); @@ -1933,16 +2020,11 @@ static JSValueRef simulateWebNotificationClickCallback(JSContextRef context, JSO return JSValueMakeUndefined(context); } -static JSValueRef failNextNewCodeBlock(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +static JSValueRef numberOfDFGCompiles(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { if (argumentCount < 1) return JSValueMakeUndefined(context); - return JSC::failNextNewCodeBlock(context); -} - -static JSValueRef numberOfDFGCompiles(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ return JSC::numberOfDFGCompiles(context, arguments[0]); } @@ -1995,7 +2077,6 @@ JSStaticValue* TestRunner::staticValues() { "titleTextDirection", getTitleTextDirectionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "databaseDefaultQuota", getDatabaseDefaultQuotaCallback, setDatabaseDefaultQuotaCallback, kJSPropertyAttributeNone }, { "databaseMaxQuota", getDatabaseMaxQuotaCallback, setDatabaseMaxQuotaCallback, kJSPropertyAttributeNone }, - { "inspectorTestStubURL", getInspectorTestStubURLCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { 0, 0, 0, 0 } }; return staticValues; @@ -2052,7 +2133,6 @@ JSStaticFunction* TestRunner::staticFunctions() { "originsWithApplicationCache", originsWithApplicationCacheCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "goBack", goBackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "ignoreLegacyWebNotificationPermissionRequests", ignoreLegacyWebNotificationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "isGeolocationProviderActive", isGeolocationProviderActiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "numberOfPendingGeolocationPermissionRequests", numberOfPendingGeolocationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -2098,6 +2178,8 @@ JSStaticFunction* TestRunner::staticFunctions() { "setMockDeviceOrientation", setMockDeviceOrientationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setMockGeolocationPositionUnavailableError", setMockGeolocationPositionUnavailableErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "addMockSpeechInputResult", addMockSpeechInputResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setMockSpeechInputDumpRect", setMockSpeechInputDumpRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setPageVisibility", setPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -2139,6 +2221,12 @@ JSStaticFunction* TestRunner::staticFunctions() { "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 }, { "setShouldStayOnPageAfterHandlingBeforeUnload", setShouldStayOnPageAfterHandlingBeforeUnloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -2154,7 +2242,6 @@ JSStaticFunction* TestRunner::staticFunctions() { "denyWebNotificationPermission", denyWebNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "removeAllWebNotificationPermissions", removeAllWebNotificationPermissionsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "simulateWebNotificationClick", simulateWebNotificationClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, - { "failNextNewCodeBlock", failNextNewCodeBlock, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "numberOfDFGCompiles", numberOfDFGCompiles, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "neverInlineFunction", neverInlineFunction, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { 0, 0, 0 } @@ -2165,37 +2252,37 @@ JSStaticFunction* TestRunner::staticFunctions() void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL) { - WorkQueue::singleton().queue(new LoadHTMLStringItem(content, baseURL)); + WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL)); } void TestRunner::queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL) { - WorkQueue::singleton().queue(new LoadHTMLStringItem(content, baseURL, unreachableURL)); + WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, unreachableURL)); } void TestRunner::queueBackNavigation(int howFarBack) { - WorkQueue::singleton().queue(new BackItem(howFarBack)); + WorkQueue::shared()->queue(new BackItem(howFarBack)); } void TestRunner::queueForwardNavigation(int howFarForward) { - WorkQueue::singleton().queue(new ForwardItem(howFarForward)); + WorkQueue::shared()->queue(new ForwardItem(howFarForward)); } void TestRunner::queueLoadingScript(JSStringRef script) { - WorkQueue::singleton().queue(new LoadingScriptItem(script)); + WorkQueue::shared()->queue(new LoadingScriptItem(script)); } void TestRunner::queueNonLoadingScript(JSStringRef script) { - WorkQueue::singleton().queue(new NonLoadingScriptItem(script)); + WorkQueue::shared()->queue(new NonLoadingScriptItem(script)); } void TestRunner::queueReload() { - WorkQueue::singleton().queue(new ReloadItem); + WorkQueue::shared()->queue(new ReloadItem); } void TestRunner::ignoreLegacyWebNotificationPermissionRequests() @@ -2206,6 +2293,7 @@ void TestRunner::ignoreLegacyWebNotificationPermissionRequests() void TestRunner::waitToDumpWatchdogTimerFired() { const char* message = "FAIL: Timed out waiting for notifyDone to be called\n"; + fprintf(stderr, "%s", message); fprintf(stdout, "%s", message); notifyDone(); } diff --git a/Tools/DumpRenderTree/TestRunner.h b/Tools/DumpRenderTree/TestRunner.h index d51ac6feb..882c0e96c 100644 --- a/Tools/DumpRenderTree/TestRunner.h +++ b/Tools/DumpRenderTree/TestRunner.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -39,7 +39,7 @@ class TestRunner : public RefCounted<TestRunner> { public: - static PassRefPtr<TestRunner> create(const std::string& testURL, const std::string& expectedPixelHash); + static PassRefPtr<TestRunner> create(const std::string& testPathOrURL, const std::string& expectedPixelHash); static const unsigned viewWidth; static const unsigned viewHeight; @@ -52,8 +52,6 @@ public: void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); void addDisallowedURL(JSStringRef url); - const std::set<std::string>& allowedHosts() const { return m_allowedHosts; } - void setAllowedHosts(std::set<std::string> hosts) { m_allowedHosts = WTFMove(hosts); } void addURLToRedirect(std::string origin, std::string destination); const std::string& redirectionDestinationForURL(std::string); void clearAllApplicationCaches(); @@ -76,7 +74,6 @@ public: void keepWebHistory(); void notifyDone(); int numberOfPendingGeolocationPermissionRequests(); - bool isGeolocationProviderActive(); void overridePreference(JSStringRef key, JSStringRef value); JSStringRef pathToLocalResource(JSContextRef, JSStringRef url); void queueBackNavigation(int howFarBackward); @@ -105,6 +102,8 @@ public: void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma); void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed); void setMockGeolocationPositionUnavailableError(JSStringRef message); + void addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language); + void setMockSpeechInputDumpRect(bool flag); void setPersistentUserStyleSheetLocation(JSStringRef path); void setPluginsEnabled(bool); void setPopupBlockingEnabled(bool); @@ -118,6 +117,7 @@ public: void setXSSAuditorEnabled(bool flag); void setSpatialNavigationEnabled(bool); void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy); + void startSpeechInput(JSContextRef inputElement); #if PLATFORM(IOS) void setTelephoneNumberParsingEnabled(bool enable); void setPagePaused(bool paused); @@ -288,7 +288,7 @@ public: bool useDeferredFrameLoading() const { return m_useDeferredFrameLoading; } void setUseDeferredFrameLoading(bool flag) { m_useDeferredFrameLoading = flag; } - const std::string& testURL() const { return m_testURL; } + const std::string& testPathOrURL() const { return m_testPathOrURL; } const std::string& expectedPixelHash() const { return m_expectedPixelHash; } const std::vector<char>& audioResult() const { return m_audioResult; } @@ -307,9 +307,7 @@ public: void setDeveloperExtrasEnabled(bool); void showWebInspector(); void closeWebInspector(); - void evaluateInWebInspector(JSStringRef script); - JSStringRef inspectorTestStubURL(); - + void evaluateInWebInspector(long callId, JSStringRef script); void evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script); void evaluateScriptInIsolatedWorldAndReturnValue(unsigned worldID, JSObjectRef globalObject, JSStringRef script); @@ -338,6 +336,13 @@ public: // Simulate a request an embedding application could make, populating per-session credential storage. void authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password); + 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; } @@ -354,10 +359,8 @@ public: bool hasPendingWebNotificationClick() const { return m_hasPendingWebNotificationClick; } - void setCustomTimeout(int duration) { m_timeout = duration; } - private: - TestRunner(const std::string& testURL, const std::string& expectedPixelHash); + TestRunner(const std::string& testPathOrURL, const std::string& expectedPixelHash); void setGeolocationPermissionCommon(bool allow); @@ -418,22 +421,19 @@ private: std::string m_authenticationUsername; std::string m_authenticationPassword; - std::string m_testURL; + std::string m_testPathOrURL; std::string m_expectedPixelHash; // empty string if no hash std::string m_titleTextDirection; std::set<std::string> m_willSendRequestClearHeaders; - std::set<std::string> m_allowedHosts; std::vector<char> m_audioResult; std::map<std::string, std::string> m_URLsToRedirect; - + static JSClassRef getJSClass(); static JSStaticValue* staticValues(); static JSStaticFunction* staticFunctions(); - - int m_timeout; }; #endif // TestRunner_h diff --git a/Tools/DumpRenderTree/WorkQueue.cpp b/Tools/DumpRenderTree/WorkQueue.cpp index 097f4cdd2..0106fbac1 100644 --- a/Tools/DumpRenderTree/WorkQueue.cpp +++ b/Tools/DumpRenderTree/WorkQueue.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -31,7 +31,6 @@ #include "WorkQueueItem.h" #include <wtf/Assertions.h> -#include <wtf/NeverDestroyed.h> static const unsigned queueLength = 1024; @@ -39,9 +38,9 @@ static WorkQueueItem* theQueue[queueLength]; static unsigned startOfQueue; static unsigned endOfQueue; -WorkQueue& WorkQueue::singleton() +WorkQueue* WorkQueue::shared() { - static NeverDestroyed<WorkQueue> sharedInstance; + static WorkQueue* sharedInstance = new WorkQueue; return sharedInstance; } diff --git a/Tools/DumpRenderTree/WorkQueue.h b/Tools/DumpRenderTree/WorkQueue.h index 0697e7c3e..649c6c1f5 100644 --- a/Tools/DumpRenderTree/WorkQueue.h +++ b/Tools/DumpRenderTree/WorkQueue.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -29,15 +29,11 @@ #ifndef WorkQueue_h #define WorkQueue_h -#include <wtf/Forward.h> - class WorkQueueItem; class WorkQueue { -friend class WTF::NeverDestroyed<WorkQueue>; - public: - static WorkQueue& singleton(); + static WorkQueue* shared(); void queue(WorkQueueItem*); WorkQueueItem* dequeue(); diff --git a/Tools/DumpRenderTree/WorkQueueItem.h b/Tools/DumpRenderTree/WorkQueueItem.h index 6a49f593f..08fc2208b 100644 --- a/Tools/DumpRenderTree/WorkQueueItem.h +++ b/Tools/DumpRenderTree/WorkQueueItem.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h b/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h new file mode 100644 index 000000000..0feef55c8 --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h @@ -0,0 +1,44 @@ +/* + * 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 + +#if HAVE(ACCESSIBILITY) + +#include "AccessibilityNotificationHandlerAtk.h" +#include "AccessibilityUIElement.h" + +void connectAccessibilityCallbacks(); +bool disconnectAccessibilityCallbacks(); +void addAccessibilityNotificationHandler(AccessibilityNotificationHandler*); +void removeAccessibilityNotificationHandler(AccessibilityNotificationHandler*); + +#endif // HAVE(ACCESSIBILITY) + +#endif // AccessibilityCallbacks_h diff --git a/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp new file mode 100644 index 000000000..01f6651b4 --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp @@ -0,0 +1,297 @@ +/* + * 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" + +#if HAVE(ACCESSIBILITY) + +#include "AccessibilityController.h" +#include "AccessibilityNotificationHandlerAtk.h" +#include "DumpRenderTree.h" +#include "JSRetainPtr.h" +#include <atk/atk.h> +#include <wtf/gobject/GUniquePtr.h> + +#if PLATFORM(GTK) +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <webkit/webkit.h> +#endif + +#if PLATFORM(EFL) +#include "DumpRenderTreeChrome.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#endif + +typedef HashMap<PlatformUIElement, AccessibilityNotificationHandler*> NotificationHandlersMap; + +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 guint loadCompleteListenerId = 0; +// Up to 2014 it was obligatory to mirror the changes from +// WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp, +// but the habit has been dropped: https://bugs.webkit.org/show_bug.cgi?id=132527#c6 +static NotificationHandlersMap notificationHandlers; +static AccessibilityNotificationHandler* globalNotificationHandler = 0; + +extern bool loggingAccessibilityEvents; + +static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName, const gchar* signalValue) +{ + // Do not handle state-change:defunct signals, as the AtkObject + // associated to them will not be valid at this point already. + if (!signalName || !g_strcmp0(signalName, "state-change:defunct")) + return; + + if (!accessible || !ATK_IS_OBJECT(accessible)) + return; + + const gchar* objectName = atk_object_get_name(accessible); + AtkRole 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)"; + + GUniquePtr<gchar> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName)); + printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), 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 signalQuery; + GUniquePtr<gchar> signalName; + GUniquePtr<gchar> signalValue; + String notificationName; + + g_signal_query(signalHint->signal_id, &signalQuery); + + if (!g_strcmp0(signalQuery.signal_name, "state-change")) { + signalName.reset(g_strdup_printf("state-change:%s", g_value_get_string(¶mValues[1]))); + signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(¶mValues[2]))); + if (!g_strcmp0(g_value_get_string(¶mValues[1]), "checked")) + notificationName = "CheckedStateChanged"; + else if (!g_strcmp0(g_value_get_string(¶mValues[1]), "invalid-entry")) + notificationName = "AXInvalidStatusChanged"; + } else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) { + signalName.reset(g_strdup("focus-event")); + signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(¶mValues[1]))); + if (g_value_get_boolean(¶mValues[1])) + notificationName = "AXFocusedUIElementChanged"; + } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) { + const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail); + signalName.reset(g_strdup_printf("children-changed:%s", childrenChangedDetail)); + signalValue.reset(g_strdup_printf("%d", g_value_get_uint(¶mValues[1]))); + notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved"; + } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) { + signalName.reset(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail))); + if (!g_strcmp0(g_quark_to_string(signalHint->detail), "accessible-value")) + notificationName = "AXValueChanged"; + } else if (!g_strcmp0(signalQuery.signal_name, "load-complete")) + notificationName = "AXLoadComplete"; + else + signalName.reset(g_strdup(signalQuery.signal_name)); + + if (loggingAccessibilityEvents) + printAccessibilityEvent(accessible, signalName.get(), signalValue.get()); + +#if PLATFORM(GTK) + JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame); +#elif PLATFORM(EFL) + JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame()); +#else + JSContextRef jsContext = 0; +#endif + if (!jsContext) + return true; + + if (notificationName.length()) { + JSRetainPtr<JSStringRef> jsNotificationEventName(Adopt, JSStringCreateWithUTF8CString(notificationName.utf8().data())); + JSValueRef notificationNameArgument = JSValueMakeString(jsContext, jsNotificationEventName.get()); + NotificationHandlersMap::iterator elementNotificationHandler = notificationHandlers.find(accessible); + if (elementNotificationHandler != notificationHandlers.end()) { + // Listener for one element just gets one argument, the notification name. + JSObjectCallAsFunction(jsContext, elementNotificationHandler->value->notificationFunctionCallback(), 0, 1, ¬ificationNameArgument, 0); + } + + if (globalNotificationHandler) { + // A global listener gets the element and the notification name as arguments. + JSValueRef arguments[2]; + arguments[0] = AccessibilityUIElement::makeJSAccessibilityUIElement(jsContext, AccessibilityUIElement(accessible)); + arguments[1] = notificationNameArgument; + JSObjectCallAsFunction(jsContext, globalNotificationHandler->notificationFunctionCallback(), 0, 2, arguments, 0); + } + } + + return true; +} + +void connectAccessibilityCallbacks() +{ + // Ensure no callbacks are connected before. + if (!disconnectAccessibilityCallbacks()) + return; + + // Ensure that accessibility is initialized for the WebView by querying for + // the root accessible object, which will create the full hierarchy. +#if PLATFORM(GTK) + DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame); +#elif PLATFORM(EFL) + DumpRenderTreeSupportEfl::rootAccessibleElement(browser->mainFrame()); +#endif + + // Add global listeners for AtkObject's signals. + stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:state-change"); + focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:focus-event"); + activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:active-descendant-changed"); + childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:children-changed"); + propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:property-change"); + visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:visible-data-changed"); + loadCompleteListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkDocument:load-complete"); + + // 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); +} + +bool disconnectAccessibilityCallbacks() +{ + // Only disconnect if logging is off and there is no notification handler. + if (loggingAccessibilityEvents || !notificationHandlers.isEmpty() || globalNotificationHandler) + return false; + + // 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; + } + if (loadCompleteListenerId) { + atk_remove_global_event_listener(loadCompleteListenerId); + loadCompleteListenerId = 0; + } + + return true; +} + +void addAccessibilityNotificationHandler(AccessibilityNotificationHandler* notificationHandler) +{ + if (!notificationHandler) + return; + +#if PLATFORM(GTK) + JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame); +#elif PLATFORM(EFL) + JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame()); +#else + JSContextRef jsContext = 0; +#endif + if (!jsContext) + return; + + JSValueProtect(jsContext, notificationHandler->notificationFunctionCallback()); + // Check if this notification handler is related to a specific element. + if (notificationHandler->platformElement()) { + NotificationHandlersMap::iterator currentNotificationHandler = notificationHandlers.find(notificationHandler->platformElement()); + if (currentNotificationHandler != notificationHandlers.end()) { + ASSERT(currentNotificationHandler->value->platformElement()); + JSValueUnprotect(jsContext, currentNotificationHandler->value->notificationFunctionCallback()); + notificationHandlers.remove(currentNotificationHandler->value->platformElement()); + } + notificationHandlers.add(notificationHandler->platformElement(), notificationHandler); + } else { + if (globalNotificationHandler) + JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback()); + globalNotificationHandler = notificationHandler; + } + + connectAccessibilityCallbacks(); +} + +void removeAccessibilityNotificationHandler(AccessibilityNotificationHandler* notificationHandler) +{ + if (!notificationHandler) + return; + +#if PLATFORM(GTK) + JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame); +#elif PLATFORM(EFL) + JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame()); +#else + JSGlobalContextRef jsContext = 0; +#endif + if (!jsContext) + return; + + if (globalNotificationHandler == notificationHandler) { + JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback()); + globalNotificationHandler = 0; + } else if (notificationHandler->platformElement()) { + NotificationHandlersMap::iterator removeNotificationHandler = notificationHandlers.find(notificationHandler->platformElement()); + if (removeNotificationHandler != notificationHandlers.end()) { + JSValueUnprotect(jsContext, removeNotificationHandler->value->notificationFunctionCallback()); + notificationHandlers.remove(removeNotificationHandler); + } + } +} + +#endif diff --git a/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp new file mode 100644 index 000000000..d8d0fc96c --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp @@ -0,0 +1,145 @@ +/* + * 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" + +#if HAVE(ACCESSIBILITY) + +#include "AccessibilityCallbacks.h" +#include "AccessibilityUIElement.h" +#include "DumpRenderTree.h" + +#include <atk/atk.h> + +bool loggingAccessibilityEvents = false; + +AccessibilityController::AccessibilityController() + : m_globalNotificationHandler(nullptr) +{ +} + +AccessibilityController::~AccessibilityController() +{ +} + +AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y) +{ + // FIXME: implement + return nullptr; +} + +void AccessibilityController::platformResetToConsistentState() +{ +} + +void AccessibilityController::setLogFocusEvents(bool) +{ +} + +void AccessibilityController::setLogScrollingStartEvents(bool) +{ +} + +void AccessibilityController::setLogValueChangeEvents(bool) +{ +} + +void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents) +{ + if (logAccessibilityEvents == loggingAccessibilityEvents) + return; + + if (!logAccessibilityEvents) { + loggingAccessibilityEvents = false; + disconnectAccessibilityCallbacks(); + return; + } + + connectAccessibilityCallbacks(); + loggingAccessibilityEvents = true; +} + +bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + // Only one global notification listener. + if (m_globalNotificationHandler) + return false; + + m_globalNotificationHandler = AccessibilityNotificationHandler::create(); + m_globalNotificationHandler->setNotificationFunctionCallback(functionCallback); + + return true; +} + +void AccessibilityController::removeNotificationListener() +{ + // Programmers should not be trying to remove a listener that's already removed. + ASSERT(m_globalNotificationHandler); + + m_globalNotificationHandler = nullptr; +} + +JSRetainPtr<JSStringRef> AccessibilityController::platformName() const +{ + JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("atk")); + return platformName; +} + +AtkObject* AccessibilityController::childElementById(AtkObject* parent, const char* id) +{ + if (!ATK_IS_OBJECT(parent)) + return nullptr; + + bool parentFound = false; + AtkAttributeSet* attributeSet(atk_object_get_attributes(parent)); + for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) { + AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data); + if (!strcmp(attribute->name, "html-id")) { + if (!strcmp(attribute->value, id)) + parentFound = true; + break; + } + } + atk_attribute_set_free(attributeSet); + + if (parentFound) + return parent; + + int childCount = atk_object_get_n_accessible_children(parent); + for (int i = 0; i < childCount; i++) { + AtkObject* result = childElementById(atk_object_ref_accessible_child(parent, i), id); + if (ATK_IS_OBJECT(result)) + return result; + } + + return nullptr; +} + +#endif diff --git a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp new file mode 100644 index 000000000..4565d5506 --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved. + * + * 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 "AccessibilityNotificationHandlerAtk.h" + +#if HAVE(ACCESSIBILITY) + +#include "AccessibilityCallbacks.h" + +AccessibilityNotificationHandler::AccessibilityNotificationHandler(void) + : m_platformElement(nullptr) + , m_notificationFunctionCallback(nullptr) +{ +} + +AccessibilityNotificationHandler::~AccessibilityNotificationHandler() +{ + removeAccessibilityNotificationHandler(this); + disconnectAccessibilityCallbacks(); +} + +void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSObjectRef notificationFunctionCallback) +{ + if (!notificationFunctionCallback) { + removeAccessibilityNotificationHandler(this); + disconnectAccessibilityCallbacks(); + return; + } + + if (m_notificationFunctionCallback) + removeAccessibilityNotificationHandler(this); + + m_notificationFunctionCallback = notificationFunctionCallback; + connectAccessibilityCallbacks(); + addAccessibilityNotificationHandler(this); +} + +#endif // HAVE(ACCESSIBILITY) diff --git a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h new file mode 100644 index 000000000..9018e7290 --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved. + * + * 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. + */ + +#ifndef AccessibilityNotificationHandlerAtk_h +#define AccessibilityNotificationHandlerAtk_h + +#if HAVE(ACCESSIBILITY) + +#include <JavaScriptCore/JSObjectRef.h> +#include <atk/atk.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +class AccessibilityNotificationHandler : public RefCounted<AccessibilityNotificationHandler> { +public: + static PassRefPtr<AccessibilityNotificationHandler> create() + { + return adoptRef(new AccessibilityNotificationHandler()); + } + AccessibilityNotificationHandler(void); + ~AccessibilityNotificationHandler(); + + void setPlatformElement(AtkObject* platformElement) { m_platformElement = platformElement; } + AtkObject* platformElement(void) const { return m_platformElement; } + void setNotificationFunctionCallback(JSObjectRef); + JSObjectRef notificationFunctionCallback(void) const { return m_notificationFunctionCallback; } + +private: + AtkObject* m_platformElement; + JSObjectRef m_notificationFunctionCallback; +}; + +#endif // HAVE(ACCESSIBILITY) + +#endif // AccessibilityNotificationHandlerAtk_h diff --git a/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp new file mode 100644 index 000000000..41317bdd1 --- /dev/null +++ b/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp @@ -0,0 +1,1604 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Jan Michael Alonzo + * Copyright (C) 2013 Samsung Electronics. 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" + +#if HAVE(ACCESSIBILITY) + +#include "AccessibilityNotificationHandlerAtk.h" +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <atk/atk.h> +#include <wtf/Assertions.h> +#include <wtf/gobject/GRefPtr.h> +#include <wtf/gobject/GUniquePtr.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/text/WTFString.h> +#include <wtf/unicode/CharacterNames.h> + +namespace { + +enum AtkAttributeType { + ObjectAttributeType, + TextAttributeType +}; + +enum AttributeDomain { + CoreDomain = 0, + AtkDomain +}; + +enum AttributesIndex { + // Attribute names. + InvalidNameIndex = 0, + PlaceholderNameIndex, + SortNameIndex, + + // Attribute values. + SortAscendingValueIndex, + SortDescendingValueIndex, + SortUnknownValueIndex, + + NumberOfAttributes +}; + +// Attribute names & Values (keep on sync with enum AttributesIndex). +const String attributesMap[][2] = { + // Attribute names. + { "AXInvalid", "invalid" }, + { "AXPlaceholderValue", "placeholder-text" } , + { "AXSortDirection", "sort" }, + + // Attribute values. + { "AXAscendingSortDirection", "ascending" }, + { "AXDescendingSortDirection", "descending" }, + { "AXUnknownSortDirection", "unknown" } +}; + +#if ATK_CHECK_VERSION(2, 11, 3) +const char* landmarkStringBanner = "AXLandmarkBanner"; +const char* landmarkStringComplementary = "AXLandmarkComplementary"; +const char* landmarkStringContentinfo = "AXLandmarkContentInfo"; +const char* landmarkStringMain = "AXLandmarkMain"; +const char* landmarkStringNavigation = "AXLandmarkNavigation"; +const char* landmarkStringSearch = "AXLandmarkSearch"; +#endif + +String jsStringToWTFString(JSStringRef attribute) +{ + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(attribute); + GUniquePtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(attribute, buffer.get(), bufferSize); + + return String::fromUTF8(buffer.get()); +} + +String coreAttributeToAtkAttribute(JSStringRef attribute) +{ + String attributeString = jsStringToWTFString(attribute); + for (int i = 0; i < NumberOfAttributes; ++i) { + if (attributesMap[i][CoreDomain] == attributeString) + return attributesMap[i][AtkDomain]; + } + + return attributeString; +} + +String atkAttributeValueToCoreAttributeValue(AtkAttributeType type, const String& id, const String& value) +{ + if (type == ObjectAttributeType) { + // We need to translate ATK values exposed for 'aria-sort' (e.g. 'ascending') + // into those expected by the layout tests (e.g. 'AXAscendingSortDirection'). + if (id == attributesMap[SortNameIndex][AtkDomain] && !value.isEmpty()) { + if (value == attributesMap[SortAscendingValueIndex][AtkDomain]) + return attributesMap[SortAscendingValueIndex][CoreDomain]; + if (value == attributesMap[SortDescendingValueIndex][AtkDomain]) + return attributesMap[SortDescendingValueIndex][CoreDomain]; + + return attributesMap[SortUnknownValueIndex][CoreDomain]; + } + } else if (type == TextAttributeType) { + // In case of 'aria-invalid' when the attribute empty or has "false" for ATK + // it should not be mapped at all, but layout tests will expect 'false'. + if (id == attributesMap[InvalidNameIndex][AtkDomain] && value.isEmpty()) + return "false"; + } + + return value; +} + +AtkAttributeSet* getAttributeSet(AtkObject* accessible, AtkAttributeType type) +{ + if (type == ObjectAttributeType) + return atk_object_get_attributes(accessible); + + if (type == TextAttributeType) { + if (!ATK_IS_TEXT(accessible)) + return nullptr; + + return atk_text_get_default_attributes(ATK_TEXT(accessible)); + } + + ASSERT_NOT_REACHED(); + return nullptr; +} + +String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, String id) +{ + AtkAttributeSet* attributeSet = getAttributeSet(accessible, type); + if (!attributeSet) + return String(); + + String attributeValue; + for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) { + AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data); + if (id == atkAttribute->name) { + attributeValue = String::fromUTF8(atkAttribute->value); + break; + } + } + atk_attribute_set_free(attributeSet); + + return atkAttributeValueToCoreAttributeValue(type, id, attributeValue); +} + +String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type) +{ + AtkAttributeSet* attributeSet = getAttributeSet(accessible, type); + if (!attributeSet) + return String(); + + StringBuilder builder; + for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) { + AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data); + GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL)); + builder.append(attributeData.get()); + if (attributes->next) + builder.append(", "); + } + atk_attribute_set_free(attributeSet); + + return builder.toString(); +} + +const char* roleToString(AtkObject* object) +{ + AtkRole role = atk_object_get_role(object); + +#if ATK_CHECK_VERSION(2, 11, 3) + if (role == ATK_ROLE_LANDMARK) { + String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles"); + if (equalIgnoringCase(xmlRolesValue, "banner")) + return landmarkStringBanner; + if (equalIgnoringCase(xmlRolesValue, "complementary")) + return landmarkStringComplementary; + if (equalIgnoringCase(xmlRolesValue, "contentinfo")) + return landmarkStringContentinfo; + if (equalIgnoringCase(xmlRolesValue, "main")) + return landmarkStringMain; + if (equalIgnoringCase(xmlRolesValue, "navigation")) + return landmarkStringNavigation; + if (equalIgnoringCase(xmlRolesValue, "search")) + return landmarkStringSearch; + } +#endif + + switch (role) { + case ATK_ROLE_ALERT: + return "AXAlert"; + case ATK_ROLE_DIALOG: + return "AXDialog"; + case ATK_ROLE_CANVAS: + return "AXCanvas"; + case ATK_ROLE_CHECK_BOX: + return "AXCheckBox"; + case ATK_ROLE_COLOR_CHOOSER: + return "AXColorWell"; + case ATK_ROLE_COLUMN_HEADER: + return "AXColumnHeader"; + case ATK_ROLE_COMBO_BOX: + return "AXComboBox"; + case ATK_ROLE_COMMENT: + return "AXComment"; + case ATK_ROLE_DOCUMENT_FRAME: + return "AXDocument"; + case ATK_ROLE_DOCUMENT_WEB: + return "AXWebArea"; + case ATK_ROLE_EMBEDDED: + return "AXEmbedded"; + case ATK_ROLE_ENTRY: + return "AXTextField"; + case ATK_ROLE_FOOTER: + return "AXFooter"; + case ATK_ROLE_FORM: + return "AXForm"; + case ATK_ROLE_GROUPING: + return "AXGroup"; + case ATK_ROLE_HEADING: + return "AXHeading"; + case ATK_ROLE_IMAGE: + return "AXImage"; + case ATK_ROLE_IMAGE_MAP: + return "AXImageMap"; + case ATK_ROLE_LABEL: + return "AXLabel"; + case ATK_ROLE_LINK: + return "AXLink"; + case ATK_ROLE_LIST: + return "AXList"; + case ATK_ROLE_LIST_BOX: + return "AXListBox"; + case ATK_ROLE_LIST_ITEM: + return "AXListItem"; + case ATK_ROLE_MENU: + return "AXMenu"; + case ATK_ROLE_MENU_BAR: + return "AXMenuBar"; + case ATK_ROLE_MENU_ITEM: + return "AXMenuItem"; + case ATK_ROLE_PAGE_TAB: + return "AXTab"; + case ATK_ROLE_PAGE_TAB_LIST: + return "AXTabGroup"; + case ATK_ROLE_PANEL: + return "AXGroup"; + case ATK_ROLE_PARAGRAPH: + return "AXParagraph"; + case ATK_ROLE_PASSWORD_TEXT: + return "AXPasswordField"; + case ATK_ROLE_PROGRESS_BAR: + return "AXProgressIndicator"; + case ATK_ROLE_PUSH_BUTTON: + return "AXButton"; + case ATK_ROLE_RADIO_BUTTON: + return "AXRadioButton"; + case ATK_ROLE_RADIO_MENU_ITEM: + return "AXRadioMenuItem"; + case ATK_ROLE_ROW_HEADER: + return "AXRowHeader"; + case ATK_ROLE_CHECK_MENU_ITEM: + return "AXCheckMenuItem"; + case ATK_ROLE_RULER: + return "AXRuler"; + case ATK_ROLE_SCROLL_BAR: + return "AXScrollBar"; + case ATK_ROLE_SCROLL_PANE: + return "AXScrollArea"; + case ATK_ROLE_SECTION: + return "AXSection"; + case ATK_ROLE_SEPARATOR: + return "AXSeparator"; + case ATK_ROLE_SLIDER: + return "AXSlider"; + case ATK_ROLE_SPIN_BUTTON: + return "AXSpinButton"; + case ATK_ROLE_STATUSBAR: + return "AXStatusBar"; + case ATK_ROLE_TABLE: + return "AXTable"; + case ATK_ROLE_TABLE_CELL: + return "AXCell"; + case ATK_ROLE_TABLE_COLUMN_HEADER: + return "AXColumnHeader"; + case ATK_ROLE_TABLE_ROW: + return "AXRow"; + case ATK_ROLE_TABLE_ROW_HEADER: + return "AXRowHeader"; + case ATK_ROLE_TOGGLE_BUTTON: + return "AXToggleButton"; + case ATK_ROLE_TOOL_BAR: + return "AXToolbar"; + case ATK_ROLE_TOOL_TIP: + return "AXUserInterfaceTooltip"; + case ATK_ROLE_TREE: + return "AXTree"; + case ATK_ROLE_TREE_TABLE: + return "AXTreeGrid"; + case ATK_ROLE_TREE_ITEM: + return "AXTreeItem"; + case ATK_ROLE_WINDOW: + return "AXWindow"; + case ATK_ROLE_UNKNOWN: + return "AXUnknown"; +#if ATK_CHECK_VERSION(2, 11, 3) + case ATK_ROLE_ARTICLE: + return "AXArticle"; + case ATK_ROLE_DEFINITION: + return "AXDefinition"; + case ATK_ROLE_LOG: + return "AXLog"; + case ATK_ROLE_MARQUEE: + return "AXMarquee"; + case ATK_ROLE_MATH: + return "AXMath"; + case ATK_ROLE_TIMER: + return "AXTimer"; +#endif +#if ATK_CHECK_VERSION(2, 11, 4) + case ATK_ROLE_DESCRIPTION_LIST: + return "AXDescriptionList"; + case ATK_ROLE_DESCRIPTION_TERM: + return "AXDescriptionTerm"; + case ATK_ROLE_DESCRIPTION_VALUE: + return "AXDescriptionValue"; +#endif + default: + // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which + // our DRT isn't properly handling. + return "FIXME not identified"; + } +} + +inline gchar* replaceCharactersForResults(gchar* str) +{ + String uString = String::fromUTF8(str); + + // The object replacement character is passed along to ATs so we need to be + // able to test for their presence and do so without causing test failures. + uString.replace(objectReplacementCharacter, "<obj>"); + + // The presence of newline characters in accessible text of a single object + // is appropriate, but it makes test results (especially the accessible tree) + // harder to read. + uString.replace("\n", "<\\n>"); + + return g_strdup(uString.utf8().data()); +} + +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); +} + +String attributesOfElement(AccessibilityUIElement* element) +{ + StringBuilder builder; + + builder.append(String::format("%s\n", element->role()->string().utf8().data())); + + // For the parent we print its role and its name, if available. + builder.append("AXParent: "); + AccessibilityUIElement parent = element->parentElement(); + if (AtkObject* atkParent = parent.platformUIElement()) { + builder.append(roleToString(atkParent)); + const char* parentName = atk_object_get_name(atkParent); + if (parentName && g_utf8_strlen(parentName, -1)) + builder.append(String::format(": %s", parentName)); + } else + builder.append("(null)"); + builder.append("\n"); + + builder.append(String::format("AXChildren: %d\n", element->childrenCount())); + builder.append(String::format("AXPosition: { %f, %f }\n", element->x(), element->y())); + builder.append(String::format("AXSize: { %f, %f }\n", element->width(), element->height())); + + String title = element->title()->string(); + if (!title.isEmpty()) + builder.append(String::format("%s\n", title.utf8().data())); + + String description = element->description()->string(); + if (!description.isEmpty()) + builder.append(String::format("%s\n", description.utf8().data())); + + String value = element->stringValue()->string(); + if (!value.isEmpty()) + builder.append(String::format("%s\n", value.utf8().data())); + + builder.append(String::format("AXFocusable: %d\n", element->isFocusable())); + builder.append(String::format("AXFocused: %d\n", element->isFocused())); + builder.append(String::format("AXSelectable: %d\n", element->isSelectable())); + builder.append(String::format("AXSelected: %d\n", element->isSelected())); + builder.append(String::format("AXMultiSelectable: %d\n", element->isMultiSelectable())); + builder.append(String::format("AXEnabled: %d\n", element->isEnabled())); + builder.append(String::format("AXExpanded: %d\n", element->isExpanded())); + builder.append(String::format("AXRequired: %d\n", element->isRequired())); + builder.append(String::format("AXChecked: %d\n", element->isChecked())); + + String url = element->url()->string(); + if (!url.isEmpty()) + builder.append(String::format("%s\n", url.utf8().data())); + + // We append the ATK specific attributes as a single line at the end. + builder.append("AXPlatformAttributes: "); + builder.append(getAtkAttributeSetAsString(element->platformUIElement(), ObjectAttributeType)); + + return builder.toString(); +} + +static JSStringRef createStringWithAttributes(const Vector<AccessibilityUIElement>& elements) +{ + StringBuilder builder; + + for (Vector<AccessibilityUIElement>::const_iterator it = elements.begin(); it != elements.end(); ++it) { + builder.append(attributesOfElement(const_cast<AccessibilityUIElement*>(it))); + builder.append("\n------------\n"); + } + + return JSStringCreateWithUTF8CString(builder.toString().utf8().data()); +} + +static Vector<AccessibilityUIElement> getRowHeaders(AtkTable* accessible) +{ + Vector<AccessibilityUIElement> rowHeaders; + + int rowsCount = atk_table_get_n_rows(accessible); + for (int row = 0; row < rowsCount; ++row) + rowHeaders.append(AccessibilityUIElement(atk_table_get_row_header(accessible, row))); + + return rowHeaders; +} + +static Vector<AccessibilityUIElement> getColumnHeaders(AtkTable* accessible) +{ + Vector<AccessibilityUIElement> columnHeaders; + + int columnsCount = atk_table_get_n_columns(accessible); + for (int column = 0; column < columnsCount; ++column) + columnHeaders.append(AccessibilityUIElement(atk_table_get_column_header(accessible, column))); + + return columnHeaders; +} + +static Vector<AccessibilityUIElement> getVisibleCells(AccessibilityUIElement* element) +{ + Vector<AccessibilityUIElement> visibleCells; + + AtkTable* accessible = ATK_TABLE(element->platformUIElement()); + int rowsCount = atk_table_get_n_rows(accessible); + int columnsCount = atk_table_get_n_columns(accessible); + + for (int row = 0; row < rowsCount; ++row) { + for (int column = 0; column < columnsCount; ++column) + visibleCells.append(element->cellForColumnAndRow(column, row)); + } + + return visibleCells; +} + +} // namespace + +JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) +{ + GUniquePtr<gchar> rangeString(g_strdup("{0, 0}")); + + if (!ATK_IS_OBJECT(element)) + return JSStringCreateWithUTF8CString(rangeString.get()); + + 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.reset(g_strdup_printf("{%d, %d}", base, length)); + } + + return JSStringCreateWithUTF8CString(rangeString.get()); +} + +void alterCurrentValue(PlatformUIElement element, int factor) +{ + if (!ATK_IS_VALUE(element)) + return; + + GValue currentValue = G_VALUE_INIT; + atk_value_get_current_value(ATK_VALUE(element), ¤tValue); + + GValue increment = G_VALUE_INIT; + atk_value_get_minimum_increment(ATK_VALUE(element), &increment); + + GValue newValue = G_VALUE_INIT; + g_value_init(&newValue, G_TYPE_FLOAT); + + g_value_set_float(&newValue, g_value_get_float(¤tValue) + factor * g_value_get_float(&increment)); + atk_value_set_current_value(ATK_VALUE(element), &newValue); + + g_value_unset(&newValue); + g_value_unset(&increment); + g_value_unset(¤tValue); +} + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) +{ + if (m_element) + g_object_ref(m_element); +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) +{ + if (m_element) + g_object_ref(m_element); +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ + if (m_element) + g_object_unref(m_element); +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements) +{ + // FIXME: implement +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) +{ + // FIXME: implement +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) +{ + if (!ATK_IS_OBJECT(m_element)) + return; + + 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) +{ + if (!ATK_IS_OBJECT(m_element)) + return; + + 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 (!ATK_IS_TABLE(m_element)) + return 0; + + return atk_table_get_n_rows(ATK_TABLE(m_element)); +} + +int AccessibilityUIElement::columnCount() +{ + if (!ATK_IS_TABLE(m_element)) + return 0; + + return atk_table_get_n_columns(ATK_TABLE(m_element)); +} + +int AccessibilityUIElement::childrenCount() +{ + if (!ATK_IS_OBJECT(m_element)) + return 0; + + return atk_object_get_n_accessible_children(ATK_OBJECT(m_element)); +} + +AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) +{ + if (!ATK_IS_COMPONENT(m_element)) + return nullptr; + + GRefPtr<AtkObject> objectAtPoint = adoptGRef(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element), x, y, ATK_XY_WINDOW)); + return AccessibilityUIElement(objectAtPoint ? objectAtPoint.get() : m_element); +} + +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + // FIXME: implement + return nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + if (!ATK_IS_OBJECT(m_element)) + return nullptr; + + Vector<AccessibilityUIElement> children; + getChildrenWithRange(children, index, index + 1); + + if (children.size() == 1) + return children.at(0); + + return nullptr; +} + +unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) +{ + // FIXME: implement + return 0; +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + return JSStringCreateWithUTF8CString(attributesOfElement(this).utf8().data()); +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + if (!ATK_IS_OBJECT(m_element)) + return nullptr; + + AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element)); + if (!set) + return nullptr; + + AtkObject* target = nullptr; + int count = atk_relation_set_get_n_relations(set); + for (int i = 0; i < count; i++) { + AtkRelation* relation = atk_relation_set_get_relation(set, i); + if (atk_relation_get_relation_type(relation) == ATK_RELATION_LABELLED_BY) { + GPtrArray* targetList = atk_relation_get_target(relation); + if (targetList->len) + target = static_cast<AtkObject*>(g_ptr_array_index(targetList, 0)); + } + } + + g_object_unref(set); + return target ? AccessibilityUIElement(target) : nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::parentElement() +{ + if (!ATK_IS_OBJECT(m_element)) + return nullptr; + + AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element)); + return parent ? AccessibilityUIElement(parent) : nullptr; +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + Vector<AccessibilityUIElement> children; + getChildren(children); + + return createStringWithAttributes(children); +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::role() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + if (!atk_object_get_role(ATK_OBJECT(m_element))) + return JSStringCreateWithCharacters(0, 0); + + GUniquePtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(ATK_OBJECT(m_element)))); + return JSStringCreateWithUTF8CString(roleStringWithPrefix.get()); +} + +JSStringRef AccessibilityUIElement::subrole() +{ + return nullptr; +} + +JSStringRef AccessibilityUIElement::roleDescription() +{ + return nullptr; +} + +JSStringRef AccessibilityUIElement::title() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + const gchar* name = atk_object_get_name(ATK_OBJECT(m_element)); + GUniquePtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : "")); + + return JSStringCreateWithUTF8CString(axTitle.get()); +} + +JSStringRef AccessibilityUIElement::description() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + const gchar* description = atk_object_get_description(ATK_OBJECT(m_element)); + if (!description) + return JSStringCreateWithCharacters(0, 0); + + GUniquePtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description)); + + return JSStringCreateWithUTF8CString(axDesc.get()); +} + +JSStringRef AccessibilityUIElement::stringValue() +{ + if (!ATK_IS_TEXT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element), 0, -1)); + GUniquePtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get())); + GUniquePtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get())); + + return JSStringCreateWithUTF8CString(axValue.get()); +} + +JSStringRef AccessibilityUIElement::language() +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + const gchar* locale = atk_object_get_object_locale(ATK_OBJECT(m_element)); + if (!locale) + return JSStringCreateWithCharacters(0, 0); + + GUniquePtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale)); + return JSStringCreateWithUTF8CString(axValue.get()); +} + +JSStringRef AccessibilityUIElement::helpText() const +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element)); + if (!relationSet) + return nullptr; + + AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY); + if (!relation) + return nullptr; + + GPtrArray* targetList = atk_relation_get_target(relation); + if (!targetList || !targetList->len) + return nullptr; + + StringBuilder builder; + builder.append("AXHelp: "); + + for (int targetCount = 0; targetCount < targetList->len; targetCount++) { + if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) { + GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1)); + if (!builder.isEmpty()) + builder.append(" "); + builder.append(text.get()); + } + } + + g_object_unref(relationSet); + + return JSStringCreateWithUTF8CString(builder.toString().utf8().data()); + +} + +double AccessibilityUIElement::x() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int x, y; + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); + + return x; +} + +double AccessibilityUIElement::y() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int x, y; + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN); + + return y; +} + +double AccessibilityUIElement::width() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int width, height; + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return width; +} + +double AccessibilityUIElement::height() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int width, height; + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return height; +} + +double AccessibilityUIElement::clickPointX() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int x, y; + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_WINDOW); + + int width, height; + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return x + width / 2.0; +} + +double AccessibilityUIElement::clickPointY() +{ + if (!ATK_IS_COMPONENT(m_element)) + return 0; + + int x, y; + atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_WINDOW); + + int width, height; + atk_component_get_size(ATK_COMPONENT(m_element), &width, &height); + + return y + height / 2.0; +} + +JSStringRef AccessibilityUIElement::orientation() const +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + const char* axOrientation = nullptr; + if (checkElementState(m_element, ATK_STATE_HORIZONTAL)) + axOrientation = "AXOrientation: AXHorizontalOrientation"; + else if (checkElementState(m_element, ATK_STATE_VERTICAL)) + axOrientation = "AXOrientation: AXVerticalOrientation"; + + if (!axOrientation) + return JSStringCreateWithCharacters(0, 0); + + return JSStringCreateWithUTF8CString(axOrientation); +} + +double AccessibilityUIElement::intValue() const +{ + if (!ATK_IS_OBJECT(m_element)) + return 0; + + if (ATK_IS_VALUE(m_element)) { + GValue value = G_VALUE_INIT; + atk_value_get_current_value(ATK_VALUE(m_element), &value); + if (!G_VALUE_HOLDS_FLOAT(&value)) + return 0; + return g_value_get_float(&value); + } + + // Consider headings as an special case when returning the "int value" of + // an AccessibilityUIElement, so we can reuse some tests to check the level + // both for HTML headings and objects with the aria-level attribute. + if (atk_object_get_role(ATK_OBJECT(m_element)) == ATK_ROLE_HEADING) { + String headingLevel = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, "level"); + bool ok; + double headingLevelValue = headingLevel.toDouble(&ok); + if (ok) + return headingLevelValue; + } + + return 0; +} + +double AccessibilityUIElement::minValue() +{ + if (!ATK_IS_VALUE(m_element)) + return 0; + + GValue value = G_VALUE_INIT; + atk_value_get_minimum_value(ATK_VALUE(m_element), &value); + if (!G_VALUE_HOLDS_FLOAT(&value)) + return 0; + return g_value_get_float(&value); +} + +double AccessibilityUIElement::maxValue() +{ + if (!ATK_IS_VALUE(m_element)) + return 0; + + GValue value = G_VALUE_INIT; + atk_value_get_maximum_value(ATK_VALUE(m_element), &value); + if (!G_VALUE_HOLDS_FLOAT(&value)) + return 0; + return g_value_get_float(&value); +} + +JSStringRef AccessibilityUIElement::valueDescription() +{ + // FIXME: implement after it has been implemented in ATK. + // See: https://bugzilla.gnome.org/show_bug.cgi?id=684576 + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::isEnabled() +{ + return checkElementState(m_element, ATK_STATE_ENABLED); +} + +int AccessibilityUIElement::insertionPointLineNumber() +{ + // FIXME: implement + return 0; +} + +bool AccessibilityUIElement::isPressActionSupported() +{ + if (!ATK_IS_ACTION(m_element)) + return false; + + const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element), 0); + return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump")); +} + +bool AccessibilityUIElement::isIncrementActionSupported() +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isDecrementActionSupported() +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isRequired() const +{ + return checkElementState(m_element, ATK_STATE_REQUIRED); +} + +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 nullptr; +} + +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; +} + +bool AccessibilityUIElement::isIndeterminate() const +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element))); + return atk_state_set_contains_state(stateSet.get(), ATK_STATE_INDETERMINATE); +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + if (!ATK_IS_TABLE(m_element)) + return JSStringCreateWithCharacters(0, 0); + + Vector<AccessibilityUIElement> columnHeaders = getColumnHeaders(ATK_TABLE(m_element)); + return createStringWithAttributes(columnHeaders); +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + if (!ATK_IS_TABLE(m_element)) + return JSStringCreateWithCharacters(0, 0); + + Vector<AccessibilityUIElement> rowHeaders = getRowHeaders(ATK_TABLE(m_element)); + return createStringWithAttributes(rowHeaders); +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + if (!ATK_IS_TABLE(m_element)) + return JSStringCreateWithCharacters(0, 0); + + Vector<AccessibilityUIElement> visibleCells = getVisibleCells(this); + return createStringWithAttributes(visibleCells); +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +int AccessibilityUIElement::indexInTable() +{ + // FIXME: implement + return 0; +} + +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 index) +{ + if (!ATK_IS_TEXT(m_element)) + return -1; + + if (index < 0 || index > atk_text_get_character_count(ATK_TEXT(m_element))) + return -1; + + GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element), 0, index)); + int lineNo = 0; + for (gchar* offset = text.get(); *offset; ++offset) { + if (*offset == '\n') + ++lineNo; + } + + return lineNo; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length) +{ + if (!ATK_IS_TEXT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + String string = atk_text_get_text(ATK_TEXT(m_element), location, location + length); + return JSStringCreateWithUTF8CString(string.utf8().data()); +} + +JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) +{ + // FIXME: implement + return false; +} + +unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly) +{ + // FIXME: implement + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly) +{ + // FIXME: implement + return nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) +{ + if (!ATK_IS_TABLE(m_element)) + return nullptr; + + // Adopt the AtkObject representing the cell because + // at_table_ref_at() transfers full ownership. + GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element), row, column)); + return foundCell ? AccessibilityUIElement(foundCell.get()) : nullptr; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + if (!ATK_IS_TEXT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + gint start, end; + g_free(atk_text_get_selection(ATK_TEXT(m_element), 0, &start, &end)); + + GUniquePtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start)); + return JSStringCreateWithUTF8CString(selection.get()); +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ + if (!ATK_IS_TEXT(m_element)) + return; + + atk_text_set_selection(ATK_TEXT(m_element), 0, location, location + length); +} + +JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) +{ + if (!ATK_IS_OBJECT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + String atkAttributeName = coreAttributeToAtkAttribute(attribute); + + // Try object attributes first. + String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, atkAttributeName); + + // Try text attributes if the requested one was not found and we have an AtkText object. + if (attributeValue.isEmpty() && ATK_IS_TEXT(m_element)) + attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), TextAttributeType, atkAttributeName); + + // Additional check to make sure that the exposure of the state ATK_STATE_INVALID_ENTRY + // is consistent with the exposure of aria-invalid as a text attribute, if present. + if (atkAttributeName == attributesMap[InvalidNameIndex][AtkDomain]) { + bool isInvalidState = checkElementState(m_element, ATK_STATE_INVALID_ENTRY); + if (attributeValue.isEmpty()) + return JSStringCreateWithUTF8CString(isInvalidState ? "true" : "false"); + + // If the text attribute was there, check that it's consistent with + // what the state says or force the test to fail otherwise. + bool isAriaInvalid = attributeValue != "false"; + if (isInvalidState != isAriaInvalid) + return JSStringCreateWithCharacters(0, 0); + } + + return JSStringCreateWithUTF8CString(attributeValue.utf8().data()); +} + +double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return 0; +} + +bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + String attributeString = jsStringToWTFString(attribute); + if (attributeString == "AXValue") + return checkElementState(m_element, ATK_STATE_EDITABLE); + + return false; +} + +bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + String atkAttributeName = coreAttributeToAtkAttribute(attribute); + if (atkAttributeName.isEmpty()) + return false; + + // For now, an attribute is supported whether it's exposed as a object or a text attribute. + String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, atkAttributeName); + if (attributeValue.isEmpty()) + attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), TextAttributeType, atkAttributeName); + + return !attributeValue.isEmpty(); +} + +void AccessibilityUIElement::increment() +{ + alterCurrentValue(m_element, 1); +} + +void AccessibilityUIElement::decrement() +{ + alterCurrentValue(m_element, -1); +} + +void AccessibilityUIElement::press() +{ + 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 nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +{ + return nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + if (!ATK_IS_OBJECT(m_element)) + return nullptr; + + AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element)); + if (!relationSet) + return nullptr; + + AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO); + if (!relation) + return nullptr; + + GPtrArray* targetList = atk_relation_get_target(relation); + if (!targetList || !targetList->len || index >= targetList->len) + return nullptr; + + g_object_unref(relationSet); + + AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index)); + return target ? AccessibilityUIElement(target) : nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) +{ + return nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index) +{ + return nullptr; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedByRow() +{ + return nullptr; +} + +JSStringRef AccessibilityUIElement::accessibilityValue() const +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentEncoding() +{ + if (!ATK_IS_DOCUMENT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + 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() +{ + if (!ATK_IS_DOCUMENT(m_element)) + return JSStringCreateWithCharacters(0, 0); + + 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() +{ + if (!ATK_IS_HYPERLINK_IMPL(m_element)) + return JSStringCreateWithCharacters(0, 0); + + AtkHyperlink* hyperlink = atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(m_element)); + GUniquePtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0)); + + // Build the result string, stripping the absolute URL paths if present. + char* localURI = g_strstr_len(hyperlinkURI.get(), -1, "LayoutTests"); + String axURL = String::format("AXURL: %s", localURI ? localURI : hyperlinkURI.get()); + return JSStringCreateWithUTF8CString(axURL.utf8().data()); +} + +bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + // Only one notification listener per element. + if (m_notificationHandler) + return false; + + m_notificationHandler = AccessibilityNotificationHandler::create(); + m_notificationHandler->setPlatformElement(platformUIElement()); + m_notificationHandler->setNotificationFunctionCallback(functionCallback); + + return true; +} + +void AccessibilityUIElement::removeNotificationListener() +{ + // Programmers should not be trying to remove a listener that's already removed. + ASSERT(m_notificationHandler); + + m_notificationHandler = nullptr; +} + +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 +{ + return checkElementState(m_element, ATK_STATE_SELECTABLE); +} + +bool AccessibilityUIElement::isMultiSelectable() const +{ + return checkElementState(m_element, ATK_STATE_MULTISELECTABLE); +} + +bool AccessibilityUIElement::isSelectedOptionActive() const +{ + return checkElementState(m_element, ATK_STATE_ACTIVE); +} + +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 +{ + if (!ATK_IS_OBJECT(m_element)) + return false; + + String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, "haspopup"); + return equalIgnoringCase(hasPopupValue, "true"); +} + +void AccessibilityUIElement::takeFocus() +{ + // FIXME: implement +} + +void AccessibilityUIElement::takeSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::addSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::removeSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::scrollToMakeVisible() +{ + // FIXME: implement +} + +void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height) +{ + // FIXME: implement +} + +void AccessibilityUIElement::scrollToGlobalPoint(int x, int y) +{ + // FIXME: implement +} + +JSStringRef AccessibilityUIElement::classList() const +{ + // FIXME: implement + return nullptr; +} + +JSStringRef stringAtOffset(PlatformUIElement element, AtkTextBoundary boundary, int offset) +{ + if (!ATK_IS_TEXT(element)) + return JSStringCreateWithCharacters(0, 0); + + gint startOffset, endOffset; + StringBuilder builder; + +#if ATK_CHECK_VERSION(2, 10, 0) + AtkTextGranularity granularity; + switch (boundary) { + case ATK_TEXT_BOUNDARY_CHAR: + granularity = ATK_TEXT_GRANULARITY_CHAR; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + granularity = ATK_TEXT_GRANULARITY_WORD; + break; + case ATK_TEXT_BOUNDARY_LINE_START: + granularity = ATK_TEXT_GRANULARITY_LINE; + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + granularity = ATK_TEXT_GRANULARITY_SENTENCE; + break; + default: + return JSStringCreateWithCharacters(0, 0); + } + + builder.append(atk_text_get_string_at_offset(ATK_TEXT(element), offset, granularity, &startOffset, &endOffset)); +#else + builder.append(atk_text_get_text_at_offset(ATK_TEXT(element), offset, boundary, &startOffset, &endOffset)); +#endif + builder.append(String::format(", %i, %i", startOffset, endOffset)); + return JSStringCreateWithUTF8CString(builder.toString().utf8().data()); +} + +JSStringRef AccessibilityUIElement::characterAtOffset(int offset) +{ + return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_CHAR, offset); +} + +JSStringRef AccessibilityUIElement::wordAtOffset(int offset) +{ + return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_WORD_START, offset); +} + +JSStringRef AccessibilityUIElement::lineAtOffset(int offset) +{ + return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_LINE_START, offset); +} + +JSStringRef AccessibilityUIElement::sentenceAtOffset(int offset) +{ + return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_SENTENCE_START, offset); +} + +#endif diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp index 9c8931075..fe6046c68 100644 --- a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp +++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp @@ -12,7 +12,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h index a2fac882b..071e874d0 100644 --- a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h +++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h @@ -11,7 +11,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h index 9e0fe4fd4..ddb1d5195 100644 --- a/Tools/DumpRenderTree/config.h +++ b/Tools/DumpRenderTree/config.h @@ -20,11 +20,16 @@ #define Config_H -#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE) +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#if defined(BUILDING_WITH_CMAKE) #include "cmakeconfig.h" +#else +#include "autotoolsconfig.h" +#endif #endif -#include <WebCore/PlatformExportMacros.h> +#include <wtf/Platform.h> +#include <wtf/ExportMacros.h> #include <runtime/JSExportMacros.h> #ifdef __cplusplus @@ -33,25 +38,39 @@ #include <wtf/FastMalloc.h> #endif -#if PLATFORM(COCOA) -#define USE_CF 1 -#endif +#if PLATFORM(MAC) +#define WTF_USE_CF 1 + +// FIXME: These can be removed after sufficient time has passed since the removal of BUILDING_ON / TARGETING macros. + +#define ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED 0 / 0 +#define ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED 0 / 0 + +#define BUILDING_ON_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED +#define BUILDING_ON_SNOW_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED +#define BUILDING_ON_LION ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED + +#define TARGETING_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED +#define TARGETING_SNOW_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED +#define TARGETING_LION ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED + +#endif // PLATFORM(MAC) #if PLATFORM(WIN) -#define USE_CF 1 +#define WTF_USE_CF 1 #if PLATFORM(WIN_CAIRO) -#define USE_CAIRO 1 -#define USE_CURL 1 +#define WTF_USE_CAIRO 1 +#define WTF_USE_CURL 1 #else -#define USE_CG 1 -#define USE_CFNETWORK 1 +#define WTF_USE_CG 1 +#define WTF_USE_CFNETWORK 1 #endif #undef _WIN32_WINNT -#define _WIN32_WINNT 0x601 +#define _WIN32_WINNT 0x0502 #undef WINVER -#define WINVER 0x0601 +#define WINVER 0x0502 #undef _WINSOCKAPI_ #define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp new file mode 100644 index 000000000..7ee1d9460 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp @@ -0,0 +1,79 @@ +/* + * 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" + +#if HAVE(ACCESSIBILITY) + +#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> +#include <wtf/gobject/GUniquePtr.h> + +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); +} + +AccessibilityUIElement AccessibilityController::accessibleElementById(JSStringRef id) +{ + AtkObject* root = DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame); + if (!root) + return 0; + + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(id); + GUniquePtr<gchar> idBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(id, idBuffer.get(), bufferSize); + + AtkObject* result = childElementById(root, idBuffer.get()); + if (ATK_IS_OBJECT(result)) + return AccessibilityUIElement(result); + + return 0; + +} + +#endif // HAVE(ACCESSIBILITY) diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp new file mode 100644 index 000000000..73d710a04 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -0,0 +1,1557 @@ +/* + * 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 "PixelDumpSupport.h" +#include "SelfScrollingWebKitWebView.h" +#include "TestRunner.h" +#include "TextInputController.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include "WebCoreTestSupport.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include <JavaScriptCore/JavaScript.h> +#include <WebCore/platform/network/soup/GUniquePtrSoup.h> +#include <cassert> +#include <cstdlib> +#include <cstring> +#include <getopt.h> +#include <gtk/gtk.h> +#include <locale.h> +#include <webkit/webkit.h> +#include <wtf/Assertions.h> +#include <wtf/gobject/GlibUtilities.h> +#include <wtf/text/WTFString.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 dumpPixelsForAllTests = false; +static bool dumpPixelsForCurrentTest; +static int dumpTree = 1; +static int useTimeoutWatchdog = 1; + +#if HAVE(ACCESSIBILITY) +AccessibilityController* axController = 0; +#endif +RefPtr<TestRunner> gTestRunner; +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& inputLine); + +static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url); + +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) +{ + WebKitDOMDocument* document = webkit_web_frame_get_dom_document(frame); + if (!document) + return; + + WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document); + if (!domWindow) + return; + + glong x = webkit_dom_dom_window_get_page_x_offset(domWindow); + glong y = webkit_dom_dom_window_get_page_y_offset(domWindow); + + if (abs(x) > 0 || abs(y) > 0) { + if (webkit_web_frame_get_parent(frame)) + printf("frame '%s' ", webkit_web_frame_get_name(frame)); + printf("scrolled to %ld,%ld\n", x, y); + } + + if (gTestRunner->dumpChildFrameScrollPositions()) { + GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame); + for (GSList* child = children; child; child = g_slist_next(child)) + dumpFrameScrollPosition(static_cast<WebKitWebFrame*>(child->data)); + g_slist_free(children); + } +} + +void displayWebView() +{ + DumpRenderTreeSupportGtk::forceWebViewPaint(webView); + DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, true); + DumpRenderTreeSupportGtk::resetTrackedRepaints(mainFrame); +} + +static void appendString(gchar*& target, const 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", + "gtk-icon-theme-name", "gnome", + 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); +} + +CString getTopLevelPath() +{ + if (const gchar* topLevel = g_getenv("WEBKIT_TOP_LEVEL")) + return topLevel; + + g_setenv("WEBKIT_TOP_LEVEL", TOP_LEVEL_DIR, FALSE); + return TOP_LEVEL_DIR; +} + +CString getOutputDir() +{ + const char* webkitOutputDir = g_getenv("WEBKIT_OUTPUTDIR"); + if (webkitOutputDir) + return webkitOutputDir; + + CString topLevelPath = getTopLevelPath(); + GUniquePtr<char> outputDir(g_build_filename(topLevelPath.data(), "WebKitBuild", NULL)); + return outputDir.get(); +} + +static CString getFontsPath() +{ + CString webkitOutputDir = getOutputDir(); + GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "Dependencies", "Root", "webkitgtk-test-fonts", NULL)); + if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + return fontsPath.get(); + + // Try alternative fonts path. + fontsPath.reset(g_build_filename(webkitOutputDir.data(), "webkitgtk-test-fonts", NULL)); + if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + return fontsPath.get(); + + return CString(); +} + +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(); + GUniquePtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", nullptr)); + if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true)) + g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get()); + + CString fontsPath = getFontsPath(); + if (fontsPath.isNull()) + g_error("Could not locate test fonts at $WEBKIT_TOP_LEVEL/WebKitBuild/Dependencies/Root/webkitgtk-test-fonts. " + "WEBKIT_TOP_LEVEL is your WebKit checkout by default, and can be overridden by setting it as an environment variable."); + + GUniquePtr<GDir> fontsDirectory(g_dir_open(fontsPath.data(), 0, nullptr)); + while (const char* directoryEntry = g_dir_read_name(fontsDirectory.get())) { + if (!g_str_has_suffix(directoryEntry, ".ttf") && !g_str_has_suffix(directoryEntry, ".otf")) + continue; + GUniquePtr<gchar> fontPath(g_build_filename(fontsPath.data(), directoryEntry, nullptr)); + 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. + GUniquePtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", nullptr)); + 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++) { + GUniquePtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i)); + GUniquePtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), nullptr)); + 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 + GUniquePtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", nullptr)); + 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 (gTestRunner->dumpChildFramesAsText()) { + GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame); + for (GSList* child = children; child; child = g_slist_next(child)) { + GUniquePtr<gchar> childData(dumpFramesAsText(static_cast<WebKitWebFrame*>(child->data))); + appendString(result, childData.get()); + } + g_slist_free(children); + } + + return result; +} + +static gint compareHistoryItems(gpointer* item1, gpointer* item2) +{ + GUniquePtr<gchar> firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1))); + GUniquePtr<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) { + g_free(uriScheme); + 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); + + GUniquePtr<gchar> target(webkit_web_history_item_get_target(item)); + if (target.get() && strlen(target.get()) > 0) + printf(" (in frame \"%s\")", target.get()); + 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)); +} + +void setWaitToDumpWatchdog(guint timer) +{ + waitToDumpWatchdog = timer; +} + +bool shouldSetWaitToDumpWatchdog() +{ + return !waitToDumpWatchdog && useTimeoutWatchdog; +} + +CString soupURIToStringPreservingPassword(SoupURI* soupURI) +{ + if (!soupURI->password) { + GUniquePtr<char> uriString(soup_uri_to_string(soupURI, FALSE)); + return uriString.get(); + } + + // soup_uri_to_string does not insert the password into the string, so we need to create the + // URI string and then reinsert any credentials that were present in the SoupURI. All tests that + // use URL-embedded credentials use HTTP, so it's safe here. + GUniquePtr<char> password(soupURI->password); + GUniquePtr<char> user(soupURI->user); + soupURI->password = 0; + soupURI->user = 0; + + GUniquePtr<char> uriString(soup_uri_to_string(soupURI, FALSE)); + String absoluteURIWithoutCredentialString = String::fromUTF8(uriString.get()); + String protocolAndCredential = String::format("http://%s:%s@", user ? user.get() : "", password.get()); + return absoluteURIWithoutCredentialString.replace("http://", protocolAndCredential).utf8(); +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + g_source_remove(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } + + waitForPolicy = false; +} + +static void resetDefaultsToConsistentValues() +{ + WebKitWebSettings* settings = webkit_web_view_get_settings(webView); + GUniquePtr<gchar> localStoragePath(g_build_filename(g_get_user_data_dir(), "DumpRenderTreeGtk", "databases", nullptr)); + g_object_set(G_OBJECT(settings), + "enable-accelerated-compositing", FALSE, + "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, + "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-file-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, + "auto-load-images", TRUE, + "enable-java-applet", FALSE, + "enable-plugins", TRUE, + "enable-hyperlink-auditing", FALSE, + "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, + "enable-fullscreen", TRUE, + "enable-mediasource", 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::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::setDefersLoading(webView, false); + DumpRenderTreeSupportGtk::setSerializeHTTPLoads(false); + +#if HAVE(ACCESSIBILITY) + if (axController) + axController->resetToConsistentState(); +#endif + + DumpRenderTreeSupportGtk::clearOpener(mainFrame); + DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, false); + + DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView); + + DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(webView, false); + DumpRenderTreeSupportGtk::setCSSRegionsEnabled(webView, true); + DumpRenderTreeSupportGtk::setExperimentalContentSecurityPolicyFeaturesEnabled(true); + DumpRenderTreeSupportGtk::setSeamlessIFramesEnabled(true); + DumpRenderTreeSupportGtk::setShadowDOMEnabled(true); + + if (gTestRunner) { + gTestRunner->setAuthenticationPassword(""); + gTestRunner->setAuthenticationUsername(""); + gTestRunner->setHandlesAuthenticationChallenges(false); + } + + gtk_widget_set_direction(GTK_WIDGET(webView), GTK_TEXT_DIR_NONE); +} + +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, &dumpPixelsForAllTests, true}, + {"tree", no_argument, &dumpTree, true}, + {"no-timeout", no_argument, &useTimeoutWatchdog, false}, + {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(); + + // Grab widget focus before dumping the contents of a widget, in + // case it was lost in the course of the test. + gtk_widget_grab_focus(GTK_WIDGET(webView)); + + if (dumpTree) { + char* result = 0; + gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame); + + if (g_str_equal(responseMimeType, "text/plain")) { + gTestRunner->setDumpAsText(true); + gTestRunner->setGeneratePixelResults(false); + } + g_free(responseMimeType); + + if (gTestRunner->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 (gTestRunner->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (gTestRunner->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (gTestRunner->dumpSourceAsWebArchive()) + errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + printf("ERROR: nil result from %s", errorMessage); + } else { + printf("%s", result); + g_free(result); + if (!gTestRunner->dumpAsText() && !gTestRunner->dumpDOMAsWebArchive() && !gTestRunner->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + + if (gTestRunner->dumpBackForwardList()) + dumpBackForwardListForAllWebViews(); + } + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (dumpPixelsForCurrentTest + && gTestRunner->generatePixelResults() + && !gTestRunner->dumpDOMAsWebArchive() + && !gTestRunner->dumpSourceAsWebArchive()) { + DumpRenderTreeSupportGtk::forceWebViewPaint(webView); + dumpWebViewAsPixelsAndCompareWithExpected(gTestRunner->expectedPixelHash()); + } + + // FIXME: call displayWebView here when we support --paint + + done = true; + gtk_main_quit(); +} + +static CString temporaryDatabaseDirectory() +{ + const char* directoryFromEnvironment = g_getenv("DUMPRENDERTREE_TEMP"); + if (directoryFromEnvironment) + return directoryFromEnvironment; + GUniquePtr<char> fallback(g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL)); + return fallback.get(); +} + +static void setDefaultsToConsistentStateValuesForTesting() +{ + resetDefaultsToConsistentValues(); + +#if PLATFORM(X11) + webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR); +#endif + + webkit_set_web_database_directory_path(temporaryDatabaseDirectory().data()); + +#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, + "@binding-set NoKeyboardNavigation { " + " unbind \"<shift>F10\"; " + "} " + " * { " + " -GtkScrolledWindow-scrollbar-spacing: 0;" + " gtk-key-bindings: NoKeyboardNavigation; " + "} ", + -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& inputLine) +{ + ASSERT(!inputLine.empty()); + + TestCommand command = parseInputLine(inputLine); + string& testURL = command.pathOrURL; + dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests; + + // 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(); + + gTestRunner = TestRunner::create(testURL, command.expectedPixelHash); + topLoadingFrame = 0; + done = false; + + gTestRunner->setIconDatabaseEnabled(false); + + if (shouldLogFrameLoadDelegates(testURL)) + gTestRunner->setDumpFrameLoadCallbacks(true); + + if (shouldEnableDeveloperExtras(testURL)) { + gTestRunner->setDeveloperExtrasEnabled(true); + if (shouldOpenWebInspector(testURL)) + gTestRunner->showWebInspector(); + if (shouldDumpAsText(testURL)) { + gTestRunner->setDumpAsText(true); + gTestRunner->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 ? TestRunner::w3cSVGViewWidth : TestRunner::viewWidth; + size.height = isSVGW3CTest ? TestRunner::w3cSVGViewHeight : TestRunner::viewHeight; + 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)) { + gTestRunner->closeWebInspector(); + gTestRunner->setDeveloperExtrasEnabled(false); + } + + // Also check if we still have opened webViews and free them. + if (gTestRunner->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)); + DumpRenderTreeSupportGtk::clearMemoryCache(); + DumpRenderTreeSupportGtk::clearApplicationCache(); + + // A blank load seems to be necessary to reset state after certain tests. + webkit_web_view_open(webView, "about:blank"); + + gTestRunner.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() && !gTestRunner->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 (gTestRunner->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 && gTestRunner->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 && gTestRunner->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(gTestRunner); + + gTestRunner->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + +#if HAVE(ACCESSIBILITY) + axController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); +#endif + + addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame))); + 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) { + // If the path is a lone slash, keep it to avoid empty output. + if (strlen(filename) > 1) + 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: "); + if (line) + fprintf(stdout, "line %d: ", line); + fprintf(stdout, "%s\n", 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); + fflush(stdout); + 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 (gTestRunner->dumpFrameLoadCallbacks() && !done) { + GUniquePtr<char> frameName(getFrameNameSuitableForTestResult(view, frame)); + printf("%s - didReceiveTitle: %s\n", frameName.get(), title ? title : ""); + } + + if (gTestRunner->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., TestRunner::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); + gTestRunner->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 (gTestRunner->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 (gTestRunner->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 (!gTestRunner->isGeolocationPermissionSet()) + return FALSE; + if (gTestRunner->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), TestRunner::viewWidth, TestRunner::viewHeight); + 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 (gTestRunner->waitToDump()) + return; + + if (WorkQueue::shared()->count()) + g_idle_add_full(G_PRIORITY_DEFAULT, processWork, 0, 0); + else + dump(); +} + +static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data) +{ + WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame); + + if (gTestRunner->dumpFrameLoadCallbacks()) { + GUniquePtr<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; + case WEBKIT_LOAD_FAILED: + if (!done) + printf("%s - didFailLoadWithError\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); + g_signal_connect(webFrame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL); +} + +static String pathFromSoupURI(SoupURI* uri) +{ + if (!uri) + return "(null)"; + + if (!g_str_equal(uri->scheme, "file")) + return soupURIToStringPreservingPassword(uri).data(); + + String pathString = uri->path; + GUniquePtr<gchar> pathBasename(g_path_get_basename(pathString.utf8().data())); + + WebKitWebFrame* mainFrame = webkit_web_view_get_main_frame(webView); + GUniquePtr<SoupURI> mainFrameUri(soup_uri_new(webkit_web_frame_get_uri(mainFrame))); + + String mainFrameUriPathString = mainFrameUri.get()->path; + String basePath = mainFrameUriPathString.substring(0, mainFrameUriPathString.reverseFind('/') + 1); + + if (!basePath.isEmpty() && pathString.startsWith(basePath)) + return pathString.substring(basePath.length()); + + return pathBasename.get(); +} + +static CString convertSoupMessageToURLPath(SoupMessage* soupMessage) +{ + if (!soupMessage) + return CString("(null)"); + if (SoupURI* requestURI = soup_message_get_uri(soupMessage)) + return pathFromSoupURI(requestURI).utf8(); + return CString("(null)"); +} + +static CString convertNetworkRequestToURLPath(WebKitNetworkRequest* request) +{ + return convertSoupMessageToURLPath(webkit_network_request_get_message(request)); +} + +static CString convertWebResourceToURLPath(WebKitWebResource* webResource) +{ + GUniquePtr<SoupURI> uri(soup_uri_new(webkit_web_resource_get_uri(webResource))); + return pathFromSoupURI(uri.get()).utf8(); +} + +static CString urlSuitableForTestResult(const char* uriString) +{ + if (!g_str_has_prefix(uriString, "file://")) + return CString(uriString); + + GUniquePtr<gchar> basename(g_path_get_basename(uriString)); + return CString(basename.get()); +} + +static CString descriptionSuitableForTestResult(SoupURI* uri) +{ + if (!uri) + return CString("(null)"); + + GUniquePtr<char> uriString(soup_uri_to_string(uri, false)); + return urlSuitableForTestResult(uriString.get()); +} + +static CString descriptionSuitableForTestResult(GError* error, WebKitWebResource* webResource) +{ + const gchar* errorDomain = g_quark_to_string(error->domain); + CString resourceURIString(urlSuitableForTestResult(webkit_web_resource_get_uri(webResource))); + + if (g_str_equal(errorDomain, "webkit-network-error-quark") || g_str_equal(errorDomain, "soup_http_error_quark")) + errorDomain = "NSURLErrorDomain"; + + if (g_str_equal(errorDomain, "WebKitPolicyError")) + errorDomain = "WebKitErrorDomain"; + + // TODO: the other ports get the failingURL from the ResourceError + GUniquePtr<char> errorString(g_strdup_printf("<NSError domain %s, code %d, failing URL \"%s\">", + errorDomain, error->code, resourceURIString.data())); + return CString(errorString.get()); +} + +static CString descriptionSuitableForTestResult(WebKitNetworkRequest* request) +{ + SoupMessage* soupMessage = webkit_network_request_get_message(request); + + if (!soupMessage) + return CString("(null)"); + + SoupURI* mainDocumentURI = soup_message_get_first_party(soupMessage); + CString mainDocumentURIString(descriptionSuitableForTestResult(mainDocumentURI)); + CString path(convertNetworkRequestToURLPath(request)); + GUniquePtr<char> description(g_strdup_printf("<NSURLRequest URL %s, main document URL %s, http method %s>", + path.data(), mainDocumentURIString.data(), soupMessage->method)); + return CString(description.get()); +} + +static CString descriptionSuitableForTestResult(WebKitNetworkResponse* response) +{ + if (!response) + return CString("(null)"); + + int statusCode = 0; + CString responseURIString(urlSuitableForTestResult(webkit_network_response_get_uri(response))); + SoupMessage* soupMessage = webkit_network_response_get_message(response); + CString path; + + if (soupMessage) { + statusCode = soupMessage->status_code; + path = convertSoupMessageToURLPath(soupMessage); + } else + path = CString("(null)"); + + GUniquePtr<char> description(g_strdup_printf("<NSURLResponse %s, http status code %d>", path.data(), statusCode)); + return CString(description.get()); +} + +static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response) +{ + + + if (!done && gTestRunner->willSendRequestReturnsNull()) { + // As requested by the TestRunner, don't perform the request. + webkit_network_request_set_uri(request, "about:blank"); + return; + } + + if (!done && gTestRunner->dumpResourceLoadCallbacks()) + printf("%s - willSendRequest %s redirectResponse %s\n", + convertNetworkRequestToURLPath(request).data(), + descriptionSuitableForTestResult(request).data(), + descriptionSuitableForTestResult(response).data()); + + SoupMessage* soupMessage = webkit_network_request_get_message(request); + SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request)); + + if (SOUP_URI_IS_VALID(uri)) { + GUniquePtr<char> uriString(soup_uri_to_string(uri, FALSE)); + + 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", uriString.get()); + // Cancel load of blocked resource to avoid potential + // network-related timeouts in tests. + webkit_network_request_set_uri(request, "about:blank"); + soup_uri_free(uri); + return; + } + + const string& destination = gTestRunner->redirectionDestinationForURL(uriString.get()); + if (!destination.empty()) + webkit_network_request_set_uri(request, destination.c_str()); + } + + if (uri) + soup_uri_free(uri); + + if (soupMessage) { + const set<string>& clearHeaders = gTestRunner->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) + soup_message_headers_remove(soupMessage->request_headers, header->c_str()); + } +} + + +static void didReceiveResponse(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource* webResource, WebKitNetworkResponse* response) +{ + if (!done && gTestRunner->dumpResourceLoadCallbacks()) { + CString responseDescription(descriptionSuitableForTestResult(response)); + CString path(convertWebResourceToURLPath(webResource)); + printf("%s - didReceiveResponse %s\n", path.data(), responseDescription.data()); + } + + // TODO: add "has MIME type" whenever dumpResourceResponseMIMETypes() is supported. + // See https://bugs.webkit.org/show_bug.cgi?id=58222. +} + +static void didFinishLoading(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource) +{ + if (!done && gTestRunner->dumpResourceLoadCallbacks()) + printf("%s - didFinishLoading\n", convertWebResourceToURLPath(webResource).data()); +} + +static void didFailLoadingWithError(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource, GError* webError) +{ + if (!done && gTestRunner->dumpResourceLoadCallbacks()) { + CString webErrorString(descriptionSuitableForTestResult(webError, webResource)); + printf("%s - didFailLoadingWithError: %s\n", convertWebResourceToURLPath(webResource).data(), + webErrorString.data()); + } +} + +static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url) +{ + if (!done && gTestRunner->dumpFrameLoadCallbacks()) + printf("didRunInsecureContent\n"); +} + +static gboolean webViewRunFileChooser(WebKitWebView*, WebKitFileChooserRequest*) +{ + // We return TRUE to not propagate the event further so the + // default file chooser dialog is not shown. + return TRUE; +} + +static void frameLoadEventCallback(WebKitWebFrame* frame, DumpRenderTreeSupportGtk::FrameLoadEvent event, const char* url) +{ + if (done || !gTestRunner->dumpFrameLoadCallbacks()) + return; + + GUniquePtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame)); + switch (event) { + case DumpRenderTreeSupportGtk::WillPerformClientRedirectToURL: + ASSERT(url); + printf("%s - willPerformClientRedirectToURL: %s \n", frameName.get(), url); + break; + case DumpRenderTreeSupportGtk::DidCancelClientRedirect: + printf("%s - didCancelClientRedirectForFrame\n", frameName.get()); + break; + case DumpRenderTreeSupportGtk::DidReceiveServerRedirectForProvisionalLoad: + printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", frameName.get()); + break; + case DumpRenderTreeSupportGtk::DidDisplayInsecureContent: + printf ("didDisplayInsecureContent\n"); + break; + case DumpRenderTreeSupportGtk::DidDetectXSS: + printf ("didDetectXSS\n"); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +static bool authenticationCallback(CString& username, CString& password, WebKitWebResource* webResource) +{ + CString description(convertWebResourceToURLPath(webResource)); + + if (!gTestRunner->handlesAuthenticationChallenges()) { + printf("%s - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", description.data()); + return false; + } + + username = gTestRunner->authenticationUsername().c_str(); + password = gTestRunner->authenticationPassword().c_str(); + printf("%s - didReceiveAuthenticationChallenge - Responding with %s:%s\n", description.data(), username.data(), password.data()); + return true; +} + +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); + + DumpRenderTreeSupportGtk::setFrameLoadEventCallback(frameLoadEventCallback); + DumpRenderTreeSupportGtk::setAuthenticationCallback(authenticationCallback); + + 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, + "signal::resource-response-received", didReceiveResponse, 0, + "signal::resource-load-finished", didFinishLoading, 0, + "signal::resource-load-failed", didFailLoadingWithError, 0, + "signal::run-file-chooser", webViewRunFileChooser, 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); + g_signal_connect(frame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL); + + return view; +} + +static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame) +{ + if (!gTestRunner->canOpenWindows()) + return 0; + + // Make sure that waitUntilDone has been called. + ASSERT(gTestRunner->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_TOPLEVEL); +#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(); +#if HAVE(ACCESSIBILITY) + axController = new AccessibilityController(); +#endif + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = true; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc-1 || (dumpPixelsForCurrentTest && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + delete gcController; + gcController = 0; + +#if HAVE(ACCESSIBILITY) + delete axController; + axController = 0; +#endif + + 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..4b33458f3 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h @@ -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. + */ + +#ifndef DumpRenderTreeGtk_h +#define DumpRenderTreeGtk_h + +#include <JavaScriptCore/JSBase.h> +#include <glib.h> +#include <libsoup/soup.h> +#include <webkit/webkitdefines.h> +#include <wtf/text/CString.h> + +extern WebKitWebFrame* mainFrame; +extern WebKitWebFrame* topLoadingFrame; +extern bool waitForPolicy; +extern GSList* webViewList; + +gchar* JSStringCopyUTF8CString(JSStringRef jsString); +CString getTopLevelPath(); + +void setWaitToDumpWatchdog(guint timer); +bool shouldSetWaitToDumpWatchdog(); +CString soupURIToStringPreservingPassword(SoupURI* soupURI); + +#endif // DumpRenderTreeGtk_h diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp new file mode 100644 index 000000000..3c08f80b3 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp @@ -0,0 +1,202 @@ +/* + * 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 "DumpRenderTree.h" +#include "TestRunner.h" +#include <gtk/gtk.h> +#include <webkit/webkit.h> +#include <wtf/gobject/GUniquePtr.h> +#include <wtf/text/CString.h> + +static CString dumpNodePath(WebKitDOMNode* node) +{ + GUniquePtr<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) { + GUniquePtr<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); + } + + GUniquePtr<gchar> pathBuffer(g_string_free(path, FALSE)); + return pathBuffer.get(); +} + +static CString dumpRange(WebKitDOMRange* range) +{ + if (!range) + return "(null)"; + + GUniquePtr<gchar> dump(g_strdup_printf("range from %li of %s to %li of %s", + webkit_dom_range_get_start_offset(range, 0), + dumpNodePath(webkit_dom_range_get_start_container(range, 0)).data(), + webkit_dom_range_get_end_offset(range, 0), + dumpNodePath(webkit_dom_range_get_end_container(range, 0)).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 && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldEndEditing(WebKitWebView* webView, WebKitDOMRange* range) +{ + if (!done && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldInsertNode(WebKitWebView* webView, WebKitDOMNode* node, WebKitDOMRange* range, WebKitInsertAction action) +{ + if (!done && gTestRunner->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 && gTestRunner->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 && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", dumpRange(range).data()); + return TRUE; +} + +gboolean shouldShowDeleteInterfaceForElement(WebKitWebView* webView, WebKitDOMHTMLElement* element) +{ + return FALSE; +} + +gboolean shouldChangeSelectedRange(WebKitWebView* webView, WebKitDOMRange* fromRange, WebKitDOMRange* toRange, WebKitSelectionAffinity affinity, gboolean stillSelecting) +{ + if (!done && gTestRunner->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 && gTestRunner->dumpEditingCallbacks()) { + GUniquePtr<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 && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n"); +} + +void userChangedContents(WebKitWebView*) +{ + if (!done && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n"); +} + +void editingEnded(WebKitWebView*) +{ + if (!done && gTestRunner->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n"); +} + +void selectionChanged(WebKitWebView*) +{ + if (!done && gTestRunner->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..bd8e4fb8f --- /dev/null +++ b/Tools/DumpRenderTree/gtk/EventSender.cpp @@ -0,0 +1,1004 @@ +/* + * 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) 2012 ChangSeok Oh <shivamidow@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. + */ + +#include "config.h" +#include "EventSender.h" + +#include "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.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/gobject/GUniquePtr.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; + +// WebCore and layout tests assume this value. +static const float pixelsPerScrollTick = 40; + +// 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)); + + JSRetainPtr<JSStringRef> itemText(Adopt, JSStringCreateWithUTF8CString(label.data())); + return JSValueMakeString(context, itemText.get()); +} + +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)) { + gdk_event_free(pressEvent); + 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) { + GUniquePtr<GList> items(gtk_container_get_children(GTK_CONTAINER(gtkMenu))); + JSValueRef arrayValues[g_list_length(items.get())]; + int index = 0; + for (GList* item = g_list_first(items.get()); 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_full(G_PRIORITY_DEFAULT, sendClick, 0, 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; + JSRetainPtr<JSStringRef> lengthProperty(Adopt, JSStringCreateWithUTF8CString("length")); + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty.get(), 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)) { + gdk_event_free(event); + 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) { + gdk_event_free(event); + 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)) { + gdk_event_free(event); + 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)); + + // Copy behaviour of Qt and EFL - just return in case of (0,0) mouse scroll + if (!horizontal && !vertical) + return 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); + + // GTK+ only supports one tick in each scroll event that is not smooth. For the cases of more than one direction, + // and more than one step in a direction, we can only use smooth events, supported from Gtk 3.3.18. +#if GTK_CHECK_VERSION(3, 3, 18) + if ((horizontal && vertical) || horizontal > 1 || horizontal < -1 || vertical > 1 || vertical < -1) { + event->scroll.direction = GDK_SCROLL_SMOOTH; + event->scroll.delta_x = -horizontal; + event->scroll.delta_y = -vertical; + + sendOrQueueEvent(event); + return JSValueMakeUndefined(context); + } +#else + g_return_val_if_fail((!vertical || !horizontal), JSValueMakeUndefined(context)); +#endif + + 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) +{ +#if GTK_CHECK_VERSION(3, 3, 18) + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + if (!view) + return JSValueMakeUndefined(context); + + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + int horizontal = JSValueToNumber(context, arguments[0], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + int vertical = JSValueToNumber(context, arguments[1], exception); + g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); + + // We do not yet support continuous scrolling by page. + if (argumentCount >= 3 && JSValueToBoolean(context, arguments[2])) + return 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); + + event->scroll.direction = GDK_SCROLL_SMOOTH; + event->scroll.delta_x = -horizontal / pixelsPerScrollTick; + event->scroll.delta_y = -vertical / pixelsPerScrollTick; + + sendOrQueueEvent(event); +#endif + 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. + GUniquePtr<gchar> scheme(g_file_get_uri_scheme(parentDirectory.get())); + if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) { + GUniquePtr<gchar> currentDirectory(g_get_current_dir()); + parentDirectory = adoptGRef(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); + GUniquePtr<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; + } + + // The widget focus may have been lost in the course of the test, + // so force another explicit focus grab here. + gtk_widget_grab_focus(GTK_WIDGET(view)); + 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 GdkEvent* createKeyPressEvent(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + g_return_val_if_fail(argumentCount >= 1, 0); + 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), 0); + + 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 if (JSStringIsEqualToUTF8CString(character, "leftAlt")) + gdkKeySym = GDK_Alt_L; + else if (JSStringIsEqualToUTF8CString(character, "leftControl")) + gdkKeySym = GDK_Control_L; + else if (JSStringIsEqualToUTF8CString(character, "leftShift")) + gdkKeySym = GDK_Shift_L; + else if (JSStringIsEqualToUTF8CString(character, "rightAlt")) + gdkKeySym = GDK_Alt_R; + else if (JSStringIsEqualToUTF8CString(character, "rightControl")) + gdkKeySym = GDK_Control_R; + else if (JSStringIsEqualToUTF8CString(character, "rightShift")) + gdkKeySym = GDK_Shift_R; + 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); + g_return_val_if_fail(view, 0); + + 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+. + GUniqueOutPtr<GdkKeymapKey> keys; + gint nKeys; + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys.outPtr(), &nKeys)) + pressEvent->key.hardware_keycode = keys.get()[0].keycode; + + return pressEvent; +} + +static void sendKeyDown(GdkEvent* pressEvent) +{ + g_return_if_fail(pressEvent); + GdkEvent* releaseEvent = gdk_event_copy(pressEvent); + releaseEvent->type = GDK_KEY_RELEASE; + + dispatchEvent(pressEvent); + dispatchEvent(releaseEvent); + + DumpRenderTreeSupportGtk::deliverAllMutationsIfNecessary(); +} + +static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GdkEvent* pressEvent = createKeyPressEvent(context, argumentCount, arguments, exception); + sendKeyDown(pressEvent); + + 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 gboolean sendAsynchronousKeyDown(gpointer userData) +{ + sendKeyDown(static_cast<GdkEvent*>(userData)); + return FALSE; +} + +static JSValueRef scheduleAsynchronousKeyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + GdkEvent* pressEvent = createKeyPressEvent(context, argumentCount, arguments, exception); + if (pressEvent) + g_idle_add_full(G_PRIORITY_DEFAULT, sendAsynchronousKeyDown, static_cast<gpointer>(pressEvent), 0); + + return JSValueMakeUndefined(context); +} + +static JSValueRef clearTouchPointsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + 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 }, + { "scheduleAsynchronousKeyDown", scheduleAsynchronousKeyDownCallback, 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/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp new file mode 100644 index 000000000..0a800ec13 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp @@ -0,0 +1,115 @@ +/* + * 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> + +static void paintOverlay(cairo_surface_t* surface) +{ + cairo_t* context = cairo_create(surface); + + // Paint a transparent black overlay from which the repainted rectangles are then cleared. + // The alpha component of the overlay should have a value of 0.66, as on other ports. + cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.66); + cairo_rectangle(context, 0, 0, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface)); + cairo_fill(context); + + GSList* trackedRectsList = DumpRenderTreeSupportGtk::trackedRepaintRects(mainFrame); + for (GSList* listElement = trackedRectsList; listElement; listElement = g_slist_next(listElement)) { + GdkRectangle* rect = static_cast<GdkRectangle*>(listElement->data); + + cairo_set_operator(context, CAIRO_OPERATOR_CLEAR); + cairo_rectangle(context, rect->x, rect->y, rect->width, rect->height); + cairo_fill(context); + } + + g_slist_free_full(trackedRectsList, g_free); + cairo_destroy(context); +} + +static void fillRepaintOverlayIntoContext(cairo_t* context, gint width, gint height) +{ + cairo_surface_t* overlaySurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + paintOverlay(overlaySurface); + + cairo_set_source_surface(context, overlaySurface, 0, 0); + cairo_rectangle(context, 0, 0, width, height); + cairo_fill(context); + + cairo_surface_destroy(overlaySurface); +} + +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 + + while (gtk_events_pending()) + gtk_main_iteration(); + + 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 (DumpRenderTreeSupportGtk::isTrackingRepaints(mainFrame)) + fillRepaintOverlayIntoContext(context, width, height); + + 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); + } + + cairo_surface_destroy(imageSurface); + return BitmapContext::createByAdoptingBitmapAndContext(0, context); +} 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/TestRunnerGtk.cpp b/Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp new file mode 100644 index 000000000..c0b2deca2 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2007, 2012 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 "TestRunner.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/GUniquePtr.h> +#include <wtf/text/WTFString.h> + +extern "C" { +void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script); +} + +TestRunner::~TestRunner() +{ + // FIXME: implement +} + +void TestRunner::addDisallowedURL(JSStringRef url) +{ + // FIXME: implement +} + +void TestRunner::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 TestRunner::copyDecodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +JSStringRef TestRunner::copyEncodedHostName(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +void TestRunner::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 +} + +void TestRunner::display() +{ + displayWebView(); +} + +void TestRunner::keepWebHistory() +{ + // FIXME: implement +} + +size_t TestRunner::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); +} + +void TestRunner::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; + waitForPolicy = false; +} + +JSStringRef TestRunner::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + GUniquePtr<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/"); + GUniquePtr<char> testPath(g_build_filename(getTopLevelPath().data(), layoutTestsSuffix, nullptr)); + GUniquePtr<char> testURI(g_filename_to_uri(testPath.get(), 0, 0)); + return JSStringCreateWithUTF8CString(testURI.get()); +} + +void TestRunner::queueLoad(JSStringRef url, JSStringRef target) +{ + GUniquePtr<gchar> relativeURL(JSStringCopyUTF8CString(url)); + SoupURI* baseURI = soup_uri_new(webkit_web_frame_get_uri(mainFrame)); + SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL.get()); + soup_uri_free(baseURI); + + if (!absoluteURI) { + WorkQueue::shared()->queue(new LoadItem(url, target)); + return; + } + + CString absoluteURIString = soupURIToStringPreservingPassword(absoluteURI); + JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteURIString.data())); + WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target)); + soup_uri_free(absoluteURI); +} + +void TestRunner::setAcceptsEditing(bool acceptsEditing) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + webkit_web_view_set_editable(webView, acceptsEditing); +} + +void TestRunner::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 TestRunner::setCustomPolicyDelegate(bool setDelegate, bool permissive) +{ + // FIXME: implement +} + +void TestRunner::waitForPolicyDelegate() +{ + waitForPolicy = true; + setWaitToDump(true); +} + +void TestRunner::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +void TestRunner::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 TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains) +{ + GUniquePtr<gchar> sourceOriginGChar(JSStringCopyUTF8CString(sourceOrigin)); + GUniquePtr<gchar> protocolGChar(JSStringCopyUTF8CString(protocol)); + GUniquePtr<gchar> hostGChar(JSStringCopyUTF8CString(host)); + DumpRenderTreeSupportGtk::removeWhiteListAccessFromOrigin(sourceOriginGChar.get(), protocolGChar.get(), hostGChar.get(), includeSubdomains); +} + +void TestRunner::setMainFrameIsFirstResponder(bool flag) +{ + // FIXME: implement +} + +void TestRunner::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 TestRunner::setUseDashboardCompatibilityMode(bool flag) +{ + // FIXME: implement +} + +static gchar* userStyleSheet = NULL; +static gboolean userStyleSheetEnabled = TRUE; + +void TestRunner::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 TestRunner::setUserStyleSheetLocation(JSStringRef path) +{ + g_free(userStyleSheet); + userStyleSheet = JSStringCopyUTF8CString(path); + if (userStyleSheetEnabled) + setUserStyleSheetEnabled(true); +} + +void TestRunner::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value) +{ + DumpRenderTreeSupportGtk::setValueForUser(context, nodeObject, value); +} + +void TestRunner::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 TestRunner::setWindowIsKey(bool windowIsKey) +{ + // FIXME: implement +} + +static gboolean waitToDumpWatchdogFired(void*) +{ + setWaitToDumpWatchdog(0); + gTestRunner->waitToDumpWatchdogTimerFired(); + return FALSE; +} + +void TestRunner::setWaitToDump(bool waitUntilDone) +{ + static const int timeoutSeconds = 30; + + m_waitToDump = waitUntilDone; + if (m_waitToDump && shouldSetWaitToDumpWatchdog()) { + guint id = g_timeout_add_seconds(timeoutSeconds, waitToDumpWatchdogFired, 0); + g_source_set_name_by_id(id, "[WebKit] waitToDumpWatchdogFired"); + setWaitToDumpWatchdog(id); + } +} + +int TestRunner::windowCount() +{ + // +1 -> including the main view + return g_slist_length(webViewList) + 1; +} + +void TestRunner::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 TestRunner::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 TestRunner::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 TestRunner::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 TestRunner::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 TestRunner::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 TestRunner::setAuthorAndUserStylesEnabled(bool flag) +{ + // FIXME: implement +} + +void TestRunner::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 TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool, double, bool, double, bool, double, bool, double) +{ + 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 TestRunner::setMockGeolocationPositionUnavailableError(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); + + GUniquePtr<gchar> cMessage(JSStringCopyUTF8CString(message)); + DumpRenderTreeSupportGtk::setMockGeolocationPositionUnavailableError(view, cMessage.get()); +} + +void TestRunner::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 TestRunner::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 TestRunner::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 TestRunner::setMockSpeechInputDumpRect(bool flag) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void TestRunner::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void TestRunner::setIconDatabaseEnabled(bool enabled) +{ + WebKitIconDatabase* database = webkit_get_icon_database(); + if (enabled) { + GUniquePtr<gchar> iconDatabasePath(g_build_filename(g_get_tmp_dir(), "DumpRenderTree", "icondatabase", nullptr)); + webkit_icon_database_set_path(database, iconDatabasePath.get()); + } else + webkit_icon_database_set_path(database, 0); +} + +void TestRunner::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 TestRunner::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); +} + +void TestRunner::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 TestRunner::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; + + GUniquePtr<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 TestRunner::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 TestRunner::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 2: + webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +void TestRunner::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + // FIXME: implement +} + +void TestRunner::clearPersistentUserStyleSheet() +{ + // FIXME: implement +} + +void TestRunner::clearAllApplicationCaches() +{ + // FIXME: Implement to support application cache quotas. +} + +void TestRunner::clearApplicationCacheForOrigin(OpaqueJSString*) +{ + // FIXME: Implement to support deleting all application caches for an origin. +} + +long long TestRunner::localStorageDiskUsageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + return 0; +} + +JSValueRef TestRunner::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that contain application caches. + return JSValueMakeUndefined(context); +} + +long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef name) +{ + // FIXME: implement + return 0; +} + +void TestRunner::clearAllDatabases() +{ + webkit_remove_all_web_databases(); +} + +void TestRunner::setDatabaseQuota(unsigned long long quota) +{ + WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(mainFrame); + webkit_security_origin_set_web_database_quota(origin, quota); +} + +JSValueRef TestRunner::originsWithLocalStorage(JSContextRef context) +{ + // FIXME: implement + return JSValueMakeUndefined(context); +} + +void TestRunner::deleteAllLocalStorage() +{ + // FIXME: implement +} + +void TestRunner::deleteLocalStorageForOrigin(JSStringRef originIdentifier) +{ + // FIXME: implement +} + +void TestRunner::observeStorageTrackerNotifications(unsigned number) +{ + // FIXME: implement +} + +void TestRunner::syncLocalStorage() +{ + // FIXME: implement +} + +void TestRunner::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme) +{ + GUniquePtr<gchar> urlScheme(JSStringCopyUTF8CString(scheme)); + DumpRenderTreeSupportGtk::setDomainRelaxationForbiddenForURLScheme(forbidden, urlScheme.get()); +} + +void TestRunner::goBack() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + webkit_web_view_go_back(webView); +} + +void TestRunner::setDefersLoading(bool defers) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + DumpRenderTreeSupportGtk::setDefersLoading(webView, defers); +} + +void TestRunner::setAppCacheMaximumSize(unsigned long long size) +{ + webkit_application_cache_set_maximum_size(size); +} + +static gboolean booleanFromValue(gchar* value) +{ + return !g_ascii_strcasecmp(value, "true") || !g_ascii_strcasecmp(value, "1"); +} + +void TestRunner::overridePreference(JSStringRef key, JSStringRef value) +{ + GUniquePtr<gchar> originalName(JSStringCopyUTF8CString(key)); + GUniquePtr<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(), "WebKitDisplayImagesKey")) + propertyName = "auto-load-images"; + else if (g_str_equal(originalName.get(), "WebKitShouldRespectImageOrientation")) + propertyName = "respect-image-orientation"; + else if (g_str_equal(originalName.get(), "WebKitMediaSourceEnabled")) + propertyName = "enable-mediasource"; + else if (g_str_equal(originalName.get(), "WebKitTabToLinksPreferenceKey")) { + DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(booleanFromValue(valueAsString.get())); + return; + } else if (g_str_equal(originalName.get(), "WebKitPageCacheSupportsPluginsPreferenceKey")) { + DumpRenderTreeSupportGtk::setPageCacheSupportsPlugins(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get())); + return; + } else if (g_str_equal(originalName.get(), "WebKitCSSGridLayoutEnabled")) { + DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get())); + return; + } else if (g_str_equal(originalName.get(), "WebKitCSSRegionsEnabled")) { + DumpRenderTreeSupportGtk::setCSSRegionsEnabled(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get())); + return; + } else { + fprintf(stderr, "TestRunner::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, booleanFromValue(valueAsString.get()), 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, "TestRunner::overridePreference failed to override " + "preference '%s'.\n", originalName.get()); +} + +void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + GUniquePtr<gchar> sourceCode(JSStringCopyUTF8CString(source)); + DumpRenderTreeSupportGtk::addUserScript(mainFrame, sourceCode.get(), runAtStart, allFrames); +} + +void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + GUniquePtr<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 TestRunner::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 TestRunner::showWebInspector() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + + webkit_web_inspector_show(inspector); +} + +void TestRunner::closeWebInspector() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView); + + webkit_web_inspector_close(inspector); +} + +void TestRunner::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 TestRunner::evaluateScriptInIsolatedWorldAndReturnValue(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + // FIXME: Implement this. +} + +void TestRunner::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + // FIXME: Implement this. +} + +void TestRunner::removeAllVisitedLinks() +{ + // FIXME: Implement this. +} + +bool TestRunner::callShouldCloseOnWebView() +{ + return DumpRenderTreeSupportGtk::shouldClose(mainFrame); +} + +void TestRunner::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} + +void TestRunner::apiTestGoToCurrentBackForwardItem() +{ + +} + +void TestRunner::setWebViewEditable(bool) +{ +} + +void TestRunner::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ +} + +void TestRunner::abortModal() +{ +} + +void TestRunner::setSerializeHTTPLoads(bool serialize) +{ + DumpRenderTreeSupportGtk::setSerializeHTTPLoads(serialize); +} + +void TestRunner::setTextDirection(JSStringRef direction) +{ + GUniquePtr<gchar> writingDirection(JSStringCopyUTF8CString(direction)); + + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + if (g_str_equal(writingDirection.get(), "auto")) + gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_NONE); + else if (g_str_equal(writingDirection.get(), "ltr")) + gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_LTR); + else if (g_str_equal(writingDirection.get(), "rtl")) + gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_RTL); + else + fprintf(stderr, "TestRunner::setTextDirection called with unknown direction: '%s'.\n", writingDirection.get()); +} + +void TestRunner::addChromeInputField() +{ +} + +void TestRunner::removeChromeInputField() +{ +} + +void TestRunner::focusWebView() +{ +} + +void TestRunner::setBackingScaleFactor(double) +{ +} + +void TestRunner::grantWebNotificationPermission(JSStringRef origin) +{ +} + +void TestRunner::denyWebNotificationPermission(JSStringRef jsOrigin) +{ +} + +void TestRunner::removeAllWebNotificationPermissions() +{ +} + +void TestRunner::simulateWebNotificationClick(JSValueRef jsNotification) +{ +} + +void TestRunner::simulateLegacyWebNotificationClick(JSStringRef title) +{ +} + +void TestRunner::resetPageVisibility() +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + DumpRenderTreeSupportGtk::setPageVisibility(webView, WebCore::PageVisibilityStateVisible, true); +} + +void TestRunner::setPageVisibility(const char* visibility) +{ + WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame); + String visibilityString(visibility); + WebCore::PageVisibilityState visibilityState = WebCore::PageVisibilityStateVisible; + + if (visibilityString == "visible") + visibilityState = WebCore::PageVisibilityStateVisible; + else if (visibilityString == "hidden") + visibilityState = WebCore::PageVisibilityStateHidden; + else + return; + + DumpRenderTreeSupportGtk::setPageVisibility(webView, visibilityState, false); +} + +void TestRunner::setAutomaticLinkDetectionEnabled(bool) +{ + // FIXME: Implement this. +} + +void TestRunner::setStorageDatabaseIdleInterval(double) +{ + // FIXME: Implement this. +} + +void TestRunner::closeIdleLocalStorageDatabases() +{ +} diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp new file mode 100644 index 000000000..aee5597ed --- /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 <GUniquePtrGtk.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); + GUniquePtr<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); + GUniquePtr<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); + GUniquePtr<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..95461276e --- /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 <JavaScriptCore/JSStringRef.h> +#include <string.h> +#include <webkit/webkit.h> +#include <wtf/gobject/GUniquePtr.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 +{ + GUniquePtr<gchar> content(JSStringCopyUTF8CString(m_content.get())); + GUniquePtr<gchar> baseURL(JSStringCopyUTF8CString(m_baseURL.get())); + + if (m_unreachableURL) { + GUniquePtr<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; +} |