From 07e46a567e874fc93119a249a00de9b7ff0169c6 Mon Sep 17 00:00:00 2001 From: "thomasvl@chromium.org" Date: Thu, 15 Jan 2009 15:44:54 +0000 Subject: - Bring over WebKit's DumpRenderTree support to keeping the tests out of the main pasteboard so any user actions won't break tests. Review URL: http://codereview.chromium.org/18018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8093 0039d316-1c4b-4281-b951-d872f2087c98 --- .../test_shell/mac/DumpRenderTreePasteboard.h | 47 +++++ .../test_shell/mac/DumpRenderTreePasteboard.m | 214 +++++++++++++++++++++ .../mac/TestShell.xcodeproj/project.pbxproj | 14 +- webkit/tools/test_shell/test_shell_mac.mm | 67 +++++++ 4 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 webkit/tools/test_shell/mac/DumpRenderTreePasteboard.h create mode 100644 webkit/tools/test_shell/mac/DumpRenderTreePasteboard.m diff --git a/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.h b/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.h new file mode 100644 index 0000000..60e2ab5 --- /dev/null +++ b/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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. + */ + +// +// This file comes from WebKit: +// WebKit/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.m +// It is copied here since that location is the best for pulling into Chromium +// and has a few includes commented out. darin@chromium.org suggests in the +// future we see if there is a better place for it to live so it could be +// shared. +// + +#import +// #import + +@interface DumpRenderTreePasteboard : NSPasteboard +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner; ++ (void)releaseLocalPasteboards; +@end + diff --git a/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.m b/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.m new file mode 100644 index 0000000..e8fa4ee --- /dev/null +++ b/webkit/tools/test_shell/mac/DumpRenderTreePasteboard.m @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. + * (C) 2007 Graham Dennis (graham.dennis@gmail.com) + * (C) 2007 Eric Seidel + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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. + */ + +// +// This file comes from WebKit: +// WebKit/WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.m +// It is copied here since that location is the best for pulling into Chromium +// and has a few includes commented out. darin@chromium.org suggests in the +// future we see if there is a better place for it to live so it could be +// shared. +// + +// #import "DumpRenderTreeMac.h" +#import "DumpRenderTreePasteboard.h" + +// #import + +@interface LocalPasteboard : NSPasteboard +{ + NSMutableArray *typesArray; + NSMutableSet *typesSet; + NSMutableDictionary *dataByType; + NSInteger changeCount; +} +@end + +static NSMutableDictionary *localPasteboards; + +@implementation DumpRenderTreePasteboard + +// Return a local pasteboard so we don't disturb the real pasteboards when running tests. ++ (NSPasteboard *)_pasteboardWithName:(NSString *)name +{ + static int number = 0; + if (!name) + name = [NSString stringWithFormat:@"LocalPasteboard%d", ++number]; + if (!localPasteboards) + localPasteboards = [[NSMutableDictionary alloc] init]; + LocalPasteboard *pasteboard = [localPasteboards objectForKey:name]; + if (pasteboard) + return pasteboard; + pasteboard = [[LocalPasteboard alloc] init]; + [localPasteboards setObject:pasteboard forKey:name]; + [pasteboard release]; + return pasteboard; +} + ++ (void)releaseLocalPasteboards +{ + [localPasteboards release]; + localPasteboards = nil; +} + +// Convenience method for JS so that it doesn't have to try and create a NSArray on the objc side instead +// of the usual WebScriptObject that is passed around +- (NSInteger)declareType:(NSString *)type owner:(id)newOwner +{ + return [self declareTypes:[NSArray arrayWithObject:type] owner:newOwner]; +} + +@end + +@implementation LocalPasteboard + ++ (id)alloc +{ + return NSAllocateObject(self, 0, 0); +} + +- (id)init +{ + typesArray = [[NSMutableArray alloc] init]; + typesSet = [[NSMutableSet alloc] init]; + dataByType = [[NSMutableDictionary alloc] init]; + return self; +} + +- (void)dealloc +{ + [typesArray release]; + [typesSet release]; + [dataByType release]; + [super dealloc]; +} + +- (NSString *)name +{ + return nil; +} + +- (void)releaseGlobally +{ +} + +- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner +{ + [typesArray removeAllObjects]; + [typesSet removeAllObjects]; + [dataByType removeAllObjects]; + return [self addTypes:newTypes owner:newOwner]; +} + +- (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner +{ + unsigned count = [newTypes count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [newTypes objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (!setType) { + setType = [type copy]; + [typesArray addObject:setType]; + [typesSet addObject:setType]; + [setType release]; + } + if (newOwner && [newOwner respondsToSelector:@selector(pasteboard:provideDataForType:)]) + [newOwner pasteboard:self provideDataForType:setType]; + } + return ++changeCount; +} + +- (NSInteger)changeCount +{ + return changeCount; +} + +- (NSArray *)types +{ + return typesArray; +} + +- (NSString *)availableTypeFromArray:(NSArray *)types +{ + unsigned count = [types count]; + unsigned i; + for (i = 0; i < count; ++i) { + NSString *type = [types objectAtIndex:i]; + NSString *setType = [typesSet member:type]; + if (setType) + return setType; + } + return nil; +} + +- (BOOL)setData:(NSData *)data forType:(NSString *)dataType +{ + if (data == nil) + data = [NSData data]; + if (![typesSet containsObject:dataType]) + return NO; + [dataByType setObject:data forKey:dataType]; + ++changeCount; + return YES; +} + +- (NSData *)dataForType:(NSString *)dataType +{ + return [dataByType objectForKey:dataType]; +} + +- (BOOL)setPropertyList:(id)propertyList forType:(NSString *)dataType; +{ + CFDataRef data = NULL; + if (propertyList) + data = CFPropertyListCreateXMLData(NULL, propertyList); + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +- (BOOL)setString:(NSString *)string forType:(NSString *)dataType +{ + CFDataRef data = NULL; + if (string) { + if ([string length] == 0) + data = CFDataCreate(NULL, NULL, 0); + else + data = CFStringCreateExternalRepresentation(NULL, (CFStringRef)string, kCFStringEncodingUTF8, 0); + } + BOOL result = [self setData:(NSData *)data forType:dataType]; + if (data) + CFRelease(data); + return result; +} + +@end diff --git a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj index cbeb257..7032f39 100644 --- a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj +++ b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj @@ -194,6 +194,8 @@ E456292F0E26B4FE005E4685 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; }; E45629300E26B4FE005E4685 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; }; E456296A0E26B64D005E4685 /* simple_resource_loader_bridge.cc in Sources */ = {isa = PBXBuildFile; fileRef = E45629690E26B64D005E4685 /* simple_resource_loader_bridge.cc */; }; + F431EA4A0F1D141300E8D37F /* DumpRenderTreePasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = F431EA480F1D141300E8D37F /* DumpRenderTreePasteboard.m */; }; + F4B3CA3B0F1D1AE100B9CA77 /* DumpRenderTreePasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = F431EA480F1D141300E8D37F /* DumpRenderTreePasteboard.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -822,6 +824,8 @@ E456295B0E26B5F8005E4685 /* bzip2.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = bzip2.xcodeproj; path = third_party/bzip2/bzip2.xcodeproj; sourceTree = ""; }; E45629680E26B64D005E4685 /* simple_resource_loader_bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_resource_loader_bridge.h; sourceTree = ""; }; E45629690E26B64D005E4685 /* simple_resource_loader_bridge.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_resource_loader_bridge.cc; sourceTree = ""; }; + F431EA480F1D141300E8D37F /* DumpRenderTreePasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DumpRenderTreePasteboard.m; sourceTree = ""; }; + F431EA490F1D141300E8D37F /* DumpRenderTreePasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreePasteboard.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1156,6 +1160,8 @@ 7BFDF4FD0E37AB4200F1D7D8 /* mac */ = { isa = PBXGroup; children = ( + F431EA480F1D141300E8D37F /* DumpRenderTreePasteboard.m */, + F431EA490F1D141300E8D37F /* DumpRenderTreePasteboard.h */, 29B97316FDCFA39411CA2CEA /* main.mm */, ABA65EFD0DD50BFF003A4FC8 /* test_shell_webview.h */, ABA65EFE0DD50BFF003A4FC8 /* test_shell_webview.mm */, @@ -1844,14 +1850,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 93AF4F340EFAFE2C0073C62D /* BMPImageDecoder_unittest.cpp in Sources */, E4506B8A0EF02BEF003BE099 /* bookmarklet_unittest.cc in Sources */, E4506B8C0EF02BFF003BE099 /* context_menu_unittest.cc in Sources */, E4506B910EF02C44003BE099 /* cpp_bound_class_unittest.cc in Sources */, E4506B930EF02C4B003BE099 /* cpp_variant_unittest.cc in Sources */, E4506B950EF02C53003BE099 /* dom_operations_unittest.cc in Sources */, E4506B970EF02C5B003BE099 /* dom_serializer_unittest.cc in Sources */, + F4B3CA3B0F1D1AE100B9CA77 /* DumpRenderTreePasteboard.m in Sources */, E45067B90EF015BF003BE099 /* event_sending_controller.cc in Sources */, + 93AF4F350EFAFE2C0073C62D /* GKURL_unittest.cpp in Sources */, E4506B990EF02C67003BE099 /* glue_serialize_unittest.cc in Sources */, + 93AF4F360EFAFE2C0073C62D /* ICOImageDecoder_unittest.cpp in Sources */, E4506B9B0EF02C6D003BE099 /* iframe_redirect_unittest.cc in Sources */, E45069F00EF017D0003BE099 /* image_decoder_unittest.cc in Sources */, E45069FB0EF01895003BE099 /* keyboard_unittest.cc in Sources */, @@ -1880,9 +1890,6 @@ E4506BE00EF03318003BE099 /* webframe_unittest.cc in Sources */, E45067C70EF01689003BE099 /* webview_host.mm in Sources */, E45067C80EF0168B003BE099 /* webwidget_host.mm in Sources */, - 93AF4F340EFAFE2C0073C62D /* BMPImageDecoder_unittest.cpp in Sources */, - 93AF4F350EFAFE2C0073C62D /* GKURL_unittest.cpp in Sources */, - 93AF4F360EFAFE2C0073C62D /* ICOImageDecoder_unittest.cpp in Sources */, 93AF4F370EFAFE2C0073C62D /* XBMImageDecoder_unittest.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1891,6 +1898,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F431EA4A0F1D141300E8D37F /* DumpRenderTreePasteboard.m in Sources */, E45629160E26B4FE005E4685 /* event_sending_controller.cc in Sources */, E45629170E26B4FE005E4685 /* layout_test_controller.cc in Sources */, E45629150E26B4FE005E4685 /* main.mm in Sources */, diff --git a/webkit/tools/test_shell/test_shell_mac.mm b/webkit/tools/test_shell/test_shell_mac.mm index 5b56949..47fd8a3 100644 --- a/webkit/tools/test_shell/test_shell_mac.mm +++ b/webkit/tools/test_shell/test_shell_mac.mm @@ -4,6 +4,7 @@ #include #import +#import #include #include "webkit/tools/test_shell/test_shell.h" @@ -37,6 +38,8 @@ #import "skia/include/SkBitmap.h" +#import "mac/DumpRenderTreePasteboard.h" + #define MAX_LOADSTRING 100 #define BUTTON_WIDTH 72 @@ -124,6 +127,69 @@ void TestShell::PlatformShutdown() { } // assert if we have anything left over, that would be bad. DCHECK(window_map_.Get().size() == 0); + + // Dump the pasteboards we built up. + [DumpRenderTreePasteboard releaseLocalPasteboards]; +} + +#if OBJC_API_VERSION == 2 +static void SwizzleAllMethods(Class imposter, Class original) { + unsigned int imposterMethodCount = 0; + Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount); + + unsigned int originalMethodCount = 0; + Method* originalMethods = class_copyMethodList(original, &originalMethodCount); + + for (unsigned int i = 0; i < imposterMethodCount; i++) { + SEL imposterMethodName = method_getName(imposterMethods[i]); + + // Attempt to add the method to the original class. If it fails, the method + // already exists and we should instead exchange the implementations. + if (class_addMethod(original, + imposterMethodName, + method_getImplementation(originalMethods[i]), + method_getTypeEncoding(originalMethods[i]))) { + continue; + } + + unsigned int j = 0; + for (; j < originalMethodCount; j++) { + SEL originalMethodName = method_getName(originalMethods[j]); + if (sel_isEqual(imposterMethodName, originalMethodName)) { + break; + } + } + + // If class_addMethod failed above then the method must exist on the + // original class. + DCHECK(j < originalMethodCount) << "method wasn't found?"; + method_exchangeImplementations(imposterMethods[i], originalMethods[j]); + } + + if (imposterMethods) { + free(imposterMethods); + } + if (originalMethods) { + free(originalMethods); + } +} +#endif + +static void SwizzleNSPasteboard(void) { + // We replace NSPaseboard w/ the shim (from WebKit) that avoids having + // sideeffects w/ whatever the user does at the same time. + + Class imposterClass = objc_getClass("DumpRenderTreePasteboard"); + Class originalClass = objc_getClass("NSPasteboard"); +#if OBJC_API_VERSION == 0 + class_poseAs(imposterClass, originalClass); +#else + // Swizzle instance methods... + SwizzleAllMethods(imposterClass, originalClass); + // and then class methods. + SwizzleAllMethods(object_getClass(imposterClass), + object_getClass(originalClass)); +#endif } static void SetDefaultsToLayoutTestValues(void) { @@ -281,6 +347,7 @@ void TestShell::InitializeTestShell(bool layout_test_mode) { layout_test_mode_ = layout_test_mode; if (layout_test_mode_) { + SwizzleNSPasteboard(); SetDefaultsToLayoutTestValues(); // If we could check the command line to see if we're doing pixel tests, // then we only install the color profile in that case. -- cgit v1.1