diff options
author | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
---|---|---|
committer | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
commit | d8543bb6618c17b12da906afa77d216f58cf4058 (patch) | |
tree | c58dc05ed86825bd0ef8d305d58c8205106b540f /WebKitTools/DumpRenderTree/mac | |
download | external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2 |
external/webkit r30707
Diffstat (limited to 'WebKitTools/DumpRenderTree/mac')
43 files changed, 5284 insertions, 0 deletions
diff --git a/WebKitTools/DumpRenderTree/mac/AppleScriptController.h b/WebKitTools/DumpRenderTree/mac/AppleScriptController.h new file mode 100644 index 0000000..c29789c --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/AppleScriptController.m b/WebKitTools/DumpRenderTree/mac/AppleScriptController.m new file mode 100644 index 0000000..86d2881 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/AppleScriptController.m @@ -0,0 +1,126 @@ +/* + * 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 "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/WebKitTools/DumpRenderTree/mac/CheckedMalloc.cpp b/WebKitTools/DumpRenderTree/mac/CheckedMalloc.cpp new file mode 100644 index 0000000..467f1bb --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/CheckedMalloc.cpp @@ -0,0 +1,59 @@ +/* + * 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 "CheckedMalloc.h" + +#import <malloc/malloc.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(); + savedMalloc = zone->malloc; + savedRealloc = zone->realloc; + zone->malloc = checkedMalloc; + zone->realloc = checkedRealloc; +} diff --git a/WebKitTools/DumpRenderTree/mac/CheckedMalloc.h b/WebKitTools/DumpRenderTree/mac/CheckedMalloc.h new file mode 100644 index 0000000..c03bd20 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig new file mode 100644 index 0000000..d2291a0 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig @@ -0,0 +1,16 @@ +HEADER_SEARCH_PATHS = ForwardingHeaders +FRAMEWORK_SEARCH_PATHS = $(FRAMEWORK_SEARCH_PATHS_$(MAC_OS_X_VERSION_MAJOR)); +FRAMEWORK_SEARCH_PATHS_ = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks +FRAMEWORK_SEARCH_PATHS_1040 = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks +FRAMEWORK_SEARCH_PATHS_1050 = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks +FRAMEWORK_SEARCH_PATHS_1060 = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks +DEBUG_INFORMATION_FORMAT = dwarf +PREBINDING = NO +GCC_C_LANGUAGE_STANDARD = gnu99 +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 +VALID_ARCHS = ppc7400 ppc970 i386 ppc diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig new file mode 100644 index 0000000..e17439e --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig @@ -0,0 +1,5 @@ +#include "Base.xcconfig" +MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(MAC_OS_X_VERSION_MAJOR)) +MACOSX_DEPLOYMENT_TARGET_ = 10.4 +MACOSX_DEPLOYMENT_TARGET_1040 = 10.4 +MACOSX_DEPLOYMENT_TARGET_1050 = 10.5 diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig new file mode 100644 index 0000000..c8a7bdc --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig @@ -0,0 +1,4 @@ +OTHER_LDFLAGS = -sectcreate __DATA Ahem qt/fonts/AHEM____.TTF +PRODUCT_NAME = DumpRenderTree +GCC_ENABLE_OBJC_EXCEPTIONS = YES +GCC_PREFIX_HEADER = DumpRenderTreePrefix.h diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig new file mode 100644 index 0000000..fcd64c5 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig @@ -0,0 +1 @@ +PRODUCT_NAME = ImageDiff diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig new file mode 100644 index 0000000..ea17629 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig @@ -0,0 +1,6 @@ +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/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm new file mode 100644 index 0000000..4d5ea72 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm @@ -0,0 +1,931 @@ +/* + * Copyright (C) 2005, 2006, 2007 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 "DumpRenderTree.h" + +#import "CheckedMalloc.h" +#import "DumpRenderTreePasteboard.h" +#import "DumpRenderTreeWindow.h" +#import "EditingDelegate.h" +#import "EventSendingController.h" +#import "FrameLoadDelegate.h" +#import "JavaScriptThreading.h" +#import "LayoutTestController.h" +#import "NavigationController.h" +#import "ObjCPlugin.h" +#import "ObjCPluginFunction.h" +#import "PixelDumpSupport.h" +#import "PolicyDelegate.h" +#import "ResourceLoadDelegate.h" +#import "UIDelegate.h" +#import "WorkQueue.h" +#import "WorkQueueItem.h" +#import <CoreFoundation/CoreFoundation.h> +#import <WebKit/DOMElementPrivate.h> +#import <WebKit/DOMExtensions.h> +#import <WebKit/DOMRange.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebCoreStatistics.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebDataSourcePrivate.h> +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebEditingDelegate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebHistoryItemPrivate.h> +#import <WebKit/WebPluginDatabase.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebResourceLoadDelegate.h> +#import <WebKit/WebViewPrivate.h> +#import <getopt.h> +#import <mach-o/getsect.h> +#import <objc/objc-runtime.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> + +@interface DumpRenderTreeEvent : NSEvent +@end + +static void runTest(const char *pathOrURL); + +// 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* navigationController = 0; +LayoutTestController* layoutTestController = 0; + +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; +PolicyDelegate *policyDelegate; + +static int dumpPixels; +static int dumpAllPixels; +static int threaded; +static int testRepaintDefault; +static int repaintSweepHorizontallyDefault; +static int dumpTree = YES; +static BOOL printSeparators; +static NSString *currentTest = nil; +static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; + +static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test + +const unsigned maxViewHeight = 600; +const unsigned maxViewWidth = 800; + +void setPersistentUserStyleSheetLocation(CFStringRef url) +{ + persistentUserStyleSheetLocation = url; +} + +static BOOL shouldIgnoreWebCoreNodeLeaks(CFStringRef URLString) +{ + static CFStringRef const ignoreSet[] = { + // Keeping this infrastructure around in case we ever need it again. + }; + static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(CFStringRef); + + for (int i = 0; i < ignoreSetCount; i++) { + CFStringRef ignoreString = ignoreSet[i]; + CFRange range = CFRangeMake(0, CFStringGetLength(URLString)); + CFOptionFlags flags = kCFCompareAnchored | kCFCompareBackwards | kCFCompareCaseInsensitive; + if (CFStringFindWithOptions(URLString, ignoreString, range, flags, NULL)) + return YES; + } + return NO; +} + +static void activateAhemFont() +{ + unsigned long fontDataLength; + char* fontData = getsectdata("__DATA", "Ahem", &fontDataLength); + if (!fontData) { + fprintf(stderr, "Failed to locate the Ahem font.\n"); + exit(1); + } + + ATSFontContainerRef fontContainer; + OSStatus status = ATSFontActivateFromMemory(fontData, fontDataLength, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &fontContainer); + + if (status != noErr) { + fprintf(stderr, "Failed to activate the Ahem font.\n"); + exit(1); + } +} + +WebView *createWebViewAndOffscreenWindow() +{ + NSRect rect = NSMakeRect(0, 0, maxViewWidth, 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]; + + // 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]; + [[window contentView] addSubview:webView]; + [window orderBack:nil]; + [window setAutodisplay:NO]; + + // 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 void setDefaultsToConsistentValuesForTesting() +{ + // Give some clear to undocumented defaults values + static const int MediumFontSmoothing = 2; + static const int BlueTintedAppearance = 1; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; + [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on + [defaults setInteger:MediumFontSmoothing 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"]; + + NSString *libraryPath = [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath]; + [defaults setObject:[libraryPath stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey]; + + WebPreferences *preferences = [WebPreferences standardPreferences]; + + [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:1]; + [preferences setJavaEnabled:NO]; + [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey]; + [preferences setTabsToLinks:NO]; + [preferences setDOMPasteAllowed:YES]; + + // 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]; +} + +static void crashHandler(int sig) +{ + fprintf(stderr, "%s\n", strsignal(sig)); + restoreColorSpace(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 + navigationController = [[NavigationController alloc] init]; + frameLoadDelegate = [[FrameLoadDelegate alloc] init]; + uiDelegate = [[UIDelegate alloc] init]; + editingDelegate = [[EditingDelegate alloc] init]; + resourceLoadDelegate = [[ResourceLoadDelegate alloc] init]; + policyDelegate = [[PolicyDelegate 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(&navigationController); + releaseAndZero(&frameLoadDelegate); + releaseAndZero(&editingDelegate); + releaseAndZero(&resourceLoadDelegate); + releaseAndZero(&uiDelegate); + releaseAndZero(&policyDelegate); +} + +static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[]) +{ + struct option options[] = { + {"dump-all-pixels", no_argument, &dumpAllPixels, YES}, + {"horizontal-sweep", no_argument, &repaintSweepHorizontallyDefault, YES}, + {"notree", no_argument, &dumpTree, NO}, + {"pixel-tests", no_argument, &dumpPixels, YES}, + {"repaint", no_argument, &testRepaintDefault, YES}, + {"tree", no_argument, &dumpTree, YES}, + {"threaded", no_argument, &threaded, 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() +{ + class_poseAs(objc_getClass("DumpRenderTreePasteboard"), objc_getClass("NSPasteboard")); + class_poseAs(objc_getClass("DumpRenderTreeEvent"), objc_getClass("NSEvent")); + + setDefaultsToConsistentValuesForTesting(); + activateAhemFont(); + + if (dumpPixels) + initializeColorSpaceAndScreeBufferForPixelTests(); + allocateGlobalControllers(); + + makeLargeMallocFailSilently(); +} + +void dumpRenderTree(int argc, const char *argv[]) +{ + initializeGlobalsFromCommandLineOptions(argc, argv); + prepareConsistentTestingEnvironment(); + addTestPluginsToPluginSearchPath(argv[0]); + if (dumpPixels) + installSignalHandlers(); + + WebView *webView = createWebViewAndOffscreenWindow(); + mainFrame = [webView mainFrame]; + + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + + // <rdar://problem/5222911> + testStringByEvaluatingJavaScriptFromString(); + + 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(); + + [WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts + [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). + NSWindow *window = [webView window]; + [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) + restoreColorSpace(0); +} + +int main(int argc, const char *argv[]) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; // Force AppKit to init itself + dumpRenderTree(argc, argv); + [WebCoreStatistics garbageCollectJavaScriptObjects]; + [pool release]; + return 0; +} + +static int 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(' '); + printf("%s", [[item 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 (layoutTestController->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 (layoutTestController->dumpChildFramesAsText()) { + NSArray *kids = [frame childFrames]; + if (kids) { + for (unsigned i = 0; i < [kids count]; i++) + [result appendString:dumpFramesAsText([kids objectAtIndex:i])]; + } + } + + return result; +} + +static void convertMIMEType(NSMutableString *mimeType) +{ + if ([mimeType isEqualToString:@"application/x-javascript"]) + [mimeType setString:@"text/javascript"]; +} + +static void convertWebResourceDataToString(NSMutableDictionary *resource) +{ + NSMutableString *mimeType = [resource objectForKey:@"WebResourceMIMEType"]; + convertMIMEType(mimeType); + + if ([mimeType hasPrefix:@"text/"]) { + NSData *data = [resource objectForKey:@"WebResourceData"]; + NSString *dataAsString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + [resource setObject:dataAsString forKey:@"WebResourceData"]; + } +} + +static void normalizeWebResourceURL(NSMutableString *webResourceURL) +{ + static int fileUrlLength = [@"file://" length]; + NSRange layoutTestsWebArchivePathRange = [webResourceURL rangeOfString:@"/LayoutTests/" options:NSBackwardsSearch]; + if (layoutTestsWebArchivePathRange.location == NSNotFound) + return; + NSRange currentWorkingDirectoryRange = NSMakeRange(fileUrlLength, layoutTestsWebArchivePathRange.location - fileUrlLength); + [webResourceURL replaceCharactersInRange:currentWorkingDirectoryRange withString:@""]; +} + +static void convertWebResourceResponseToDictionary(NSMutableDictionary *propertyList) +{ + NSURLResponse *response = nil; + NSData *responseData = [propertyList objectForKey:@"WebResourceResponse"]; // WebResourceResponseKey in WebResource.m + if ([responseData isKindOfClass:[NSData class]]) { + // Decode NSURLResponse + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:responseData]; + response = [unarchiver decodeObjectForKey:@"WebResourceResponse"]; // WebResourceResponseKey in WebResource.m + [unarchiver finishDecoding]; + [unarchiver release]; + } + + NSMutableDictionary *responseDictionary = [[NSMutableDictionary alloc] init]; + + NSMutableString *urlString = [[[response URL] description] mutableCopy]; + normalizeWebResourceURL(urlString); + [responseDictionary setObject:urlString forKey:@"URL"]; + [urlString release]; + + NSMutableString *mimeTypeString = [[response MIMEType] mutableCopy]; + convertMIMEType(mimeTypeString); + [responseDictionary setObject:mimeTypeString forKey:@"MIMEType"]; + [mimeTypeString release]; + + NSString *textEncodingName = [response textEncodingName]; + if (textEncodingName) + [responseDictionary setObject:textEncodingName forKey:@"textEncodingName"]; + [responseDictionary setObject:[NSNumber numberWithLongLong:[response expectedContentLength]] forKey:@"expectedContentLength"]; + + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + [responseDictionary setObject:[httpResponse allHeaderFields] forKey:@"allHeaderFields"]; + [responseDictionary setObject:[NSNumber numberWithInt:[httpResponse statusCode]] forKey:@"statusCode"]; + } + + [propertyList setObject:responseDictionary forKey:@"WebResourceResponse"]; + [responseDictionary release]; +} + +static NSString *serializeWebArchiveToXML(WebArchive *webArchive) +{ + NSString *errorString; + NSMutableDictionary *propertyList = [NSPropertyListSerialization propertyListFromData:[webArchive data] + mutabilityOption:NSPropertyListMutableContainersAndLeaves + format:NULL + errorDescription:&errorString]; + if (!propertyList) + return errorString; + + NSMutableArray *resources = [NSMutableArray arrayWithCapacity:1]; + [resources addObject:propertyList]; + + while ([resources count]) { + NSMutableDictionary *resourcePropertyList = [resources objectAtIndex:0]; + [resources removeObjectAtIndex:0]; + + NSMutableDictionary *mainResource = [resourcePropertyList objectForKey:@"WebMainResource"]; + normalizeWebResourceURL([mainResource objectForKey:@"WebResourceURL"]); + convertWebResourceDataToString(mainResource); + + // Add subframeArchives to list for processing + NSMutableArray *subframeArchives = [resourcePropertyList objectForKey:@"WebSubframeArchives"]; // WebSubframeArchivesKey in WebArchive.m + if (subframeArchives) + [resources addObjectsFromArray:subframeArchives]; + + NSMutableArray *subresources = [resourcePropertyList objectForKey:@"WebSubresources"]; // WebSubresourcesKey in WebArchive.m + NSEnumerator *enumerator = [subresources objectEnumerator]; + NSMutableDictionary *subresourcePropertyList; + while ((subresourcePropertyList = [enumerator nextObject])) { + normalizeWebResourceURL([subresourcePropertyList objectForKey:@"WebResourceURL"]); + convertWebResourceResponseToDictionary(subresourcePropertyList); + convertWebResourceDataToString(subresourcePropertyList); + } + } + + NSData *xmlData = [NSPropertyListSerialization dataFromPropertyList:propertyList + format:NSPropertyListXMLFormat_v1_0 + errorDescription:&errorString]; + if (!xmlData) + return errorString; + + NSMutableString *string = [[[NSMutableString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding] autorelease]; + + // Replace "Apple Computer" with "Apple" in the DTD declaration. + NSRange range = [string rangeOfString:@"-//Apple Computer//"]; + if (range.location != NSNotFound) + [string replaceCharactersInRange:range withString:@"-//Apple//"]; + + return string; +} + +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 = ([currentTest rangeOfString:@"svg/W3C-SVG-1.1"].length); + if (isSVGW3CTest) + [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)]; + else + [[mainFrame webView] setFrameSize:NSMakeSize(maxViewWidth, maxViewHeight)]; +} + +static const char *methodNameStringForFailedTest() +{ + const char *errorMessage; + if (layoutTestController->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (layoutTestController->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (layoutTestController->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; + + bool dumpAsText = layoutTestController->dumpAsText(); + dumpAsText |= [[[mainFrame dataSource] _responseMIMEType] isEqualToString:@"text/plain"]; + layoutTestController->setDumpAsText(dumpAsText); + if (layoutTestController->dumpAsText()) { + resultString = dumpFramesAsText(mainFrame); + } else if (layoutTestController->dumpDOMAsWebArchive()) { + WebArchive *webArchive = [[mainFrame DOMDocument] webArchive]; + resultString = serializeWebArchiveToXML(webArchive); + } else if (layoutTestController->dumpSourceAsWebArchive()) { + WebArchive *webArchive = [[mainFrame dataSource] webArchive]; + resultString = serializeWebArchiveToXML(webArchive); + } else { + sizeWebViewForCurrentTest(); + resultString = [mainFrame renderTreeAsExternalRepresentation]; + } + + if (resultString && !resultData) + resultData = [resultString dataUsingEncoding:NSUTF8StringEncoding]; + + if (resultData) { + fwrite([resultData bytes], 1, [resultData length], stdout); + + if (!layoutTestController->dumpAsText() && !layoutTestController->dumpDOMAsWebArchive() && !layoutTestController->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + + if (layoutTestController->dumpBackForwardList()) + dumpBackForwardListForAllWindows(); + } else + printf("ERROR: nil result from %s", methodNameStringForFailedTest()); + + if (printSeparators) + puts("#EOF"); + } + + if (dumpPixels) + dumpWebViewAsPixelsAndCompareWithExpected([currentTest UTF8String], dumpAllPixels); + + fflush(stdout); + + done = YES; +} + +static bool shouldLogFrameLoadDelegates(const char *pathOrURL) +{ + return strstr(pathOrURL, "loading/"); +} + +static CFURLRef createCFURLFromPathOrURL(CFStringRef pathOrURLString) +{ + CFURLRef URL; + if (CFStringHasPrefix(pathOrURLString, CFSTR("http://")) || CFStringHasPrefix(pathOrURLString, CFSTR("https://"))) + URL = CFURLCreateWithString(NULL, pathOrURLString, NULL); + else + URL = CFURLCreateWithFileSystemPath(NULL, pathOrURLString, kCFURLPOSIXPathStyle, FALSE); + return URL; +} + +static void resetWebViewToConsistentStateBeforeTesting() +{ + WebView *webView = [mainFrame webView]; + [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES]; + [webView makeTextStandardSize:nil]; + [webView setTabKeyCyclesThroughElements: YES]; + [webView setPolicyDelegate:nil]; + [webView _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO]; + + WebPreferences *preferences = [webView preferences]; + [preferences setPrivateBrowsingEnabled:NO]; + [preferences setAuthorAndUserStylesEnabled:YES]; + [preferences setJavaScriptCanOpenWindowsAutomatically:YES]; + + if (persistentUserStyleSheetLocation) { + [preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]]; + [preferences setUserStyleSheetEnabled:YES]; + } else + [preferences setUserStyleSheetEnabled:NO]; + + [WebView _setUsesTestModeFocusRingColor:YES]; +} + +static void runTest(const char *pathOrURL) +{ + CFStringRef pathOrURLString = CFStringCreateWithCString(NULL, pathOrURL, kCFStringEncodingUTF8); + if (!pathOrURLString) { + fprintf(stderr, "Failed to parse filename as UTF-8: %s\n", pathOrURL); + return; + } + + CFURLRef URL = createCFURLFromPathOrURL(pathOrURLString); + if (!URL) { + CFRelease(pathOrURLString); + fprintf(stderr, "Can't turn %s into a CFURL\n", pathOrURL); + return; + } + + resetWebViewToConsistentStateBeforeTesting(); + + layoutTestController = new LayoutTestController(testRepaintDefault, repaintSweepHorizontallyDefault); + topLoadingFrame = nil; + done = NO; + + if (disallowedURLs) + CFSetRemoveAllValues(disallowedURLs); + if (shouldLogFrameLoadDelegates(pathOrURL)) + layoutTestController->setDumpFrameLoadCallbacks(true); + + if ([WebHistory optionalSharedHistory]) + [WebHistory setOptionalSharedHistory:nil]; + lastMousePosition = NSZeroPoint; + lastClickPosition = NSZeroPoint; + + if (currentTest != nil) + CFRelease(currentTest); + currentTest = (NSString *)pathOrURLString; + [prevTestBFItem release]; + prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain]; + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + BOOL _shouldIgnoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(CFURLGetString(URL)); + if (_shouldIgnoreWebCoreNodeLeaks) + [WebCoreStatistics startIgnoringWebCoreNodeLeaks]; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [mainFrame loadRequest:[NSURLRequest requestWithURL:(NSURL *)URL]]; + CFRelease(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 (layoutTestController->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]; + } + } + + [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]); + + delete layoutTestController; + layoutTestController = 0; + + if (_shouldIgnoreWebCoreNodeLeaks) + [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 diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h new file mode 100644 index 0000000..249809c --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm new file mode 100644 index 0000000..41aa639 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm @@ -0,0 +1,108 @@ +/* + * 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 "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; +} + +@end + diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h new file mode 100644 index 0000000..c4c7573 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h @@ -0,0 +1,57 @@ +/* + * 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 + +// FIXME: we should add a config.h file for DumpRenderTree. +#define WTF_PLATFORM_CF 1 + +@class DumpRenderTreeDraggingInfo; +@class NavigationController; +@class PolicyDelegate; +@class WebFrame; +@class WebView; + +typedef const struct __CFString* CFStringRef; + +extern CFMutableArrayRef openWindowsRef; +extern CFMutableSetRef disallowedURLs; +extern WebFrame* mainFrame; +extern WebFrame* topLoadingFrame; +extern DumpRenderTreeDraggingInfo *draggingInfo; +extern NavigationController* navigationController; +extern PolicyDelegate* policyDelegate; + +extern const unsigned maxViewHeight; +extern const unsigned maxViewWidth; + +WebView* createWebViewAndOffscreenWindow(); +void setPersistentUserStyleSheetLocation(CFStringRef); + +#endif // DumpRenderTreeMac_h diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.h new file mode 100644 index 0000000..6a01a42 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.h @@ -0,0 +1,37 @@ +/* + * 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> + +@interface DumpRenderTreePasteboard : NSPasteboard +- (int)declareType:(NSString *)type owner:(id)newOwner; ++ (void)releaseLocalPasteboards; +@end + diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.m b/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.m new file mode 100644 index 0000000..b5a9b7a --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.m @@ -0,0 +1,202 @@ +/* + * 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 "DumpRenderTreePasteboard.h" + +@interface LocalPasteboard : NSPasteboard +{ + NSMutableArray *typesArray; + NSMutableSet *typesSet; + NSMutableDictionary *dataByType; + int 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 +- (int)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 +{ +} + +- (int)declareTypes:(NSArray *)newTypes owner:(id)newOwner +{ + [typesArray removeAllObjects]; + [typesSet removeAllObjects]; + [dataByType removeAllObjects]; + return [self addTypes:newTypes owner:newOwner]; +} + +- (int)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; +} + +- (int)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/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h new file mode 100644 index 0000000..3ac3223 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h @@ -0,0 +1,36 @@ +/* + * 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> + +@interface DumpRenderTreeWindow : NSWindow +// I'm not sure why we can't just use [NSApp windows] ++ (NSArray *)openWindows; +@end diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm new file mode 100644 index 0000000..9e5e104 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm @@ -0,0 +1,85 @@ +/* + * 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 "DumpRenderTreeWindow.h" + +#import "DumpRenderTree.h" + +// FIXME: This file is ObjC++ only because of this include. :( +#import "LayoutTestController.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:(unsigned int)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 +{ + CFRange arrayRange = CFRangeMake(0, CFArrayGetCount(openWindowsRef)); + CFIndex i = CFArrayGetFirstIndexOfValue(openWindowsRef, arrayRange, self); + assert(i != -1); + CFArrayRemoveValueAtIndex(openWindowsRef, i); + [super close]; +} + +- (BOOL)isKeyWindow +{ + return layoutTestController ? layoutTestController->windowIsKey() : YES; +} + +- (void)keyDown:(id)sender +{ + // Do nothing, avoiding the beep we'd otherwise get from NSResponder, + // once we get to the end of the responder chain. +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/EditingDelegate.h b/WebKitTools/DumpRenderTree/mac/EditingDelegate.h new file mode 100644 index 0000000..b5563c8 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/EditingDelegate.mm b/WebKitTools/DumpRenderTree/mac/EditingDelegate.mm new file mode 100644 index 0000000..a8f0815 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/EditingDelegate.mm @@ -0,0 +1,191 @@ +/* + * 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 "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 && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", [[range dump] UTF8String]); + return acceptsEditing; +} + +- (BOOL)webView:(WebView *)webView shouldEndEditingInDOMRange:(DOMRange *)range +{ + if (!done && layoutTestController->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 && layoutTestController->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 && layoutTestController->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 && layoutTestController->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 && layoutTestController->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 && layoutTestController->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 && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n", [[currentStyle description] UTF8String], [[proposedStyle description] UTF8String]); + return acceptsEditing; +} + +- (void)webViewDidBeginEditing:(NSNotification *)notification +{ + if (!done && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidBeginEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChange:(NSNotification *)notification +{ + if (!done && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChange:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidEndEditing:(NSNotification *)notification +{ + if (!done && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidEndEditing:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeTypingStyle:(NSNotification *)notification +{ + if (!done && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n", [[notification name] UTF8String]); +} + +- (void)webViewDidChangeSelection:(NSNotification *)notification +{ + if (!done && layoutTestController->dumpEditingCallbacks()) + printf("EDITING DELEGATE: webViewDidChangeSelection:%s\n", [[notification name] UTF8String]); +} + +- (void)setAcceptsEditing:(BOOL)newAcceptsEditing +{ + acceptsEditing = newAcceptsEditing; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/EventSendingController.h b/WebKitTools/DumpRenderTree/mac/EventSendingController.h new file mode 100644 index 0000000..28d0385 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/EventSendingController.h @@ -0,0 +1,53 @@ +/* + * 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 down; + BOOL dragMode; + int clickCount; + NSTimeInterval lastClick; + int eventNumber; + double timeOffset; +} + ++ (void)saveEvent:(NSInvocation *)event; ++ (void)replaySavedEvents; ++ (void)clearSavedEvents; + +- (void)enableDOMUIEventLogging:(WebScriptObject *)node; + +- (void)handleEvent:(DOMEvent *)event; + +@end + +extern NSPoint lastMousePosition; +extern NSPoint lastClickPosition;
\ No newline at end of file diff --git a/WebKitTools/DumpRenderTree/mac/EventSendingController.mm b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm new file mode 100644 index 0000000..8e9be38 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm @@ -0,0 +1,589 @@ +/* + * 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 "EventSendingController.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" + +#import <Carbon/Carbon.h> // for GetCurrentEventTime() +#import <WebKit/WebKit.h> +#import <WebKit/DOMPrivate.h> + +extern "C" void _NSNewKillRingSequence(); + +NSPoint lastMousePosition; +NSPoint lastClickPosition; +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(mouseDown) + || aSelector == @selector(mouseUp) + || aSelector == @selector(contextClick) + || aSelector == @selector(mouseMoveToX:Y:) + || aSelector == @selector(leapForward:) + || aSelector == @selector(keyDown:withModifiers:) + || aSelector == @selector(enableDOMUIEventLogging:) + || aSelector == @selector(fireKeyboardEventsToElement:) + || aSelector == @selector(clearKillRing) + || aSelector == @selector(textZoomIn) + || aSelector == @selector(textZoomOut)) + 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(mouseMoveToX:Y:)) + return @"mouseMoveTo"; + if (aSelector == @selector(leapForward:)) + return @"leapForward"; + if (aSelector == @selector(keyDown:withModifiers:)) + return @"keyDown"; + if (aSelector == @selector(enableDOMUIEventLogging:)) + return @"enableDOMUIEventLogging"; + if (aSelector == @selector(fireKeyboardEventsToElement:)) + return @"fireKeyboardEventsToElement"; + if (aSelector == @selector(setDragMode:)) + return @"setDragMode"; + 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 && down && !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(); +} + +- (void)mouseDown +{ + [[[mainFrame frameView] documentView] layout]; + if (([self currentEventTime] - lastClick >= 1) || + !NSEqualPoints(lastMousePosition, lastClickPosition)) + clickCount = 1; + else + clickCount++; + NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown + 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]]; + if (subView) { + [subView mouseDown:event]; + down = YES; + } +} + +- (void)textZoomIn +{ + [[mainFrame webView] makeTextLarger:self]; +} + +- (void)textZoomOut +{ + [[mainFrame webView] makeTextSmaller:self]; +} + +- (void)mouseUp +{ + if (dragMode && !replayingSavedEvents) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(mouseUp)]; + + [EventSendingController saveEvent:invocation]; + [EventSendingController replaySavedEvents]; + + return; + } + + [[[mainFrame frameView] documentView] layout]; + NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseUp + location:lastMousePosition + modifierFlags:0 + 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]; + down = 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]; + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] endedAt:lastMousePosition operation:dragOperation]; + [draggingInfo release]; + draggingInfo = nil; + } +} + +- (void)mouseMoveToX:(int)x Y:(int)y +{ + if (dragMode && down && !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:(down ? NSLeftMouseDragged : NSMouseMoved) + location:lastMousePosition + modifierFlags:0 + timestamp:[self currentEventTime] + windowNumber:[[view window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:++eventNumber + clickCount:(down ? clickCount : 0) + pressure:0.0]; + + NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + if (subView) { + if (down) { + [subView mouseDragged:event]; + if (draggingInfo) { + [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] movedTo:lastMousePosition]; + [[mainFrame webView] draggingUpdated:draggingInfo]; + } + } else + [subView mouseMoved:event]; + } +} + +- (void)contextClick +{ + [[[mainFrame frameView] documentView] layout]; + if ([self currentEventTime] - lastClick >= 1) + clickCount = 1; + else + clickCount++; + 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]]; + if (subView) + [subView menuForEvent:event]; +} + ++ (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 +{ + NSString *eventCharacter = character; + if ([character isEqualToString:@"leftArrow"]) { + const unichar ch = NSLeftArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"rightArrow"]) { + const unichar ch = NSRightArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"upArrow"]) { + const unichar ch = NSUpArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"downArrow"]) { + const unichar ch = NSDownArrowFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"pageUp"]) { + const unichar ch = NSPageUpFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"pageDown"]) { + const unichar ch = NSPageDownFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"home"]) { + const unichar ch = NSHomeFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"end"]) { + const unichar ch = NSEndFunctionKey; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } else if ([character isEqualToString:@"delete"]) { + const unichar ch = 0x7f; + eventCharacter = [NSString stringWithCharacters:&ch length:1]; + } + + NSString *charactersIgnoringModifiers = eventCharacter; + + int modifierFlags = 0; + + if ([character length] == 1 && [character characterAtIndex:0] >= 'A' && [character characterAtIndex:0] <= 'Z') { + modifierFlags |= NSShiftKeyMask; + charactersIgnoringModifiers = [character lowercaseString]; + } + + if ([modifiers isKindOfClass:[WebScriptObject class]]) + for (unsigned i = 0; [[modifiers webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) { + NSString *modifier = (NSString *)[modifiers webScriptValueAtIndex:i]; + if ([modifier isEqual:@"ctrlKey"]) + modifierFlags |= NSControlKeyMask; + else if ([modifier isEqual:@"shiftKey"]) + modifierFlags |= NSShiftKeyMask; + else if ([modifier isEqual:@"altKey"]) + modifierFlags |= NSAlternateKeyMask; + else if ([modifier isEqual:@"metaKey"]) + modifierFlags |= NSCommandKeyMask; + } + + [[[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:0]; + + [[[[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:0]; + + [[[[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/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.h b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.h new file mode 100644 index 0000000..3b86fdf --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.h @@ -0,0 +1,37 @@ +/* + * 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 GCController; + +@interface FrameLoadDelegate : NSObject +{ + GCController* gcController; +} +@end diff --git a/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm new file mode 100644 index 0000000..98b6bac --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm @@ -0,0 +1,333 @@ +/* + * 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 "DumpRenderTree.h" +#import "FrameLoadDelegate.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 "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 <wtf/Assertions.h> + +@interface NSURLRequest (PrivateThingsWeShouldntReallyUse) ++(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host; +@end + +@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)"; + } +} +@end + +@implementation FrameLoadDelegate + +- (id)init +{ + if ((self = [super init])) + gcController = new GCController; + return self; +} + +- (void)dealloc +{ + delete gcController; + [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 +{ + // quit doing work once a load is in progress + while (WorkQueue::shared()->count() > 0 && !topLoadingFrame) { + WorkQueueItem* item = WorkQueue::shared()->dequeue(); + ASSERT(item); + item->invoke(); + delete item; + } + + // if we didn't start a new load, then we finished all the commands, so we're ready to dump state + if (!topLoadingFrame && !layoutTestController->waitToDump()) + dump(); +} + +- (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 (!layoutTestController->waitToDump()) { + if (WorkQueue::shared()->count()) + [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; + else + dump(); + } + } +} + +- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + 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; +} + +- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT(![frame provisionalDataSource]); + ASSERT([frame dataSource]); + + layoutTestController->setWindowIsKey(true); + NSView *documentView = [[mainFrame frameView] documentView]; + [[[mainFrame webView] window] makeFirstResponder:documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _updateFocusedAndActiveState]; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + if ([error domain] == NSURLErrorDomain && [error code] == NSURLErrorServerCertificateHasUnknownRoot) { + NSURL *failedURL = [[error userInfo] objectForKey:@"NSErrorFailingURLKey"]; + [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[failedURL _web_hostString]]; + [frame loadRequest:[[[[frame provisionalDataSource] request] mutableCopy] autorelease]]; + 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 && layoutTestController->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]]; + [navigationController webView:sender didFinishLoadForFrame:frame]; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame; +{ + if (!done && layoutTestController->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 && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; + printf ("%s\n", [string UTF8String]); + } + + ASSERT_NOT_REACHED(); +} + +- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)obj forFrame:(WebFrame *)frame +{ + ASSERT(obj == [frame windowObject]); + ASSERT([obj JSObject] == JSContextGetGlobalObject([frame globalContext])); + + // Make New-Style LayoutTestController + JSContextRef context = [frame globalContext]; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSValueRef exception = 0; + + ASSERT(layoutTestController); + layoutTestController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(context, globalObject, &exception); + ASSERT(!exception); + + // Make Old-Style controllers + EventSendingController *esc = [[EventSendingController alloc] init]; + [obj setValue:esc forKey:@"eventSender"]; + [esc release]; + + TextInputController *tic = [[TextInputController alloc] initWithWebView:sender]; + [obj setValue:tic forKey:@"textInputController"]; + [tic release]; + + AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:sender]; + [obj setValue:asc forKey:@"appleScriptController"]; + [asc release]; + + ObjCController *occ = [[ObjCController alloc] init]; + [obj setValue:occ forKey:@"objCController"]; + [occ release]; + + [obj setValue:navigationController forKey:@"navigationController"]; + + ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; + [obj setValue:plugin forKey:@"objCPlugin"]; + [plugin release]; + + ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; + [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; + [pluginFunction release]; +} + +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; + printf ("%s\n", [string UTF8String]); + } + + if (layoutTestController->dumpTitleChanges()) + printf("TITLE CHANGED: %s\n", [title UTF8String]); +} + +- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame +{ + if (!done && layoutTestController->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 && layoutTestController->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 && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame; +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +- (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame; +{ + if (!done && layoutTestController->dumpFrameLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/GCControllerMac.mm b/WebKitTools/DumpRenderTree/mac/GCControllerMac.mm new file mode 100644 index 0000000..4b845ba --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/GCControllerMac.mm @@ -0,0 +1,47 @@ +/* + * 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 "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/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm new file mode 100644 index 0000000..4774310 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -0,0 +1,282 @@ +/* + * 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 "DumpRenderTree.h" +#import "LayoutTestController.h" + +#import "EditingDelegate.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/WebBackForwardList.h> +#import <WebKit/WebDatabaseManagerPrivate.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebHistory.h> +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebPreferencesPrivate.h> +#import <WebKit/WebSecurityOriginPrivate.h> +#import <WebKit/WebView.h> +#import <WebKit/WebViewPrivate.h> +#import <wtf/RetainPtr.h> + +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]); +} + +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(); +} + +void LayoutTestController::keepWebHistory() +{ + if (![WebHistory optionalSharedHistory]) { + WebHistory *history = [[WebHistory alloc] init]; + [WebHistory setOptionalSharedHistory:history]; + [history release]; + } +} + +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::queueBackNavigation(int howFarBack) +{ + WorkQueue::shared()->queue(new BackItem(howFarBack)); +} + +void LayoutTestController::queueForwardNavigation(int howFarForward) +{ + WorkQueue::shared()->queue(new ForwardItem(howFarForward)); +} + +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::queueReload() +{ + WorkQueue::shared()->queue(new ReloadItem); +} + +void LayoutTestController::queueScript(JSStringRef script) +{ + WorkQueue::shared()->queue(new ScriptItem(script)); +} + +void LayoutTestController::setAcceptsEditing(bool newAcceptsEditing) +{ + [(EditingDelegate *)[[mainFrame webView] editingDelegate] setAcceptsEditing:newAcceptsEditing]; +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) +{ + [[[mainFrame webView] preferences] setAuthorAndUserStylesEnabled:flag]; +} + +void LayoutTestController::setCustomPolicyDelegate(bool setDelegate) +{ + if (setDelegate) + [[mainFrame webView] setPolicyDelegate:policyDelegate]; + else + [[mainFrame webView] setPolicyDelegate:nil]; +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithProtocol:@"file" domain:nil]; + [origin setQuota:quota]; + [origin release]; +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool flag) +{ + NSView *documentView = [[mainFrame frameView] documentView]; + + NSResponder *firstResponder = flag ? documentView : nil; + [[[mainFrame webView] window] makeFirstResponder:firstResponder]; + + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _updateFocusedAndActiveState]; +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) +{ + [[[mainFrame webView] preferences] setPrivateBrowsingEnabled:privateBrowsingEnabled]; +} + +void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled) +{ + [[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled]; +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles) +{ + [[mainFrame webView] setTabKeyCyclesThroughElements:cycles]; +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool flag) +{ + [[mainFrame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:flag]; +} + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + [[WebPreferences standardPreferences] setUserStyleSheetEnabled:flag]; +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + RetainPtr<CFStringRef> pathCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, path)); + NSURL *url = [NSURL URLWithString:(NSString *)pathCF.get()]; + [[WebPreferences standardPreferences] setUserStyleSheetLocation:url]; +} + +void LayoutTestController::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; + NSView *documentView = [[mainFrame frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _updateFocusedAndActiveState]; +} + +static const CFTimeInterval waitToDumpWatchdogInterval = 10.0; + +static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info) +{ + const char* message = "FAIL: Timed out waiting for notifyDone to be called\n"; + fprintf(stderr, message); + fprintf(stdout, message); + dump(); +} + +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); +} + +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]; +} diff --git a/WebKitTools/DumpRenderTree/mac/NavigationController.h b/WebKitTools/DumpRenderTree/mac/NavigationController.h new file mode 100644 index 0000000..8ee3432 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/NavigationController.m b/WebKitTools/DumpRenderTree/mac/NavigationController.m new file mode 100644 index 0000000..44aed8a --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/NavigationController.m @@ -0,0 +1,109 @@ +/* + * 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 <WebKit/WebFrame.h> +#import <WebKit/WebScriptObject.h> +#import "NavigationController.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/WebKitTools/DumpRenderTree/mac/ObjCController.h b/WebKitTools/DumpRenderTree/mac/ObjCController.h new file mode 100644 index 0000000..d1d001c --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/ObjCController.m b/WebKitTools/DumpRenderTree/mac/ObjCController.m new file mode 100644 index 0000000..9ca9299 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/ObjCController.m @@ -0,0 +1,231 @@ +/* + * 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 "ObjCController.h" + +#import <JavaScriptCore/JavaScriptCore.h> +#import <WebKit/DOMAbstractView.h> +#import <WebKit/WebScriptObject.h> +#import <WebKit/WebView.h> +#import <pthread.h> +#import <wtf/Assertions.h> + +static void* runJavaScriptThread(void* arg) +{ + JSGlobalContextRef ctx = JSGlobalContextCreate(0); + JSStringRef scriptRef = JSStringCreateWithUTF8CString("'Hello World!'"); + + JSValueRef exception = 0; + JSEvaluateScript(ctx, scriptRef, 0, 0, 0, &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(identityIsEqual::) + || aSelector == @selector(longLongRoundTrip:) + || aSelector == @selector(unsignedLongLongRoundTrip:) + || aSelector == @selector(testWrapperRoundTripping:) + || aSelector == @selector(accessStoredWebScriptObject) + || aSelector == @selector(storeWebScriptObject:) + || aSelector == @selector(testValueForKey) + ) + return NO; + return YES; +} + ++ (NSString *)webScriptNameForSelector:(SEL)aSelector +{ + if (aSelector == @selector(classNameOf:)) + return @"className"; + if (aSelector == @selector(objectOfClass:)) + return @"objectOfClass"; + 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"; + + 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; +} + +- (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)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]]; +#endif + JSObjectRef jsObject = [storedWebScriptObject JSObject]; + ASSERT((jsObject && isWindowObject) || (!jsObject && !isWindowObject)); + + [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]; +} + +- (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; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/ObjCPlugin.h b/WebKitTools/DumpRenderTree/mac/ObjCPlugin.h new file mode 100644 index 0000000..a6d3e50 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/ObjCPlugin.m b/WebKitTools/DumpRenderTree/mac/ObjCPlugin.m new file mode 100644 index 0000000..18b174c --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/ObjCPlugin.m @@ -0,0 +1,206 @@ +/* + * 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 "ObjCPlugin.h" +#import <objc/objc-runtime.h> +#import <WebKit/WebKit.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/WebKitTools/DumpRenderTree/mac/ObjCPluginFunction.h b/WebKitTools/DumpRenderTree/mac/ObjCPluginFunction.h new file mode 100644 index 0000000..1e81b21 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/ObjCPluginFunction.m b/WebKitTools/DumpRenderTree/mac/ObjCPluginFunction.m new file mode 100644 index 0000000..5cd16f8 --- /dev/null +++ b/WebKitTools/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 "ObjCPluginFunction.h" + + +@implementation ObjCPluginFunction + +- (id)invokeDefaultMethodWithArguments:(NSArray *)args +{ + return @"test"; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm new file mode 100644 index 0000000..5a19164 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm @@ -0,0 +1,162 @@ +/* + * 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 "DumpRenderTree.h" +#include "PixelDumpSupport.h" +#include "PixelDumpSupportCG.h" + +#include "LayoutTestController.h" +#include <CoreGraphics/CGBitmapContext.h> +#include <wtf/Assertions.h> +#include <wtf/RetainPtr.h> + +#import <WebKit/WebDocumentPrivate.h> +#import <WebKit/WebKit.h> + +static unsigned char* screenCaptureBuffer; + +static CMProfileRef currentColorProfile = 0; +static CGColorSpaceRef sharedColorSpace; + +void restoreColorSpace(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 (currentColorProfile) { + // This call is deprecated in Leopard, but there appears to be no replacement. + int error = CMSetDefaultProfileByUse(cmDisplayUse, currentColorProfile); + if (error) + fprintf(stderr, "Failed to retore previous color profile! You may need to open System Preferences : Displays : Color and manually restore your color settings. (Error: %i)", error); + currentColorProfile = 0; + } +} + +static void setDefaultColorProfileToRGB() +{ + CMProfileRef genericProfile = (CMProfileRef)[[NSColorSpace genericRGBColorSpace] colorSyncProfile]; + CMProfileRef previousProfile; + int error = CMGetDefaultProfileByUse(cmDisplayUse, &previousProfile); + if (error) { + fprintf(stderr, "Failed to get current color profile. I will not be able to restore your current profile, thus I'm not changing it. Many pixel tests may fail as a result. (Error: %i)\n", error); + return; + } + if (previousProfile == genericProfile) + return; + CFStringRef previousProfileName; + CFStringRef genericProfileName; + char previousProfileNameString[1024]; + char genericProfileNameString[1024]; + CMCopyProfileDescriptionString(previousProfile, &previousProfileName); + CMCopyProfileDescriptionString(genericProfile, &genericProfileName); + CFStringGetCString(previousProfileName, previousProfileNameString, sizeof(previousProfileNameString), kCFStringEncodingUTF8); + CFStringGetCString(genericProfileName, genericProfileNameString, sizeof(previousProfileNameString), kCFStringEncodingUTF8); + CFRelease(previousProfileName); + CFRelease(genericProfileName); + + fprintf(stderr, "\n\nWARNING: Temporarily changing your system color profile from \"%s\" to \"%s\".\n", previousProfileNameString, genericProfileNameString); + fprintf(stderr, "This allows the WebKit pixel-based regression tests to have consistent color values across all machines.\n"); + fprintf(stderr, "The colors on your screen will change for the duration of the testing.\n\n"); + + if ((error = CMSetDefaultProfileByUse(cmDisplayUse, genericProfile))) { + fprintf(stderr, "Failed to set color profile to \"%s\"! Many pixel tests will fail as a result. (Error: %i)", + genericProfileNameString, error); + } else { + currentColorProfile = previousProfile; + signal(SIGINT, restoreColorSpace); + signal(SIGHUP, restoreColorSpace); + signal(SIGTERM, restoreColorSpace); + } +} + +void initializeColorSpaceAndScreeBufferForPixelTests() +{ + setDefaultColorProfileToRGB(); + screenCaptureBuffer = (unsigned char *)malloc(maxViewHeight * maxViewWidth * 4); + sharedColorSpace = CGColorSpaceCreateDeviceRGB(); +} + +// Declared in PixelDumpSupportCG.h + +RetainPtr<CGContextRef> getBitmapContextFromWebView() +{ + NSSize webViewSize = [[mainFrame webView] frame].size; + return RetainPtr<CGContextRef>(AdoptCF, CGBitmapContextCreate(screenCaptureBuffer, static_cast<size_t>(webViewSize.width), static_cast<size_t>(webViewSize.height), 8, static_cast<size_t>(webViewSize.width) * 4, sharedColorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast)); +} + +void paintWebView(CGContextRef context) +{ + RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; + + NSGraphicsContext* nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; + [NSGraphicsContext setCurrentContext:nsContext]; + + WebView* view = [mainFrame webView]; + [view displayIfNeeded]; + [view lockFocus]; + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]]; + [view unlockFocus]; + [imageRep draw]; + [imageRep release]; + + [NSGraphicsContext setCurrentContext:savedContext.get()]; +} + +void repaintWebView(CGContextRef context, bool horizontal) +{ + RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; + + NSGraphicsContext* nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; + [NSGraphicsContext setCurrentContext:nsContext]; + + WebView *view = [mainFrame webView]; + NSSize webViewSize = [view frame].size; + + if (horizontal) { + 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]; + } + + [NSGraphicsContext setCurrentContext:savedContext.get()]; +} + +CGRect getSelectionRect() +{ + NSView *documentView = [[mainFrame frameView] documentView]; + if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) { + NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil]; + return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + } + + ASSERT_NOT_REACHED(); + return CGRectZero; +} diff --git a/WebKitTools/DumpRenderTree/mac/PolicyDelegate.h b/WebKitTools/DumpRenderTree/mac/PolicyDelegate.h new file mode 100644 index 0000000..f8bce68 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/PolicyDelegate.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 PolicyDelegate : NSObject { +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/PolicyDelegate.mm b/WebKitTools/DumpRenderTree/mac/PolicyDelegate.mm new file mode 100644 index 0000000..fc4ac74 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/PolicyDelegate.mm @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "PolicyDelegate.h" + +#import "DumpRenderTree.h" +#import "DumpRenderTreeDraggingInfo.h" +#import <WebKit/WebPolicyDelegate.h> + +@implementation PolicyDelegate +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation + request:(NSURLRequest *)request + frame:(WebFrame *)frame + decisionListener:(id<WebPolicyDecisionListener>)listener +{ + printf("Policy delegate: attempt to load %s\n", [[[request URL] absoluteString] UTF8String]); + [listener ignore]; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.h b/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.h new file mode 100644 index 0000000..0c4618e --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm b/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm new file mode 100644 index 0000000..cc0eb4a --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm @@ -0,0 +1,179 @@ +/* + * 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 "ResourceLoadDelegate.h" + +#import "DumpRenderTree.h" +#import "LayoutTestController.h" +#import <WebKit/WebKit.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 + +@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 +{ + return [NSString stringWithFormat:@"<NSURLResponse %@>", [[self URL] _drt_descriptionSuitableForTestResult]]; +} + +@end + +@implementation NSURLRequest (DRTExtras) + +- (NSString *)_drt_descriptionSuitableForTestResult +{ + return [NSString stringWithFormat:@"<NSURLRequest %@>", [[self URL] _drt_descriptionSuitableForTestResult]]; +} + +@end + +@implementation ResourceLoadDelegate + +- webView: (WebView *)wv identifierForInitialRequest: (NSURLRequest *)request fromDataSource: (WebDataSource *)dataSource +{ + ASSERT([[dataSource webFrame] dataSource] || [[dataSource webFrame] provisionalDataSource]); + + if (!done && layoutTestController->dumpResourceLoadCallbacks()) + return [[request URL] _drt_descriptionSuitableForTestResult]; + + return @"<unknown>"; +} + +-(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource +{ + if (!done && layoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [newRequest _drt_descriptionSuitableForTestResult], + [redirectResponse _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } + + if (disallowedURLs && CFSetContainsValue(disallowedURLs, [newRequest URL])) + return nil; + + return newRequest; +} + +- (void)webView:(WebView *)wv resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource +{ +} + +- (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 && layoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - didReceiveResponse %@", identifier, [response _drt_descriptionSuitableForTestResult]]; + printf ("%s\n", [string UTF8String]); + } +} + +-(void)webView: (WebView *)wv resource:identifier didReceiveContentLength: (unsigned)length fromDataSource:(WebDataSource *)dataSource +{ +} + +-(void)webView: (WebView *)wv resource:identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource +{ + if (!done && layoutTestController->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 && layoutTestController->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 +{ +} + +-(NSCachedURLResponse *) webView: (WebView *)wv resource:(id)identifier willCacheResponse:(NSCachedURLResponse *)response fromDataSource:(WebDataSource *)dataSource +{ + if (!done && layoutTestController->dumpResourceLoadCallbacks()) { + NSString *string = [NSString stringWithFormat:@"%@ - willCacheResponse: called", identifier]; + printf ("%s\n", [string UTF8String]); + } + return response; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/TextInputController.h b/WebKitTools/DumpRenderTree/mac/TextInputController.h new file mode 100644 index 0000000..767e72f --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/TextInputController.m b/WebKitTools/DumpRenderTree/mac/TextInputController.m new file mode 100644 index 0000000..88b480b --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/TextInputController.m @@ -0,0 +1,423 @@ +/* + * 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 "TextInputController.h" + +#import <AppKit/NSInputManager.h> +#import <WebKit/WebDocument.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebScriptObject.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; +} + +- (int)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]; + return [textInput characterIndexForPoint:point]; + } + + 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/WebKitTools/DumpRenderTree/mac/UIDelegate.h b/WebKitTools/DumpRenderTree/mac/UIDelegate.h new file mode 100644 index 0000000..da472d6 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/UIDelegate.h @@ -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. + * 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; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/UIDelegate.mm b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm new file mode 100644 index 0000000..9c440a7 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm @@ -0,0 +1,153 @@ +/* + * 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 "DumpRenderTree.h" +#import "UIDelegate.h" + +#import "DumpRenderTreeDraggingInfo.h" +#import "EventSendingController.h" +#import "LayoutTestController.h" +#import <WebKit/WebFramePrivate.h> +#import <WebKit/WebHTMLViewPrivate.h> +#import <WebKit/WebView.h> +#import <WebKit/WebSecurityOriginPrivate.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)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; +} + +- (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); + if (layoutTestController->addFileToPasteboardOnDrag()) { + [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil]; + [pboard setPropertyList:[NSArray arrayWithObject:@"DRTFakeFile"] forType:NSFilenamesPboardType]; + } + draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj]; + [EventSendingController replaySavedEvents]; +} + +- (void)webViewFocus:(WebView *)webView +{ + layoutTestController->setWindowIsKey(true); + NSView *documentView = [[mainFrame frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _updateFocusedAndActiveState]; +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request +{ + if (!layoutTestController->canOpenWindows()) + return nil; + + // Make sure that waitUntilDone has been called. + ASSERT(layoutTestController->waitToDump()); + + WebView *webView = createWebViewAndOffscreenWindow(); + + return [webView autorelease]; +} + +- (void)webViewClose:(WebView *)sender +{ + NSWindow* window = [sender window]; + + if (layoutTestController->callCloseOnWebViews()) + [sender close]; + + [window close]; +} + +- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier +{ + if (!done && layoutTestController->dumpDatabaseCallbacks()) + printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin domain] UTF8String], + [origin port], [databaseIdentifier UTF8String]); + + static const unsigned long long defaultQuota = 5 * 1024 * 1024; + [origin setQuota:defaultQuota]; +} + +- (void)webView:(WebView *)sender setStatusText:(NSString *)text +{ + if (layoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]); +} + +- (void)dealloc +{ + [draggingInfo release]; + draggingInfo = nil; + + [super dealloc]; +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/WorkQueueItemMac.mm b/WebKitTools/DumpRenderTree/mac/WorkQueueItemMac.mm new file mode 100644 index 0000000..3a7b0e2 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/WorkQueueItemMac.mm @@ -0,0 +1,77 @@ +/* + * 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 "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> + +void 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]]]; +} + +void ReloadItem::invoke() const +{ + [[mainFrame webView] reload:nil]; +} + +void ScriptItem::invoke() const +{ + RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_script.get())); + NSString *scriptNS = (NSString *)scriptCF.get(); + [[mainFrame webView] stringByEvaluatingJavaScriptFromString:scriptNS]; +} + +void 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]]; + } +} |