diff options
author | Ben Murdoch <benm@google.com> | 2011-05-05 14:36:32 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-10 15:38:30 +0100 |
commit | f05b935882198ccf7d81675736e3aeb089c5113a (patch) | |
tree | 4ea0ca838d9ef1b15cf17ddb3928efb427c7e5a1 /Tools/DumpRenderTree/mac | |
parent | 60fbdcc62bced8db2cb1fd233cc4d1e4ea17db1b (diff) | |
download | external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.zip external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.gz external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.bz2 |
Merge WebKit at r74534: Initial merge by git.
Change-Id: I6ccd1154fa1b19c2ec2a66878eb675738735f1eb
Diffstat (limited to 'Tools/DumpRenderTree/mac')
58 files changed, 10616 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm new file mode 100644 index 0000000..9d7edef --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" +#import "AccessibilityController.h" + +#import "AccessibilityUIElement.h" +#import <Foundation/Foundation.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebHTMLView.h> + +AccessibilityController::AccessibilityController() +{ +} + +AccessibilityController::~AccessibilityController() +{ +} + +AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y) +{ + id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityHitTest:NSMakePoint(x, y)]; + return AccessibilityUIElement(accessibilityObject); +} + +AccessibilityUIElement AccessibilityController::focusedElement() +{ + // FIXME: we could do some caching here. + id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityFocusedUIElement]; + return AccessibilityUIElement(accessibilityObject); +} + +AccessibilityUIElement AccessibilityController::rootElement() +{ + // FIXME: we could do some caching here. + id accessibilityObject = [[mainFrame frameView] documentView]; + return AccessibilityUIElement(accessibilityObject); +} + +void AccessibilityController::setLogFocusEvents(bool) +{ +} + +void AccessibilityController::setLogScrollingStartEvents(bool) +{ +} + +void AccessibilityController::setLogValueChangeEvents(bool) +{ +} + +void AccessibilityController::addNotificationListener(PlatformUIElement, JSObjectRef) +{ +} + +void AccessibilityController::notificationReceived(PlatformUIElement, const std::string&) +{ +} diff --git a/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm new file mode 100644 index 0000000..9170ab6 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" + +#import "AccessibilityTextMarker.h" +#import "DumpRenderTree.h" + +#pragma mark AccessibilityTextMarker + +AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker marker) + : m_textMarker(marker) +{ +} + +AccessibilityTextMarker::AccessibilityTextMarker(const AccessibilityTextMarker& marker) + : m_textMarker(marker.platformTextMarker()) +{ +} + +AccessibilityTextMarker::~AccessibilityTextMarker() +{ +} + +bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker* other) +{ + return [(id)platformTextMarker() isEqual:(id)other->platformTextMarker()]; +} + +PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const +{ + return m_textMarker.get(); +} + +#pragma mark AccessibilityTextMarkerRange + +AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange markerRange) + : m_textMarkerRange(markerRange) +{ +} + +AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange& markerRange) + : m_textMarkerRange(markerRange.platformTextMarkerRange()) +{ +} + +AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange() +{ +} + +bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange* other) +{ + return [(id)platformTextMarkerRange() isEqual:(id)other->platformTextMarkerRange()]; +} + +PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const +{ + return m_textMarkerRange.get(); +} diff --git a/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm new file mode 100644 index 0000000..e2f0597 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm @@ -0,0 +1,1341 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" +#import "AccessibilityUIElement.h" + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JSRetainPtr.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebHTMLView.h> +#import <WebKit/WebTypesInternal.h> +#import <wtf/RetainPtr.h> +#import <wtf/Vector.h> + +#ifdef BUILDING_ON_TIGER +#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription" +#endif + +#ifndef NSAccessibilityOwnsAttribute +#define NSAccessibilityOwnsAttribute @"AXOwns" +#endif + +#ifndef NSAccessibilityGrabbedAttribute +#define NSAccessibilityGrabbedAttribute @"AXGrabbed" +#endif + +#ifndef NSAccessibilityDropEffectsAttribute +#define NSAccessibilityDropEffectsAttribute @"AXDropEffects" +#endif + +// If an unsupported attribute is passed in, it will raise an accessibility exception. These are usually caught by the Accessibility Runtime to inform +// the AX client app of the error. However, DRT is the AX client app, so it must catch these exceptions. +#define BEGIN_AX_OBJC_EXCEPTIONS @try { +#define END_AX_OBJC_EXCEPTIONS } @catch(NSException *e) { if (![[e name] isEqualToString:NSAccessibilityException]) @throw; } + + +typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context); + +@interface NSObject (WebKitAccessibilityAdditions) +- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount; +- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost; +- (NSUInteger)accessibilityIndexOfChild:(id)child; +- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute; +@end + +@interface NSString (JSStringRefAdditions) ++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef; +- (JSStringRef)createJSStringRef; +@end + +@implementation NSString (JSStringRefAdditions) + ++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef +{ + if (!jsStringRef) + return NULL; + + CFStringRef cfString = JSStringCopyCFString(kCFAllocatorDefault, jsStringRef); + return [(NSString *)cfString autorelease]; +} + +- (JSStringRef)createJSStringRef +{ + return JSStringCreateWithCFString((CFStringRef)self); +} + +@end + +@interface AccessibilityNotificationHandler : NSObject +{ + id m_platformElement; + JSObjectRef m_notificationFunctionCallback; +} + +@end + +@implementation AccessibilityNotificationHandler + +- (id)initWithPlatformElement:(id)platformElement +{ + self = [super init]; + + m_platformElement = platformElement; + + // Once an object starts requesting notifications, it's on for the duration of the program. + // This is to avoid any race conditions between tests turning this flag on and off. Instead + // AccessibilityNotificationHandler can just listen when they want to. + [m_platformElement accessibilitySetShouldRepostNotifications:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil]; + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback); + m_notificationFunctionCallback = 0; + + [super dealloc]; +} + +- (void)_notificationReceived:(NSNotification *)notification +{ + NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"]; + if (!notificationName) + return; + + JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]); + JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get()); + JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, &argument, 0); +} + +- (void)setCallback:(JSObjectRef)callback +{ + if (!callback) + return; + + // Release the old callback. + if (m_notificationFunctionCallback) + JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback); + + m_notificationFunctionCallback = callback; + JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback); +} + +@end + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) + , m_notificationHandler(0) +{ + // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac. + [m_element retain]; +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) + , m_notificationHandler(0) +{ + [m_element retain]; +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ + // The notification handler should be nil because removeNotificationListener() should have been called in the test. + ASSERT(!m_notificationHandler); + [m_element release]; +} + +static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject) +{ + if (!valueObject) + return NULL; + + if ([valueObject isKindOfClass:[NSArray class]]) + return [NSString stringWithFormat:@"<array of size %d>", [(NSArray*)valueObject count]]; + + if ([valueObject isKindOfClass:[NSNumber class]]) + return [(NSNumber*)valueObject stringValue]; + + if ([valueObject isKindOfClass:[NSValue class]]) { + NSString* type = [NSString stringWithCString:[valueObject objCType] encoding:NSASCIIStringEncoding]; + NSValue* value = (NSValue*)valueObject; + if ([type rangeOfString:@"NSRect"].length > 0) + return [NSString stringWithFormat:@"NSRect: %@", NSStringFromRect([value rectValue])]; + if ([type rangeOfString:@"NSPoint"].length > 0) + return [NSString stringWithFormat:@"NSPoint: %@", NSStringFromPoint([value pointValue])]; + if ([type rangeOfString:@"NSSize"].length > 0) + return [NSString stringWithFormat:@"NSSize: %@", NSStringFromSize([value sizeValue])]; + if ([type rangeOfString:@"NSRange"].length > 0) + return [NSString stringWithFormat:@"NSRange: %@", NSStringFromRange([value rangeValue])]; + } + + // Strip absolute URL paths + NSString* description = [valueObject description]; + NSRange range = [description rangeOfString:@"LayoutTests"]; + if (range.length) + return [description substringFromIndex:range.location]; + + // Strip pointer locations + if ([description rangeOfString:@"0x"].length) { + NSString* role = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityRoleAttribute]; + NSString* title = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityTitleAttribute]; + if ([title length]) + return [NSString stringWithFormat:@"<%@: '%@'>", role, title]; + return [NSString stringWithFormat:@"<%@>", role]; + } + + return [valueObject description]; +} + +static NSString* attributesOfElement(id accessibilityObject) +{ + NSArray* supportedAttributes = [accessibilityObject accessibilityAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedAttributes count]; ++i) { + NSString* attribute = [supportedAttributes objectAtIndex:i]; + + // Right now, position provides useless and screen-specific information, so we do not + // want to include it for the sake of universally passing tests. + if ([attribute isEqualToString:@"AXPosition"]) + continue; + + // accessibilityAttributeValue: can throw an if an attribute is not returned. + // For DumpRenderTree's purpose, we should ignore those exceptions + BEGIN_AX_OBJC_EXCEPTIONS + id valueObject = [accessibilityObject accessibilityAttributeValue:attribute]; + NSString* value = descriptionOfValue(valueObject, accessibilityObject); + [attributesString appendFormat:@"%@: %@\n", attribute, value]; + END_AX_OBJC_EXCEPTIONS + } + + return attributesString; +} + +static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value) +{ + Vector<UniChar> buffer([attribute length]); + [attribute getCharacters:buffer.data()]; + buffer.append(':'); + buffer.append(' '); + + Vector<UniChar> valueBuffer([value length]); + [value getCharacters:valueBuffer.data()]; + buffer.append(valueBuffer); + + return JSStringCreateWithCharacters(buffer.data(), buffer.size()); +} + +static void convertNSArrayToVector(NSArray* array, Vector<AccessibilityUIElement>& elementVector) +{ + NSUInteger count = [array count]; + for (NSUInteger i = 0; i < count; ++i) + elementVector.append(AccessibilityUIElement([array objectAtIndex:i])); +} + +static JSStringRef descriptionOfElements(Vector<AccessibilityUIElement>& elementVector) +{ + NSMutableString* allElementString = [NSMutableString string]; + size_t size = elementVector.size(); + for (size_t i = 0; i < size; ++i) { + NSString* attributes = attributesOfElement(elementVector[i].platformUIElement()); + [allElementString appendFormat:@"%@\n------------\n", attributes]; + } + + return [allElementString createJSStringRef]; +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* linkedElements = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + convertNSArrayToVector(linkedElements, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* linkElements = [m_element accessibilityAttributeValue:@"AXLinkUIElements"]; + convertNSArrayToVector(linkElements, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* children = [m_element accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; + convertNSArrayToVector(children, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* children = [m_element accessibilityArrayAttributeValues:NSAccessibilityChildrenAttribute index:location maxCount:length]; + convertNSArrayToVector(children, elementVector); + END_AX_OBJC_EXCEPTIONS +} + +int AccessibilityUIElement::childrenCount() +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + + return children.size(); +} + +AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) +{ + id element = [m_element accessibilityHitTest:NSMakePoint(x, y)]; + if (!element) + return nil; + + return AccessibilityUIElement(element); +} + +unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) +{ + return [m_element accessibilityIndexOfChild:element->platformUIElement()]; +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + Vector<AccessibilityUIElement> children; + getChildrenWithRange(children, index, 1); + + if (children.size() == 1) + return children[0]; + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityOwnsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedRowsAttribute]; + if (index < [rows count]) + return [rows objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned index) const +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* array = [m_element accessibilityAttributeValue:NSAccessibilitySelectedChildrenAttribute]; + if (index < [array count]) + return [array objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +unsigned AccessibilityUIElement::selectedChildrenCount() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilitySelectedChildrenAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilitySelectedRowsAttribute]; + if (index < [rows count]) + return [rows objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityTitleUIElementAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::parentElement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityParentAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::disclosedByRow() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedByRowAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + Vector<AccessibilityUIElement> linkedElements; + getLinkedUIElements(linkedElements); + return descriptionOfElements(linkedElements); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + Vector<AccessibilityUIElement> linkElements; + getDocumentLinks(linkElements); + return descriptionOfElements(linkElements); +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + return descriptionOfElements(children); +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + NSString* attributes = attributesOfElement(m_element); + return [attributes createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + if ([value isKindOfClass:[NSString class]]) + return [value createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [[m_element accessibilityAttributeNames] containsObject:[NSString stringWithJSStringRef:attribute]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedParameterizedAttributes count]; ++i) { + [attributesString appendFormat:@"%@\n", [supportedParameterizedAttributes objectAtIndex:i]]; + } + + return [attributesString createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::role() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString *role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleAttribute], m_element); + return concatenateAttributeAndValue(@"AXRole", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::subrole() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilitySubroleAttribute], m_element); + return concatenateAttributeAndValue(@"AXSubrole", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::roleDescription() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], m_element); + return concatenateAttributeAndValue(@"AXRoleDescription", role); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::title() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityTitleAttribute], m_element); + return concatenateAttributeAndValue(@"AXTitle", title); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::description() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityDescriptionAttribute], m_element); + return concatenateAttributeAndValue(@"AXDescription", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::orientation() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityOrientationAttribute], m_element); + return concatenateAttributeAndValue(@"AXOrientation", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::stringValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityValueAttribute], m_element); + return concatenateAttributeAndValue(@"AXValue", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::language() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXLanguage"], m_element); + return concatenateAttributeAndValue(@"AXLanguage", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::helpText() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element); + return concatenateAttributeAndValue(@"AXHelp", description); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +double AccessibilityUIElement::x() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute]; + return static_cast<double>([positionValue pointValue].x); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::y() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute]; + return static_cast<double>([positionValue pointValue].y); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::width() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute]; + return static_cast<double>([sizeValue sizeValue].width); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::height() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute]; + return static_cast<double>([sizeValue sizeValue].height); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::clickPointX() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"]; + return static_cast<double>([positionValue pointValue].x); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::clickPointY() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"]; + return static_cast<double>([positionValue pointValue].y); + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::intValue() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::minValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityMinValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0f; +} + +double AccessibilityUIElement::maxValue() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityMaxValueAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + END_AX_OBJC_EXCEPTIONS + + return 0.0; +} + +JSStringRef AccessibilityUIElement::valueDescription() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSString* valueDescription = [m_element accessibilityAttributeValue:NSAccessibilityValueDescriptionAttribute]; + if ([valueDescription isKindOfClass:[NSString class]]) + return [valueDescription createJSStringRef]; + + END_AX_OBJC_EXCEPTIONS + return 0; +} + +int AccessibilityUIElement::insertionPointLineNumber() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityInsertionPointLineNumberAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +bool AccessibilityUIElement::isActionSupported(JSStringRef action) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* actions = [m_element accessibilityActionNames]; + return [actions containsObject:[NSString stringWithJSStringRef:action]]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isEnabled() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityEnabledAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isRequired() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXRequired"]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isFocused() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelected() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilitySelectedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isExpanded() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityExpandedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +bool AccessibilityUIElement::isChecked() const +{ + // On the Mac, intValue()==1 if a a checkable control is checked. + return intValue() == 1; +} + +int AccessibilityUIElement::hierarchicalLevel() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityDisclosureLevelAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value intValue]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::speak() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXDRTSpeechAttribute"]; + if ([value isKindOfClass:[NSString class]]) + return [value createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::ariaIsGrabbed() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityGrabbedAttribute]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +JSStringRef AccessibilityUIElement::ariaDropEffects() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityDropEffectsAttribute]; + if (![value isKindOfClass:[NSArray class]]) + return 0; + + NSMutableString* dropEffects = [NSMutableString string]; + NSInteger length = [value count]; + for (NSInteger k = 0; k < length; ++k) { + [dropEffects appendString:[value objectAtIndex:k]]; + if (k < length - 1) + [dropEffects appendString:@","]; + } + + return [dropEffects createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +// parameterized attributes +int AccessibilityUIElement::lineForIndex(int index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:[NSNumber numberWithInt:index]]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +JSStringRef AccessibilityUIElement::rangeForLine(int line) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityRangeForLineParameterizedAttribute forParameter:[NSNumber numberWithInt:line]]; + if ([value isKindOfClass:[NSValue class]]) { + return [NSStringFromRange([value rangeValue]) createJSStringRef]; + } + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:NSAccessibilityBoundsForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + NSRect rect = NSMakeRect(0,0,0,0); + if ([value isKindOfClass:[NSValue class]]) + rect = [value rectValue]; + + // don't return position information because it is platform dependent + NSMutableString* boundsDescription = [NSMutableString stringWithFormat:@"{{%f, %f}, {%f, %f}}",-1.0f,-1.0f,rect.size.width,rect.size.height]; + return [boundsDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + id string = [m_element accessibilityAttributeValue:NSAccessibilityStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSString class]]) + return 0; + + return [string createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSAttributedString class]]) + return 0; + + NSString* stringWithAttrs = [string description]; + return [stringWithAttrs createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + BEGIN_AX_OBJC_EXCEPTIONS + NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + if (![string isKindOfClass:[NSAttributedString class]]) + return false; + + NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil]; + if([[attrs objectForKey:NSAccessibilityMisspelledTextAttribute] boolValue]) + return true; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + // not yet defined in AppKit... odd + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* columnHeadersArray = [m_element accessibilityAttributeValue:@"AXColumnHeaderUIElements"]; + Vector<AccessibilityUIElement> columnHeadersVector; + convertNSArrayToVector(columnHeadersArray, columnHeadersVector); + return descriptionOfElements(columnHeadersVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rowHeadersArray = [m_element accessibilityAttributeValue:@"AXRowHeaderUIElements"]; + Vector<AccessibilityUIElement> rowHeadersVector; + convertNSArrayToVector(rowHeadersArray, rowHeadersVector); + return descriptionOfElements(rowHeadersVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* columnsArray = [m_element accessibilityAttributeValue:NSAccessibilityColumnsAttribute]; + Vector<AccessibilityUIElement> columnsVector; + convertNSArrayToVector(columnsArray, columnsVector); + return descriptionOfElements(columnsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* rowsArray = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute]; + Vector<AccessibilityUIElement> rowsVector; + convertNSArrayToVector(rowsArray, rowsVector); + return descriptionOfElements(rowsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* cellsArray = [m_element accessibilityAttributeValue:@"AXVisibleCells"]; + Vector<AccessibilityUIElement> cellsVector; + convertNSArrayToVector(cellsArray, cellsVector); + return descriptionOfElements(cellsVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + BEGIN_AX_OBJC_EXCEPTIONS + id headerObject = [m_element accessibilityAttributeValue:NSAccessibilityHeaderAttribute]; + if (!headerObject) + return [@"" createJSStringRef]; + + Vector<AccessibilityUIElement> headerVector; + headerVector.append(headerObject); + return descriptionOfElements(headerVector); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::rowCount() +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::columnCount() +{ + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::indexInTable() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute]; + if (indexNumber) + return [indexNumber intValue]; + END_AX_OBJC_EXCEPTIONS + + return -1; +} + +JSStringRef AccessibilityUIElement::rowIndexRange() +{ + NSRange range = NSMakeRange(0,0); + BEGIN_AX_OBJC_EXCEPTIONS + NSValue* indexRange = [m_element accessibilityAttributeValue:@"AXRowIndexRange"]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::columnIndexRange() +{ + NSRange range = NSMakeRange(0,0); + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* indexRange = [m_element accessibilityAttributeValue:@"AXColumnIndexRange"]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) +{ + NSArray *colRowArray = [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:col], [NSNumber numberWithUnsignedInt:row], nil]; + BEGIN_AX_OBJC_EXCEPTIONS + return [m_element accessibilityAttributeValue:@"AXCellForColumnAndRow" forParameter:colRowArray]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + NSRange range = NSMakeRange(NSNotFound, 0); + BEGIN_AX_OBJC_EXCEPTIONS + NSValue *indexRange = [m_element accessibilityAttributeValue:NSAccessibilitySelectedTextRangeAttribute]; + if (indexRange) + range = [indexRange rangeValue]; + NSMutableString *rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ + NSRange textRange = NSMakeRange(location, length); + NSValue *textRangeValue = [NSValue valueWithRange:textRange]; + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilitySetValue:textRangeValue forAttribute:NSAccessibilitySelectedTextRangeAttribute]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::increment() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityIncrementAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::decrement() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityDecrementAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::showMenu() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityShowMenuAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::press() +{ + BEGIN_AX_OBJC_EXCEPTIONS + [m_element accessibilityPerformAction:NSAccessibilityPressAction]; + END_AX_OBJC_EXCEPTIONS +} + +void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* array = [NSArray arrayWithObject:element->platformUIElement()]; + [m_element accessibilitySetValue:array forAttribute:NSAccessibilitySelectedChildrenAttribute]; + END_AX_OBJC_EXCEPTIONS +} + +JSStringRef AccessibilityUIElement::accessibilityValue() const +{ + // FIXME: implement + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentEncoding() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::documentURI() +{ + return JSStringCreateWithCharacters(0, 0); +} + +JSStringRef AccessibilityUIElement::url() +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSURL *url = [m_element accessibilityAttributeValue:NSAccessibilityURLAttribute]; + return [[url absoluteString] createJSStringRef]; + END_AX_OBJC_EXCEPTIONS + + return nil; +} + +bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) +{ + if (!functionCallback) + return false; + + // Mac programmers should not be adding more than one notification listener per element. + // Other platforms may be different. + if (m_notificationHandler) + return false; + m_notificationHandler = [[AccessibilityNotificationHandler alloc] initWithPlatformElement:platformUIElement()]; + [m_notificationHandler setCallback:functionCallback]; + + return true; +} + +void AccessibilityUIElement::removeNotificationListener() +{ + // Mac programmers should not be trying to remove a listener that's already removed. + ASSERT(m_notificationHandler); + + [m_notificationHandler release]; + m_notificationHandler = nil; +} + +bool AccessibilityUIElement::isFocusable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isMultiSelectable() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isVisible() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isOffScreen() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isCollapsed() const +{ + // FIXME: implement + return false; +} + +bool AccessibilityUIElement::isIgnored() const +{ + BOOL result = NO; + BEGIN_AX_OBJC_EXCEPTIONS + result = [m_element accessibilityIsIgnored]; + END_AX_OBJC_EXCEPTIONS + return result; +} + +bool AccessibilityUIElement::hasPopup() const +{ + BEGIN_AX_OBJC_EXCEPTIONS + id value = [m_element accessibilityAttributeValue:@"AXHasPopup"]; + if ([value isKindOfClass:[NSNumber class]]) + return [value boolValue]; + END_AX_OBJC_EXCEPTIONS + + return false; +} + +void AccessibilityUIElement::takeFocus() +{ + // FIXME: implement +} + +void AccessibilityUIElement::takeSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::addSelection() +{ + // FIXME: implement +} + +void AccessibilityUIElement::removeSelection() +{ + // FIXME: implement +} + +#if SUPPORTS_AX_TEXTMARKERS + +// Text markers +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUIElement" forParameter:element->platformUIElement()]; + return AccessibilityTextMarkerRange(textMarkerRange); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSNumber* lengthValue = [m_element accessibilityAttributeValue:@"AXLengthForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return [lengthValue intValue]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + + +AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil]; + id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUnorderedTextMarkers" forParameter:textMarkers]; + return AccessibilityTextMarkerRange(textMarkerRange); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id textMarker = [m_element accessibilityAttributeValue:@"AXTextMarkerForPosition" forParameter:[NSValue valueWithPoint:NSMakePoint(x, y)]]; + return AccessibilityTextMarker(textMarker); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker) +{ + BEGIN_AX_OBJC_EXCEPTIONS + id uiElement = [m_element accessibilityAttributeValue:@"AXUIElementForTextMarker" forParameter:(id)marker->platformTextMarker()]; + return AccessibilityUIElement(uiElement); + END_AX_OBJC_EXCEPTIONS + + return 0; +} + +#endif // SUPPORTS_AX_TEXTMARKERS diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.h b/Tools/DumpRenderTree/mac/AppleScriptController.h new file mode 100644 index 0000000..c29789c --- /dev/null +++ b/Tools/DumpRenderTree/mac/AppleScriptController.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> + +@class WebView; + +@interface AppleScriptController : NSObject +{ + WebView *webView; +} +- (id)initWithWebView:(WebView *)view; +@end diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.m b/Tools/DumpRenderTree/mac/AppleScriptController.m new file mode 100644 index 0000000..2eab827 --- /dev/null +++ b/Tools/DumpRenderTree/mac/AppleScriptController.m @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "AppleScriptController.h" + +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> // for aeDescByEvaluatingJavaScriptFromString, which is pending API review + +@implementation AppleScriptController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(doJavaScript:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(doJavaScript:)) + return @"doJavaScript"; + + return nil; +} + +- (id)initWithWebView:(WebView *)wv +{ + self = [super init]; + webView = wv; + return self; +} + +static id convertAEDescToObject(NSAppleEventDescriptor *aeDesc) +{ + id value = nil; + + DescType descType = [aeDesc descriptorType]; + switch (descType) { + case typeUnicodeText: + value = [NSString stringWithFormat:@"\"%@\"", [aeDesc stringValue]]; + break; + case typeLongDateTime: + if ([[aeDesc data] length] == sizeof(LongDateTime)) { + LongDateTime d; + [[aeDesc data] getBytes:&d]; + value = [NSString stringWithFormat:@"%016llX", (unsigned long long)d]; + } + break; + case typeAEList: + value = [NSMutableString stringWithString:@"("]; + int numItems = [aeDesc numberOfItems]; + for (int i = 0; i < numItems; ++i) { + if (i != 0) + [(NSMutableString*)value appendString:@", "]; + id obj = convertAEDescToObject([aeDesc descriptorAtIndex:(i + 1)]); + [(NSMutableString*)value appendString:[obj description]]; + } + [(NSMutableString*)value appendString:@")"]; + break; + case typeType: { + OSType type = [aeDesc typeCodeValue]; + + char typeStr[5]; + typeStr[0] = type >> 24; + typeStr[1] = type >> 16; + typeStr[2] = type >> 8; + typeStr[3] = type; + typeStr[4] = 0; + + value = [NSString stringWithFormat:@"'%s'", typeStr]; + break; + } + } + + if (!value) + value = [aeDesc stringValue]; + if (!value) + value = [aeDesc data]; + + return value; +} + +- (NSString *)doJavaScript:(NSString *)aString +{ + NSAppleEventDescriptor *aeDesc = [webView aeDescByEvaluatingJavaScriptFromString:aString]; + if (!aeDesc) + return @"(null)"; + + DescType descType = [aeDesc descriptorType]; + char descTypeStr[5]; + descTypeStr[0] = descType >> 24; + descTypeStr[1] = descType >> 16; + descTypeStr[2] = descType >> 8; + descTypeStr[3] = descType; + descTypeStr[4] = 0; + + return [NSString stringWithFormat:@"%@ ('%s')", convertAEDescToObject(aeDesc), descTypeStr]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.cpp b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp new file mode 100644 index 0000000..faef760 --- /dev/null +++ b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "CheckedMalloc.h" + +#import <malloc/malloc.h> +#import <sys/mman.h> + +static void* (*savedMalloc)(malloc_zone_t*, size_t); +static void* (*savedRealloc)(malloc_zone_t*, void*, size_t); + +static void* checkedMalloc(malloc_zone_t* zone, size_t size) +{ + if (size >= 0x10000000) + return 0; + return savedMalloc(zone, size); +} + +static void* checkedRealloc(malloc_zone_t* zone, void* ptr, size_t size) +{ + if (size >= 0x10000000) + return 0; + return savedRealloc(zone, ptr, size); +} + +void makeLargeMallocFailSilently() +{ + malloc_zone_t* zone = malloc_default_zone(); + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + vm_address_t pageStart = reinterpret_cast<vm_address_t>(zone) & static_cast<vm_size_t>(~(getpagesize() - 1)); + vm_size_t len = reinterpret_cast<vm_address_t>(zone) - pageStart + sizeof(malloc_zone_t); + mprotect(reinterpret_cast<void*>(pageStart), len, PROT_READ | PROT_WRITE); +#endif + + savedMalloc = zone->malloc; + savedRealloc = zone->realloc; + zone->malloc = checkedMalloc; + zone->realloc = checkedRealloc; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + mprotect(reinterpret_cast<void*>(pageStart), len, PROT_READ); +#endif +} diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.h b/Tools/DumpRenderTree/mac/CheckedMalloc.h new file mode 100644 index 0000000..c03bd20 --- /dev/null +++ b/Tools/DumpRenderTree/mac/CheckedMalloc.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +void makeLargeMallocFailSilently(); diff --git a/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig new file mode 100644 index 0000000..28a0518 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig @@ -0,0 +1,69 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +HEADER_SEARCH_PATHS = ForwardingHeaders mac/InternalHeaders; +FRAMEWORK_SEARCH_PATHS = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks; +GCC_PREPROCESSOR_DEFINITIONS = ENABLE_DASHBOARD_SUPPORT WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST; +DEBUG_INFORMATION_FORMAT = dwarf +PREBINDING = NO +GCC_C_LANGUAGE_STANDARD = gnu99 +GCC_OBJC_CALL_CXX_CDTORS = YES +GCC_PRECOMPILE_PREFIX_HEADER = YES +GCC_TREAT_WARNINGS_AS_ERRORS = YES +GCC_WARN_UNUSED_FUNCTION = YES +GCC_WARN_UNUSED_VARIABLE = YES +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO +WARNING_CFLAGS = -Wall -W -Wno-unused-parameter +LINKER_DISPLAYS_MANGLED_NAMES = YES; + + +TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR); + + +// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0. +// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version +// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and +// XCODE_VERSION_ACTUAL for the full version number. +TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040); +TARGET_GCC_VERSION_1040 = GCC_40; +TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR)); +TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL)); +TARGET_GCC_VERSION_1050_0310 = GCC_42; +TARGET_GCC_VERSION_1050_0320 = GCC_42; +TARGET_GCC_VERSION_1060 = GCC_42; +TARGET_GCC_VERSION_1070 = LLVM_GCC_42; + +GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION)); +GCC_VERSION_GCC_40 = 4.0; +GCC_VERSION_GCC_42 = 4.2; +GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42; + +// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK. +SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +SDKROOT_1050_1040 = macosx10.4; +SDKROOT_1060_1040 = macosx10.4; +SDKROOT_1060_1050 = macosx10.5; +SDKROOT_1070_1040 = macosx10.4; +SDKROOT_1070_1050 = macosx10.5; +SDKROOT_1070_1060 = macosx10.6; diff --git a/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig new file mode 100644 index 0000000..ab3278e --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig @@ -0,0 +1,40 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "Base.xcconfig" + +ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +ARCHS_ = $(ARCHS_1040); +ARCHS_1040 = $(NATIVE_ARCH); +ARCHS_1050 = $(NATIVE_ARCH); +ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT); +ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT); + +ONLY_ACTIVE_ARCH = YES; + +MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR)) +MACOSX_DEPLOYMENT_TARGET_ = 10.4; +MACOSX_DEPLOYMENT_TARGET_1040 = 10.4; +MACOSX_DEPLOYMENT_TARGET_1050 = 10.5; +MACOSX_DEPLOYMENT_TARGET_1060 = 10.6; +MACOSX_DEPLOYMENT_TARGET_1070 = 10.7; diff --git a/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig new file mode 100644 index 0000000..35a0720 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig @@ -0,0 +1,27 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OTHER_LDFLAGS = -sectcreate __DATA Ahem qt/fonts/AHEM____.TTF -sectcreate __DATA WeightWatcher100 fonts/WebKitWeightWatcher100.ttf -sectcreate __DATA WeightWatcher200 fonts/WebKitWeightWatcher200.ttf -sectcreate __DATA WeightWatcher300 fonts/WebKitWeightWatcher300.ttf -sectcreate __DATA WeightWatcher400 fonts/WebKitWeightWatcher400.ttf -sectcreate __DATA WeightWatcher500 fonts/WebKitWeightWatcher500.ttf -sectcreate __DATA WeightWatcher600 fonts/WebKitWeightWatcher600.ttf -sectcreate __DATA WeightWatcher700 fonts/WebKitWeightWatcher700.ttf -sectcreate __DATA WeightWatcher800 fonts/WebKitWeightWatcher800.ttf -sectcreate __DATA WeightWatcher900 fonts/WebKitWeightWatcher900.ttf +PRODUCT_NAME = DumpRenderTree +GCC_ENABLE_OBJC_EXCEPTIONS = YES +GCC_PREFIX_HEADER = DumpRenderTreePrefix.h diff --git a/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig new file mode 100644 index 0000000..35968af --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig @@ -0,0 +1,24 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +PRODUCT_NAME = ImageDiff diff --git a/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig new file mode 100644 index 0000000..22ea4c2 --- /dev/null +++ b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig @@ -0,0 +1,29 @@ +// Copyright (C) 2009 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +PRODUCT_NAME = TestNetscapePlugIn +WRAPPER_EXTENSION = plugin +INFOPLIST_FILE = TestNetscapePlugIn.subproj/Info.plist +INSTALL_PATH = "$(USER_LIBRARY_DIR)/Plugins" +WARNING_CFLAGS = -Wmost -Wno-four-char-constants -Wno-unknown-pragmas +LIBRARY_STYLE = BUNDLE diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm new file mode 100644 index 0000000..ed09cf6 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm @@ -0,0 +1,1188 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" + +#import "AccessibilityController.h" +#import "CheckedMalloc.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "DumpRenderTreePasteboard.h" +#import "DumpRenderTreeWindow.h" +#import "EditingDelegate.h" +#import "EventSendingController.h" +#import "FrameLoadDelegate.h" +#import "HistoryDelegate.h" +#import "JavaScriptThreading.h" +#import "LayoutTestController.h" +#import "MockGeolocationProvider.h" +#import "NavigationController.h" +#import "ObjCPlugin.h" +#import "ObjCPluginFunction.h" +#import "PixelDumpSupport.h" +#import "PolicyDelegate.h" +#import "ResourceLoadDelegate.h" +#import "UIDelegate.h" +#import "WebArchiveDumpSupport.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <Carbon/Carbon.h> +#import <CoreFoundation/CoreFoundation.h> +#import <WebCore/FoundationExtras.h> +#import <WebKit/DOMElement.h> +#import <WebKit/DOMExtensions.h> +#import <WebKit/DOMRange.h> +#import <WebKit/WebArchive.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebCache.h> +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDataSourcePrivate.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebDeviceOrientationProviderMock.h> +#import <WebKit/WebEditingDelegate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebHistoryItemPrivate.h> +#import <WebKit/WebInspector.h> +#import <WebKit/WebKitNSStringExtras.h> +#import <WebKit/WebPluginDatabase.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebPreferenceKeysPrivate.h> +#import <WebKit/WebResourceLoadDelegate.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebViewPrivate.h> +#import <getopt.h> +#import <objc/objc-runtime.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> +#import <wtf/Threading.h> +#import <wtf/OwnPtr.h> + +extern "C" { +#import <mach-o/getsect.h> +} + +using namespace std; + +@interface DumpRenderTreeApplication : NSApplication +@end + +@interface DumpRenderTreeEvent : NSEvent +@end + +@interface NSURLRequest (PrivateThingsWeShouldntReallyUse) ++(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host; +@end + +static void runTest(const string& testPathOrURL); + +// Deciding when it's OK to dump out the state is a bit tricky. All these must be true: +// - There is no load in progress +// - There is no work queued up (see workQueue var, below) +// - waitToDump==NO. This means either waitUntilDone was never called, or it was called +// and notifyDone was called subsequently. +// Note that the call to notifyDone and the end of the load can happen in either order. + +volatile bool done; + +NavigationController* gNavigationController = 0; +RefPtr<LayoutTestController> gLayoutTestController; + +WebFrame *mainFrame = 0; +// This is the topmost frame that is loading, during a given load, or nil when no load is +// in progress. Usually this is the same as the main frame, but not always. In the case +// where a frameset is loaded, and then new content is loaded into one of the child frames, +// that child frame is the "topmost frame that is loading". +WebFrame *topLoadingFrame = nil; // !nil iff a load is in progress + + +CFMutableSetRef disallowedURLs = 0; +CFRunLoopTimerRef waitToDumpWatchdog = 0; + +// Delegates +static FrameLoadDelegate *frameLoadDelegate; +static UIDelegate *uiDelegate; +static EditingDelegate *editingDelegate; +static ResourceLoadDelegate *resourceLoadDelegate; +static HistoryDelegate *historyDelegate; +PolicyDelegate *policyDelegate; + +static int dumpPixels; +static int threaded; +static int dumpTree = YES; +static int forceComplexText; +static BOOL printSeparators; +static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; + +static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test + +#if __OBJC2__ +static void swizzleAllMethods(Class imposter, Class original) +{ + unsigned int imposterMethodCount; + Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount); + + unsigned int originalMethodCount; + Method* originalMethods = class_copyMethodList(original, &originalMethodCount); + + for (unsigned int i = 0; i < imposterMethodCount; i++) { + SEL imposterMethodName = method_getName(imposterMethods[i]); + + // Attempt to add the method to the original class. If it fails, the method already exists and we should + // instead exchange the implementations. + if (class_addMethod(original, imposterMethodName, method_getImplementation(imposterMethods[i]), method_getTypeEncoding(imposterMethods[i]))) + continue; + + unsigned int j = 0; + for (; j < originalMethodCount; j++) { + SEL originalMethodName = method_getName(originalMethods[j]); + if (sel_isEqual(imposterMethodName, originalMethodName)) + break; + } + + // If class_addMethod failed above then the method must exist on the original class. + ASSERT(j < originalMethodCount); + method_exchangeImplementations(imposterMethods[i], originalMethods[j]); + } + + free(imposterMethods); + free(originalMethods); +} +#endif + +static void poseAsClass(const char* imposter, const char* original) +{ + Class imposterClass = objc_getClass(imposter); + Class originalClass = objc_getClass(original); + +#if !__OBJC2__ + class_poseAs(imposterClass, originalClass); +#else + + // Swizzle instance methods + swizzleAllMethods(imposterClass, originalClass); + // and then class methods + swizzleAllMethods(object_getClass(imposterClass), object_getClass(originalClass)); +#endif +} + +void setPersistentUserStyleSheetLocation(CFStringRef url) +{ + persistentUserStyleSheetLocation = url; +} + +static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString) +{ + static char* const ignoreSet[] = { + // Keeping this infrastructure around in case we ever need it again. + }; + static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*); + + for (int i = 0; i < ignoreSetCount; i++) { + // FIXME: ignore case + string curIgnore(ignoreSet[i]); + // Match at the end of the URLString + if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore)) + return true; + } + return false; +} + +static void activateFonts() +{ +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_TIGER) + static const char* fontSectionNames[] = { + "Ahem", + "WeightWatcher100", + "WeightWatcher200", + "WeightWatcher300", + "WeightWatcher400", + "WeightWatcher500", + "WeightWatcher600", + "WeightWatcher700", + "WeightWatcher800", + "WeightWatcher900", + 0 + }; + + for (unsigned i = 0; fontSectionNames[i]; ++i) { + unsigned long fontDataLength; + char* fontData = getsectdata("__DATA", fontSectionNames[i], &fontDataLength); + if (!fontData) { + fprintf(stderr, "Failed to locate the %s font.\n", fontSectionNames[i]); + exit(1); + } + + ATSFontContainerRef fontContainer; + OSStatus status = ATSFontActivateFromMemory(fontData, fontDataLength, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &fontContainer); + + if (status != noErr) { + fprintf(stderr, "Failed to activate the %s font.\n", fontSectionNames[i]); + exit(1); + } + } +#else + + // Work around <rdar://problem/6698023> by activating fonts from disk + // FIXME: This code can be removed once <rdar://problem/6698023> is addressed. + + static const char* fontFileNames[] = { + "AHEM____.TTF", + "ColorBits.ttf", + "WebKitWeightWatcher100.ttf", + "WebKitWeightWatcher200.ttf", + "WebKitWeightWatcher300.ttf", + "WebKitWeightWatcher400.ttf", + "WebKitWeightWatcher500.ttf", + "WebKitWeightWatcher600.ttf", + "WebKitWeightWatcher700.ttf", + "WebKitWeightWatcher800.ttf", + "WebKitWeightWatcher900.ttf", + 0 + }; + + NSMutableArray *fontURLs = [NSMutableArray array]; + NSURL *resourcesDirectory = [NSURL URLWithString:@"DumpRenderTree.resources" relativeToURL:[[NSBundle mainBundle] executableURL]]; + for (unsigned i = 0; fontFileNames[i]; ++i) { + NSURL *fontURL = [resourcesDirectory URLByAppendingPathComponent:[NSString stringWithUTF8String:fontFileNames[i]]]; + [fontURLs addObject:[fontURL absoluteURL]]; + } + + CFArrayRef errors = 0; + if (!CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeProcess, &errors)) { + NSLog(@"Failed to activate fonts: %@", errors); + CFRelease(errors); + exit(1); + } +#endif +} + +WebView *createWebViewAndOffscreenWindow() +{ + NSRect rect = NSMakeRect(0, 0, LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight); + WebView *webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:@"org.webkit.DumpRenderTree"]; + + [webView setUIDelegate:uiDelegate]; + [webView setFrameLoadDelegate:frameLoadDelegate]; + [webView setEditingDelegate:editingDelegate]; + [webView setResourceLoadDelegate:resourceLoadDelegate]; + [webView _setGeolocationProvider:[MockGeolocationProvider shared]]; + [webView _setDeviceOrientationProvider:[WebDeviceOrientationProviderMock shared]]; + + // Register the same schemes that Safari does + [WebView registerURLSchemeAsLocal:@"feed"]; + [WebView registerURLSchemeAsLocal:@"feeds"]; + [WebView registerURLSchemeAsLocal:@"feedsearch"]; + + [webView setContinuousSpellCheckingEnabled:YES]; + + // To make things like certain NSViews, dragging, and plug-ins work, put the WebView a window, but put it off-screen so you don't see it. + // Put it at -10000, -10000 in "flipped coordinates", since WebCore and the DOM use flipped coordinates. + NSRect windowRect = NSOffsetRect(rect, -10000, [[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000); + DumpRenderTreeWindow *window = [[DumpRenderTreeWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + [window setColorSpace:[[NSScreen mainScreen] colorSpace]]; +#endif + + [[window contentView] addSubview:webView]; + [window orderBack:nil]; + [window setAutodisplay:NO]; + + [window startListeningForAcceleratedCompositingChanges]; + + // For reasons that are not entirely clear, the following pair of calls makes WebView handle its + // dynamic scrollbars properly. Without it, every frame will always have scrollbars. + NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:[webView bounds]]; + [webView cacheDisplayInRect:[webView bounds] toBitmapImageRep:imageRep]; + + return webView; +} + +void testStringByEvaluatingJavaScriptFromString() +{ + // maps expected result <= JavaScript expression + NSDictionary *expressions = [NSDictionary dictionaryWithObjectsAndKeys: + @"0", @"0", + @"0", @"'0'", + @"", @"", + @"", @"''", + @"", @"new String()", + @"", @"new String('0')", + @"", @"throw 1", + @"", @"{ }", + @"", @"[ ]", + @"", @"//", + @"", @"a.b.c", + @"", @"(function() { throw 'error'; })()", + @"", @"null", + @"", @"undefined", + @"true", @"true", + @"false", @"false", + nil + ]; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""]; + + NSEnumerator *enumerator = [expressions keyEnumerator]; + id expression; + while ((expression = [enumerator nextObject])) { + NSString *expectedResult = [expressions objectForKey:expression]; + NSString *result = [webView stringByEvaluatingJavaScriptFromString:expression]; + assert([result isEqualToString:expectedResult]); + } + + [webView close]; + [webView release]; + [pool release]; +} + +static NSString *libraryPathForDumpRenderTree() +{ + //FIXME: This may not be sufficient to prevent interactions/crashes + //when running more than one copy of DumpRenderTree. + //See https://bugs.webkit.org/show_bug.cgi?id=10906 + char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP"); + if (dumpRenderTreeTemp) + return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:dumpRenderTreeTemp length:strlen(dumpRenderTreeTemp)]; + else + return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath]; +} + +// Called before each test. +static void resetDefaultsToConsistentValues() +{ + // Give some clear to undocumented defaults values + static const int NoFontSmoothing = 0; + static const int BlueTintedAppearance = 1; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on + [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"]; + [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"]; + [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"]; + [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"]; + [defaults setObject:[NSArray arrayWithObject:@"en"] forKey:@"AppleLanguages"]; + [defaults setBool:YES forKey:WebKitEnableFullDocumentTeardownPreferenceKey]; + [defaults setBool:YES forKey:WebKitFullScreenEnabledPreferenceKey]; + + // Scrollbars are drawn either using AppKit (which uses NSUserDefaults) or using HIToolbox (which uses CFPreferences / kCFPreferencesAnyApplication / kCFPreferencesCurrentUser / kCFPreferencesAnyHost) + [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; + RetainPtr<CFTypeRef> initialValue = CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), CFSTR("DoubleMax"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); +#ifndef __LP64__ + // See <rdar://problem/6347388>. + ThemeScrollBarArrowStyle style; + GetThemeScrollBarArrowStyle(&style); // Force HIToolbox to read from CFPreferences +#endif + + [defaults setBool:NO forKey:@"AppleScrollAnimationEnabled"]; + [defaults setBool:NO forKey:@"NSOverlayScrollersEnabled"]; + + if (initialValue) + CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + + NSString *path = libraryPathForDumpRenderTree(); + [defaults setObject:[path stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey]; + [defaults setObject:[path stringByAppendingPathComponent:@"LocalCache"] forKey:WebKitLocalCacheDefaultsKey]; + + WebPreferences *preferences = [WebPreferences standardPreferences]; + + [preferences setAllowUniversalAccessFromFileURLs:YES]; + [preferences setAllowFileAccessFromFileURLs:YES]; + [preferences setStandardFontFamily:@"Times"]; + [preferences setFixedFontFamily:@"Courier"]; + [preferences setSerifFontFamily:@"Times"]; + [preferences setSansSerifFontFamily:@"Helvetica"]; + [preferences setCursiveFontFamily:@"Apple Chancery"]; + [preferences setFantasyFontFamily:@"Papyrus"]; + [preferences setDefaultFontSize:16]; + [preferences setDefaultFixedFontSize:13]; + [preferences setMinimumFontSize:0]; + [preferences setJavaEnabled:NO]; + [preferences setJavaScriptEnabled:YES]; + [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey]; + [preferences setTabsToLinks:NO]; + [preferences setDOMPasteAllowed:YES]; + [preferences setShouldPrintBackgrounds:YES]; + [preferences setCacheModel:WebCacheModelDocumentBrowser]; + [preferences setXSSAuditorEnabled:NO]; + [preferences setExperimentalNotificationsEnabled:NO]; + [preferences setPluginAllowedRunTime:1]; + [preferences setPlugInsEnabled:YES]; + + [preferences setPrivateBrowsingEnabled:NO]; + [preferences setAuthorAndUserStylesEnabled:YES]; + [preferences setJavaScriptCanOpenWindowsAutomatically:YES]; + [preferences setJavaScriptCanAccessClipboard:YES]; + [preferences setOfflineWebApplicationCacheEnabled:YES]; + [preferences setDeveloperExtrasEnabled:NO]; + [preferences setLoadsImagesAutomatically:YES]; + [preferences setFrameFlatteningEnabled:NO]; + [preferences setEditingBehavior:WebKitEditingMacBehavior]; + if (persistentUserStyleSheetLocation) { + [preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]]; + [preferences setUserStyleSheetEnabled:YES]; + } else + [preferences setUserStyleSheetEnabled:NO]; + + // The back/forward cache is causing problems due to layouts during transition from one page to another. + // So, turn it off for now, but we might want to turn it back on some day. + [preferences setUsesPageCache:NO]; + [preferences setAcceleratedCompositingEnabled:YES]; + [preferences setWebGLEnabled:NO]; + [preferences setUsePreHTML5ParserQuirks:NO]; + [preferences setAsynchronousSpellCheckingEnabled:NO]; + + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain]; + + LayoutTestController::setSerializeHTTPLoads(false); + + setlocale(LC_ALL, ""); +} + +// Called once on DumpRenderTree startup. +static void setDefaultsToConsistentValuesForTesting() +{ + resetDefaultsToConsistentValues(); + + NSString *path = libraryPathForDumpRenderTree(); + NSURLCache *sharedCache = + [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024 + diskCapacity:0 + diskPath:[path stringByAppendingPathComponent:@"URLCache"]]; + [NSURLCache setSharedURLCache:sharedCache]; + [sharedCache release]; + +} + +static void* runThread(void* arg) +{ + static ThreadIdentifier previousId = 0; + ThreadIdentifier currentId = currentThread(); + // Verify 2 successive threads do not get the same Id. + ASSERT(previousId != currentId); + previousId = currentId; + return 0; +} + +static void testThreadIdentifierMap() +{ + // Imitate 'foreign' threads that are not created by WTF. + pthread_t pthread; + pthread_create(&pthread, 0, &runThread, 0); + pthread_join(pthread, 0); + + pthread_create(&pthread, 0, &runThread, 0); + pthread_join(pthread, 0); + + // Now create another thread using WTF. On OSX, it will have the same pthread handle + // but should get a different ThreadIdentifier. + createThread(runThread, 0, "DumpRenderTree: test"); +} + +static void crashHandler(int sig) +{ + char *signalName = strsignal(sig); + write(STDERR_FILENO, signalName, strlen(signalName)); + write(STDERR_FILENO, "\n", 1); + restoreMainDisplayColorProfile(0); + exit(128 + sig); +} + +static void installSignalHandlers() +{ + signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */ + signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */ + signal(SIGEMT, crashHandler); /* 7: EMT instruction */ + signal(SIGFPE, crashHandler); /* 8: floating point exception */ + signal(SIGBUS, crashHandler); /* 10: bus error */ + signal(SIGSEGV, crashHandler); /* 11: segmentation violation */ + signal(SIGSYS, crashHandler); /* 12: bad argument to system call */ + signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */ + signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */ + signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */ +} + +static void allocateGlobalControllers() +{ + // FIXME: We should remove these and move to the ObjC standard [Foo sharedInstance] model + gNavigationController = [[NavigationController alloc] init]; + frameLoadDelegate = [[FrameLoadDelegate alloc] init]; + uiDelegate = [[UIDelegate alloc] init]; + editingDelegate = [[EditingDelegate alloc] init]; + resourceLoadDelegate = [[ResourceLoadDelegate alloc] init]; + policyDelegate = [[PolicyDelegate alloc] init]; + historyDelegate = [[HistoryDelegate alloc] init]; +} + +// ObjC++ doens't seem to let me pass NSObject*& sadly. +static inline void releaseAndZero(NSObject** object) +{ + [*object release]; + *object = nil; +} + +static void releaseGlobalControllers() +{ + releaseAndZero(&gNavigationController); + releaseAndZero(&frameLoadDelegate); + releaseAndZero(&editingDelegate); + releaseAndZero(&resourceLoadDelegate); + releaseAndZero(&uiDelegate); + releaseAndZero(&policyDelegate); +} + +static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[]) +{ + struct option options[] = { + {"notree", no_argument, &dumpTree, NO}, + {"pixel-tests", no_argument, &dumpPixels, YES}, + {"tree", no_argument, &dumpTree, YES}, + {"threaded", no_argument, &threaded, YES}, + {"complex-text", no_argument, &forceComplexText, YES}, + {NULL, 0, NULL, 0} + }; + + int option; + while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) { + switch (option) { + case '?': // unknown or ambiguous option + case ':': // missing argument + exit(1); + break; + } + } +} + +static void addTestPluginsToPluginSearchPath(const char* executablePath) +{ + NSString *pwd = [[NSString stringWithUTF8String:executablePath] stringByDeletingLastPathComponent]; + [WebPluginDatabase setAdditionalWebPlugInPaths:[NSArray arrayWithObject:pwd]]; + [[WebPluginDatabase sharedDatabase] refresh]; +} + +static bool useLongRunningServerMode(int argc, const char *argv[]) +{ + // This assumes you've already called getopt_long + return (argc == optind+1 && strcmp(argv[optind], "-") == 0); +} + +static void runTestingServerLoop() +{ + // When DumpRenderTree run in server mode, we just wait around for file names + // to be passed to us and read each in turn, passing the results back to the client + char filenameBuffer[2048]; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + char *newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (strlen(filenameBuffer) == 0) + continue; + + runTest(filenameBuffer); + } +} + +static void prepareConsistentTestingEnvironment() +{ + poseAsClass("DumpRenderTreePasteboard", "NSPasteboard"); + poseAsClass("DumpRenderTreeEvent", "NSEvent"); + + setDefaultsToConsistentValuesForTesting(); + activateFonts(); + + if (dumpPixels) + setupMainDisplayColorProfile(); + allocateGlobalControllers(); + + makeLargeMallocFailSilently(); +} + +void dumpRenderTree(int argc, const char *argv[]) +{ + initializeGlobalsFromCommandLineOptions(argc, argv); + prepareConsistentTestingEnvironment(); + addTestPluginsToPluginSearchPath(argv[0]); + if (dumpPixels) + installSignalHandlers(); + + if (forceComplexText) + [WebView _setAlwaysUsesComplexTextCodePath:YES]; + + WebView *webView = createWebViewAndOffscreenWindow(); + mainFrame = [webView mainFrame]; + + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + [WebCache empty]; + + // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL + // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1. +#if BUILDING_ON_TIGER + // Initialize internal NSURLRequest data for setAllowsAnyHTTPSCertificate:forHost: to work properly. + [[[[NSURLRequest alloc] init] autorelease] HTTPMethod]; +#endif + [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"]; + [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"]; + + // <rdar://problem/5222911> + testStringByEvaluatingJavaScriptFromString(); + + // http://webkit.org/b/32689 + testThreadIdentifierMap(); + + if (threaded) + startJavaScriptThreads(); + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = YES; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + if (threaded) + stopJavaScriptThreads(); + + NSWindow *window = [webView window]; + [webView close]; + mainFrame = nil; + + // Work around problem where registering drag types leaves an outstanding + // "perform selector" on the window, which retains the window. It's a bit + // inelegant and perhaps dangerous to just blow them all away, but in practice + // it probably won't cause any trouble (and this is just a test tool, after all). + [NSObject cancelPreviousPerformRequestsWithTarget:window]; + + [window close]; // releases when closed + [webView release]; + + releaseGlobalControllers(); + + [DumpRenderTreePasteboard releaseLocalPasteboards]; + + // FIXME: This should be moved onto LayoutTestController and made into a HashSet + if (disallowedURLs) { + CFRelease(disallowedURLs); + disallowedURLs = 0; + } + + if (dumpPixels) + restoreMainDisplayColorProfile(0); +} + +int main(int argc, const char *argv[]) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [DumpRenderTreeApplication sharedApplication]; // Force AppKit to init itself + dumpRenderTree(argc, argv); + [WebCoreStatistics garbageCollectJavaScriptObjects]; + [WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts + [pool release]; + return 0; +} + +static NSInteger compareHistoryItems(id item1, id item2, void *context) +{ + return [[item1 target] caseInsensitiveCompare:[item2 target]]; +} + +static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current) +{ + int start = 0; + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + NSString *urlString = [item URLString]; + if ([[NSURL URLWithString:urlString] isFileURL]) { + NSRange range = [urlString rangeOfString:@"/LayoutTests/"]; + urlString = [@"(file test):" stringByAppendingString:[urlString substringFromIndex:(range.length + range.location)]]; + } + + printf("%s", [urlString UTF8String]); + NSString *target = [item target]; + if (target && [target length] > 0) + printf(" (in frame \"%s\")", [target UTF8String]); + if ([item isTargetItem]) + printf(" **nav target**"); + putchar('\n'); + NSArray *kids = [item children]; + if (kids) { + // must sort to eliminate arbitrary result ordering which defeats reproducible testing + kids = [kids sortedArrayUsingFunction:&compareHistoryItems context:nil]; + for (unsigned i = 0; i < [kids count]; i++) + dumpHistoryItem([kids objectAtIndex:i], indent+4, NO); + } +} + +static void dumpFrameScrollPosition(WebFrame *f) +{ + NSPoint scrollPosition = [[[[f frameView] documentView] superview] bounds].origin; + if (ABS(scrollPosition.x) > 0.00000001 || ABS(scrollPosition.y) > 0.00000001) { + if ([f parentFrame] != nil) + printf("frame '%s' ", [[f name] UTF8String]); + printf("scrolled to %.f,%.f\n", scrollPosition.x, scrollPosition.y); + } + + if (gLayoutTestController->dumpChildFrameScrollPositions()) { + NSArray *kids = [f childFrames]; + if (kids) + for (unsigned i = 0; i < [kids count]; i++) + dumpFrameScrollPosition([kids objectAtIndex:i]); + } +} + +static NSString *dumpFramesAsText(WebFrame *frame) +{ + DOMDocument *document = [frame DOMDocument]; + DOMElement *documentElement = [document documentElement]; + + if (!documentElement) + return @""; + + NSMutableString *result = [[[NSMutableString alloc] init] autorelease]; + + // Add header for all but the main frame. + if ([frame parentFrame]) + result = [NSMutableString stringWithFormat:@"\n--------\nFrame: '%@'\n--------\n", [frame name]]; + + [result appendFormat:@"%@\n", [documentElement innerText]]; + + if (gLayoutTestController->dumpChildFramesAsText()) { + NSArray *kids = [frame childFrames]; + if (kids) { + for (unsigned i = 0; i < [kids count]; i++) + [result appendString:dumpFramesAsText([kids objectAtIndex:i])]; + } + } + + return result; +} + +static NSData *dumpFrameAsPDF(WebFrame *frame) +{ + if (!frame) + return nil; + + // Sadly we have to dump to a file and then read from that file again + // +[NSPrintOperation PDFOperationWithView:insideRect:] requires a rect and prints to a single page + // likewise +[NSView dataWithPDFInsideRect:] also prints to a single continuous page + // The goal of this function is to test "real" printing across multiple pages. + // FIXME: It's possible there might be printing SPI to let us print a multi-page PDF to an NSData object + NSString *path = [libraryPathForDumpRenderTree() stringByAppendingPathComponent:@"test.pdf"]; + + NSMutableDictionary *printInfoDict = [NSMutableDictionary dictionaryWithDictionary:[[NSPrintInfo sharedPrintInfo] dictionary]]; + [printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition]; + [printInfoDict setObject:path forKey:NSPrintSavePath]; + + NSPrintInfo *printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict]; + [printInfo setHorizontalPagination:NSAutoPagination]; + [printInfo setVerticalPagination:NSAutoPagination]; + [printInfo setVerticallyCentered:NO]; + + NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:[frame frameView] printInfo:printInfo]; + [printOperation setShowPanels:NO]; + [printOperation runOperation]; + + [printInfo release]; + + NSData *pdfData = [NSData dataWithContentsOfFile:path]; + [[NSFileManager defaultManager] removeFileAtPath:path handler:nil]; + + return pdfData; +} + +static void dumpBackForwardListForWebView(WebView *view) +{ + printf("\n============== Back Forward List ==============\n"); + WebBackForwardList *bfList = [view backForwardList]; + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + NSMutableArray *itemsToPrint = [[NSMutableArray alloc] init]; + for (int i = [bfList forwardListCount]; i > 0; i--) { + WebHistoryItem *item = [bfList itemAtIndex:i]; + // something is wrong if the item from the last test is in the forward part of the b/f list + assert(item != prevTestBFItem); + [itemsToPrint addObject:item]; + } + + assert([bfList currentItem] != prevTestBFItem); + [itemsToPrint addObject:[bfList currentItem]]; + int currentItemIndex = [itemsToPrint count] - 1; + + for (int i = -1; i >= -[bfList backListCount]; i--) { + WebHistoryItem *item = [bfList itemAtIndex:i]; + if (item == prevTestBFItem) + break; + [itemsToPrint addObject:item]; + } + + for (int i = [itemsToPrint count]-1; i >= 0; i--) + dumpHistoryItem([itemsToPrint objectAtIndex:i], 8, i == currentItemIndex); + + [itemsToPrint release]; + printf("===============================================\n"); +} + +static void sizeWebViewForCurrentTest() +{ + // W3C SVG tests expect to be 480x360 + bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos); + if (isSVGW3CTest) + [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)]; + else + [[mainFrame webView] setFrameSize:NSMakeSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)]; +} + +static const char *methodNameStringForFailedTest() +{ + const char *errorMessage; + if (gLayoutTestController->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (gLayoutTestController->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (gLayoutTestController->dumpSourceAsWebArchive()) + errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + + return errorMessage; +} + +static void dumpBackForwardListForAllWindows() +{ + CFArrayRef openWindows = (CFArrayRef)[DumpRenderTreeWindow openWindows]; + unsigned count = CFArrayGetCount(openWindows); + for (unsigned i = 0; i < count; i++) { + NSWindow *window = (NSWindow *)CFArrayGetValueAtIndex(openWindows, i); + WebView *webView = [[[window contentView] subviews] objectAtIndex:0]; + dumpBackForwardListForWebView(webView); + } +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + CFRunLoopTimerInvalidate(waitToDumpWatchdog); + CFRelease(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } +} + +void dump() +{ + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (dumpTree) { + NSString *resultString = nil; + NSData *resultData = nil; + NSString *resultMimeType = @"text/plain"; + + if ([[[mainFrame dataSource] _responseMIMEType] isEqualToString:@"text/plain"]) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } + if (gLayoutTestController->dumpAsText()) { + resultString = dumpFramesAsText(mainFrame); + } else if (gLayoutTestController->dumpAsPDF()) { + resultData = dumpFrameAsPDF(mainFrame); + resultMimeType = @"application/pdf"; + } else if (gLayoutTestController->dumpDOMAsWebArchive()) { + WebArchive *webArchive = [[mainFrame DOMDocument] webArchive]; + resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data])); + resultMimeType = @"application/x-webarchive"; + } else if (gLayoutTestController->dumpSourceAsWebArchive()) { + WebArchive *webArchive = [[mainFrame dataSource] webArchive]; + resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data])); + resultMimeType = @"application/x-webarchive"; + } else { + sizeWebViewForCurrentTest(); + resultString = [mainFrame renderTreeAsExternalRepresentationForPrinting:gLayoutTestController->isPrinting()]; + } + + if (resultString && !resultData) + resultData = [resultString dataUsingEncoding:NSUTF8StringEncoding]; + + printf("Content-Type: %s\n", [resultMimeType UTF8String]); + + if (resultData) { + fwrite([resultData bytes], 1, [resultData length], stdout); + + if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + + if (gLayoutTestController->dumpBackForwardList()) + dumpBackForwardListForAllWindows(); + } else + printf("ERROR: nil result from %s", methodNameStringForFailedTest()); + + // Stop the watchdog thread before we leave this test to make sure it doesn't + // fire in between tests causing the next test to fail. + // This is a speculative fix for: https://bugs.webkit.org/show_bug.cgi?id=32339 + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + } + } + + if (dumpPixels && gLayoutTestController->generatePixelResults()) + // FIXME: when isPrinting is set, dump the image with page separators. + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + puts("#EOF"); // terminate the (possibly empty) pixels block + + fflush(stdout); + fflush(stderr); + + done = YES; +} + +static bool shouldLogFrameLoadDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "loading/"); +} + +static bool shouldLogHistoryDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "globalhistory/"); +} + +static bool shouldOpenWebInspector(const char* pathOrURL) +{ + return strstr(pathOrURL, "inspector/"); +} + +static bool shouldEnableDeveloperExtras(const char* pathOrURL) +{ + return true; +} + +static void resetWebViewToConsistentStateBeforeTesting() +{ + WebView *webView = [mainFrame webView]; + [webView setEditable:NO]; + [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES]; + [webView makeTextStandardSize:nil]; + [webView resetPageZoom:nil]; + [webView setTabKeyCyclesThroughElements:YES]; + [webView setPolicyDelegate:nil]; + [policyDelegate setPermissive:NO]; + [policyDelegate setControllerToNotifyDone:0]; + [frameLoadDelegate resetToConsistentState]; + [webView _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO]; + [webView _clearMainFrameName]; + [[webView undoManager] removeAllActions]; + [WebView _removeAllUserContentFromGroup:[webView groupName]]; + [[webView window] setAutodisplay:NO]; + + resetDefaultsToConsistentValues(); + + [[mainFrame webView] setSmartInsertDeleteEnabled:YES]; + [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO]; + + [WebView _setUsesTestModeFocusRingColor:YES]; + [WebView _resetOriginAccessWhitelists]; + + [[MockGeolocationProvider shared] stopTimer]; + + // Clear the contents of the general pasteboard + [[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; +} + +static void runTest(const string& testPathOrURL) +{ + ASSERT(!testPathOrURL.empty()); + + // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. + string pathOrURL(testPathOrURL); + string expectedPixelHash; + + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != string::npos) { + pathOrURL = string(testPathOrURL, 0, separatorPos); + expectedPixelHash = string(testPathOrURL, separatorPos + 1); + } + + NSString *pathOrURLString = [NSString stringWithUTF8String:pathOrURL.c_str()]; + if (!pathOrURLString) { + fprintf(stderr, "Failed to parse \"%s\" as UTF-8\n", pathOrURL.c_str()); + return; + } + + NSURL *url; + if ([pathOrURLString hasPrefix:@"http://"] || [pathOrURLString hasPrefix:@"https://"]) + url = [NSURL URLWithString:pathOrURLString]; + else + url = [NSURL fileURLWithPath:pathOrURLString]; + if (!url) { + fprintf(stderr, "Failed to parse \"%s\" as a URL\n", pathOrURL.c_str()); + return; + } + + const string testURL([[url absoluteString] UTF8String]); + + resetWebViewToConsistentStateBeforeTesting(); + + gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash); + topLoadingFrame = nil; + ASSERT(!draggingInfo); // the previous test should have called eventSender.mouseUp to drop! + releaseAndZero(&draggingInfo); + done = NO; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (disallowedURLs) + CFSetRemoveAllValues(disallowedURLs); + if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + if (shouldLogHistoryDelegates(pathOrURL.c_str())) + [[mainFrame webView] setHistoryDelegate:historyDelegate]; + else + [[mainFrame webView] setHistoryDelegate:nil]; + + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->setDeveloperExtrasEnabled(true); + if (shouldOpenWebInspector(pathOrURL.c_str())) + gLayoutTestController->showWebInspector(); + } + + if ([WebHistory optionalSharedHistory]) + [WebHistory setOptionalSharedHistory:nil]; + lastMousePosition = NSZeroPoint; + lastClickPosition = NSZeroPoint; + + [prevTestBFItem release]; + prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain]; + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + bool ignoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(testURL); + if (ignoreWebCoreNodeLeaks) + [WebCoreStatistics startIgnoringWebCoreNodeLeaks]; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [mainFrame loadRequest:[NSURLRequest requestWithURL:url]]; + [pool release]; + + while (!done) { + pool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; + [pool release]; + } + + pool = [[NSAutoreleasePool alloc] init]; + [EventSendingController clearSavedEvents]; + [[mainFrame webView] setSelectedDOMRange:nil affinity:NSSelectionAffinityDownstream]; + + WorkQueue::shared()->clear(); + + if (gLayoutTestController->closeRemainingWindowsWhenComplete()) { + NSArray* array = [DumpRenderTreeWindow openWindows]; + + unsigned count = [array count]; + for (unsigned i = 0; i < count; i++) { + NSWindow *window = [array objectAtIndex:i]; + + // Don't try to close the main window + if (window == [[mainFrame webView] window]) + continue; + + WebView *webView = [[[window contentView] subviews] objectAtIndex:0]; + + [webView close]; + [window close]; + } + } + + // If developer extras enabled Web Inspector may have been open by the test. + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } + + resetWebViewToConsistentStateBeforeTesting(); + + [mainFrame loadHTMLString:@"<html></html>" baseURL:[NSURL URLWithString:@"about:blank"]]; + [mainFrame stopLoading]; + + [pool release]; + + // We should only have our main window left open when we're done + ASSERT(CFArrayGetCount(openWindowsRef) == 1); + ASSERT(CFArrayGetValueAtIndex(openWindowsRef, 0) == [[mainFrame webView] window]); + + gLayoutTestController.clear(); + + if (ignoreWebCoreNodeLeaks) + [WebCoreStatistics stopIgnoringWebCoreNodeLeaks]; +} + +void displayWebView() +{ + NSView *webView = [mainFrame webView]; + [webView display]; + [webView lockFocus]; + [[[NSColor blackColor] colorWithAlphaComponent:0.66] set]; + NSRectFillUsingOperation([webView frame], NSCompositeSourceOver); + [webView unlockFocus]; +} + +@implementation DumpRenderTreeEvent + ++ (NSPoint)mouseLocation +{ + return [[[mainFrame webView] window] convertBaseToScreen:lastMousePosition]; +} + +@end + +@implementation DumpRenderTreeApplication + +- (BOOL)isRunning +{ + // <rdar://problem/7686123> Java plug-in freezes unless NSApplication is running + return YES; +} + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h new file mode 100644 index 0000000..249809c --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@interface DumpRenderTreeDraggingInfo : NSObject <NSDraggingInfo> { +@private + NSSize offset; + NSImage *draggedImage; + NSPasteboard *draggingPasteboard; + id draggingSource; +} + +- (id)initWithImage:(NSImage *)image offset:(NSSize)offset pasteboard:(NSPasteboard *)pasteboard source:(id)source; + +- (NSWindow *)draggingDestinationWindow; +- (NSDragOperation)draggingSourceOperationMask; +- (NSPoint)draggingLocation; +- (NSPoint)draggedImageLocation; +- (NSImage *)draggedImage; +- (NSPasteboard *)draggingPasteboard; +- (id)draggingSource; +- (int)draggingSequenceNumber; + +- (void)slideDraggedImageTo:(NSPoint)screenPoint; +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination; +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm new file mode 100644 index 0000000..8eded66 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTreeDraggingInfo.h" + +#import "DumpRenderTree.h" +#import "EventSendingController.h" +#import <WebKit/WebKit.h> + +@implementation DumpRenderTreeDraggingInfo + +- (id)initWithImage:(NSImage *)anImage offset:(NSSize)o pasteboard:(NSPasteboard *)pboard source:(id)source +{ + draggedImage = [anImage retain]; + draggingPasteboard = [pboard retain]; + draggingSource = [source retain]; + offset = o; + + return [super init]; +} + +- (void)dealloc +{ + [draggedImage release]; + [draggingPasteboard release]; + [draggingSource release]; + [super dealloc]; +} + +- (NSWindow *)draggingDestinationWindow +{ + return [[mainFrame webView] window]; +} + +- (NSDragOperation)draggingSourceOperationMask +{ + return [draggingSource draggingSourceOperationMaskForLocal:YES]; +} + +- (NSPoint)draggingLocation +{ + return lastMousePosition; +} + +- (NSPoint)draggedImageLocation +{ + return NSMakePoint(lastMousePosition.x + offset.width, lastMousePosition.y + offset.height); +} + +- (NSImage *)draggedImage +{ + return draggedImage; +} + +- (NSPasteboard *)draggingPasteboard +{ + return draggingPasteboard; +} + +- (id)draggingSource +{ + return draggingSource; +} + +- (int)draggingSequenceNumber +{ + NSLog(@"DumpRenderTree doesn't support draggingSequenceNumber"); + return 0; +} + +- (void)slideDraggedImageTo:(NSPoint)screenPoint +{ + NSLog(@"DumpRenderTree doesn't support slideDraggedImageTo:"); +} + +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination +{ + NSLog(@"DumpRenderTree doesn't support namesOfPromisedFilesDroppedAtDestination:"); + return nil; +} + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +- (NSDraggingFormation)draggingFormation +{ + return NSDraggingFormationDefault; +} + +- (void)setDraggingFormation:(NSDraggingFormation)formation +{ + // Ignored. +} + +- (BOOL)animatesToDestination +{ + return NO; +} + +- (void)setAnimatesToDestination:(BOOL)flag +{ + // Ignored. +} + +- (NSInteger)numberOfValidItemsForDrop +{ + return 1; +} + +- (void)setNumberOfValidItemsForDrop:(NSInteger)number +{ + // Ignored. +} + +- (void)enumerateDraggingItemsWithOptions:(NSEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block +{ + // Ignored. +} +#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h new file mode 100644 index 0000000..36c5eac --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DumpRenderTreeMac_h +#define DumpRenderTreeMac_h + +#include <CoreFoundation/CoreFoundation.h> + +#ifdef __OBJC__ +@class DumpRenderTreeDraggingInfo; +@class NavigationController; +@class PolicyDelegate; +@class WebFrame; +@class WebScriptWorld; +@class WebView; +#else +class DumpRenderTreeDraggingInfo; +class NavigationController; +class PolicyDelegate; +class WebFrame; +class WebScriptWorld; +class WebView; +#endif + +extern CFMutableArrayRef openWindowsRef; +extern CFMutableSetRef disallowedURLs; +extern WebFrame* mainFrame; +extern WebFrame* topLoadingFrame; +extern DumpRenderTreeDraggingInfo *draggingInfo; +extern NavigationController* gNavigationController; +extern PolicyDelegate* policyDelegate; + +extern const unsigned maxViewHeight; +extern const unsigned maxViewWidth; + +extern CFRunLoopTimerRef waitToDumpWatchdog; + +WebView* createWebViewAndOffscreenWindow(); +void setPersistentUserStyleSheetLocation(CFStringRef); + +unsigned worldIDForWorld(WebScriptWorld *); + +#endif // DumpRenderTreeMac_h diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h new file mode 100644 index 0000000..ba2754b --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <AppKit/AppKit.h> +#import <WebKit/WebTypesInternal.h> + +@interface DumpRenderTreePasteboard : NSPasteboard +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner; ++ (void)releaseLocalPasteboards; +@end + diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m new file mode 100644 index 0000000..b1b3b86 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTreeMac.h" +#import "DumpRenderTreePasteboard.h" + +#import <WebKit/WebTypesInternal.h> + +@interface LocalPasteboard : NSPasteboard +{ + NSMutableArray *typesArray; + NSMutableSet *typesSet; + NSMutableDictionary *dataByType; + NSInteger changeCount; +} +@end + +static NSMutableDictionary *localPasteboards; + +@implementation DumpRenderTreePasteboard + +// Return a local pasteboard so we don't disturb the real pasteboards when running tests. ++ (NSPasteboard *)_pasteboardWithName:(NSString *)name +{ + static int number = 0; + if (!name) + name = [NSString stringWithFormat:@"LocalPasteboard%d", ++number]; + if (!localPasteboards) + localPasteboards = [[NSMutableDictionary alloc] init]; + LocalPasteboard *pasteboard = [localPasteboards objectForKey:name]; + if (pasteboard) + return pasteboard; + pasteboard = [[LocalPasteboard alloc] init]; + [localPasteboards setObject:pasteboard forKey:name]; + [pasteboard release]; + return pasteboard; +} + ++ (void)releaseLocalPasteboards +{ + [localPasteboards release]; + localPasteboards = nil; +} + +// Convenience method for JS so that it doesn't have to try and create a NSArray on the objc side instead +// of the usual WebScriptObject that is passed around +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner +{ + return [self declareTypes:[NSArray arrayWithObject:type] owner:newOwner]; +} + +@end + +@implementation LocalPasteboard + ++ (id)alloc +{ + return NSAllocateObject(self, 0, 0); +} + +- (id)init +{ + typesArray = [[NSMutableArray alloc] init]; + typesSet = [[NSMutableSet alloc] init]; + dataByType = [[NSMutableDictionary alloc] init]; + return self; +} + +- (void)dealloc +{ + [typesArray release]; + [typesSet release]; + [dataByType release]; + [super dealloc]; +} + +- (NSString *)name +{ + return nil; +} + +- (void)releaseGlobally +{ +} + +- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner +{ + [typesArray removeAllObjects]; + [typesSet removeAllObjects]; + [dataByType removeAllObjects]; + return [self addTypes:newTypes owner:newOwner]; +} + +- (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner +{ + unsigned count = [newTypes count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [newTypes objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (!setType) { + setType = [type copy]; + [typesArray addObject:setType]; + [typesSet addObject:setType]; + [setType release]; + } + if (newOwner && [newOwner respondsToSelector:@selector(pasteboard:provideDataForType:)]) + [newOwner pasteboard:self provideDataForType:setType]; + } + return ++changeCount; +} + +- (NSInteger)changeCount +{ + return changeCount; +} + +- (NSArray *)types +{ + return typesArray; +} + +- (NSString *)availableTypeFromArray:(NSArray *)types +{ + unsigned count = [types count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [types objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (setType) + return setType; + } + return nil; +} + +- (BOOL)setData:(NSData *)data forType:(NSString *)dataType +{ + if (data == nil) + data = [NSData data]; + if (![typesSet containsObject:dataType]) + return NO; + [dataByType setObject:data forKey:dataType]; + ++changeCount; + return YES; +} + +- (NSData *)dataForType:(NSString *)dataType +{ + return [dataByType objectForKey:dataType]; +} + +- (BOOL)setPropertyList:(id)propertyList forType:(NSString *)dataType +{ + CFDataRef data = NULL; + if (propertyList) + data = CFPropertyListCreateXMLData(NULL, propertyList); + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +- (BOOL)setString:(NSString *)string forType:(NSString *)dataType +{ + CFDataRef data = NULL; + if (string) { + if ([string length] == 0) + data = CFDataCreate(NULL, NULL, 0); + else + data = CFStringCreateExternalRepresentation(NULL, (CFStringRef)string, kCFStringEncodingUTF8, 0); + } + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h new file mode 100644 index 0000000..a229d20 --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <AppKit/AppKit.h> + +@class WebView; + +@interface DumpRenderTreeWindow : NSWindow +{ +} + +// I'm not sure why we can't just use [NSApp windows] ++ (NSArray *)openWindows; + +- (WebView *)webView; + +- (void)startListeningForAcceleratedCompositingChanges; + +@end diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm new file mode 100644 index 0000000..e0cdc6b --- /dev/null +++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTreeWindow.h" + +#import "DumpRenderTree.h" + +// FIXME: This file is ObjC++ only because of this include. :( +#import "LayoutTestController.h" +#import <WebKit/WebViewPrivate.h> +#import <WebKit/WebTypesInternal.h> + +CFMutableArrayRef openWindowsRef = 0; + +static CFArrayCallBacks NonRetainingArrayCallbacks = { + 0, + NULL, + NULL, + CFCopyDescription, + CFEqual +}; + +@implementation DumpRenderTreeWindow + ++ (NSArray *)openWindows +{ + return [[(NSArray *)openWindowsRef copy] autorelease]; +} + +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation +{ + if (!openWindowsRef) + openWindowsRef = CFArrayCreateMutable(NULL, 0, &NonRetainingArrayCallbacks); + + CFArrayAppendValue(openWindowsRef, self); + + return [super initWithContentRect:contentRect styleMask:styleMask backing:bufferingType defer:deferCreation]; +} + +- (void)close +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + CFRange arrayRange = CFRangeMake(0, CFArrayGetCount(openWindowsRef)); + CFIndex i = CFArrayGetFirstIndexOfValue(openWindowsRef, arrayRange, self); + if (i != kCFNotFound) + CFArrayRemoveValueAtIndex(openWindowsRef, i); + + [super close]; +} + +- (BOOL)isKeyWindow +{ + return gLayoutTestController ? gLayoutTestController->windowIsKey() : YES; +} + +- (void)keyDown:(NSEvent *)event +{ + // Do nothing, avoiding the beep we'd otherwise get from NSResponder, + // once we get to the end of the responder chain. +} + +- (WebView *)webView +{ + NSView *firstView = nil; + if ([[[self contentView] subviews] count] > 0) { + firstView = [[[self contentView] subviews] objectAtIndex:0]; + if ([firstView isKindOfClass:[WebView class]]) + return static_cast<WebView *>(firstView); + } + return nil; +} + +- (void)startListeningForAcceleratedCompositingChanges +{ + [[self webView] _setPostsAcceleratedCompositingNotifications:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewStartedAcceleratedCompositing:) + name:_WebViewDidStartAcceleratedCompositingNotification object:nil]; +} + +- (void)webViewStartedAcceleratedCompositing:(NSNotification *)notification +{ + // If the WebView has gone into compositing mode, turn on window autodisplay. This is necessary for CA + // to update layers and start animations. + // We only ever turn autodisplay on here, because we turn it off before every test. + if ([[self webView] _isUsingAcceleratedCompositing]) + [self setAutodisplay:YES]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.h b/Tools/DumpRenderTree/mac/EditingDelegate.h new file mode 100644 index 0000000..b5563c8 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EditingDelegate.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@interface EditingDelegate : NSObject +{ + BOOL acceptsEditing; +} + +- (void)setAcceptsEditing:(BOOL)newAcceptsEditing; + +@end diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.mm b/Tools/DumpRenderTree/mac/EditingDelegate.mm new file mode 100644 index 0000000..02e931c --- /dev/null +++ b/Tools/DumpRenderTree/mac/EditingDelegate.mm @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "EditingDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/WebKit.h> + +@interface DOMNode (dumpPath) +- (NSString *)dumpPath; +@end + +@implementation DOMNode (dumpPath) +- (NSString *)dumpPath +{ + DOMNode *parent = [self parentNode]; + NSString *str = [NSString stringWithFormat:@"%@", [self nodeName]]; + if (parent != nil) { + str = [str stringByAppendingString:@" > "]; + str = [str stringByAppendingString:[parent dumpPath]]; + } + return str; +} +@end + +@interface DOMRange (dump) +- (NSString *)dump; +@end + +@implementation DOMRange (dump) +- (NSString *)dump +{ + return [NSString stringWithFormat:@"range from %ld of %@ to %ld of %@", [self startOffset], [[self startContainer] dumpPath], [self endOffset], [[self endContainer] dumpPath]]; +} +@end + +@implementation EditingDelegate + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + acceptsEditing = YES; + return self; +} + +- (BOOL)webView:(WebView *)webView shouldBeginEditingInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldEndEditingInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldInsertNode:(DOMNode *)node replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action +{ + static const char *insertactionstring[] = { + "WebViewInsertActionTyped", + "WebViewInsertActionPasted", + "WebViewInsertActionDropped", + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n", [[node dumpPath] UTF8String], [[range dump] UTF8String], insertactionstring[action]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action +{ + static const char *insertactionstring[] = { + "WebViewInsertActionTyped", + "WebViewInsertActionPasted", + "WebViewInsertActionDropped", + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n", [[text description] UTF8String], [[range dump] UTF8String], insertactionstring[action]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldDeleteDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldShowDeleteInterfaceForElement:(DOMHTMLElement *)element +{ + return [[element className] isEqualToString:@"needsDeletionUI"]; +} + +- (BOOL)webView:(WebView *)webView shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag +{ + static const char *affinitystring[] = { + "NSSelectionAffinityUpstream", + "NSSelectionAffinityDownstream" + }; + static const char *boolstring[] = { + "FALSE", + "TRUE" + }; + + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n", [[currentRange dump] UTF8String], [[proposedRange dump] UTF8String], affinitystring[selectionAffinity], boolstring[flag]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldApplyStyle:(DOMCSSStyleDeclaration *)style toElementsInDOMRange:(DOMRange *)range +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n", [[style description] UTF8String], [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldChangeTypingStyle:(DOMCSSStyleDeclaration *)currentStyle toStyle:(DOMCSSStyleDeclaration *)proposedStyle +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n", [[currentStyle description] UTF8String], [[proposedStyle description] UTF8String]); + return acceptsEditing; +} + +- (void)webViewDidBeginEditing:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidBeginEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChange:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChange:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidEndEditing:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidEndEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeTypingStyle:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeSelection:(NSNotification *)notification +{ + if (!done && gLayoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeSelection:%s\n", [[notification name] UTF8String]); +} + +- (void)setAcceptsEditing:(BOOL)newAcceptsEditing +{ + acceptsEditing = newAcceptsEditing; +} + +@end diff --git a/Tools/DumpRenderTree/mac/EventSendingController.h b/Tools/DumpRenderTree/mac/EventSendingController.h new file mode 100644 index 0000000..9440575 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EventSendingController.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> +#import <WebKit/WebKit.h> + +@interface EventSendingController : NSObject <DOMEventListener> +{ + BOOL leftMouseButtonDown; + BOOL dragMode; + int clickCount; + NSTimeInterval lastClick; + int eventNumber; + double timeOffset; +} + ++ (void)saveEvent:(NSInvocation *)event; ++ (void)replaySavedEvents; ++ (void)clearSavedEvents; + +- (void)scheduleAsynchronousClick; + +- (void)enableDOMUIEventLogging:(WebScriptObject *)node; + +- (void)handleEvent:(DOMEvent *)event; + +@end + +extern NSPoint lastMousePosition; +extern NSPoint lastClickPosition;
\ No newline at end of file diff --git a/Tools/DumpRenderTree/mac/EventSendingController.mm b/Tools/DumpRenderTree/mac/EventSendingController.mm new file mode 100644 index 0000000..9031c63 --- /dev/null +++ b/Tools/DumpRenderTree/mac/EventSendingController.mm @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Jonas Witt <jonas.witt@gmail.com> + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "EventSendingController.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "DumpRenderTreeFileDraggingSource.h" + +#import <Carbon/Carbon.h> // for GetCurrentEventTime() +#import <WebKit/DOMPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebViewPrivate.h> + +extern "C" void _NSNewKillRingSequence(); + +enum MouseAction { + MouseDown, + MouseUp, + MouseDragged +}; + +// Match the DOM spec (sadly the DOM spec does not provide an enum) +enum MouseButton { + LeftMouseButton = 0, + MiddleMouseButton = 1, + RightMouseButton = 2, + NoMouseButton = -1 +}; + +NSPoint lastMousePosition; +NSPoint lastClickPosition; +int lastClickButton = NoMouseButton; +NSArray *webkitDomEventNames; +NSMutableArray *savedMouseEvents; // mouse events sent between mouseDown and mouseUp are stored here, and then executed at once. +BOOL replayingSavedEvents; + +@implementation EventSendingController + ++ (void)initialize +{ + webkitDomEventNames = [[NSArray alloc] initWithObjects: + @"abort", + @"beforecopy", + @"beforecut", + @"beforepaste", + @"blur", + @"change", + @"click", + @"contextmenu", + @"copy", + @"cut", + @"dblclick", + @"drag", + @"dragend", + @"dragenter", + @"dragleave", + @"dragover", + @"dragstart", + @"drop", + @"error", + @"focus", + @"input", + @"keydown", + @"keypress", + @"keyup", + @"load", + @"mousedown", + @"mousemove", + @"mouseout", + @"mouseover", + @"mouseup", + @"mousewheel", + @"beforeunload", + @"paste", + @"readystatechange", + @"reset", + @"resize", + @"scroll", + @"search", + @"select", + @"selectstart", + @"submit", + @"textInput", + @"textzoomin", + @"textzoomout", + @"unload", + @"zoom", + nil]; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(beginDragWithFiles:) + || aSelector == @selector(clearKillRing) + || aSelector == @selector(contextClick) + || aSelector == @selector(enableDOMUIEventLogging:) + || aSelector == @selector(fireKeyboardEventsToElement:) + || aSelector == @selector(keyDown:withModifiers:withLocation:) + || aSelector == @selector(leapForward:) + || aSelector == @selector(mouseDown:withModifiers:) + || aSelector == @selector(mouseMoveToX:Y:) + || aSelector == @selector(mouseUp:withModifiers:) + || aSelector == @selector(scheduleAsynchronousClick) + || aSelector == @selector(textZoomIn) + || aSelector == @selector(textZoomOut) + || aSelector == @selector(zoomPageIn) + || aSelector == @selector(zoomPageOut) + || aSelector == @selector(mouseScrollByX:andY:) + || aSelector == @selector(continuousMouseScrollByX:andY:)) + return NO; + return YES; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char*)name +{ + if (strcmp(name, "dragMode") == 0) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(beginDragWithFiles:)) + return @"beginDragWithFiles"; + if (aSelector == @selector(contextClick)) + return @"contextClick"; + if (aSelector == @selector(enableDOMUIEventLogging:)) + return @"enableDOMUIEventLogging"; + if (aSelector == @selector(fireKeyboardEventsToElement:)) + return @"fireKeyboardEventsToElement"; + if (aSelector == @selector(keyDown:withModifiers:withLocation:)) + return @"keyDown"; + if (aSelector == @selector(leapForward:)) + return @"leapForward"; + if (aSelector == @selector(mouseDown:withModifiers:)) + return @"mouseDown"; + if (aSelector == @selector(mouseUp:withModifiers:)) + return @"mouseUp"; + if (aSelector == @selector(mouseMoveToX:Y:)) + return @"mouseMoveTo"; + if (aSelector == @selector(setDragMode:)) + return @"setDragMode"; + if (aSelector == @selector(mouseScrollByX:andY:)) + return @"mouseScrollBy"; + if (aSelector == @selector(continuousMouseScrollByX:andY:)) + return @"continuousMouseScrollBy"; + return nil; +} + +- (id)init +{ + self = [super init]; + if (self) + dragMode = YES; + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +- (double)currentEventTime +{ + return GetCurrentEventTime() + timeOffset; +} + +- (void)leapForward:(int)milliseconds +{ + if (dragMode && leftMouseButtonDown && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(leapForward:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(leapForward:)]; + [invocation setArgument:&milliseconds atIndex:2]; + + [EventSendingController saveEvent:invocation]; + + return; + } + + timeOffset += milliseconds / 1000.0; +} + +- (void)clearKillRing +{ + _NSNewKillRingSequence(); +} + +static NSEventType eventTypeForMouseButtonAndAction(int button, MouseAction action) +{ + switch (button) { + case LeftMouseButton: + switch (action) { + case MouseDown: + return NSLeftMouseDown; + case MouseUp: + return NSLeftMouseUp; + case MouseDragged: + return NSLeftMouseDragged; + } + case RightMouseButton: + switch (action) { + case MouseDown: + return NSRightMouseDown; + case MouseUp: + return NSRightMouseUp; + case MouseDragged: + return NSRightMouseDragged; + } + default: + switch (action) { + case MouseDown: + return NSOtherMouseDown; + case MouseUp: + return NSOtherMouseUp; + case MouseDragged: + return NSOtherMouseDragged; + } + } + assert(0); + return static_cast<NSEventType>(0); +} + +- (void)beginDragWithFiles:(WebScriptObject*)jsFilePaths +{ + assert(!draggingInfo); + assert([jsFilePaths isKindOfClass:[WebScriptObject class]]); + + NSPasteboard *pboard = [NSPasteboard pasteboardWithUniqueName]; + [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil]; + + NSURL *currentTestURL = [NSURL URLWithString:[[mainFrame webView] mainFrameURL]]; + + NSMutableArray *filePaths = [NSMutableArray array]; + for (unsigned i = 0; [[jsFilePaths webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) { + NSString *filePath = (NSString *)[jsFilePaths webScriptValueAtIndex:i]; + // Have NSURL encode the name so that we handle '?' in file names correctly. + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSURL *absoluteFileURL = [NSURL URLWithString:[fileURL relativeString] relativeToURL:currentTestURL]; + [filePaths addObject:[absoluteFileURL path]]; + } + + [pboard setPropertyList:filePaths forType:NSFilenamesPboardType]; + assert([pboard propertyListForType:NSFilenamesPboardType]); // setPropertyList will silently fail on error, assert that it didn't fail + + // Provide a source, otherwise [DumpRenderTreeDraggingInfo draggingSourceOperationMask] defaults to NSDragOperationNone + DumpRenderTreeFileDraggingSource *source = [[[DumpRenderTreeFileDraggingSource alloc] init] autorelease]; + draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:nil offset:NSZeroSize pasteboard:pboard source:source]; + [[mainFrame webView] draggingEntered:draggingInfo]; + + dragMode = NO; // dragMode saves events and then replays them later. We don't need/want that. + leftMouseButtonDown = YES; // Make the rest of eventSender think a drag is in progress +} + +- (void)updateClickCountForButton:(int)buttonNumber +{ + if (([self currentEventTime] - lastClick >= 1) || + !NSEqualPoints(lastMousePosition, lastClickPosition) || + lastClickButton != buttonNumber) { + clickCount = 1; + lastClickButton = buttonNumber; + } else + clickCount++; +} + +static int buildModifierFlags(const WebScriptObject* modifiers) +{ + int flags = 0; + if (![modifiers isKindOfClass:[WebScriptObject class]]) + return flags; + for (unsigned i = 0; [[modifiers webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) { + NSString* modifierName = (NSString*)[modifiers webScriptValueAtIndex:i]; + if ([modifierName isEqual:@"ctrlKey"]) + flags |= NSControlKeyMask; + else if ([modifierName isEqual:@"shiftKey"] || [modifierName isEqual:@"rangeSelectionKey"]) + flags |= NSShiftKeyMask; + else if ([modifierName isEqual:@"altKey"]) + flags |= NSAlternateKeyMask; + else if ([modifierName isEqual:@"metaKey"] || [modifierName isEqual:@"addSelectionKey"]) + flags |= NSCommandKeyMask; + } + return flags; +} + +- (void)mouseDown:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers +{ + [[[mainFrame frameView] documentView] layout]; + [self updateClickCountForButton:buttonNumber]; + + NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseDown); + NSEvent *event = [NSEvent mouseEventWithType:eventType + location:lastMousePosition + modifierFlags:buildModifierFlags(modifiers) + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + if (subView) { + [subView mouseDown:event]; + if (buttonNumber == LeftMouseButton) + leftMouseButtonDown = YES; + } +} + +- (void)mouseDown:(int)buttonNumber +{ + [self mouseDown:buttonNumber withModifiers:nil]; +} + +- (void)textZoomIn +{ + [[mainFrame webView] makeTextLarger:self]; +} + +- (void)textZoomOut +{ + [[mainFrame webView] makeTextSmaller:self]; +} + +- (void)zoomPageIn +{ + [[mainFrame webView] zoomPageIn:self]; +} + +- (void)zoomPageOut +{ + [[mainFrame webView] zoomPageOut:self]; +} + +- (void)mouseUp:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers +{ + if (dragMode && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp:withModifiers:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(mouseUp:withModifiers:)]; + [invocation setArgument:&buttonNumber atIndex:2]; + [invocation setArgument:&modifiers atIndex:3]; + + [EventSendingController saveEvent:invocation]; + [EventSendingController replaySavedEvents]; + + return; + } + + [[[mainFrame frameView] documentView] layout]; + NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseUp); + NSEvent *event = [NSEvent mouseEventWithType:eventType + location:lastMousePosition + modifierFlags:buildModifierFlags(modifiers) + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *targetView = [[mainFrame webView] hitTest:[event locationInWindow]]; + // FIXME: Silly hack to teach DRT to respect capturing mouse events outside the WebView. + // The right solution is just to use NSApplication's built-in event sending methods, + // instead of rolling our own algorithm for selecting an event target. + targetView = targetView ? targetView : [[mainFrame frameView] documentView]; + assert(targetView); + [targetView mouseUp:event]; + if (buttonNumber == LeftMouseButton) + leftMouseButtonDown = NO; + lastClick = [event timestamp]; + lastClickPosition = lastMousePosition; + if (draggingInfo) { + WebView *webView = [mainFrame webView]; + + NSDragOperation dragOperation = [webView draggingUpdated:draggingInfo]; + + if (dragOperation != NSDragOperationNone) + [webView performDragOperation:draggingInfo]; + else + [webView draggingExited:draggingInfo]; + // Per NSDragging.h: draggingSources may not implement draggedImage:endedAt:operation: + if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:endedAt:operation:)]) + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] endedAt:lastMousePosition operation:dragOperation]; + [draggingInfo release]; + draggingInfo = nil; + } +} + +- (void)mouseUp:(int)buttonNumber +{ + [self mouseUp:buttonNumber withModifiers:nil]; +} + +- (void)mouseMoveToX:(int)x Y:(int)y +{ + if (dragMode && leftMouseButtonDown && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseMoveToX:Y:)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(mouseMoveToX:Y:)]; + [invocation setArgument:&x atIndex:2]; + [invocation setArgument:&y atIndex:3]; + + [EventSendingController saveEvent:invocation]; + return; + } + + NSView *view = [mainFrame webView]; + lastMousePosition = [view convertPoint:NSMakePoint(x, [view frame].size.height - y) toView:nil]; + NSEvent *event = [NSEvent mouseEventWithType:(leftMouseButtonDown ? NSLeftMouseDragged : NSMouseMoved) + location:lastMousePosition + modifierFlags:0 + timestamp:[self currentEventTime] + windowNumber:[[view window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:(leftMouseButtonDown ? clickCount : 0) + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + if (subView) { + if (leftMouseButtonDown) { + if (draggingInfo) { + // Per NSDragging.h: draggingSources may not implement draggedImage:movedTo: + if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:movedTo:)]) + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] movedTo:lastMousePosition]; + [[mainFrame webView] draggingUpdated:draggingInfo]; + } else + [subView mouseDragged:event]; + } else + [subView mouseMoved:event]; + } +} + +- (void)mouseScrollByX:(int)x andY:(int)y continuously:(BOOL)c +{ + // CGEventCreateScrollWheelEvent() was introduced in 10.5 +#if !defined(BUILDING_ON_TIGER) + CGScrollEventUnit unit = c?kCGScrollEventUnitPixel:kCGScrollEventUnitLine; + CGEventRef cgScrollEvent = CGEventCreateScrollWheelEvent(NULL, unit, 2, y, x); + + // CGEvent locations are in global display coordinates. + CGPoint lastGlobalMousePosition = { + lastMousePosition.x, + [[NSScreen mainScreen] frame].size.height - lastMousePosition.y + }; + CGEventSetLocation(cgScrollEvent, lastGlobalMousePosition); + + NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgScrollEvent]; + CFRelease(cgScrollEvent); + + NSView *subView = [[mainFrame webView] hitTest:[scrollEvent locationInWindow]]; + if (subView) + [subView scrollWheel:scrollEvent]; +#endif +} + +- (void)continuousMouseScrollByX:(int)x andY:(int)y +{ + [self mouseScrollByX:x andY:y continuously:YES]; +} + +- (void)mouseScrollByX:(int)x andY:(int)y +{ + [self mouseScrollByX:x andY:y continuously:NO]; +} + +- (NSArray *)contextClick +{ + [[[mainFrame frameView] documentView] layout]; + [self updateClickCountForButton:RightMouseButton]; + + NSEvent *event = [NSEvent mouseEventWithType:NSRightMouseDown + location:lastMousePosition + modifierFlags:0 + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:clickCount + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + NSMutableArray *menuItemStrings = [NSMutableArray array]; + + if (subView) { + NSMenu* menu = [subView menuForEvent:event]; + + for (int i = 0; i < [menu numberOfItems]; ++i) { + NSMenuItem* menuItem = [menu itemAtIndex:i]; + if (!strcmp("Inspect Element", [[menuItem title] UTF8String])) + continue; + + if ([menuItem isSeparatorItem]) + [menuItemStrings addObject:@"<separator>"]; + else + [menuItemStrings addObject:[menuItem title]]; + } + } + + return menuItemStrings; +} + +- (void)scheduleAsynchronousClick +{ + [self performSelector:@selector(mouseDown:) withObject:nil afterDelay:0]; + [self performSelector:@selector(mouseUp:) withObject:nil afterDelay:0]; +} + ++ (void)saveEvent:(NSInvocation *)event +{ + if (!savedMouseEvents) + savedMouseEvents = [[NSMutableArray alloc] init]; + [savedMouseEvents addObject:event]; +} + ++ (void)replaySavedEvents +{ + replayingSavedEvents = YES; + while ([savedMouseEvents count]) { + // if a drag is initiated, the remaining saved events will be dispatched from our dragging delegate + NSInvocation *invocation = [[[savedMouseEvents objectAtIndex:0] retain] autorelease]; + [savedMouseEvents removeObjectAtIndex:0]; + [invocation invoke]; + } + replayingSavedEvents = NO; +} + ++ (void)clearSavedEvents +{ + [savedMouseEvents release]; + savedMouseEvents = nil; +} + +- (void)keyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation +{ + NSString *eventCharacter = character; + unsigned short keyCode = 0; + if ([character isEqualToString:@"leftArrow"]) { + const unichar ch = NSLeftArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7B; + } else if ([character isEqualToString:@"rightArrow"]) { + const unichar ch = NSRightArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7C; + } else if ([character isEqualToString:@"upArrow"]) { + const unichar ch = NSUpArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7E; + } else if ([character isEqualToString:@"downArrow"]) { + const unichar ch = NSDownArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x7D; + } else if ([character isEqualToString:@"pageUp"]) { + const unichar ch = NSPageUpFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x74; + } else if ([character isEqualToString:@"pageDown"]) { + const unichar ch = NSPageDownFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x79; + } else if ([character isEqualToString:@"home"]) { + const unichar ch = NSHomeFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x73; + } else if ([character isEqualToString:@"end"]) { + const unichar ch = NSEndFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x77; + } else if ([character isEqualToString:@"insert"]) { + const unichar ch = NSInsertFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x72; + } else if ([character isEqualToString:@"delete"]) { + const unichar ch = NSDeleteFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x75; + } else if ([character isEqualToString:@"printScreen"]) { + const unichar ch = NSPrintScreenFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + keyCode = 0x0; // There is no known virtual key code for PrintScreen. + } + + // Compare the input string with the function-key names defined by the DOM spec (i.e. "F1",...,"F24"). + // If the input string is a function-key name, set its key code. + for (unsigned i = 1; i <= 24; i++) { + if ([character isEqualToString:[NSString stringWithFormat:@"F%u", i]]) { + const unichar ch = NSF1FunctionKey + (i - 1); + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + switch (i) { + case 1: keyCode = 0x7A; break; + case 2: keyCode = 0x78; break; + case 3: keyCode = 0x63; break; + case 4: keyCode = 0x76; break; + case 5: keyCode = 0x60; break; + case 6: keyCode = 0x61; break; + case 7: keyCode = 0x62; break; + case 8: keyCode = 0x64; break; + case 9: keyCode = 0x65; break; + case 10: keyCode = 0x6D; break; + case 11: keyCode = 0x67; break; + case 12: keyCode = 0x6F; break; + case 13: keyCode = 0x69; break; + case 14: keyCode = 0x6B; break; + case 15: keyCode = 0x71; break; + case 16: keyCode = 0x6A; break; + case 17: keyCode = 0x40; break; + case 18: keyCode = 0x4F; break; + case 19: keyCode = 0x50; break; + case 20: keyCode = 0x5A; break; + } + } + } + + // FIXME: No keyCode is set for most keys. + if ([character isEqualToString:@"\t"]) + keyCode = 0x30; + else if ([character isEqualToString:@" "]) + keyCode = 0x31; + else if ([character isEqualToString:@"\r"]) + keyCode = 0x24; + else if ([character isEqualToString:@"\n"]) + keyCode = 0x4C; + else if ([character isEqualToString:@"\x8"]) + keyCode = 0x33; + else if ([character isEqualToString:@"7"]) + keyCode = 0x1A; + else if ([character isEqualToString:@"5"]) + keyCode = 0x17; + else if ([character isEqualToString:@"9"]) + keyCode = 0x19; + else if ([character isEqualToString:@"0"]) + keyCode = 0x1D; + else if ([character isEqualToString:@"a"]) + keyCode = 0x00; + else if ([character isEqualToString:@"b"]) + keyCode = 0x0B; + else if ([character isEqualToString:@"d"]) + keyCode = 0x02; + else if ([character isEqualToString:@"e"]) + keyCode = 0x0E; + + NSString *charactersIgnoringModifiers = eventCharacter; + + int modifierFlags = 0; + + if ([character length] == 1 && [character characterAtIndex:0] >= 'A' && [character characterAtIndex:0] <= 'Z') { + modifierFlags |= NSShiftKeyMask; + charactersIgnoringModifiers = [character lowercaseString]; + } + + modifierFlags |= buildModifierFlags(modifiers); + + if (keyLocation == DOM_KEY_LOCATION_NUMPAD) + modifierFlags |= NSNumericPadKeyMask; + + [[[mainFrame frameView] documentView] layout]; + + NSEvent *event = [NSEvent keyEventWithType:NSKeyDown + location:NSMakePoint(5, 5) + modifierFlags:modifierFlags + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + characters:eventCharacter + charactersIgnoringModifiers:charactersIgnoringModifiers + isARepeat:NO + keyCode:keyCode]; + + [[[[mainFrame webView] window] firstResponder] keyDown:event]; + + event = [NSEvent keyEventWithType:NSKeyUp + location:NSMakePoint(5, 5) + modifierFlags:modifierFlags + timestamp:[self currentEventTime] + windowNumber:[[[mainFrame webView] window] windowNumber] + context:[NSGraphicsContext currentContext] + characters:eventCharacter + charactersIgnoringModifiers:charactersIgnoringModifiers + isARepeat:NO + keyCode:keyCode]; + + [[[[mainFrame webView] window] firstResponder] keyUp:event]; +} + +- (void)enableDOMUIEventLogging:(WebScriptObject *)node +{ + NSEnumerator *eventEnumerator = [webkitDomEventNames objectEnumerator]; + id eventName; + while ((eventName = [eventEnumerator nextObject])) { + [(id<DOMEventTarget>)node addEventListener:eventName listener:self useCapture:NO]; + } +} + +- (void)handleEvent:(DOMEvent *)event +{ + DOMNode *target = [event target]; + + printf("event type: %s\n", [[event type] UTF8String]); + printf(" target: <%s>\n", [[[target nodeName] lowercaseString] UTF8String]); + + if ([event isKindOfClass:[DOMEvent class]]) { + printf(" eventPhase: %d\n", [event eventPhase]); + printf(" bubbles: %d\n", [event bubbles] ? 1 : 0); + printf(" cancelable: %d\n", [event cancelable] ? 1 : 0); + } + + if ([event isKindOfClass:[DOMUIEvent class]]) { + printf(" detail: %d\n", [(DOMUIEvent*)event detail]); + + DOMAbstractView *view = [(DOMUIEvent*)event view]; + if (view) { + printf(" view: OK"); + if ([view document]) + printf(" (document: OK)"); + printf("\n"); + } + } + + if ([event isKindOfClass:[DOMKeyboardEvent class]]) { + printf(" keyIdentifier: %s\n", [[(DOMKeyboardEvent*)event keyIdentifier] UTF8String]); + printf(" keyLocation: %d\n", [(DOMKeyboardEvent*)event keyLocation]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMKeyboardEvent*)event ctrlKey] ? 1 : 0, + [(DOMKeyboardEvent*)event shiftKey] ? 1 : 0, + [(DOMKeyboardEvent*)event altKey] ? 1 : 0, + [(DOMKeyboardEvent*)event metaKey] ? 1 : 0); + printf(" keyCode: %d\n", [(DOMKeyboardEvent*)event keyCode]); + printf(" charCode: %d\n", [(DOMKeyboardEvent*)event charCode]); + } + + if ([event isKindOfClass:[DOMMouseEvent class]]) { + printf(" button: %d\n", [(DOMMouseEvent*)event button]); + printf(" clientX: %d\n", [(DOMMouseEvent*)event clientX]); + printf(" clientY: %d\n", [(DOMMouseEvent*)event clientY]); + printf(" screenX: %d\n", [(DOMMouseEvent*)event screenX]); + printf(" screenY: %d\n", [(DOMMouseEvent*)event screenY]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMMouseEvent*)event ctrlKey] ? 1 : 0, + [(DOMMouseEvent*)event shiftKey] ? 1 : 0, + [(DOMMouseEvent*)event altKey] ? 1 : 0, + [(DOMMouseEvent*)event metaKey] ? 1 : 0); + id relatedTarget = [(DOMMouseEvent*)event relatedTarget]; + if (relatedTarget) { + printf(" relatedTarget: %s", [[[relatedTarget class] description] UTF8String]); + if ([relatedTarget isKindOfClass:[DOMNode class]]) + printf(" (nodeName: %s)", [[(DOMNode*)relatedTarget nodeName] UTF8String]); + printf("\n"); + } + } + + if ([event isKindOfClass:[DOMMutationEvent class]]) { + printf(" prevValue: %s\n", [[(DOMMutationEvent*)event prevValue] UTF8String]); + printf(" newValue: %s\n", [[(DOMMutationEvent*)event newValue] UTF8String]); + printf(" attrName: %s\n", [[(DOMMutationEvent*)event attrName] UTF8String]); + printf(" attrChange: %d\n", [(DOMMutationEvent*)event attrChange]); + DOMNode *relatedNode = [(DOMMutationEvent*)event relatedNode]; + if (relatedNode) { + printf(" relatedNode: %s (nodeName: %s)\n", + [[[relatedNode class] description] UTF8String], + [[relatedNode nodeName] UTF8String]); + } + } + + if ([event isKindOfClass:[DOMWheelEvent class]]) { + printf(" clientX: %d\n", [(DOMWheelEvent*)event clientX]); + printf(" clientY: %d\n", [(DOMWheelEvent*)event clientY]); + printf(" screenX: %d\n", [(DOMWheelEvent*)event screenX]); + printf(" screenY: %d\n", [(DOMWheelEvent*)event screenY]); + printf(" modifier keys: c:%d s:%d a:%d m:%d\n", + [(DOMWheelEvent*)event ctrlKey] ? 1 : 0, + [(DOMWheelEvent*)event shiftKey] ? 1 : 0, + [(DOMWheelEvent*)event altKey] ? 1 : 0, + [(DOMWheelEvent*)event metaKey] ? 1 : 0); + printf(" isHorizontal: %d\n", [(DOMWheelEvent*)event isHorizontal] ? 1 : 0); + printf(" wheelDelta: %d\n", [(DOMWheelEvent*)event wheelDelta]); + } +} + +// FIXME: It's not good to have a test hard-wired into this controller like this. +// Instead we need to get testing framework based on the Objective-C bindings +// to work well enough that we can test that way instead. +- (void)fireKeyboardEventsToElement:(WebScriptObject *)element { + + if (![element isKindOfClass:[DOMHTMLElement class]]) + return; + + DOMHTMLElement *target = (DOMHTMLElement*)element; + DOMDocument *document = [target ownerDocument]; + + // Keyboard Event 1 + + DOMEvent *domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keydown" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000041" + keyLocation:0 + ctrlKey:YES + altKey:NO + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + + // Keyboard Event 2 + + domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keypress" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000045" + keyLocation:1 + ctrlKey:NO + altKey:YES + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + + // Keyboard Event 3 + + domEvent = [document createEvent:@"KeyboardEvent"]; + [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keyup" + canBubble:YES + cancelable:YES + view:[document defaultView] + keyIdentifier:@"U+000056" + keyLocation:0 + ctrlKey:NO + altKey:NO + shiftKey:NO + metaKey:NO]; + [target dispatchEvent:domEvent]; + +} + +@end diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.h b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h new file mode 100644 index 0000000..390a881 --- /dev/null +++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> + +class AccessibilityController; +class GCController; + +@interface FrameLoadDelegate : NSObject +{ + AccessibilityController* accessibilityController; + GCController* gcController; +} + +- (void)resetToConsistentState; + +@end diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm new file mode 100644 index 0000000..a36982c --- /dev/null +++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" +#import "FrameLoadDelegate.h" + +#import "AccessibilityController.h" +#import "AppleScriptController.h" +#import "EventSendingController.h" +#import "GCController.h" +#import "LayoutTestController.h" +#import "NavigationController.h" +#import "ObjCController.h" +#import "ObjCPlugin.h" +#import "ObjCPluginFunction.h" +#import "PlainTextController.h" +#import "TextInputController.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <JavaScriptCore/JavaScriptCore.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebScriptWorld.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebViewPrivate.h> +#import <wtf/Assertions.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLResponse (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLRequest (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface WebFrame (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation WebFrame (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult +{ + BOOL isMainFrame = (self == [[self webView] mainFrame]); + NSString *name = [self name]; + if (isMainFrame) { + if ([name length]) + return [NSString stringWithFormat:@"main frame \"%@\"", name]; + else + return @"main frame"; + } else { + if (name) + return [NSString stringWithFormat:@"frame \"%@\"", name]; + else + return @"frame (anonymous)"; + } +} + +- (NSString *)_drt_printFrameUserGestureStatus +{ + BOOL isUserGesture = [[self webView] _isProcessingUserGesture]; + return [NSString stringWithFormat:@"Frame with user gesture \"%@\"", isUserGesture ? @"true" : @"false"]; +} +@end + +@implementation FrameLoadDelegate + +- (id)init +{ + if ((self = [super init])) { + gcController = new GCController; + accessibilityController = new AccessibilityController; + } + return self; +} + +- (void)dealloc +{ + delete gcController; + delete accessibilityController; + [super dealloc]; +} + +// Exec messages in the work queue until they're all done, or one of them starts a new load +- (void)processWork:(id)dummy +{ + // if another load started, then wait for it to complete. + if (topLoadingFrame) + return; + + // if we finish all the commands, we're ready to dump state + if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) + dump(); +} + +- (void)resetToConsistentState +{ + accessibilityController->resetToConsistentState(); +} + +- (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource +{ + if ([dataSource webFrame] == topLoadingFrame) { + topLoadingFrame = nil; + WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test + if (!gLayoutTestController->waitToDump()) { + if (WorkQueue::shared()->count()) + [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; + else + dump(); + } + } +} + +- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - in didStartProvisionalLoadForFrame", [frame _drt_printFrameUserGestureStatus]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT([frame provisionalDataSource]); + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; + + if (!done && gLayoutTestController->stopProvisionalFrameLoads()) { + NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + [frame stopLoading]; + } +} + +- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT(![frame provisionalDataSource]); + ASSERT([frame dataSource]); + + gLayoutTestController->setWindowIsKey(true); + NSView *documentView = [[mainFrame frameView] documentView]; + [[[mainFrame webView] window] makeFirstResponder:documentView]; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + + if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) { + // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL + // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree. + // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need + // to apply the workaround to. + ASSERT_NOT_REACHED(); + return; + } + + ASSERT([frame provisionalDataSource]); + [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]]; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + ASSERT([frame dataSource]); + ASSERT(frame == [[frame dataSource] webFrame]); + + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed. + // After that is fixed, we will reenable painting after WebCore is done loading the document, + // and this call will no longer be needed. + if ([[sender mainFrame] isEqual:frame]) + [sender displayIfNeeded]; + [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]]; + [gNavigationController webView:sender didFinishLoadForFrame:frame]; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT(![frame provisionalDataSource]); + ASSERT([frame dataSource]); + + [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]]; +} + +- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT_NOT_REACHED(); +} + +- (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame +{ + // Make New-Style LayoutTestController + JSContextRef context = [frame globalContext]; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSValueRef exception = 0; + + ASSERT(gLayoutTestController); + gLayoutTestController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + accessibilityController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + // Make Old-Style controllers + + WebView *webView = [frame webView]; + WebScriptObject *obj = [frame windowObject]; + AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView]; + [obj setValue:asc forKey:@"appleScriptController"]; + [asc release]; + + EventSendingController *esc = [[EventSendingController alloc] init]; + [obj setValue:esc forKey:@"eventSender"]; + [esc release]; + + [obj setValue:gNavigationController forKey:@"navigationController"]; + + ObjCController *occ = [[ObjCController alloc] init]; + [obj setValue:occ forKey:@"objCController"]; + [occ release]; + + ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; + [obj setValue:plugin forKey:@"objCPlugin"]; + [plugin release]; + + ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; + [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; + [pluginFunction release]; + + [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"]; + + TextInputController *tic = [[TextInputController alloc] initWithWebView:webView]; + [obj setValue:tic forKey:@"textInputController"]; + [tic release]; +} + +- (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world +{ + JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world]; + if (!ctx) + return; + + JSObjectRef globalObject = JSContextGetGlobalObject(ctx); + if (!globalObject) + return; + + JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); +} + +- (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world +{ + if (world == [WebScriptWorld standardWorld]) + [self didClearWindowObjectInStandardWorldForFrame:frame]; + else + [self didClearWindowObjectForFrame:frame inIsolatedWorld:world]; +} + +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; + printf ("%s\n", [string UTF8String]); + } + + if (gLayoutTestController->dumpTitleChanges()) + printf("TITLE CHANGED: %s\n", [title UTF8String]); +} + +- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } else if (!done) { + unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount]; + if (pendingFrameUnloadEvents) { + NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents]; + printf ("%s\n", [string UTF8String]); + } + } +} + +- (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webViewDidDisplayInsecureContent:(WebView *)sender +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf ("didDisplayInsecureContent\n"); +} + +- (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin +{ + if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) + printf ("didRunInsecureContent\n"); +} + +@end diff --git a/Tools/DumpRenderTree/mac/GCControllerMac.mm b/Tools/DumpRenderTree/mac/GCControllerMac.mm new file mode 100644 index 0000000..de8a61e --- /dev/null +++ b/Tools/DumpRenderTree/mac/GCControllerMac.mm @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "GCController.h" + +#import <WebKit/WebCoreStatistics.h> + + +void GCController::collect() const +{ + [WebCoreStatistics garbageCollectJavaScriptObjects]; +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + [WebCoreStatistics garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging:waitUntilDone]; +} + +size_t GCController::getJSObjectCount() const +{ + return [WebCoreStatistics javaScriptObjectsCount]; +} diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.h b/Tools/DumpRenderTree/mac/HistoryDelegate.h new file mode 100644 index 0000000..c56d203 --- /dev/null +++ b/Tools/DumpRenderTree/mac/HistoryDelegate.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@interface HistoryDelegate : NSObject +{ +} + +@end diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.mm b/Tools/DumpRenderTree/mac/HistoryDelegate.mm new file mode 100644 index 0000000..cbc4093 --- /dev/null +++ b/Tools/DumpRenderTree/mac/HistoryDelegate.mm @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#import "config.h" +#import "HistoryDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" + +#import <WebKit/WebNavigationData.h> +#import <WebKit/WebView.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation HistoryDelegate + +- (void)webView:(WebView *)webView didNavigateWithNavigationData:(WebNavigationData *)navigationData inFrame:(WebFrame *)webFrame +{ + NSURL *url = [navigationData url] ? [NSURL URLWithString:[navigationData url]] : nil; + bool hasClientRedirect = [[navigationData clientRedirectSource] length]; + NSHTTPURLResponse *httpResponse = [[navigationData response] isKindOfClass:[NSHTTPURLResponse class]] ? (NSHTTPURLResponse *)[navigationData response] : nil; + bool wasFailure = [navigationData hasSubstituteData] || (httpResponse && [httpResponse statusCode] >= 400); + + printf("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was %s and was %s%s.\n", + url ? [[url _drt_descriptionSuitableForTestResult] UTF8String] : "<none>", + [navigationData title] ? [[navigationData title] UTF8String] : "", + [navigationData originalRequest] ? [[[navigationData originalRequest] HTTPMethod] UTF8String] : "", + wasFailure ? "a failure" : "successful", + hasClientRedirect ? "a client redirect from " : "not a client redirect", + hasClientRedirect ? [[navigationData clientRedirectSource] UTF8String] : ""); +} + +- (void)webView:(WebView *)webView didPerformClientRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame +{ + NSURL *source = [NSURL URLWithString:sourceURL]; + NSURL *dest = [NSURL URLWithString:destinationURL]; + printf("WebView performed a client redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]); +} + +- (void)webView:(WebView *)webView didPerformServerRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame +{ + NSURL *source = [NSURL URLWithString:sourceURL]; + NSURL *dest = [NSURL URLWithString:destinationURL]; + printf("WebView performed a server redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]); +} + +- (void)webView:(WebView *)webView updateHistoryTitle:(NSString *)title forURL:(NSString *)url +{ + printf("WebView updated the title for history URL \"%s\" to \"%s\".\n", [[[NSURL URLWithString:url]_drt_descriptionSuitableForTestResult] UTF8String], [title UTF8String]); +} + +- (void)populateVisitedLinksForWebView:(WebView *)webView +{ + if (gLayoutTestController->dumpVisitedLinksCallback()) + printf("Asked to populate visited links for WebView \"%s\"\n", [[[NSURL URLWithString:[webView mainFrameURL]] _drt_descriptionSuitableForTestResult] UTF8String]); +} + +@end diff --git a/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h new file mode 100644 index 0000000..58049c2 --- /dev/null +++ b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h @@ -0,0 +1 @@ +#include "../../../../WebKit/mac/Misc/WebTypesInternal.h" diff --git a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm new file mode 100644 index 0000000..a691951 --- /dev/null +++ b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -0,0 +1,1005 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" +#import "LayoutTestController.h" + +#import "EditingDelegate.h" +#import "MockGeolocationProvider.h" +#import "PolicyDelegate.h" +#import "UIDelegate.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JSRetainPtr.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/DOMDocument.h> +#import <WebKit/DOMElement.h> +#import <WebKit/WebApplicationCache.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDOMOperationsPrivate.h> +#import <WebKit/WebDataSource.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebDeviceOrientation.h> +#import <WebKit/WebDeviceOrientationProviderMock.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFrameViewPrivate.h> +#import <WebKit/WebGeolocationPosition.h> +#import <WebKit/WebHTMLRepresentation.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebHistoryPrivate.h> +#import <WebKit/WebIconDatabasePrivate.h> +#import <WebKit/WebInspectorPrivate.h> +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebKitErrors.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebQuotaManager.h> +#import <WebKit/WebScriptWorld.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> +#import <WebKit/WebWorkersPrivate.h> +#import <wtf/CurrentTime.h> +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +@interface CommandValidationTarget : NSObject <NSValidatedUserInterfaceItem> +{ + SEL _action; +} +- (id)initWithAction:(SEL)action; +@end + +@implementation CommandValidationTarget + +- (id)initWithAction:(SEL)action +{ + self = [super init]; + if (!self) + return nil; + + _action = action; + return self; +} + +- (SEL)action +{ + return _action; +} + +- (NSInteger)tag +{ + return 0; +} + +@end + +LayoutTestController::~LayoutTestController() +{ +} + +void LayoutTestController::addDisallowedURL(JSStringRef url) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + + if (!disallowedURLs) + disallowedURLs = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); + + // Canonicalize the URL + NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]]; + request = [NSURLProtocol canonicalRequestForRequest:request]; + + CFSetAddValue(disallowedURLs, [request URL]); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + return [[mainFrame webView] shouldClose]; +} + +void LayoutTestController::clearAllApplicationCaches() +{ + [WebApplicationCache deleteAllApplicationCaches]; +} + +void LayoutTestController::clearAllDatabases() +{ + [[WebDatabaseManager sharedWebDatabaseManager] deleteAllDatabases]; +} + +void LayoutTestController::clearBackForwardList() +{ + WebBackForwardList *backForwardList = [[mainFrame webView] backForwardList]; + WebHistoryItem *item = [[backForwardList currentItem] retain]; + + // We clear the history by setting the back/forward list's capacity to 0 + // then restoring it back and adding back the current item. + int capacity = [backForwardList capacity]; + [backForwardList setCapacity:0]; + [backForwardList setCapacity:capacity]; + [backForwardList addItem:item]; + [backForwardList goToItem:item]; + [item release]; +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + return JSStringCreateWithCFString((CFStringRef)[nameNS _web_decodeHostName]); +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + return JSStringCreateWithCFString((CFStringRef)[nameNS _web_encodeHostName]); +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + if (!element) + return 0; + + JSRetainPtr<JSStringRef> counterValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame counterValueForElement:element])); + return counterValue; +} + +void LayoutTestController::keepWebHistory() +{ + if (![WebHistory optionalSharedHistory]) { + WebHistory *history = [[WebHistory alloc] init]; + [WebHistory setOptionalSharedHistory:history]; + [history release]; + } +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value) +{ + return [[mainFrame webView] _computedStyleIncludingVisitedInfo:context forElement:value]; +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + return [[mainFrame webView] _nodesFromRect:context forDocument:value x:x y:y top:top right:right bottom:bottom left:left ignoreClipping:ignoreClipping]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame _layerTreeAsText])); + return string; +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const +{ + DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject]; + if (!element) + return JSRetainPtr<JSStringRef>(); + + JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithCFString((CFStringRef)[element _markerTextForListItem])); + return markerText; +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + if (!element) + return -1; + + return [mainFrame pageNumberForElement:element:pageWidthInPixels:pageHeightInPixels]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageProperty:propertyName:pageNumber])); + return propertyValue; +} + +bool LayoutTestController::isPageBoxVisible(int pageNumber) const +{ + return [mainFrame isPageBoxVisible:pageNumber]; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const +{ + JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageSizeAndMarginsInPixels:pageNumber:width:height:marginTop:marginRight:marginBottom:marginLeft])); + return propertyValue; +} + +int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels) +{ + return [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels]; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + return [[[WebHistory optionalSharedHistory] allItems] count]; +} + +unsigned LayoutTestController::workerThreadCount() const +{ + return [WebWorkersPrivate workerThreadCount]; +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + return JSStringRetain(url); // Do nothing on mac. +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + NSString *urlNS = (NSString *)urlCF.get(); + + NSURL *nsurl = [NSURL URLWithString:urlNS relativeToURL:[[[mainFrame dataSource] response] URL]]; + NSString* nsurlString = [nsurl absoluteString]; + + JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString([nsurlString UTF8String])); + WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool newAcceptsEditing) +{ + [(EditingDelegate *)[[mainFrame webView] editingDelegate] setAcceptsEditing:newAcceptsEditing]; +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + if (alwaysAcceptCookies == m_alwaysAcceptCookies) + return; + + m_alwaysAcceptCookies = alwaysAcceptCookies; + NSHTTPCookieAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? NSHTTPCookieAcceptPolicyAlways : NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:cookieAcceptPolicy]; +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + [WebApplicationCache setMaximumSize:size]; +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota) +{ + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"http://127.0.0.1:8000"]]; + [[origin applicationCacheQuotaManager] setQuota:quota]; + [origin release]; +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + [[[mainFrame webView] preferences] setAuthorAndUserStylesEnabled:flag]; +} + +void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive) +{ + if (setDelegate) { + [policyDelegate setPermissive:permissive]; + [[mainFrame webView] setPolicyDelegate:policyDelegate]; + } else + [[mainFrame webView] setPolicyDelegate:nil]; +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"file:///"]]; + [[origin databaseQuotaManager] setQuota:quota]; + [origin release]; +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme) +{ + RetainPtr<CFStringRef> schemeCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, scheme)); + [WebView _setDomainRelaxationForbidden:forbidden forURLScheme:(NSString *)schemeCFString.get()]; +} + +void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + // DumpRenderTree configured the WebView to use WebDeviceOrientationProviderMock. + id<WebDeviceOrientationProvider> provider = [[mainFrame webView] _deviceOrientationProvider]; + WebDeviceOrientationProviderMock* mockProvider = static_cast<WebDeviceOrientationProviderMock*>(provider); + WebDeviceOrientation* orientation = [[WebDeviceOrientation alloc] initWithCanProvideAlpha:canProvideAlpha alpha:alpha canProvideBeta:canProvideBeta beta:beta canProvideGamma:canProvideGamma gamma:gamma]; + [mockProvider setOrientation:orientation]; + [orientation release]; +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + WebGeolocationPosition *position = [[WebGeolocationPosition alloc] initWithTimestamp:currentTime() latitude:latitude longitude:longitude accuracy:accuracy]; + [[MockGeolocationProvider shared] setPosition:position]; + [position release]; +} + +void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) +{ + RetainPtr<CFStringRef> messageCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, message)); + NSString *messageNS = (NSString *)messageCF.get(); + NSError *error = [NSError errorWithDomain:WebKitErrorDomain code:code userInfo:[NSDictionary dictionaryWithObject:messageNS forKey:NSLocalizedDescriptionKey]]; + [[MockGeolocationProvider shared] setError:error]; +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + setGeolocationPermissionCommon(allow); + [[[mainFrame webView] UIDelegate] didSetMockGeolocationPermission]; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. +} + +void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled) +{ + // FIXME: Workaround <rdar://problem/6480108> + static WebIconDatabase* sharedWebIconDatabase = NULL; + if (!sharedWebIconDatabase) { + if (!iconDatabaseEnabled) + return; + sharedWebIconDatabase = [WebIconDatabase sharedIconDatabase]; + if ([sharedWebIconDatabase isEnabled] == iconDatabaseEnabled) + return; + } + [sharedWebIconDatabase setEnabled:iconDatabaseEnabled]; +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool profilingEnabled) +{ + setDeveloperExtrasEnabled(profilingEnabled); + [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:profilingEnabled]; +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + NSView *documentView = [[mainFrame frameView] documentView]; + + NSResponder *firstResponder = flag ? documentView : nil; + [[[mainFrame webView] window] makeFirstResponder:firstResponder]; +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + [[[mainFrame webView] preferences] setPrivateBrowsingEnabled:privateBrowsingEnabled]; +} + +void LayoutTestController::setXSSAuditorEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setXSSAuditorEnabled:enabled]; +} + +void LayoutTestController::setFrameFlatteningEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setFrameFlatteningEnabled:enabled]; +} + +void LayoutTestController::setSpatialNavigationEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setSpatialNavigationEnabled:enabled]; +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) +{ + [[[mainFrame webView] preferences] setAllowUniversalAccessFromFileURLs:enabled]; +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + [[[mainFrame webView] preferences] setAllowFileAccessFromFileURLs:enabled]; +} + +void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled) +{ + [[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled]; +} + +void LayoutTestController::setPluginsEnabled(bool pluginsEnabled) +{ + [[[mainFrame webView] preferences] setPlugInsEnabled:pluginsEnabled]; +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled) +{ + [[[mainFrame webView] preferences] setJavaScriptCanAccessClipboard:enabled]; +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles) +{ + [[mainFrame webView] setTabKeyCyclesThroughElements:cycles]; +} + +void LayoutTestController::setTimelineProfilingEnabled(bool enabled) +{ + [[[mainFrame webView] inspector] setTimelineProfilingEnabled:enabled]; +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + [[mainFrame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:flag]; +} + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + [[WebPreferences standardPreferences] setUserStyleSheetEnabled:flag]; +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + RetainPtr<CFStringRef> pathCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, path)); + NSURL *url = [NSURL URLWithString:(NSString *)pathCF.get()]; + [[WebPreferences standardPreferences] setUserStyleSheetLocation:url]; +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef mode) +{ + // FIXME: implement +} + +void LayoutTestController::disableImageLoading() +{ + [[WebPreferences standardPreferences] setLoadsImagesAutomatically:NO]; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + [[mainFrame webView] _dispatchPendingLoadRequests]; +} + +void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value) +{ + RetainPtr<CFStringRef> keyCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, key)); + NSString *keyNS = (NSString *)keyCF.get(); + + RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value)); + NSString *valueNS = (NSString *)valueCF.get(); + + [[WebPreferences standardPreferences] _setPreferenceForTestWithValue:valueNS forKey:keyNS]; +} + +void LayoutTestController::removeAllVisitedLinks() +{ + [WebHistory _removeAllVisitedLinks]; +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL) +{ + RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL)); + ::setPersistentUserStyleSheetLocation(urlString.get()); +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + ::setPersistentUserStyleSheetLocation(0); +} + +void LayoutTestController::setWindowIsKey(bool windowIsKey) +{ + m_windowIsKey = windowIsKey; + [[mainFrame webView] _updateActiveState]; +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool flag) +{ + [[mainFrame webView] setSmartInsertDeleteEnabled:flag]; +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag) +{ + [[mainFrame webView] setSelectTrailingWhitespaceEnabled:flag]; +} + +static const CFTimeInterval waitToDumpWatchdogInterval = 30.0; + +static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info) +{ + gLayoutTestController->waitToDumpWatchdogTimerFired(); +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) { + waitToDumpWatchdog = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogInterval, 0, 0, 0, waitUntilDoneWatchdogFired, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), waitToDumpWatchdog, kCFRunLoopCommonModes); + } +} + +int LayoutTestController::windowCount() +{ + return CFArrayGetCount(openWindowsRef); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef jsString) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, jsString)); + NSString *idNS = (NSString *)idCF.get(); + + DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS]; + id rep = [[mainFrame dataSource] representation]; + + if ([rep class] == [WebHTMLRepresentation class]) + return [(WebHTMLRepresentation *)rep elementDoesAutoComplete:element]; + + return false; +} + +void LayoutTestController::execCommand(JSStringRef name, JSStringRef value) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + + RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value)); + NSString *valueNS = (NSString *)valueCF.get(); + + [[mainFrame webView] _executeCoreCommandByName:nameNS value:valueNS]; +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + WebFindOptions options = 0; + + JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); + if (!JSValueIsNumber(context, lengthValue)) + return false; + + RetainPtr<CFStringRef> targetCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, target)); + + size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); + for (size_t i = 0; i < length; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); + if (!JSValueIsString(context, value)) + continue; + + JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); + + if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive")) + options |= WebFindOptionsCaseInsensitive; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts")) + options |= WebFindOptionsAtWordStarts; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart")) + options |= WebFindOptionsTreatMedialCapitalAsWordStart; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards")) + options |= WebFindOptionsBackwards; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround")) + options |= WebFindOptionsWrapAround; + else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) + options |= WebFindOptionsStartInSelection; + } + + return [[mainFrame webView] findString:(NSString *)targetCFString.get() options:options]; +} + +void LayoutTestController::setCacheModel(int cacheModel) +{ + [[WebPreferences standardPreferences] setCacheModel:cacheModel]; +} + +bool LayoutTestController::isCommandEnabled(JSStringRef name) +{ + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name)); + NSString *nameNS = (NSString *)nameCF.get(); + + // Accept command strings with capital letters for first letter without trailing colon. + if (![nameNS hasSuffix:@":"] && [nameNS length]) { + nameNS = [[[[nameNS substringToIndex:1] lowercaseString] + stringByAppendingString:[nameNS substringFromIndex:1]] + stringByAppendingString:@":"]; + } + + SEL selector = NSSelectorFromString(nameNS); + RetainPtr<CommandValidationTarget> target(AdoptNS, [[CommandValidationTarget alloc] initWithAction:selector]); + id validator = [NSApp targetForAction:selector to:[mainFrame webView] from:target.get()]; + if (!validator) + return false; + if (![validator respondsToSelector:selector]) + return false; + if (![validator respondsToSelector:@selector(validateUserInterfaceItem:)]) + return true; + return [validator validateUserInterfaceItem:target.get()]; +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *idNS = (NSString *)idCF.get(); + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationName)); + NSString *nameNS = (NSString *)nameCF.get(); + + return [mainFrame _pauseAnimation:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time]; +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *idNS = (NSString *)idCF.get(); + RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, propertyName)); + NSString *nameNS = (NSString *)nameCF.get(); + + return [mainFrame _pauseTransitionOfProperty:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time]; +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + RetainPtr<CFStringRef> animationIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationId)); + NSString *animationIDNS = (NSString *)animationIDCF.get(); + RetainPtr<CFStringRef> elementIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId)); + NSString *elementIDNS = (NSString *)elementIDCF.get(); + + return [mainFrame _pauseSVGAnimation:elementIDNS onSMILNode:[[mainFrame DOMDocument] getElementById:animationIDNS] atTime:time]; +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + return [mainFrame _numberOfActiveAnimations]; +} + +void LayoutTestController::suspendAnimations() const +{ + return [mainFrame _suspendAnimations]; +} + +void LayoutTestController::resumeAnimations() const +{ + return [mainFrame _resumeAnimations]; +} + +void LayoutTestController::waitForPolicyDelegate() +{ + setWaitToDump(true); + [policyDelegate setControllerToNotifyDone:this]; + [[mainFrame webView] setPolicyDelegate:policyDelegate]; +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin)); + NSString *sourceOriginNS = (NSString *)sourceOriginCF.get(); + RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol)); + NSString *destinationProtocolNS = (NSString *)protocolCF.get(); + RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost)); + NSString *destinationHostNS = (NSString *)hostCF.get(); + [WebView _addOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains]; +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) +{ + RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin)); + NSString *sourceOriginNS = (NSString *)sourceOriginCF.get(); + RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol)); + NSString *destinationProtocolNS = (NSString *)protocolCF.get(); + RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost)); + NSString *destinationHostNS = (NSString *)hostCF.get(); + [WebView _removeOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains]; +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy) +{ + // FIXME: implement +} + +void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) +{ + RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source)); + NSString *sourceNS = (NSString *)sourceCF.get(); + [WebView _addUserScriptToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectionTime:(runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd) injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)]; +} + +void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) +{ + RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source)); + NSString *sourceNS = (NSString *)sourceCF.get(); + [WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)]; +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:enabled]; +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool enabled) +{ + [[[mainFrame webView] preferences] setAsynchronousSpellCheckingEnabled:enabled]; +} + +void LayoutTestController::showWebInspector() +{ + [[[mainFrame webView] inspector] show:nil]; +} + +void LayoutTestController::closeWebInspector() +{ + [[[mainFrame webView] inspector] close:nil]; +} + +void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script) +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script)); + NSString *scriptNS = (NSString *)scriptCF.get(); + [[[mainFrame webView] inspector] evaluateInFrontend:nil callId:callId script:scriptNS]; +} + +typedef HashMap<unsigned, RetainPtr<WebScriptWorld> > WorldMap; +static WorldMap& worldMap() +{ + static WorldMap& map = *new WorldMap; + return map; +} + +unsigned worldIDForWorld(WebScriptWorld *world) +{ + WorldMap::const_iterator end = worldMap().end(); + for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) { + if (it->second == world) + return it->first; + } + + return 0; +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script) +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script)); + NSString *scriptNS = (NSString *)scriptCF.get(); + + // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world + // that is created once and cached forever. + WebScriptWorld *world; + if (!worldID) + world = [WebScriptWorld world]; + else { + RetainPtr<WebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second; + if (!worldSlot) + worldSlot.adoptNS([[WebScriptWorld alloc] init]); + world = worldSlot.get(); + } + + [mainFrame _stringByEvaluatingJavaScriptFromString:scriptNS withGlobalObject:globalObject inScriptWorld:world]; +} + +@interface APITestDelegate : NSObject +{ + bool* m_condition; +} +@end + +@implementation APITestDelegate + +- (id)initWithCompletionCondition:(bool*)condition +{ + [super init]; + ASSERT(condition); + m_condition = condition; + *m_condition = false; + return self; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed provisional\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + printf("API Test load succeeded\n"); + *m_condition = true; +} + +@end + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + RetainPtr<CFStringRef> utf8DataCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, utf8Data)); + RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, baseURL)); + + WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""]; + + bool done = false; + APITestDelegate *delegate = [[APITestDelegate alloc] initWithCompletionCondition:&done]; + [webView setFrameLoadDelegate:delegate]; + + [[webView mainFrame] loadData:[(NSString *)utf8DataCF.get() dataUsingEncoding:NSUTF8StringEncoding] MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]]; + + while (!done) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; + [pool release]; + } + + [webView close]; + [webView release]; + [delegate release]; + [pool release]; +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + WebView *view = [mainFrame webView]; + [view goToBackForwardItem:[[view backForwardList] currentItem]]; +} + +void LayoutTestController::setWebViewEditable(bool editable) +{ + WebView *view = [mainFrame webView]; + [view setEditable:editable]; +} + +#ifndef BUILDING_ON_TIGER +static NSString *SynchronousLoaderRunLoopMode = @"DumpRenderTreeSynchronousLoaderRunLoopMode"; + +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) +@protocol NSURLConnectionDelegate <NSObject> +@end +#endif + +@interface SynchronousLoader : NSObject <NSURLConnectionDelegate> +{ + NSString *m_username; + NSString *m_password; + BOOL m_isDone; +} ++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password; +@end + +@implementation SynchronousLoader : NSObject +- (void)dealloc +{ + [m_username release]; + [m_password release]; + + [super dealloc]; +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection +{ + return YES; +} + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if ([challenge previousFailureCount] == 0) { + NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:m_username password:m_password persistence:NSURLCredentialPersistenceForSession]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + return; + } + [[challenge sender] cancelAuthenticationChallenge:challenge]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + printf("SynchronousLoader failed: %s\n", [[error description] UTF8String]); + m_isDone = YES; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + m_isDone = YES; +} + ++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password +{ + ASSERT(![[request URL] user]); + ASSERT(![[request URL] password]); + + SynchronousLoader *delegate = [[SynchronousLoader alloc] init]; + delegate->m_username = [username copy]; + delegate->m_password = [password copy]; + + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO]; + [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:SynchronousLoaderRunLoopMode]; + [connection start]; + + while (!delegate->m_isDone) + [[NSRunLoop currentRunLoop] runMode:SynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]]; + + [connection cancel]; + + [connection release]; + [delegate release]; +} + +@end +#endif + +void LayoutTestController::authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password) +{ + // See <rdar://problem/7880699>. +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + RetainPtr<CFStringRef> urlStringCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url)); + RetainPtr<CFStringRef> usernameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, username)); + RetainPtr<CFStringRef> passwordCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, password)); + + NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:(NSString *)urlStringCF.get()]]; + + [SynchronousLoader makeRequest:request withUsername:(NSString *)usernameCF.get() password:(NSString *)passwordCF.get()]; +#endif +} + +void LayoutTestController::setEditingBehavior(const char* editingBehavior) +{ + NSString* editingBehaviorNS = [[NSString alloc] initWithUTF8String:editingBehavior]; + if ([editingBehaviorNS isEqualToString:@"mac"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingMacBehavior]; + else if ([editingBehaviorNS isEqualToString:@"win"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingWinBehavior]; + else if ([editingBehaviorNS isEqualToString:@"unix"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingUnixBehavior]; + [editingBehaviorNS release]; +} + +void LayoutTestController::abortModal() +{ + [NSApp abortModal]; +} + +bool LayoutTestController::hasSpellingMarker(int from, int length) +{ + return [mainFrame hasSpellingMarker:from length:length]; +} +void LayoutTestController::dumpConfigurationForViewport(int /*availableWidth*/, int /*availableHeight*/) +{ + +} + +void LayoutTestController::setSerializeHTTPLoads(bool serialize) +{ + [WebView _setLoadResourcesSerially:serialize]; +} diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.h b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h new file mode 100644 index 0000000..311d1e9 --- /dev/null +++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MockGeolocationProvider_h +#define MockGeolocationProvider_h + +#import <WebKit/WebViewPrivate.h> +#import <wtf/HashSet.h> + +@interface MockGeolocationProvider : NSObject<WebGeolocationProvider> { + WebGeolocationPosition *_lastPosition; + NSError *_error; + NSTimer *_timer; + HashSet<WebView *> _registeredViews; +} + ++ (MockGeolocationProvider *)shared; + +- (void)setPosition:(WebGeolocationPosition *)position; +- (void)setError:(NSError *)error; + +- (void)stopTimer; + +@end +#endif diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm new file mode 100644 index 0000000..e03cae2 --- /dev/null +++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "MockGeolocationProvider.h" + + +@implementation MockGeolocationProvider + ++ (MockGeolocationProvider *)shared +{ + static MockGeolocationProvider *provider = [[MockGeolocationProvider alloc] init]; + return provider; +} + +- (void)dealloc +{ + ASSERT(_registeredViews.isEmpty()); + + [_lastPosition release]; + [_error release]; + [super dealloc]; +} + +- (void)setPosition:(WebGeolocationPosition *)position +{ + if (_lastPosition != position) { + [_lastPosition release]; + _lastPosition = [position retain]; + } + + [_error release]; + _error = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)setError:(NSError *)error +{ + if (_error != error) { + [_error release]; + _error = [error retain]; + } + + [_lastPosition release]; + _lastPosition = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)registerWebView:(WebView *)webView +{ + _registeredViews.add(webView); + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)unregisterWebView:(WebView *)webView +{ + _registeredViews.remove(webView); +} + +- (WebGeolocationPosition *)lastPosition +{ + return _lastPosition; +} + +- (void)stopTimer +{ + [_timer invalidate]; + _timer = 0; +} + +- (void)timerFired +{ + _timer = 0; + + // Expect that views won't be (un)registered while iterating. + HashSet<WebView*> views = _registeredViews; + for (HashSet<WebView*>::iterator iter = views.begin(); iter != views.end(); ++iter) { + if (_error) + [*iter _geolocationDidFailWithError:_error]; + else + [*iter _geolocationDidChangePosition:_lastPosition]; + } +} + +@end diff --git a/Tools/DumpRenderTree/mac/NavigationController.h b/Tools/DumpRenderTree/mac/NavigationController.h new file mode 100644 index 0000000..8ee3432 --- /dev/null +++ b/Tools/DumpRenderTree/mac/NavigationController.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> +#import <WebKit/WebView.h> + +@interface NavigationController : NSObject +{ + enum { None, Load, GoBack, ExecuteScript } pendingAction; + NSString *pendingScript; + NSURLRequest *pendingRequest; +} +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame; +@end diff --git a/Tools/DumpRenderTree/mac/NavigationController.m b/Tools/DumpRenderTree/mac/NavigationController.m new file mode 100644 index 0000000..8c01d50 --- /dev/null +++ b/Tools/DumpRenderTree/mac/NavigationController.m @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "NavigationController.h" + +#import <WebKit/WebFrame.h> +#import <WebKit/WebScriptObject.h> + + +@implementation NavigationController ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:)) + return @"evalAfterBackForwardNavigation"; + return nil; +} + +- (void)setPendingScript:(NSString *)script +{ + if (script != pendingScript) { + [pendingScript release]; + pendingScript = [script copy]; + } +} + +- (void)setPendingRequest:(NSURLRequest *)request +{ + if (request != pendingRequest) { + [pendingRequest release]; + pendingRequest = [request copy]; + } +} + +- (void)evaluateWebScript:(NSString *)script afterBackForwardNavigation:(NSString *)navigation +{ + // Allow both arguments to be optional + if (![script isKindOfClass:[NSString class]]) + script = @""; + if (![navigation isKindOfClass:[NSString class]]) + navigation = @"about:blank"; + + [self setPendingScript:script]; + [self setPendingRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:navigation]]]; + pendingAction = Load; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + if (frame == [[frame webView] mainFrame]) { + switch (pendingAction) { + case Load: + pendingAction = GoBack; + [frame loadRequest:pendingRequest]; + [self setPendingRequest:nil]; + break; + case GoBack: + pendingAction = ExecuteScript; + [[frame webView] goBack]; + break; + case ExecuteScript: + pendingAction = None; + [[[frame webView] windowScriptObject] evaluateWebScript:pendingScript]; + [self setPendingScript:nil]; + break; + case None: + default: + break; + } + } +} + +- (void)dealloc +{ + [self setPendingScript:nil]; + [self setPendingRequest:nil]; + [super dealloc]; +} +@end + diff --git a/Tools/DumpRenderTree/mac/ObjCController.h b/Tools/DumpRenderTree/mac/ObjCController.h new file mode 100644 index 0000000..d1d001c --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCController.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> + +@class WebScriptObject; + +// This controller should be used to test Objective-C language features and the WebScriptObject. +@interface ObjCController : NSObject +{ + WebScriptObject *storedWebScriptObject; +} +@end diff --git a/Tools/DumpRenderTree/mac/ObjCController.m b/Tools/DumpRenderTree/mac/ObjCController.m new file mode 100644 index 0000000..f1d1c10 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCController.m @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ObjCController.h" + +// Avoid compile error in DOMPrivate.h. +@class NSFont; + +#import <JavaScriptCore/JavaScriptCore.h> +#import <WebKit/DOMAbstractView.h> +#import <WebKit/DOMPrivate.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebView.h> +#import <pthread.h> +#import <wtf/Assertions.h> + +// Remove this once hasWebScriptKey has been made public. +@interface WebScriptObject (StagedForPublic) +- (BOOL)hasWebScriptKey:(NSString *)name; +@end + +static void* runJavaScriptThread(void* arg) +{ + JSGlobalContextRef ctx = JSGlobalContextCreate(0); + JSStringRef scriptRef = JSStringCreateWithUTF8CString("'Hello World!'"); + + JSValueRef exception = 0; + JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); + ASSERT(!exception); + + JSGlobalContextRelease(ctx); + JSStringRelease(scriptRef); + + return 0; +} + +@implementation ObjCController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (0 + || aSelector == @selector(classNameOf:) + || aSelector == @selector(objectOfClass:) + || aSelector == @selector(arrayOfString) + || aSelector == @selector(identityIsEqual::) + || aSelector == @selector(longLongRoundTrip:) + || aSelector == @selector(unsignedLongLongRoundTrip:) + || aSelector == @selector(testWrapperRoundTripping:) + || aSelector == @selector(accessStoredWebScriptObject) + || aSelector == @selector(storeWebScriptObject:) + || aSelector == @selector(testValueForKey) + || aSelector == @selector(testHasWebScriptKey:) + || aSelector == @selector(testArray) + || aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:) + ) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(classNameOf:)) + return @"className"; + if (aSelector == @selector(objectOfClass:)) + return @"objectOfClass"; + if (aSelector == @selector(arrayOfString)) + return @"arrayOfString"; + if (aSelector == @selector(identityIsEqual::)) + return @"identityIsEqual"; + if (aSelector == @selector(longLongRoundTrip:)) + return @"longLongRoundTrip"; + if (aSelector == @selector(unsignedLongLongRoundTrip:)) + return @"unsignedLongLongRoundTrip"; + if (aSelector == @selector(testWrapperRoundTripping:)) + return @"testWrapperRoundTripping"; + if (aSelector == @selector(storeWebScriptObject:)) + return @"storeWebScriptObject"; + if (aSelector == @selector(testValueForKey)) + return @"testValueForKey"; + if (aSelector == @selector(testHasWebScriptKey:)) + return @"testHasWebScriptKey"; + if (aSelector == @selector(testArray)) + return @"testArray"; + if (aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:)) + return @"setSelectElementSelectedIndexAllowingMultiple"; + + return nil; +} + +- (NSString *)classNameOf:(id)object +{ + if (!object) + return @"nil"; + return NSStringFromClass([object class]); +} + +- (id)objectOfClass:(NSString *)aClass +{ + if ([aClass isEqualToString:@"NSNull"]) + return [NSNull null]; + if ([aClass isEqualToString:@"WebUndefined"]) + return [WebUndefined undefined]; + if ([aClass isEqualToString:@"NSCFBoolean"]) + return [NSNumber numberWithBool:true]; + if ([aClass isEqualToString:@"NSCFNumber"]) + return [NSNumber numberWithInt:1]; + if ([aClass isEqualToString:@"NSCFString"]) + return @""; + if ([aClass isEqualToString:@"WebScriptObject"]) + return self; + if ([aClass isEqualToString:@"NSArray"]) + return [NSArray array]; + + return nil; +} + +- (NSArray *)arrayOfString +{ + NSString *strings[3]; + strings[0] = @"one"; + strings[1] = @"two"; + strings[2] = @"three"; + NSArray *array = [NSArray arrayWithObjects:strings count:3]; + return array; +} + +- (BOOL)identityIsEqual:(WebScriptObject *)a :(WebScriptObject *)b +{ + if ([a isKindOfClass:[NSString class]] && [b isKindOfClass:[NSString class]]) + return [(NSString *)a isEqualToString:(NSString *)b]; + return a == b; +} + +- (long long)longLongRoundTrip:(long long)num +{ + return num; +} + +- (unsigned long long)unsignedLongLongRoundTrip:(unsigned long long)num +{ + return num; +} + +- (void)testValueForKey +{ + ASSERT(storedWebScriptObject); + + @try { + [storedWebScriptObject valueForKey:@"ThisKeyDoesNotExist"]; + } @catch (NSException *e) { + } + + pthread_t pthread; + pthread_create(&pthread, 0, &runJavaScriptThread, 0); + pthread_join(pthread, 0); +} + +- (BOOL)testHasWebScriptKey:(NSString *)key +{ + ASSERT(storedWebScriptObject); + return [storedWebScriptObject hasWebScriptKey:key]; +} + +- (BOOL)testWrapperRoundTripping:(WebScriptObject *)webScriptObject +{ + JSObjectRef jsObject = [webScriptObject JSObject]; + + if (!jsObject) + return false; + + if (!webScriptObject) + return false; + + if ([[webScriptObject evaluateWebScript:@"({ })"] class] != [webScriptObject class]) + return false; + + [webScriptObject setValue:[NSNumber numberWithInt:666] forKey:@"key"]; + if (![[webScriptObject valueForKey:@"key"] isKindOfClass:[NSNumber class]] || + ![[webScriptObject valueForKey:@"key"] isEqualToNumber:[NSNumber numberWithInt:666]]) + return false; + + [webScriptObject removeWebScriptKey:@"key"]; + @try { + if ([webScriptObject valueForKey:@"key"]) + return false; + } @catch(NSException *exception) { + // NSObject throws an exception if the key doesn't exist. + } + + [webScriptObject setWebScriptValueAtIndex:0 value:webScriptObject]; + if ([webScriptObject webScriptValueAtIndex:0] != webScriptObject) + return false; + + if ([[webScriptObject stringRepresentation] isEqualToString:@"[Object object]"]) + return false; + + if ([webScriptObject callWebScriptMethod:@"returnThis" withArguments:nil] != webScriptObject) + return false; + + return true; +} + +- (void)accessStoredWebScriptObject +{ +#if !ASSERT_DISABLED + BOOL isWindowObject = [storedWebScriptObject isKindOfClass:[DOMAbstractView class]]; + JSObjectRef jsObject = [storedWebScriptObject JSObject]; + ASSERT((jsObject && isWindowObject) || (!jsObject && !isWindowObject)); +#endif + [storedWebScriptObject callWebScriptMethod:@"" withArguments:nil]; + [storedWebScriptObject evaluateWebScript:@""]; + [storedWebScriptObject setValue:[WebUndefined undefined] forKey:@"key"]; + [storedWebScriptObject valueForKey:@"key"]; + [storedWebScriptObject removeWebScriptKey:@"key"]; + [storedWebScriptObject stringRepresentation]; + [storedWebScriptObject webScriptValueAtIndex:0]; + [storedWebScriptObject setWebScriptValueAtIndex:0 value:[WebUndefined undefined]]; + [storedWebScriptObject setException:@"exception"]; +} + +- (void)storeWebScriptObject:(WebScriptObject *)webScriptObject +{ + if (webScriptObject == storedWebScriptObject) + return; + + [storedWebScriptObject release]; + storedWebScriptObject = [webScriptObject retain]; +} + +- (NSArray *)testArray +{ + return [NSArray array]; +} + +- (void)dealloc +{ + [storedWebScriptObject release]; + [super dealloc]; +} + +- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args +{ + // FIXME: Perhaps we should log that this has been called. + return nil; +} + +#pragma mark - +#pragma mark Testing Objective-C DOM HTML Bindings + +- (void)setSelectElement:(WebScriptObject *)element selectedIndex:(int)index allowingMultiple:(BOOL)allowingMultiple +{ + if (![element isKindOfClass:[DOMHTMLSelectElement class]]) + return; + + DOMHTMLSelectElement *select = (DOMHTMLSelectElement*)element; + [select _activateItemAtIndex:index allowMultipleSelection:allowingMultiple]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.h b/Tools/DumpRenderTree/mac/ObjCPlugin.h new file mode 100644 index 0000000..a6d3e50 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPlugin.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#import <Cocoa/Cocoa.h> + + +@interface ObjCPlugin : NSObject +{ + BOOL throwOnDealloc; +} + +- (void)removeBridgeRestrictions:(id)container; + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.m b/Tools/DumpRenderTree/mac/ObjCPlugin.m new file mode 100644 index 0000000..023eae1 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPlugin.m @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 James G. Speth (speth@end.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#import "config.h" +#import "ObjCPlugin.h" + +#import <WebKit/WebKit.h> +#import <objc/objc-runtime.h> + +// === NSObject category to expose almost everything to JavaScript === + +// Warning: this class introduces huge security weaknesses, and should only be used +// for testing inside of DumpRenderTree, and only with trusted code. By default, it has +// the same restrictive behavior as the standard WebKit setup. However, scripts can use the +// plugin's removeBridgeRestrictions: method to open up almost total access to the Cocoa +// frameworks. + +static BOOL _allowsScriptsFullAccess = NO; + +@interface NSObject (ObjCScriptAccess) + ++ (void)setAllowsScriptsFullAccess:(BOOL)value; ++ (BOOL)allowsScriptsFullAccess; + +@end + +@implementation NSObject (ObjCScriptAccess) + ++ (void)setAllowsScriptsFullAccess:(BOOL)value +{ + _allowsScriptsFullAccess = value; +} + ++ (BOOL)allowsScriptsFullAccess +{ + return _allowsScriptsFullAccess; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + return !_allowsScriptsFullAccess; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + return nil; +} + +@end + +@interface JSObjC : NSObject { +} + +// expose some useful objc functions to the scripting environment +- (id)lookUpClass:(NSString *)name; +- (void)log:(NSString *)message; +- (id)retainObject:(id)obj; +- (id)classOfObject:(id)obj; +- (NSString *)classNameOfObject:(id)obj; + +@end + +@implementation JSObjC + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + return nil; +} + +- (id)invokeDefaultMethodWithArguments:(NSArray *)args +{ + // this is a useful shortcut for accessing objective-c classes from the scripting + // environment, e.g. 'var myObject = objc("NSObject").alloc().init();' + if ([args count] == 1) + return [self lookUpClass:[args objectAtIndex:0]]; + return nil; +} + +- (id)lookUpClass:(NSString *)name +{ + return NSClassFromString(name); +} + +- (void)log:(NSString *)message +{ + NSLog(@"%@", message); +} + +- (id)retainObject:(id)obj +{ + return [obj retain]; +} + +- (id)classOfObject:(id)obj +{ + return (id)[obj class]; +} + +- (NSString *)classNameOfObject:(id)obj +{ + return [obj className]; +} + +@end + +@implementation ObjCPlugin + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(removeBridgeRestrictions:)) + return NO; + + if (aSelector == @selector(echo:)) + return NO; + + if (aSelector == @selector(throwIfArgumentIsNotHello:)) + return NO; + + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(echo:)) + return @"echo"; + + if (aSelector == @selector(throwIfArgumentIsNotHello:)) + return @"throwIfArgumentIsNotHello"; + + return nil; +} + ++ (NSString *)webScriptNameForKey:(const char *)key +{ + if (strcmp(key, "throwOnDealloc") == 0) + return @"throwOnDealloc"; + + return nil; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char *)key +{ + if (strcmp(key, "throwOnDealloc") == 0) + return NO; + + return YES; +} + +- (void)removeBridgeRestrictions:(id)container +{ + // let scripts invoke any selector + [NSObject setAllowsScriptsFullAccess:YES]; + + // store a JSObjC instance into the provided container + JSObjC *objc = [[JSObjC alloc] init]; + [container setValue:objc forKey:@"objc"]; + [objc release]; +} + +- (id)echo:(id)obj +{ + return obj; +} + +- (void)throwIfArgumentIsNotHello:(NSString *)str +{ + if (![str isEqualToString:@"Hello"]) + [WebScriptObject throwException:[NSString stringWithFormat:@"%@ != Hello", str]]; +} + +- (void)dealloc +{ + if (throwOnDealloc) + [WebScriptObject throwException:@"Throwing exception on dealloc of ObjCPlugin"]; + + [super dealloc]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.h b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h new file mode 100644 index 0000000..1e81b21 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#import <Cocoa/Cocoa.h> + + +@interface ObjCPluginFunction : NSObject +{ +} + +@end diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.m b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m new file mode 100644 index 0000000..5bf3617 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#import "config.h" +#import "ObjCPluginFunction.h" + + +@implementation ObjCPluginFunction + +- (id)invokeDefaultMethodWithArguments:(NSArray *)args +{ + return @"test"; +} + +@end diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c new file mode 100644 index 0000000..35f051c --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/sysctl.h> + +int processIsCrashing(int pid) +{ + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; + struct kinfo_proc info; + size_t bufferSize = sizeof(info); + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &info, &bufferSize, 0, 0)) { + perror("sysctl"); + return 0; + } + + struct extern_proc proc = info.kp_proc; + + // The process is crashing if it is waiting to exit, is not a zombie, and has a non-zero exit code. + return proc.p_stat != SZOMB && (proc.p_flag & P_WEXIT) && proc.p_xstat; +} diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm new file mode 100644 index 0000000..7b4ea34 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm @@ -0,0 +1,54 @@ +# This file was automatically generated by SWIG +package DumpRenderTreeSupport; +require Exporter; +require DynaLoader; +@ISA = qw(Exporter DynaLoader); +package DumpRenderTreeSupportc; +bootstrap DumpRenderTreeSupport; +package DumpRenderTreeSupport; +@EXPORT = qw( ); + +# ---------- BASE METHODS ------------- + +package DumpRenderTreeSupport; + +sub TIEHASH { + my ($classname,$obj) = @_; + return bless $obj, $classname; +} + +sub CLEAR { } + +sub FIRSTKEY { } + +sub NEXTKEY { } + +sub FETCH { + my ($self,$field) = @_; + my $member_func = "swig_${field}_get"; + $self->$member_func(); +} + +sub STORE { + my ($self,$field,$newval) = @_; + my $member_func = "swig_${field}_set"; + $self->$member_func($newval); +} + +sub this { + my $ptr = shift; + return tied(%$ptr); +} + + +# ------- FUNCTION WRAPPERS -------- + +package DumpRenderTreeSupport; + +*processIsCrashing = *DumpRenderTreeSupportc::processIsCrashing; + +# ------- VARIABLE STUBS -------- + +package DumpRenderTreeSupport; + +1; diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c new file mode 100644 index 0000000..f734989 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c @@ -0,0 +1,1167 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.24 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + + +#ifndef SWIG_TEMPLATE_DISAMBIGUATOR +# if defined(__SUNPRO_CC) +# define SWIG_TEMPLATE_DISAMBIGUATOR template +# else +# define SWIG_TEMPLATE_DISAMBIGUATOR +# endif +#endif + +/*********************************************************************** + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * + ************************************************************************/ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "1" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +#define SWIG_QUOTE_STRING(x) #x +#define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +#define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +#define SWIG_TYPE_TABLE_NAME +#endif + +#include <string.h> + +#ifndef SWIGINLINE +#if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +#else +# define SWIGINLINE +#endif +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ +#ifndef SWIGRUNTIME +#define SWIGRUNTIME static +#endif +#ifndef SWIGRUNTIMEINLINE +#define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +typedef struct swig_type_info { + const char *name; + swig_converter_func converter; + const char *str; + void *clientdata; + swig_dycast_func dcast; + struct swig_type_info *next; + struct swig_type_info *prev; +} swig_type_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class<int>" == "Class<int >", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return *f1 - *f2; + } + return (l1 - f1) - (l2 - f2); +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = SWIG_TypeNameComp(nb, ne, tb, te) == 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Register a type mapping with the type-checking +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeRegisterTL(swig_type_info **tl, swig_type_info *ti) { + swig_type_info *tc, *head, *ret, *next; + /* Check to see if this type has already been registered */ + tc = *tl; + while (tc) { + /* check simple type equivalence */ + int typeequiv = (strcmp(tc->name, ti->name) == 0); + /* check full type equivalence, resolving typedefs */ + if (!typeequiv) { + /* only if tc is not a typedef (no '|' on it) */ + if (tc->str && ti->str && !strstr(tc->str,"|")) { + typeequiv = SWIG_TypeEquiv(ti->str,tc->str); + } + } + if (typeequiv) { + /* Already exists in the table. Just add additional types to the list */ + if (ti->clientdata) tc->clientdata = ti->clientdata; + head = tc; + next = tc->next; + goto l1; + } + tc = tc->prev; + } + head = ti; + next = 0; + + /* Place in list */ + ti->prev = *tl; + *tl = ti; + + /* Build linked lists */ + l1: + ret = head; + tc = ti + 1; + /* Patch up the rest of the links */ + while (tc->name) { + head->next = tc; + tc->prev = head; + head = tc; + tc++; + } + if (next) next->prev = head; + head->next = next; + + return ret; +} + +/* + Check the typename +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + swig_type_info *s; + if (!ty) return 0; /* Void pointer */ + s = ty->next; /* First element always just a name */ + do { + if (strcmp(s->name,c) == 0) { + if (s == ty->next) return s; + /* Move s to the top of the linked list */ + s->prev->next = s->next; + if (s->next) { + s->next->prev = s->prev; + } + /* Insert s as second element in the list */ + s->next = ty->next; + if (ty->next) ty->next->prev = s; + ty->next = s; + s->prev = ty; + return s; + } + s = s->next; + } while (s && (s != ty->next)); + return 0; +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_type_info *ty, void *ptr) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Search for a swig_type_info structure +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryTL(swig_type_info *tl, const char *name) { + swig_type_info *ty = tl; + while (ty) { + if (ty->str && (SWIG_TypeEquiv(ty->str,name))) return ty; + if (ty->name && (strcmp(name,ty->name) == 0)) return ty; + ty = ty->prev; + } + return 0; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientDataTL(swig_type_info *tl, swig_type_info *ti, void *clientdata) { + swig_type_info *tc, *equiv; + if (ti->clientdata) return; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + equiv = ti->next; + while (equiv) { + if (!equiv->converter) { + tc = tl; + while (tc) { + if ((strcmp(tc->name, equiv->name) == 0)) + SWIG_TypeClientDataTL(tl,tc,clientdata); + tc = tc->prev; + } + } + equiv = equiv->next; + } +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static char hex[17] = "0123456789abcdef"; + unsigned char *u = (unsigned char *) ptr; + const unsigned char *eu = u + sz; + register unsigned char uu; + for (; u != eu; ++u) { + uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register int d = *(c++); + register unsigned char uu = 0; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + This function will propagate the clientdata field of type to any new + swig_type_info structures that have been added into the list of + equivalent types. It is like calling SWIG_TypeClientData(type, + clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientDataTL(swig_type_info *tl, swig_type_info *type) { + swig_type_info *equiv = type->next; + swig_type_info *tc; + if (!type->clientdata) return; + while (equiv) { + if (!equiv->converter) { + tc = tl; + while (tc) { + if ((strcmp(tc->name, equiv->name) == 0) && !tc->clientdata) + SWIG_TypeClientDataTL(tl,tc, type->clientdata); + tc = tc->prev; + } + } + equiv = equiv->next; + } +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/*********************************************************************** + * common.swg + * + * This file contains generic SWIG runtime support for pointer + * type checking as well as a few commonly used macros to control + * external linkage. + * + * Author : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (c) 1999-2000, The University of Chicago + * + * This file may be freely redistributed without license or fee provided + * this copyright message remains intact. + ************************************************************************/ + + +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if !defined(STATIC_LINKED) +# define SWIGEXPORT(a) __declspec(dllexport) a +# else +# define SWIGEXPORT(a) a +# endif +#else +# define SWIGEXPORT(a) a +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/*************************************************************************/ + + +/* The static type info list */ + +static swig_type_info *swig_type_list = 0; +static swig_type_info **swig_type_list_handle = &swig_type_list; + + +/* Register a type mapping with the type-checking */ +static swig_type_info * +SWIG_TypeRegister(swig_type_info *ti) { + return SWIG_TypeRegisterTL(swig_type_list_handle, ti); +} + +/* Search for a swig_type_info structure */ +static swig_type_info * +SWIG_TypeQuery(const char *name) { + return SWIG_TypeQueryTL(*swig_type_list_handle, name); +} + +/* Set the clientdata field for a type */ +static void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientDataTL(*swig_type_list_handle, ti, clientdata); +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +static void +SWIG_PropagateClientData(swig_type_info *type) { + SWIG_PropagateClientDataTL(*swig_type_list_handle, type); +} + +#ifdef __cplusplus +} +#endif + +/* ---------------------------------------------------------------------- -*- c -*- + * perl5.swg + * + * Perl5 runtime library + * $Header: /cvsroot/swig/SWIG/Lib/perl5/perlrun.swg,v 1.20 2004/11/29 23:13:57 wuzzeb Exp $ + * ----------------------------------------------------------------------------- */ + +#define SWIGPERL +#define SWIGPERL5 +#ifdef __cplusplus +/* Needed on some windows machines---since MS plays funny games with the header files under C++ */ +#include <math.h> +#include <stdlib.h> +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +/* Get rid of free and malloc defined by perl */ +#undef free +#undef malloc + +#ifndef pTHX_ +#define pTHX_ +#endif + +#include <string.h> +#ifdef __cplusplus +} +#endif + +/* Macro to call an XS function */ + +#ifdef PERL_OBJECT +# define SWIG_CALLXS(_name) _name(cv,pPerl) +#else +# ifndef MULTIPLICITY +# define SWIG_CALLXS(_name) _name(cv) +# else +# define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) +# endif +#endif + +/* Contract support */ + +#define SWIG_contract_assert(expr,msg) if (!(expr)) { SWIG_croak(msg); } else + +/* Note: SwigMagicFuncHack is a typedef used to get the C++ compiler to just shut up already */ + +#ifdef PERL_OBJECT +#define MAGIC_PPERL CPerlObj *pPerl = (CPerlObj *) this; +typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *); + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (CPerlObj::*SwigMagicFuncHack)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) +#define SWIGCLASS_STATIC +#else +#define MAGIC_PPERL +#define SWIGCLASS_STATIC static +#ifndef MULTIPLICITY +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) +typedef int (*SwigMagicFunc)(SV *, MAGIC *); + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFuncHack)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + + +#else +#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b) +typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *); +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFuncHack)(struct interpreter *, SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#endif +#endif + +#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE) +#define PerlIO_exportFILE(fh,fl) (FILE*)(fh) +#endif + +/* Modifications for newer Perl 5.005 releases */ + +#if !defined(PERL_REVISION) || ((PERL_REVISION >= 5) && ((PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION < 50)))) +# ifndef PL_sv_yes +# define PL_sv_yes sv_yes +# endif +# ifndef PL_sv_undef +# define PL_sv_undef sv_undef +# endif +# ifndef PL_na +# define PL_na na +# endif +#endif + +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWIG_OWNER 1 +#define SWIG_SHADOW 2 + +/* Common SWIG API */ + +#ifdef PERL_OBJECT +# define SWIG_ConvertPtr(obj, pp, type, flags) \ + SWIG_Perl_ConvertPtr(pPerl, obj, pp, type, flags) +# define SWIG_NewPointerObj(p, type, flags) \ + SWIG_Perl_NewPointerObj(pPerl, p, type, flags) +# define SWIG_MakePackedObj(sv, p, s, type) \ + SWIG_Perl_MakePackedObj(pPerl, sv, p, s, type) +# define SWIG_ConvertPacked(obj, p, s, type, flags) \ + SWIG_Perl_ConvertPacked(pPerl, obj, p, s, type, flags) + +#else +# define SWIG_ConvertPtr(obj, pp, type, flags) \ + SWIG_Perl_ConvertPtr(obj, pp, type, flags) +# define SWIG_NewPointerObj(p, type, flags) \ + SWIG_Perl_NewPointerObj(p, type, flags) +# define SWIG_MakePackedObj(sv, p, s, type) \ + SWIG_Perl_MakePackedObj(sv, p, s, type ) +# define SWIG_ConvertPacked(obj, p, s, type, flags) \ + SWIG_Perl_ConvertPacked(obj, p, s, type, flags) +#endif + +/* Perl-specific API */ +#ifdef PERL_OBJECT +# define SWIG_MakePtr(sv, ptr, type, flags) \ + SWIG_Perl_MakePtr(pPerl, sv, ptr, type, flags) +# define SWIG_SetError(str) \ + SWIG_Perl_SetError(pPerl, str) +#else +# define SWIG_MakePtr(sv, ptr, type, flags) \ + SWIG_Perl_MakePtr(sv, ptr, type, flags) +# define SWIG_SetError(str) \ + SWIG_Perl_SetError(str) +# define SWIG_SetErrorSV(str) \ + SWIG_Perl_SetErrorSV(str) +#endif + +#define SWIG_SetErrorf SWIG_Perl_SetErrorf + + +#ifdef PERL_OBJECT +# define SWIG_MAYBE_PERL_OBJECT CPerlObj *pPerl, +#else +# define SWIG_MAYBE_PERL_OBJECT +#endif + +static swig_type_info ** +SWIG_Perl_GetTypeListHandle() { + static void *type_pointer = (void *)0; + SV *pointer; + + /* first check if pointer already created */ + if (!type_pointer) { + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE); + if (pointer && SvOK(pointer)) { + type_pointer = INT2PTR(swig_type_info **, SvIV(pointer)); + } + } + + return (swig_type_info **) type_pointer; +} + +/* + Search for a swig_type_info structure + */ +SWIGRUNTIMEINLINE swig_type_info * +SWIG_Perl_GetTypeList() { + swig_type_info **tlh = SWIG_Perl_GetTypeListHandle(); + return tlh ? *tlh : (swig_type_info*)0; +} + +#define SWIG_Runtime_GetTypeList SWIG_Perl_GetTypeList + +static swig_type_info * +SWIG_Perl_TypeCheckRV(SWIG_MAYBE_PERL_OBJECT SV *rv, swig_type_info *ty) { + swig_type_info *s; + if (!ty) return 0; /* Void pointer */ + s = ty->next; /* First element always just a name */ + do { + if (sv_derived_from(rv, (char *) s->name)) { + if (s == ty->next) return s; + /* Move s to the top of the linked list */ + s->prev->next = s->next; + if (s->next) { + s->next->prev = s->prev; + } + /* Insert s as second element in the list */ + s->next = ty->next; + if (ty->next) ty->next->prev = s; + ty->next = s; + s->prev = ty; + return s; + } + s = s->next; + } while (s && (s != ty->next)); + return 0; +} + +/* Function for getting a pointer value */ + +static int +SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) { + swig_type_info *tc; + void *voidptr = (void *)0; + + /* If magical, apply more magic */ + if (SvGMAGICAL(sv)) + mg_get(sv); + + /* Check to see if this is an object */ + if (sv_isobject(sv)) { + SV *tsv = (SV*) SvRV(sv); + IV tmp = 0; + if ((SvTYPE(tsv) == SVt_PVHV)) { + MAGIC *mg; + if (SvMAGICAL(tsv)) { + mg = mg_find(tsv,'P'); + if (mg) { + sv = mg->mg_obj; + if (sv_isobject(sv)) { + tmp = SvIV((SV*)SvRV(sv)); + } + } + } else { + return -1; + } + } else { + tmp = SvIV((SV*)SvRV(sv)); + } + voidptr = (void *)tmp; + if (!_t) { + *(ptr) = voidptr; + return 0; + } + } else if (! SvOK(sv)) { /* Check for undef */ + *(ptr) = (void *) 0; + return 0; + } else if (SvTYPE(sv) == SVt_RV) { /* Check for NULL pointer */ + *(ptr) = (void *) 0; + if (!SvROK(sv)) + return 0; + else + return -1; + } else { /* Don't know what it is */ + *(ptr) = (void *) 0; + return -1; + } + if (_t) { + /* Now see if the types match */ + char *_c = HvNAME(SvSTASH(SvRV(sv))); + tc = SWIG_TypeCheck(_c,_t); + if (!tc) { + *ptr = voidptr; + return -1; + } + *ptr = SWIG_TypeCast(tc,voidptr); + return 0; + } + *ptr = voidptr; + return 0; +} + +static void +SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) { + if (ptr && (flags & SWIG_SHADOW)) { + SV *self; + SV *obj=newSV(0); + HV *hash=newHV(); + HV *stash; + sv_setref_pv(obj, (char *) t->name, ptr); + stash=SvSTASH(SvRV(obj)); + if (flags & SWIG_OWNER) { + HV *hv; + GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE); + if (!isGV(gv)) + gv_init(gv, stash, "OWNER", 5, FALSE); + hv=GvHVn(gv); + hv_store_ent(hv, obj, newSViv(1), 0); + } + sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0); + SvREFCNT_dec(obj); + self=newRV_noinc((SV *)hash); + sv_setsv(sv, self); + SvREFCNT_dec((SV *)self); + sv_bless(sv, stash); + } + else { + sv_setref_pv(sv, (char *) t->name, ptr); + } +} + +static SWIGINLINE SV * +SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) { + SV *result = sv_newmortal(); + SWIG_MakePtr(result, ptr, t, flags); + return result; +} + +static void + SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) { + char result[1024]; + char *r = result; + if ((2*sz + 1 + strlen(type->name)) > 1000) return; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + strcpy(r,type->name); + sv_setpv(sv, result); +} + +/* Convert a packed value value */ +static int +SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty, int flags) { + swig_type_info *tc; + const char *c = 0; + + if ((!obj) || (!SvOK(obj))) return -1; + c = SvPV(obj, PL_na); + /* Pointer values must start with leading underscore */ + if (*c != '_') return -1; + c++; + c = SWIG_UnpackData(c,ptr,sz); + if (ty) { + tc = SWIG_TypeCheck(c,ty); + if (!tc) return -1; + } + return 0; +} + +static SWIGINLINE void +SWIG_Perl_SetError(SWIG_MAYBE_PERL_OBJECT const char *error) { + if (error) sv_setpv(perl_get_sv("@", TRUE), error); +} + +static SWIGINLINE void +SWIG_Perl_SetErrorSV(SWIG_MAYBE_PERL_OBJECT SV *error) { + if (error) sv_setsv(perl_get_sv("@", TRUE), error); +} + +static void +SWIG_Perl_SetErrorf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + sv_vsetpvfn(perl_get_sv("@", TRUE), fmt, strlen(fmt), &args, Null(SV**), 0, Null(bool*)); + va_end(args); +} + +/* Macros for low-level exception handling */ +#define SWIG_fail goto fail +#define SWIG_croak(x) { SWIG_SetError(x); goto fail; } +#define SWIG_croakSV(x) { SWIG_SetErrorSV(x); goto fail; } +/* most preprocessors do not support vararg macros :-( */ +/* #define SWIG_croakf(x...) { SWIG_SetErrorf(x); goto fail; } */ + + +typedef XS(SwigPerlWrapper); +typedef SwigPerlWrapper *SwigPerlWrapperPtr; + +/* Structure for command table */ +typedef struct { + const char *name; + SwigPerlWrapperPtr wrapper; +} swig_command_info; + +/* Information for constant table */ + +#define SWIG_INT 1 +#define SWIG_FLOAT 2 +#define SWIG_STRING 3 +#define SWIG_POINTER 4 +#define SWIG_BINARY 5 + +/* Constant information structure */ +typedef struct swig_constant_info { + int type; + const char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_constant_info; + +#ifdef __cplusplus +} +#endif + +/* Structure for variable table */ +typedef struct { + const char *name; + SwigMagicFunc set; + SwigMagicFunc get; + swig_type_info **type; +} swig_variable_info; + +/* Magic variable code */ +#ifndef PERL_OBJECT +#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c) + #ifndef MULTIPLICITY + static void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) { + #else + static void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) { + #endif +#else +# define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c) +static void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) { +#endif + MAGIC *mg; + sv_magic(sv,sv,'U',(char *) name,strlen(name)); + mg = mg_find(sv,'U'); + mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL)); + mg->mg_virtual->svt_get = (SwigMagicFuncHack) get; + mg->mg_virtual->svt_set = (SwigMagicFuncHack) set; + mg->mg_virtual->svt_len = 0; + mg->mg_virtual->svt_clear = 0; + mg->mg_virtual->svt_free = 0; +} + + + + + + +#ifdef do_open + #undef do_open +#endif +#ifdef do_close + #undef do_close +#endif +#ifdef scalar + #undef scalar +#endif +#ifdef list + #undef list +#endif +#ifdef apply + #undef apply +#endif +#ifdef convert + #undef convert +#endif +#ifdef Error + #undef Error +#endif +#ifdef form + #undef form +#endif +#ifdef vform + #undef vform +#endif +#ifdef LABEL + #undef LABEL +#endif +#ifdef METHOD + #undef METHOD +#endif +#ifdef Move + #undef Move +#endif +#ifdef yylex + #undef yylex +#endif +#ifdef yyparse + #undef yyparse +#endif +#ifdef yyerror + #undef yyerror +#endif +#ifdef invert + #undef invert +#endif +#ifdef ref + #undef ref +#endif +#ifdef ENTER + #undef ENTER +#endif + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +static swig_type_info *swig_types[1]; + +/* -------- TYPES TABLE (END) -------- */ + +#define SWIG_init boot_DumpRenderTreeSupport + +#define SWIG_name "DumpRenderTreeSupportc::boot_DumpRenderTreeSupport" +#define SWIG_prefix "DumpRenderTreeSupportc::" + +#ifdef __cplusplus +extern "C" +#endif +#ifndef PERL_OBJECT +#ifndef MULTIPLICITY +SWIGEXPORT(void) SWIG_init (CV* cv); +#else +SWIGEXPORT(void) SWIG_init (pTHXo_ CV* cv); +#endif +#else +SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *); +#endif + +int processIsCrashing(int); +#ifdef PERL_OBJECT +#define MAGIC_CLASS _wrap_DumpRenderTreeSupport_var:: +class _wrap_DumpRenderTreeSupport_var : public CPerlObj { +public: +#else +#define MAGIC_CLASS +#endif +SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *sv, MAGIC *mg) { + MAGIC_PPERL + sv = sv; mg = mg; + croak("Value is read-only."); + return 0; +} + + +#ifdef PERL_OBJECT +}; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +XS(_wrap_processIsCrashing) { + { + int arg1 ; + int result; + int argvi = 0; + dXSARGS; + + if ((items < 1) || (items > 1)) { + SWIG_croak("Usage: processIsCrashing(pid);"); + } + arg1 = (int) SvIV(ST(0)); + result = (int)processIsCrashing(arg1); + + ST(argvi) = sv_newmortal(); + sv_setiv(ST(argvi++), (IV) result); + XSRETURN(argvi); + fail: + ; + } + croak(Nullch); +} + + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + + +static swig_type_info *swig_types_initial[] = { +0 +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_constant_info swig_constants[] = { +{0,0,0,0,0,0} +}; +#ifdef __cplusplus +} +#endif +static swig_variable_info swig_variables[] = { +{0,0,0,0} +}; +static swig_command_info swig_commands[] = { +{"DumpRenderTreeSupportc::processIsCrashing", _wrap_processIsCrashing}, +{0,0} +}; + + +static void SWIG_Perl_SetTypeListHandle(swig_type_info **handle) { + SV *pointer; + + /* create a new pointer */ + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE); + sv_setiv(pointer, PTR2IV(swig_type_list_handle)); +} + +static swig_type_info ** +SWIG_Perl_LookupTypePointer(swig_type_info **type_list_handle) { + swig_type_info **type_pointer; + + /* first check if module already created */ + type_pointer = SWIG_Perl_GetTypeListHandle(); + if (type_pointer) { + return type_pointer; + } else { + /* create a new module and variable */ + SWIG_Perl_SetTypeListHandle(type_list_handle); + return type_list_handle; + } +} + + +#ifdef __cplusplus +extern "C" +#endif + +XS(SWIG_init) { + dXSARGS; + int i; + static int _init = 0; + if (!_init) { + swig_type_list_handle = SWIG_Perl_LookupTypePointer(swig_type_list_handle); + for (i = 0; swig_types_initial[i]; i++) { + swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]); + } + _init = 1; + } + + /* Install commands */ + for (i = 0; swig_commands[i].name; i++) { + newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__); + } + + /* Install variables */ + for (i = 0; swig_variables[i].name; i++) { + SV *sv; + sv = perl_get_sv((char*) swig_variables[i].name, TRUE | 0x2); + if (swig_variables[i].type) { + SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0); + } else { + sv_setiv(sv,(IV) 0); + } + swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); + } + + /* Install constant */ + for (i = 0; swig_constants[i].type; i++) { + SV *sv; + sv = perl_get_sv((char*)swig_constants[i].name, TRUE | 0x2); + switch(swig_constants[i].type) { + case SWIG_INT: + sv_setiv(sv, (IV) swig_constants[i].lvalue); + break; + case SWIG_FLOAT: + sv_setnv(sv, (double) swig_constants[i].dvalue); + break; + case SWIG_STRING: + sv_setpv(sv, (char *) swig_constants[i].pvalue); + break; + case SWIG_POINTER: + SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0); + break; + case SWIG_BINARY: + SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype)); + break; + default: + break; + } + SvREADONLY_on(sv); + } + + ST(0) = &PL_sv_yes; + XSRETURN(1); +} + diff --git a/Tools/DumpRenderTree/mac/PerlSupport/Makefile b/Tools/DumpRenderTree/mac/PerlSupport/Makefile new file mode 100644 index 0000000..16a9e51 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PerlSupport/Makefile @@ -0,0 +1,74 @@ +# Copyright (C) 2009 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CONFIGURATION_BUILD_DIR ?= . +OUTPUT_DIR=$(CONFIGURATION_BUILD_DIR) + +WRAPPER_DIR=$(OUTPUT_DIR)/DerivedSources/DumpRenderTree +WRAPPER=$(WRAPPER_DIR)/DumpRenderTreeSupport_wrap.c +PERL_MODULE=$(OUTPUT_DIR)/DumpRenderTreeSupport.pm +DYLIB=$(OUTPUT_DIR)/DumpRenderTreeSupport.dylib +DUMPRENDERTREE=$(OUTPUT_DIR)/DumpRenderTree +PERL=/usr/bin/perl + +OSX_VERSION = $(shell sw_vers -productVersion | cut -d. -f 2) +ifeq "$(OSX_VERSION)" "4" +GENERATE_WRAPPER = NO +endif +ifeq "$(OSX_VERSION)" "7" +GENERATE_WRAPPER = NO +endif + +ifneq "$(GENERATE_WRAPPER)" "NO" + +SWIG=/usr/bin/swig + +all: $(DYLIB) $(PERL_MODULE) + +$(WRAPPER) $(PERL_MODULE): DumpRenderTreeSupport.c $(DUMPRENDERTREE) + mkdir -p $(WRAPPER_DIR) + $(SWIG) -o $(WRAPPER) -outdir $(OUTPUT_DIR) -perl -module DumpRenderTreeSupport $< + + +else + + +all: $(DYLIB) $(PERL_MODULE) + +$(WRAPPER): DumpRenderTreeSupport_wrapPregenerated.c $(DUMPRENDERTREE) + mkdir -p $(WRAPPER_DIR) + cp DumpRenderTreeSupport_wrapPregenerated.c $(WRAPPER) + +$(PERL_MODULE): DumpRenderTreeSupportPregenerated.pm $(DUMPRENDERTREE) + cp DumpRenderTreeSupportPregenerated.pm $(PERL_MODULE) + + +endif + +$(DYLIB): DumpRenderTreeSupport.c $(WRAPPER) + gcc -g -dynamiclib -o $(DYLIB) `$(PERL) -MExtUtils::Embed -eperl_inc` `$(PERL) -MExtUtils::Embed -eldopts` $^ + +clean: + rm -f $(WRAPPER) $(PERL_MODULE) $(DYLIB) + +installhdrs installsrc install: diff --git a/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm new file mode 100644 index 0000000..3967186 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PixelDumpSupport.h" +#include "PixelDumpSupportCG.h" + +#include "DumpRenderTree.h" +#include "LayoutTestController.h" +#include <CoreGraphics/CGBitmapContext.h> +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> + +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebKit.h> +#import <WebKit/WebViewPrivate.h> + +#if defined(BUILDING_ON_TIGER) +#include <OpenGL/OpenGL.h> +#include <OpenGL/CGLMacro.h> +#endif + +// To ensure pixel tests consistency, we need to always render in the same colorspace. +// Unfortunately, because of AppKit / WebKit constraints, we can't render directly in the colorspace of our choice. +// This implies we have to temporarily change the profile of the main display to the colorspace we want to render into. +// We also need to make sure the CGBitmapContext we return is in that same colorspace. + +#define PROFILE_PATH "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" // FIXME: This cannot be more than CS_MAX_PATH (256 characters) + +static CMProfileLocation sInitialProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase + +void restoreMainDisplayColorProfile(int ignored) +{ + // This is used as a signal handler, and thus the calls into ColorSync are unsafe + // But we might as well try to restore the user's color profile, we're going down anyway... + if (sInitialProfileLocation.locType != cmNoProfileBase) { + const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; + int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &sInitialProfileLocation); + if (error) + fprintf(stderr, "Failed to restore initial color profile for main display! Open System Preferences > Displays > Color and manually re-select the profile. (Error: %i)", error); + sInitialProfileLocation.locType = cmNoProfileBase; + } +} + +void setupMainDisplayColorProfile() +{ + const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; + int error; + + CMProfileRef profile = 0; + error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile); + if (!error) { + UInt32 size = sizeof(CMProfileLocation); + error = NCMGetProfileLocation(profile, &sInitialProfileLocation, &size); + CMCloseProfile(profile); + } + if (error) { + fprintf(stderr, "Failed to retrieve current color profile for main display, thus it won't be changed. Many pixel tests may fail as a result. (Error: %i)", error); + sInitialProfileLocation.locType = cmNoProfileBase; + return; + } + + CMProfileLocation location; + location.locType = cmPathBasedProfile; + strcpy(location.u.pathLoc.path, PROFILE_PATH); + error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location); + if (error) { + fprintf(stderr, "Failed to set color profile for main display! Many pixel tests may fail as a result. (Error: %i)", error); + sInitialProfileLocation.locType = cmNoProfileBase; + return; + } + + // Other signals are handled in installSignalHandlers() which also calls restoreMainDisplayColorProfile() + signal(SIGINT, restoreMainDisplayColorProfile); + signal(SIGHUP, restoreMainDisplayColorProfile); + signal(SIGTERM, restoreMainDisplayColorProfile); +} + +static PassRefPtr<BitmapContext> createBitmapContext(size_t pixelsWide, size_t pixelsHigh, size_t& rowBytes, void*& buffer) +{ + rowBytes = (4 * pixelsWide + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance + + buffer = calloc(pixelsHigh, rowBytes); + if (!buffer) + return 0; + + static CGColorSpaceRef colorSpace = 0; + if (!colorSpace) { + CMProfileLocation location; + location.locType = cmPathBasedProfile; + strcpy(location.u.pathLoc.path, PROFILE_PATH); + CMProfileRef profile; + if (CMOpenProfile(&profile, &location) == noErr) { + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(profile); + CMCloseProfile(profile); + } + } + + CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); // Use ARGB8 on PPC or BGRA8 on X86 to improve CG performance + if (!context) { + free(buffer); + return 0; + } + + return BitmapContext::createByAdoptingBitmapAndContext(buffer, context); +} + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) +{ + WebView* view = [mainFrame webView]; + + // If the WebHTMLView uses accelerated compositing, we need for force the on-screen capture path + // and also force Core Animation to start its animations with -display since the DRT window has autodisplay disabled. + if ([view _isUsingAcceleratedCompositing]) + onscreen = YES; + + NSSize webViewSize = [view frame].size; + size_t pixelsWide = static_cast<size_t>(webViewSize.width); + size_t pixelsHigh = static_cast<size_t>(webViewSize.height); + size_t rowBytes = 0; + void* buffer = 0; + RefPtr<BitmapContext> bitmapContext = createBitmapContext(pixelsWide, pixelsHigh, rowBytes, buffer); + if (!bitmapContext) + return 0; + CGContextRef context = bitmapContext->cgContext(); + + NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; + ASSERT(nsContext); + + if (incrementalRepaint) { + if (sweepHorizontally) { + for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++) + [view displayRectIgnoringOpacity:column inContext:nsContext]; + } else { + for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++) + [view displayRectIgnoringOpacity:line inContext:nsContext]; + } + } else { + + if (onscreen) { +#if !defined(BUILDING_ON_TIGER) + // displayIfNeeded does not update the CA layers if the layer-hosting view was not marked as needing display, so + // we're at the mercy of CA's display-link callback to update layers in time. So we need to force a display of the view + // to get AppKit to update the CA layers synchronously. + // FIXME: this will break repaint testing if we have compositing in repaint tests + // (displayWebView() painted gray over the webview, but we'll be making everything repaint again). + [view display]; + + // Ask the window server to provide us a composited version of the *real* window content including surfaces (i.e. OpenGL content) + // Note that the returned image might differ very slightly from the window backing because of dithering artifacts in the window server compositor + CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque); + CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); + CGImageRelease(image); +#else + // On 10.4 and earlier, we have to move the window temporarily "onscreen" and read directly from the display framebuffer using OpenGL + // In this code path, we need to ensure the window is above any other window or captured result will be corrupted + + NSWindow *window = [view window]; + int oldLevel = [window level]; + NSRect oldFrame = [window frame]; + + NSRect newFrame = [[[NSScreen screens] objectAtIndex:0] frame]; + newFrame = NSMakeRect(newFrame.origin.x + (newFrame.size.width - oldFrame.size.width) / 2, newFrame.origin.y + (newFrame.size.height - oldFrame.size.height) / 2, oldFrame.size.width, oldFrame.size.height); + [window setLevel:NSScreenSaverWindowLevel]; + [window setFrame:newFrame display:NO animate:NO]; + + CGRect rect = CGRectMake(newFrame.origin.x, newFrame.origin.y, webViewSize.width, webViewSize.height); + CGDirectDisplayID displayID; + CGDisplayCount count; + if (CGGetDisplaysWithRect(rect, 1, &displayID, &count) == kCGErrorSuccess) { + CGRect bounds = CGDisplayBounds(displayID); + rect.origin.x -= bounds.origin.x; + rect.origin.y -= bounds.origin.y; + + CGLPixelFormatAttribute attributes[] = {kCGLPFAAccelerated, kCGLPFANoRecovery, kCGLPFAFullScreen, kCGLPFADisplayMask, (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID), (CGLPixelFormatAttribute)0}; + CGLPixelFormatObj pixelFormat; + GLint num; + if (CGLChoosePixelFormat(attributes, &pixelFormat, &num) == kCGLNoError) { + CGLContextObj cgl_ctx; + if (CGLCreateContext(pixelFormat, 0, &cgl_ctx) == kCGLNoError) { + if (CGLSetFullScreen(cgl_ctx) == kCGLNoError) { + void *flipBuffer = calloc(pixelsHigh, rowBytes); + if (flipBuffer) { + glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4); + glPixelStorei(GL_PACK_ALIGNMENT, 4); +#if __BIG_ENDIAN__ + glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, flipBuffer); +#else + glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, flipBuffer); +#endif + if (!glGetError()) { + for(size_t i = 0; i < pixelsHigh; ++i) + bcopy((char*)flipBuffer + rowBytes * i, (char*)buffer + rowBytes * (pixelsHigh - i - 1), pixelsWide * 4); + } + + free(flipBuffer); + } + } + CGLDestroyContext(cgl_ctx); + } + CGLDestroyPixelFormat(pixelFormat); + } + } + + [window setFrame:oldFrame display:NO animate:NO]; + [window setLevel:oldLevel]; +#endif + } else { + // Make sure the view has been painted. + [view displayIfNeeded]; + + // Grab directly the contents of the window backing buffer (this ignores any surfaces on the window) + // FIXME: This path is suboptimal: data is read from window backing store, converted to RGB8 then drawn again into an RGBA8 bitmap + [view lockFocus]; + NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]] autorelease]; + [view unlockFocus]; + + RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; + [NSGraphicsContext setCurrentContext:nsContext]; + [imageRep draw]; + [NSGraphicsContext setCurrentContext:savedContext.get()]; + } + } + + if (drawSelectionRect) { + NSView *documentView = [[mainFrame frameView] documentView]; + ASSERT([documentView conformsToProtocol:@protocol(WebDocumentSelection)]); + NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil]; + CGContextSaveGState(context); + CGContextSetLineWidth(context, 1.0); + CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); + CGContextStrokeRect(context, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); + CGContextRestoreGState(context); + } + + return bitmapContext.release(); +} + +PassRefPtr<BitmapContext> createPagedBitmapContext() +{ + int pageWidthInPixels = LayoutTestController::maxViewWidth; + int pageHeightInPixels = LayoutTestController::maxViewHeight; + int numberOfPages = [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels]; + size_t rowBytes = 0; + void* buffer = 0; + + RefPtr<BitmapContext> bitmapContext = createBitmapContext(pageWidthInPixels, numberOfPages * (pageHeightInPixels + 1) - 1, rowBytes, buffer); + [mainFrame printToCGContext:bitmapContext->cgContext():pageWidthInPixels:pageHeightInPixels]; + return bitmapContext.release(); +} diff --git a/Tools/DumpRenderTree/mac/PlainTextController.h b/Tools/DumpRenderTree/mac/PlainTextController.h new file mode 100644 index 0000000..1488f2f --- /dev/null +++ b/Tools/DumpRenderTree/mac/PlainTextController.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +@interface PlainTextController : NSObject ++ (PlainTextController *)sharedPlainTextController; +@end diff --git a/Tools/DumpRenderTree/mac/PlainTextController.mm b/Tools/DumpRenderTree/mac/PlainTextController.mm new file mode 100644 index 0000000..eb89bce --- /dev/null +++ b/Tools/DumpRenderTree/mac/PlainTextController.mm @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "PlainTextController.h" + +#import <WebKit/WebKit.h> + +@implementation PlainTextController + ++ (PlainTextController *)sharedPlainTextController +{ + static PlainTextController *controller = [[PlainTextController alloc] init]; + return controller; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector +{ + if (selector == @selector(plainTextForRange:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)selector +{ + if (selector == @selector(plainTextForRange:)) + return @"plainText"; + return nil; +} + +- (NSString *)plainTextForRange:(DOMRange *)range +{ + if (![range isKindOfClass:[DOMRange class]]) + return nil; + return [range text]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.h b/Tools/DumpRenderTree/mac/PolicyDelegate.h new file mode 100644 index 0000000..3b95455 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PolicyDelegate.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +class LayoutTestController; + +@interface PolicyDelegate : NSObject { + BOOL permissiveDelegate; + LayoutTestController* controllerToNotifyDone; +} + +- (void)setPermissive:(BOOL)permissive; +- (void)setControllerToNotifyDone:(LayoutTestController*)controller; + +@end diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.mm b/Tools/DumpRenderTree/mac/PolicyDelegate.mm new file mode 100644 index 0000000..6935ea7 --- /dev/null +++ b/Tools/DumpRenderTree/mac/PolicyDelegate.mm @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "PolicyDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/DOMElement.h> +#import <WebKit/WebPolicyDelegate.h> +#import <WebKit/WebView.h> + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface DOMNode (dumpPath) +- (NSString *)dumpPath; +@end + +@implementation PolicyDelegate + +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation + request:(NSURLRequest *)request + frame:(WebFrame *)frame + decisionListener:(id<WebPolicyDecisionListener>)listener +{ + WebNavigationType navType = (WebNavigationType)[[actionInformation objectForKey:WebActionNavigationTypeKey] intValue]; + + const char* typeDescription; + switch (navType) { + case WebNavigationTypeLinkClicked: + typeDescription = "link clicked"; + break; + case WebNavigationTypeFormSubmitted: + typeDescription = "form submitted"; + break; + case WebNavigationTypeBackForward: + typeDescription = "back/forward"; + break; + case WebNavigationTypeReload: + typeDescription = "reload"; + break; + case WebNavigationTypeFormResubmitted: + typeDescription = "form resubmitted"; + break; + case WebNavigationTypeOther: + typeDescription = "other"; + break; + default: + typeDescription = "illegal value"; + } + + NSString *message = [NSString stringWithFormat:@"Policy delegate: attempt to load %@ with navigation type '%s'", [[request URL] _drt_descriptionSuitableForTestResult], typeDescription]; + + if (DOMElement *originatingNode = [[actionInformation objectForKey:WebActionElementKey] objectForKey:WebElementDOMNodeKey]) + message = [message stringByAppendingFormat:@" originating from %@", [originatingNode dumpPath]]; + + printf("%s\n", [message UTF8String]); + + if (permissiveDelegate) + [listener use]; + else + [listener ignore]; + + if (controllerToNotifyDone) { + controllerToNotifyDone->notifyDone(); + controllerToNotifyDone = 0; + } +} + +- (void)webView:(WebView *)webView unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame +{ + NSString *message = [NSString stringWithFormat:@"Policy delegate: unable to implement policy with error domain '%@', error code %d, in frame '%@'", [error domain], [error code], [frame name]]; + printf("%s\n", [message UTF8String]); +} + +- (void)setPermissive:(BOOL)permissive +{ + permissiveDelegate = permissive; +} + +- (void)setControllerToNotifyDone:(LayoutTestController*)controller +{ + controllerToNotifyDone = controller; +} + +@end diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h new file mode 100644 index 0000000..0c4618e --- /dev/null +++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + + +@interface ResourceLoadDelegate : NSObject { +} + +@end diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm new file mode 100644 index 0000000..0855b83 --- /dev/null +++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2007, Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ResourceLoadDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/WebKit.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebDataSourcePrivate.h> +#import <wtf/Assertions.h> + +using namespace std; + +@interface NSURL (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLResponse (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@interface NSURLRequest (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult; +@end + +@implementation NSError (DRTExtras) +- (NSString *)_drt_descriptionSuitableForTestResult +{ + NSString *str = [NSString stringWithFormat:@"<NSError domain %@, code %d", [self domain], [self code]]; + NSURL *failingURL; + + if ((failingURL = [[self userInfo] objectForKey:@"NSErrorFailingURLKey"])) + str = [str stringByAppendingFormat:@", failing URL \"%@\"", [failingURL _drt_descriptionSuitableForTestResult]]; + + str = [str stringByAppendingFormat:@">"]; + + return str; +} + +@end + +@implementation NSURL (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + if (![self isFileURL]) + return [self absoluteString]; + + WebDataSource *dataSource = [mainFrame dataSource]; + if (!dataSource) + dataSource = [mainFrame provisionalDataSource]; + + NSString *basePath = [[[[dataSource request] URL] path] stringByDeletingLastPathComponent]; + + return [[self path] substringFromIndex:[basePath length] + 1]; +} + +@end + +@implementation NSURLResponse (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + int statusCode = 0; + if ([self isKindOfClass:[NSHTTPURLResponse class]]) + statusCode = [(NSHTTPURLResponse *)self statusCode]; + return [NSString stringWithFormat:@"<NSURLResponse %@, http status code %i>", [[self URL] _drt_descriptionSuitableForTestResult], statusCode]; +} + +@end + +@implementation NSURLRequest (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + NSString *httpMethod = [self HTTPMethod]; + if (!httpMethod) + httpMethod = @"(none)"; + return [NSString stringWithFormat:@"<NSURLRequest URL %@, main document URL %@, http method %@>", [[self URL] _drt_descriptionSuitableForTestResult], [[self mainDocumentURL] _drt_descriptionSuitableForTestResult], httpMethod]; +} + +@end + +@implementation ResourceLoadDelegate + +- webView: (WebView *)wv identifierForInitialRequest: (NSURLRequest *)request fromDataSource: (WebDataSource *)dataSource +{ + ASSERT([[dataSource webFrame] dataSource] || [[dataSource webFrame] provisionalDataSource]); + + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) + return [[request URL] _drt_descriptionSuitableForTestResult]; + + return @"<unknown>"; +} + +-(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [request _drt_descriptionSuitableForTestResult], + [redirectResponse _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + + if (!done && !gLayoutTestController->deferMainResourceDataLoad()) { + [dataSource _setDeferMainResourceDataLoad:false]; + } + + if (!done && gLayoutTestController->willSendRequestReturnsNull()) + return nil; + + if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) { + printf("Returning null for this redirect\n"); + return nil; + } + + NSURL *url = [request URL]; + NSString *host = [url host]; + if (host + && (NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"http"] || NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"https"]) + && NSOrderedSame != [host compare:@"127.0.0.1"] + && NSOrderedSame != [host compare:@"255.255.255.255"] // used in some tests that expect to get back an error + && NSOrderedSame != [host caseInsensitiveCompare:@"localhost"]) { + printf("Blocked access to external URL %s\n", [[url absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]); + return nil; + } + + if (disallowedURLs && CFSetContainsValue(disallowedURLs, url)) + return nil; + + NSMutableURLRequest *newRequest = [request mutableCopy]; + const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); + for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) { + NSString *nsHeader = [[NSString alloc] initWithUTF8String:header->c_str()]; + [newRequest setValue:nil forHTTPHeaderField:nsHeader]; + [nsHeader release]; + } + + return [newRequest autorelease]; +} + +- (void)webView:(WebView *)wv resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource +{ + if (!gLayoutTestController->handlesAuthenticationChallenges()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet", identifier]; + printf("%s\n", [string UTF8String]); + + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + return; + } + + const char* user = gLayoutTestController->authenticationUsername().c_str(); + NSString *nsUser = [NSString stringWithFormat:@"%s", user ? user : ""]; + + const char* password = gLayoutTestController->authenticationPassword().c_str(); + NSString *nsPassword = [NSString stringWithFormat:@"%s", password ? password : ""]; + + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Responding with %@:%@", identifier, nsUser, nsPassword]; + printf("%s\n", [string UTF8String]); + + [[challenge sender] useCredential:[NSURLCredential credentialWithUser:nsUser password:nsPassword persistence:NSURLCredentialPersistenceForSession] + forAuthenticationChallenge:challenge]; +} + +- (void)webView:(WebView *)wv resource:(id)identifier didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource +{ +} + +-(void)webView: (WebView *)wv resource:identifier didReceiveResponse: (NSURLResponse *)response fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveResponse %@", identifier, [response _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } + if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) + printf("%s has MIME type %s\n", [[[[response URL] relativePath] lastPathComponent] UTF8String], [[response MIMEType] UTF8String]); +} + +-(void)webView: (WebView *)wv resource:identifier didReceiveContentLength: (NSInteger)length fromDataSource:(WebDataSource *)dataSource +{ +} + +-(void)webView: (WebView *)wv resource:identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoading", identifier]; + printf("%s\n", [string UTF8String]); + } +} + +-(void)webView: (WebView *)wv resource:identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadingWithError: %@", identifier, [error _drt_descriptionSuitableForTestResult]]; + printf("%s\n", [string UTF8String]); + } +} + +- (void)webView: (WebView *)wv plugInFailedWithError:(NSError *)error dataSource:(WebDataSource *)dataSource +{ + // The call to -display here simulates the "Plug-in not found" sheet that Safari shows. + // It is used for platform/mac/plugins/update-widget-from-style-recalc.html + [wv display]; +} + +-(NSCachedURLResponse *) webView: (WebView *)wv resource:(id)identifier willCacheResponse:(NSCachedURLResponse *)response fromDataSource:(WebDataSource *)dataSource +{ + if (!done && gLayoutTestController->dumpWillCacheResponse()) { + NSString *string = [NSString stringWithFormat:@"%@ - willCacheResponse: called", identifier]; + printf("%s\n", [string UTF8String]); + } + return response; +} + +@end diff --git a/Tools/DumpRenderTree/mac/TextInputController.h b/Tools/DumpRenderTree/mac/TextInputController.h new file mode 100644 index 0000000..767e72f --- /dev/null +++ b/Tools/DumpRenderTree/mac/TextInputController.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> + +@class WebView; +@class WebHTMLView; +@class WebScriptObject; + +@interface TextInputController : NSObject +{ + WebView *webView; + WebHTMLView *inputMethodView; + WebScriptObject *inputMethodHandler; +} +- (id)initWithWebView:(WebView *)view; +@end diff --git a/Tools/DumpRenderTree/mac/TextInputController.m b/Tools/DumpRenderTree/mac/TextInputController.m new file mode 100644 index 0000000..f780794 --- /dev/null +++ b/Tools/DumpRenderTree/mac/TextInputController.m @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "TextInputController.h" + +#import "DumpRenderTreeMac.h" +#import <AppKit/NSInputManager.h> +#import <WebKit/WebDocument.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebTypesInternal.h> +#import <WebKit/WebView.h> + +@interface TextInputController (DumpRenderTreeInputMethodHandler) +- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender; +@end + +@interface WebHTMLView (DumpRenderTreeInputMethodHandler) +- (void)interpretKeyEvents:(NSArray *)eventArray; +@end + +@interface WebHTMLView (WebKitSecretsTextInputControllerIsAwareOf) +- (WebFrame *)_frame; +@end + +@implementation WebHTMLView (DumpRenderTreeInputMethodHandler) +- (void)interpretKeyEvents:(NSArray *)eventArray +{ + WebScriptObject *obj = [[self _frame] windowObject]; + TextInputController *tic = [obj valueForKey:@"textInputController"]; + if (![tic interpretKeyEvents:eventArray withSender:self]) + [super interpretKeyEvents:eventArray]; +} +@end + +@implementation NSMutableAttributedString (TextInputController) + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(string) + || aSelector == @selector(getLength) + || aSelector == @selector(attributeNamesAtIndex:) + || aSelector == @selector(valueOfAttribute:atIndex:) + || aSelector == @selector(addAttribute:value:) + || aSelector == @selector(addAttribute:value:from:length:) + || aSelector == @selector(addColorAttribute:red:green:blue:alpha:) + || aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:) + || aSelector == @selector(addFontAttribute:fontName:size:) + || aSelector == @selector(addFontAttribute:fontName:size:from:length:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(getLength)) + return @"length"; + if (aSelector == @selector(attributeNamesAtIndex:)) + return @"getAttributeNamesAtIndex"; + if (aSelector == @selector(valueOfAttribute:atIndex:)) + return @"getAttributeValueAtIndex"; + if (aSelector == @selector(addAttribute:value:)) + return @"addAttribute"; + if (aSelector == @selector(addAttribute:value:from:length:)) + return @"addAttributeForRange"; + if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:)) + return @"addColorAttribute"; + if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:)) + return @"addColorAttributeForRange"; + if (aSelector == @selector(addFontAttribute:fontName:size:)) + return @"addFontAttribute"; + if (aSelector == @selector(addFontAttribute:fontName:size:from:length:)) + return @"addFontAttributeForRange"; + + return nil; +} + +- (int)getLength +{ + return (int)[self length]; +} + +- (NSArray *)attributeNamesAtIndex:(int)index +{ + NSDictionary *attributes = [self attributesAtIndex:(unsigned)index effectiveRange:nil]; + return [attributes allKeys]; +} + +- (id)valueOfAttribute:(NSString *)attrName atIndex:(int)index +{ + return [self attribute:attrName atIndex:(unsigned)index effectiveRange:nil]; +} + +- (void)addAttribute:(NSString *)attrName value:(id)value +{ + [self addAttribute:attrName value:value range:NSMakeRange(0, [self length])]; +} + +- (void)addAttribute:(NSString *)attrName value:(id)value from:(int)from length:(int)length +{ + [self addAttribute:attrName value:value range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha +{ + [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange(0, [self length])]; +} + +- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha from:(int)from length:(int)length +{ + [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize +{ + [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange(0, [self length])]; +} + +- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize from:(int)from length:(int)length +{ + [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange((unsigned)from, (unsigned)length)]; +} + +@end + +@implementation TextInputController + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + if (aSelector == @selector(insertText:) + || aSelector == @selector(doCommand:) + || aSelector == @selector(setMarkedText:selectedFrom:length:) + || aSelector == @selector(unmarkText) + || aSelector == @selector(hasMarkedText) + || aSelector == @selector(conversationIdentifier) + || aSelector == @selector(substringFrom:length:) + || aSelector == @selector(attributedSubstringFrom:length:) + || aSelector == @selector(markedRange) + || aSelector == @selector(selectedRange) + || aSelector == @selector(firstRectForCharactersFrom:length:) + || aSelector == @selector(characterIndexForPointX:Y:) + || aSelector == @selector(validAttributesForMarkedText) + || aSelector == @selector(attributedStringWithString:) + || aSelector == @selector(setInputMethodHandler:)) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(insertText:)) + return @"insertText"; + else if (aSelector == @selector(doCommand:)) + return @"doCommand"; + else if (aSelector == @selector(setMarkedText:selectedFrom:length:)) + return @"setMarkedText"; + else if (aSelector == @selector(substringFrom:length:)) + return @"substringFromRange"; + else if (aSelector == @selector(attributedSubstringFrom:length:)) + return @"attributedSubstringFromRange"; + else if (aSelector == @selector(firstRectForCharactersFrom:length:)) + return @"firstRectForCharacterRange"; + else if (aSelector == @selector(characterIndexForPointX:Y:)) + return @"characterIndexForPoint"; + else if (aSelector == @selector(attributedStringWithString:)) + return @"makeAttributedString"; // just a factory method, doesn't call into NSTextInput + else if (aSelector == @selector(setInputMethodHandler:)) + return @"setInputMethodHandler"; + + return nil; +} + +- (id)initWithWebView:(WebView *)wv +{ + self = [super init]; + webView = wv; + inputMethodView = nil; + inputMethodHandler = nil; + return self; +} + +- (void)dealloc +{ + [inputMethodHandler release]; + inputMethodHandler = nil; + + [super dealloc]; +} + +- (NSObject <NSTextInput> *)textInput +{ + NSView <NSTextInput> *view = inputMethodView ? inputMethodView : (id)[[[webView mainFrame] frameView] documentView]; + return [view conformsToProtocol:@protocol(NSTextInput)] ? view : nil; +} + +- (void)insertText:(id)aString +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput insertText:aString]; +} + +- (void)doCommand:(NSString *)aCommand +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput doCommandBySelector:NSSelectorFromString(aCommand)]; +} + +- (void)setMarkedText:(NSString *)aString selectedFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput setMarkedText:aString selectedRange:NSMakeRange(from, length)]; +} + +- (void)unmarkText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + [textInput unmarkText]; +} + +- (BOOL)hasMarkedText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput hasMarkedText]; + + return FALSE; +} + +- (long)conversationIdentifier +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput conversationIdentifier]; + + return 0; +} + +- (NSString *)substringFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [[textInput attributedSubstringFromRange:NSMakeRange(from, length)] string]; + + return @""; +} + +- (NSMutableAttributedString *)attributedSubstringFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + NSMutableAttributedString *ret = [[[NSMutableAttributedString alloc] init] autorelease]; + + if (textInput) + [ret setAttributedString:[textInput attributedSubstringFromRange:NSMakeRange(from, length)]]; + + return ret; +} + +- (NSArray *)markedRange +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRange range = [textInput markedRange]; + return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil]; + } + + return nil; +} + +- (NSArray *)selectedRange +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRange range = [textInput selectedRange]; + return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil]; + } + + return nil; +} + + +- (NSArray *)firstRectForCharactersFrom:(int)from length:(int)length +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSRect rect = [textInput firstRectForCharacterRange:NSMakeRange(from, length)]; + if (rect.origin.x || rect.origin.y || rect.size.width || rect.size.height) { + rect.origin = [[webView window] convertScreenToBase:rect.origin]; + rect = [webView convertRect:rect fromView:nil]; + } + return [NSArray arrayWithObjects: + [NSNumber numberWithFloat:rect.origin.x], + [NSNumber numberWithFloat:rect.origin.y], + [NSNumber numberWithFloat:rect.size.width], + [NSNumber numberWithFloat:rect.size.height], + nil]; + } + + return nil; +} + +- (NSInteger)characterIndexForPointX:(float)x Y:(float)y +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) { + NSPoint point = NSMakePoint(x, y); + point = [webView convertPoint:point toView:nil]; + point = [[webView window] convertBaseToScreen:point]; + NSInteger index = [textInput characterIndexForPoint:point]; + if (index == NSNotFound) + return -1; + + return index; + } + + return 0; +} + +- (NSArray *)validAttributesForMarkedText +{ + NSObject <NSTextInput> *textInput = [self textInput]; + + if (textInput) + return [textInput validAttributesForMarkedText]; + + return nil; +} + +- (NSMutableAttributedString *)attributedStringWithString:(NSString *)aString +{ + return [[[NSMutableAttributedString alloc] initWithString:aString] autorelease]; +} + +- (void)setInputMethodHandler:(WebScriptObject *)handler +{ + if (inputMethodHandler == handler) + return; + [handler retain]; + [inputMethodHandler release]; + inputMethodHandler = handler; +} + +- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender +{ + if (!inputMethodHandler) + return NO; + + inputMethodView = sender; + + NSEvent *event = [eventArray objectAtIndex:0]; + unsigned modifierFlags = [event modifierFlags]; + NSMutableArray *modifiers = [[NSMutableArray alloc] init]; + if (modifierFlags & NSAlphaShiftKeyMask) + [modifiers addObject:@"NSAlphaShiftKeyMask"]; + if (modifierFlags & NSShiftKeyMask) + [modifiers addObject:@"NSShiftKeyMask"]; + if (modifierFlags & NSControlKeyMask) + [modifiers addObject:@"NSControlKeyMask"]; + if (modifierFlags & NSAlternateKeyMask) + [modifiers addObject:@"NSAlternateKeyMask"]; + if (modifierFlags & NSCommandKeyMask) + [modifiers addObject:@"NSCommandKeyMask"]; + if (modifierFlags & NSNumericPadKeyMask) + [modifiers addObject:@"NSNumericPadKeyMask"]; + if (modifierFlags & NSHelpKeyMask) + [modifiers addObject:@"NSHelpKeyMask"]; + if (modifierFlags & NSFunctionKeyMask) + [modifiers addObject:@"NSFunctionKeyMask"]; + + WebScriptObject* eventParam = [inputMethodHandler evaluateWebScript:@"new Object();"]; + [eventParam setValue:[event characters] forKey:@"characters"]; + [eventParam setValue:[event charactersIgnoringModifiers] forKey:@"charactersIgnoringModifiers"]; + [eventParam setValue:[NSNumber numberWithBool:[event isARepeat]] forKey:@"isARepeat"]; + [eventParam setValue:[NSNumber numberWithUnsignedShort:[event keyCode]] forKey:@"keyCode"]; + [eventParam setValue:modifiers forKey:@"modifierFlags"]; + + [modifiers release]; + + id result = [inputMethodHandler callWebScriptMethod:@"call" withArguments:[NSArray arrayWithObjects:inputMethodHandler, eventParam, nil]]; + if (![result respondsToSelector:@selector(boolValue)] || ![result boolValue]) + [sender doCommandBySelector:@selector(noop:)]; // AppKit sends noop: if the ime does not handle an event + + inputMethodView = nil; + return YES; +} + +@end diff --git a/Tools/DumpRenderTree/mac/UIDelegate.h b/Tools/DumpRenderTree/mac/UIDelegate.h new file mode 100644 index 0000000..a8017ad --- /dev/null +++ b/Tools/DumpRenderTree/mac/UIDelegate.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@interface UIDelegate : NSObject { + +@private + NSRect m_frame; + NSMutableSet *m_pendingGeolocationPermissionListeners; + NSTimer *m_timer; +} + +- (void)didSetMockGeolocationPermission; + +@end diff --git a/Tools/DumpRenderTree/mac/UIDelegate.mm b/Tools/DumpRenderTree/mac/UIDelegate.mm new file mode 100644 index 0000000..6194c26 --- /dev/null +++ b/Tools/DumpRenderTree/mac/UIDelegate.mm @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2006. 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "UIDelegate.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" +#import "EventSendingController.h" +#import "LayoutTestController.h" +#import <WebKit/WebApplicationCache.h> +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebQuotaManager.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebUIDelegatePrivate.h> +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> +#import <wtf/Assertions.h> + +DumpRenderTreeDraggingInfo *draggingInfo = nil; + +@implementation UIDelegate + +- (void)webView:(WebView *)sender setFrame:(NSRect)frame +{ + m_frame = frame; +} + +- (NSRect)webViewFrame:(WebView *)sender +{ + return m_frame; +} + +- (void)webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary +{ + NSString *message = [dictionary objectForKey:@"message"]; + NSNumber *lineNumber = [dictionary objectForKey:@"lineNumber"]; + + NSRange range = [message rangeOfString:@"file://"]; + if (range.location != NSNotFound) + message = [[message substringToIndex:range.location] stringByAppendingString:[[message substringFromIndex:NSMaxRange(range)] lastPathComponent]]; + + printf ("CONSOLE MESSAGE: line %d: %s\n", [lineNumber intValue], [message UTF8String]); +} + +- (void)modalWindowWillClose:(NSNotification *)notification +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:nil]; + [NSApp abortModal]; +} + +- (void)webViewRunModal:(WebView *)sender +{ + gLayoutTestController->setWindowIsKey(false); + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modalWindowWillClose:) name:NSWindowWillCloseNotification object:nil]; + [NSApp runModalForWindow:[sender window]]; + gLayoutTestController->setWindowIsKey(true); +} + +- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("ALERT: %s\n", [message UTF8String]); +} + +- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("CONFIRM: %s\n", [message UTF8String]); + return YES; +} + +- (NSString *)webView:(WebView *)sender runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("PROMPT: %s, default text: %s\n", [prompt UTF8String], [defaultText UTF8String]); + return defaultText; +} + +- (BOOL)webView:(WebView *)c runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + if (!done) + printf("CONFIRM NAVIGATION: %s\n", [message UTF8String]); + return YES; +} + + +- (void)webView:(WebView *)sender dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag forView:(NSView *)view +{ + assert(!draggingInfo); + draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj]; + [sender draggingUpdated:draggingInfo]; + [EventSendingController replaySavedEvents]; +} + +- (void)webViewFocus:(WebView *)webView +{ + gLayoutTestController->setWindowIsKey(true); +} + +- (void)webViewUnfocus:(WebView *)webView +{ + gLayoutTestController->setWindowIsKey(false); +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request +{ + if (!gLayoutTestController->canOpenWindows()) + return nil; + + // Make sure that waitUntilDone has been called. + ASSERT(gLayoutTestController->waitToDump()); + + WebView *webView = createWebViewAndOffscreenWindow(); + + if (gLayoutTestController->newWindowsCopyBackForwardList()) + [webView _loadBackForwardListFromOtherView:sender]; + + return [webView autorelease]; +} + +- (void)webViewClose:(WebView *)sender +{ + NSWindow* window = [sender window]; + + if (gLayoutTestController->callCloseOnWebViews()) + [sender close]; + + [window close]; +} + +- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier +{ + if (!done && gLayoutTestController->dumpDatabaseCallbacks()) { + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin host] UTF8String], + [origin port], [databaseIdentifier UTF8String]); + } + + static const unsigned long long defaultQuota = 5 * 1024 * 1024; + [[origin databaseQuotaManager] setQuota:defaultQuota]; +} + +- (void)webView:(WebView *)sender exceededApplicationCacheOriginQuotaForSecurityOrigin:(WebSecurityOrigin *)origin +{ + if (!done && gLayoutTestController->dumpApplicationCacheDelegateCallbacks()) { + printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i}\n", + [[origin protocol] UTF8String], [[origin host] UTF8String], [origin port]); + } + + static const unsigned long long defaultOriginQuota = [WebApplicationCache defaultOriginQuota]; + [[origin applicationCacheQuotaManager] setQuota:defaultOriginQuota]; +} + +- (void)webView:(WebView *)sender setStatusText:(NSString *)text +{ + if (gLayoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]); +} + +- (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebGeolocationPolicyListener>)listener +{ + if (!gLayoutTestController->isGeolocationPermissionSet()) { + if (!m_pendingGeolocationPermissionListeners) + m_pendingGeolocationPermissionListeners = [[NSMutableSet set] retain]; + [m_pendingGeolocationPermissionListeners addObject:listener]; + return; + } + + if (gLayoutTestController->geolocationPermission()) + [listener allow]; + else + [listener deny]; +} + +- (void)didSetMockGeolocationPermission +{ + ASSERT(gLayoutTestController->isGeolocationPermissionSet()); + if (m_pendingGeolocationPermissionListeners && !m_timer) + m_timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)timerFired +{ + ASSERT(gLayoutTestController->isGeolocationPermissionSet()); + m_timer = 0; + NSEnumerator* enumerator = [m_pendingGeolocationPermissionListeners objectEnumerator]; + id<WebGeolocationPolicyListener> listener; + while ((listener = [enumerator nextObject])) { + if (gLayoutTestController->geolocationPermission()) + [listener allow]; + else + [listener deny]; + } + [m_pendingGeolocationPermissionListeners removeAllObjects]; + [m_pendingGeolocationPermissionListeners release]; + m_pendingGeolocationPermissionListeners = nil; +} + +- (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode +{ + return NO; +} + +- (BOOL)webView:(WebView *)webView supportsFullScreenForElement:(DOMElement*)element +{ + return YES; +} + +- (void)webView:(WebView *)webView enterFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener +{ + [listener webkitWillEnterFullScreen]; + [listener webkitDidEnterFullScreen]; +} + +- (void)webView:(WebView *)webView exitFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener +{ + [listener webkitWillExitFullScreen]; + [listener webkitDidExitFullScreen]; +} + +- (BOOL)webView:(WebView *)webView didPressMissingPluginButton:(DOMElement *)element +{ + printf("MISSING PLUGIN BUTTON PRESSED\n"); + return TRUE; +} + +- (void)dealloc +{ + [draggingInfo release]; + draggingInfo = nil; + [m_pendingGeolocationPermissionListeners release]; + m_pendingGeolocationPermissionListeners = nil; + + [super dealloc]; +} + +@end diff --git a/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm new file mode 100644 index 0000000..c273087 --- /dev/null +++ b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebArchiveDumpSupport.h" + +#import <CFNetwork/CFHTTPMessage.h> +#import <Foundation/Foundation.h> +#import <WebKit/WebHTMLRepresentation.h> +#import <wtf/RetainPtr.h> + +extern "C" { + +enum CFURLCacheStoragePolicy { + kCFURLCacheStorageAllowed = 0, + kCFURLCacheStorageAllowedInMemoryOnly = 1, + kCFURLCacheStorageNotAllowed = 2 +}; +typedef enum CFURLCacheStoragePolicy CFURLCacheStoragePolicy; + +extern const CFStringRef kCFHTTPVersion1_1; + +CFURLResponseRef CFURLResponseCreate(CFAllocatorRef alloc, CFURLRef URL, CFStringRef mimeType, SInt64 expectedContentLength, CFStringRef textEncodingName, CFURLCacheStoragePolicy recommendedPolicy); +CFURLResponseRef CFURLResponseCreateWithHTTPResponse(CFAllocatorRef alloc, CFURLRef URL, CFHTTPMessageRef httpResponse, CFURLCacheStoragePolicy recommendedPolicy); +void CFURLResponseSetExpectedContentLength(CFURLResponseRef response, SInt64 length); +void CFURLResponseSetMIMEType(CFURLResponseRef response, CFStringRef mimeType); + +} + +CFURLResponseRef createCFURLResponseFromResponseData(CFDataRef responseData) +{ + // Decode NSURLResponse + RetainPtr<NSKeyedUnarchiver> unarchiver(AdoptNS, [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)responseData]); + NSURLResponse *response = [unarchiver.get() decodeObjectForKey:@"WebResourceResponse"]; // WebResourceResponseKey in WebResource.m + [unarchiver.get() finishDecoding]; + + if (![response isKindOfClass:[NSHTTPURLResponse class]]) + return CFURLResponseCreate(kCFAllocatorDefault, (CFURLRef)[response URL], (CFStringRef)[response MIMEType], [response expectedContentLength], (CFStringRef)[response textEncodingName], kCFURLCacheStorageAllowed); + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + // NSURLResponse is not toll-free bridged to CFURLResponse. + RetainPtr<CFHTTPMessageRef> httpMessage(AdoptCF, CFHTTPMessageCreateResponse(kCFAllocatorDefault, [httpResponse statusCode], 0, kCFHTTPVersion1_1)); + + NSDictionary *headerFields = [httpResponse allHeaderFields]; + for (NSString *headerField in [headerFields keyEnumerator]) + CFHTTPMessageSetHeaderFieldValue(httpMessage.get(), (CFStringRef)headerField, (CFStringRef)[headerFields objectForKey:headerField]); + + return CFURLResponseCreateWithHTTPResponse(kCFAllocatorDefault, (CFURLRef)[response URL], httpMessage.get(), kCFURLCacheStorageAllowed); +} + +CFArrayRef supportedNonImageMIMETypes() +{ + return (CFArrayRef)[WebHTMLRepresentation supportedNonImageMIMETypes]; +} diff --git a/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm new file mode 100644 index 0000000..797afb7 --- /dev/null +++ b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "DumpRenderTree.h" +#import "WorkQueueItem.h" + +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebView.h> +#import <wtf/RetainPtr.h> + +bool LoadItem::invoke() const +{ + RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_url.get())); + NSString *urlNS = (NSString *)urlCF.get(); + RetainPtr<CFStringRef> targetCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_target.get())); + NSString *targetNS = (NSString *)targetCF.get(); + + WebFrame *targetFrame; + if (targetNS && [targetNS length]) + targetFrame = [mainFrame findFrameNamed:targetNS]; + else + targetFrame = mainFrame; + [targetFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlNS]]]; + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + RetainPtr<CFStringRef> contentCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_content.get())); + RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_baseURL.get())); + + [mainFrame loadHTMLString:(NSString *)contentCF.get() baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]]; + return true; +} + +bool ReloadItem::invoke() const +{ + [[mainFrame webView] reload:nil]; + return true; +} + +bool ScriptItem::invoke() const +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_script.get())); + NSString *scriptNS = (NSString *)scriptCF.get(); + [[mainFrame webView] stringByEvaluatingJavaScriptFromString:scriptNS]; + return true; +} + +bool BackForwardItem::invoke() const +{ + if (m_howFar == 1) + [[mainFrame webView] goForward]; + else if (m_howFar == -1) + [[mainFrame webView] goBack]; + else { + WebBackForwardList *bfList = [[mainFrame webView] backForwardList]; + [[mainFrame webView] goToBackForwardItem:[bfList itemAtIndex:m_howFar]]; + } + return true; +} |