📄 dumprendertree.mm
字号:
/* * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * (C) 2007 Graham Dennis (graham.dennis@gmail.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "DumpRenderTree.h"#import "AccessibilityController.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 <Carbon/Carbon.h>#import <CoreFoundation/CoreFoundation.h>#import <WebKit/DOMElementPrivate.h>#import <WebKit/DOMExtensions.h>#import <WebKit/DOMRange.h>#import <WebKit/WebBackForwardList.h>#import <WebKit/WebCache.h>#import <WebKit/WebCoreStatistics.h>#import <WebKit/WebDataSourcePrivate.h>#import <WebKit/WebDatabaseManagerPrivate.h>#import <WebKit/WebDocumentPrivate.h>#import <WebKit/WebEditingDelegate.h>#import <WebKit/WebFrameView.h>#import <WebKit/WebHTMLRepresentationInternal.h>#import <WebKit/WebHistory.h>#import <WebKit/WebHistoryItemPrivate.h>#import <WebKit/WebInspector.h>#import <WebKit/WebPluginDatabase.h>#import <WebKit/WebPreferences.h>#import <WebKit/WebPreferencesPrivate.h>#import <WebKit/WebResourceLoadDelegate.h>#import <WebKit/WebTypesInternal.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>#import <wtf/OwnPtr.h>using namespace std;@interface DumpRenderTreeEvent : NSEvent@endstatic void runTest(const string& testPathOrURL);// Deciding when it's OK to dump out the state is a bit tricky. All these must be true:// - There is no load in progress// - There is no work queued up (see workQueue var, below)// - waitToDump==NO. This means either waitUntilDone was never called, or it was called// and notifyDone was called subsequently.// Note that the call to notifyDone and the end of the load can happen in either order.volatile bool done;NavigationController* gNavigationController = 0;LayoutTestController* gLayoutTestController = 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 progressCFMutableSetRef disallowedURLs = 0;CFRunLoopTimerRef waitToDumpWatchdog = 0;// Delegatesstatic FrameLoadDelegate *frameLoadDelegate;static UIDelegate *uiDelegate;static EditingDelegate *editingDelegate;static ResourceLoadDelegate *resourceLoadDelegate;PolicyDelegate *policyDelegate;static int dumpPixels;static int threaded;static int dumpTree = YES;static int forceComplexText;static BOOL printSeparators;static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous testconst unsigned maxViewHeight = 600;const unsigned maxViewWidth = 800;#if __OBJC2__static void swizzleAllMethods(Class imposter, Class original){ unsigned int imposterMethodCount; Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount); unsigned int originalMethodCount; Method* originalMethods = class_copyMethodList(original, &originalMethodCount); for (unsigned int i = 0; i < imposterMethodCount; i++) { SEL imposterMethodName = method_getName(imposterMethods[i]); // Attempt to add the method to the original class. If it fails, the method already exists and we should // instead exchange the implementations. if (class_addMethod(original, imposterMethodName, method_getImplementation(imposterMethods[i]), method_getTypeEncoding(imposterMethods[i]))) continue; unsigned int j = 0; for (; j < originalMethodCount; j++) { SEL originalMethodName = method_getName(originalMethods[j]); if (sel_isEqual(imposterMethodName, originalMethodName)) break; } // If class_addMethod failed above then the method must exist on the original class. ASSERT(j < originalMethodCount); method_exchangeImplementations(imposterMethods[i], originalMethods[j]); } free(imposterMethods); free(originalMethods);}#endifstatic void poseAsClass(const char* imposter, const char* original){ Class imposterClass = objc_getClass(imposter); Class originalClass = objc_getClass(original);#if !__OBJC2__ class_poseAs(imposterClass, originalClass);#else // Swizzle instance methods swizzleAllMethods(imposterClass, originalClass); // and then class methods swizzleAllMethods(object_getClass(imposterClass), object_getClass(originalClass));#endif}void setPersistentUserStyleSheetLocation(CFStringRef url){ persistentUserStyleSheetLocation = url;}static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString){ static char* const ignoreSet[] = { // Keeping this infrastructure around in case we ever need it again. }; static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*); for (int i = 0; i < ignoreSetCount; i++) { // FIXME: ignore case string curIgnore(ignoreSet[i]); // Match at the end of the URLString if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore)) return true; } return false;}static void activateFonts(){ static const char* fontSectionNames[] = { "Ahem", "WeightWatcher100", "WeightWatcher200", "WeightWatcher300", "WeightWatcher400", "WeightWatcher500", "WeightWatcher600", "WeightWatcher700", "WeightWatcher800", "WeightWatcher900", 0 }; for (unsigned i = 0; fontSectionNames[i]; ++i) { unsigned long fontDataLength; char* fontData = getsectdata("__DATA", fontSectionNames[i], &fontDataLength); if (!fontData) { fprintf(stderr, "Failed to locate the %s font.\n", fontSectionNames[i]); exit(1); } ATSFontContainerRef fontContainer; OSStatus status = ATSFontActivateFromMemory(fontData, fontDataLength, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &fontContainer); if (status != noErr) { fprintf(stderr, "Failed to activate the %s font.\n", fontSectionNames[i]); exit(1); } }}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]; [window startObservingWebView]; // 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 NoFontSmoothing = 0; static const int BlueTintedAppearance = 1; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"]; [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"]; [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"]; [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"]; [defaults setObject:[NSArray arrayWithObject:@"en"] forKey:@"AppleLanguages"]; // Scrollbars are drawn either using AppKit (which uses NSUserDefaults) or using HIToolbox (which uses CFPreferences / kCFPreferencesAnyApplication / kCFPreferencesCurrentUser / kCFPreferencesAnyHost) [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; RetainPtr<CFTypeRef> initialValue = CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), CFSTR("DoubleMax"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);#ifndef __LP64__ // See <rdar://problem/6347388>. ThemeScrollBarArrowStyle style; GetThemeScrollBarArrowStyle(&style); // Force HIToolbox to read from CFPreferences#endif if (initialValue) CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 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 setJavaScriptEnabled:YES]; [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey]; [preferences setTabsToLinks:NO]; [preferences setDOMPasteAllowed:YES]; [preferences setFullDocumentTeardownEnabled:YES]; [preferences setShouldPrintBackgrounds: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){ char *signalName = strsignal(sig); write(STDERR_FILENO, signalName, strlen(signalName)); write(STDERR_FILENO, "\n", 1); restoreMainDisplayColorProfile(0); exit(128 + sig);}static void installSignalHandlers(){ signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */ signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */ signal(SIGEMT, crashHandler); /* 7: EMT instruction */ signal(SIGFPE, crashHandler); /* 8: floating point exception */ signal(SIGBUS, crashHandler); /* 10: bus error */ signal(SIGSEGV, crashHandler); /* 11: segmentation violation */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -