/* * Copyright (C) 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "DumpRenderTree.h" #import "FrameLoadDelegate.h" #import "AccessibilityController.h" #import "AppleScriptController.h" #import "EventSendingController.h" #import "GCController.h" #import "LayoutTestController.h" #import "NavigationController.h" #import "ObjCController.h" #import "ObjCPlugin.h" #import "ObjCPluginFunction.h" #import "PlainTextController.h" #import "TextInputController.h" #import "WorkQueue.h" #import "WorkQueueItem.h" #import #import #import #import #import #import #import #import #import @interface NSURL (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult; @end @interface NSError (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult; @end @interface NSURLResponse (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult; @end @interface NSURLRequest (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult; @end @interface WebFrame (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult; @end @implementation WebFrame (DRTExtras) - (NSString *)_drt_descriptionSuitableForTestResult { BOOL isMainFrame = (self == [[self webView] mainFrame]); NSString *name = [self name]; if (isMainFrame) { if ([name length]) return [NSString stringWithFormat:@"main frame \"%@\"", name]; else return @"main frame"; } else { if (name) return [NSString stringWithFormat:@"frame \"%@\"", name]; else return @"frame (anonymous)"; } } - (NSString *)_drt_printFrameUserGestureStatus { BOOL isUserGesture = [[self webView] _isProcessingUserGesture]; return [NSString stringWithFormat:@"Frame with user gesture \"%@\"", isUserGesture ? @"true" : @"false"]; } @end @implementation FrameLoadDelegate - (id)init { if ((self = [super init])) { gcController = new GCController; accessibilityController = new AccessibilityController; } return self; } - (void)dealloc { delete gcController; delete accessibilityController; [super dealloc]; } // Exec messages in the work queue until they're all done, or one of them starts a new load - (void)processWork:(id)dummy { // if another load started, then wait for it to complete. if (topLoadingFrame) return; // if we finish all the commands, we're ready to dump state if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) dump(); } - (void)resetToConsistentState { accessibilityController->resetToConsistentState(); } - (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource { if ([dataSource webFrame] == topLoadingFrame) { topLoadingFrame = nil; WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test if (!gLayoutTestController->waitToDump()) { if (WorkQueue::shared()->count()) [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; else dump(); } } } - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - in didStartProvisionalLoadForFrame", [frame _drt_printFrameUserGestureStatus]]; printf ("%s\n", [string UTF8String]); } ASSERT([frame provisionalDataSource]); // Make sure we only set this once per test. If it gets cleared, and then set again, we might // end up doing two dumps for one test. if (!topLoadingFrame && !done) topLoadingFrame = frame; if (!done && gLayoutTestController->stopProvisionalFrameLoads()) { NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); [frame stopLoading]; } } - (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } ASSERT(![frame provisionalDataSource]); ASSERT([frame dataSource]); gLayoutTestController->setWindowIsKey(true); NSView *documentView = [[mainFrame frameView] documentView]; [[[mainFrame webView] window] makeFirstResponder:documentView]; } - (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; printf("%s\n", [string UTF8String]); } if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) { // In order to prevent extra frame load delegate logging being generated if the first test to use SSL // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree. // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need // to apply the workaround to. ASSERT_NOT_REACHED(); return; } ASSERT([frame provisionalDataSource]); [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]]; } - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { ASSERT([frame dataSource]); ASSERT(frame == [[frame dataSource] webFrame]); if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } // FIXME: This call to displayIfNeeded can be removed when is fixed. // After that is fixed, we will reenable painting after WebCore is done loading the document, // and this call will no longer be needed. if ([[sender mainFrame] isEqual:frame]) [sender displayIfNeeded]; [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]]; [gNavigationController webView:sender didFinishLoadForFrame:frame]; } - (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } ASSERT(![frame provisionalDataSource]); ASSERT([frame dataSource]); [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]]; } - (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; printf ("%s\n", [string UTF8String]); } ASSERT_NOT_REACHED(); } - (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame { // Make New-Style LayoutTestController JSContextRef context = [frame globalContext]; JSObjectRef globalObject = JSContextGetGlobalObject(context); JSValueRef exception = 0; ASSERT(gLayoutTestController); gLayoutTestController->makeWindowObject(context, globalObject, &exception); ASSERT(!exception); gcController->makeWindowObject(context, globalObject, &exception); ASSERT(!exception); accessibilityController->makeWindowObject(context, globalObject, &exception); ASSERT(!exception); // Make Old-Style controllers WebView *webView = [frame webView]; WebScriptObject *obj = [frame windowObject]; AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView]; [obj setValue:asc forKey:@"appleScriptController"]; [asc release]; EventSendingController *esc = [[EventSendingController alloc] init]; [obj setValue:esc forKey:@"eventSender"]; [esc release]; [obj setValue:gNavigationController forKey:@"navigationController"]; ObjCController *occ = [[ObjCController alloc] init]; [obj setValue:occ forKey:@"objCController"]; [occ release]; ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; [obj setValue:plugin forKey:@"objCPlugin"]; [plugin release]; ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; [pluginFunction release]; [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"]; TextInputController *tic = [[TextInputController alloc] initWithWebView:webView]; [obj setValue:tic forKey:@"textInputController"]; [tic release]; } - (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world { JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world]; if (!ctx) return; JSObjectRef globalObject = JSContextGetGlobalObject(ctx); if (!globalObject) return; JSObjectSetProperty(ctx, globalObject, JSRetainPtr(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); } - (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world { if (world == [WebScriptWorld standardWorld]) [self didClearWindowObjectInStandardWorldForFrame:frame]; else [self didClearWindowObjectForFrame:frame inIsolatedWorld:world]; } - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; printf ("%s\n", [string UTF8String]); } if (gLayoutTestController->dumpTitleChanges()) printf("TITLE CHANGED: %s\n", [title UTF8String]); } - (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } } - (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } } - (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } } - (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } } - (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } else if (!done) { unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount]; if (pendingFrameUnloadEvents) { NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents]; printf ("%s\n", [string UTF8String]); } } } - (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; printf ("%s\n", [string UTF8String]); } } - (void)webViewDidDisplayInsecureContent:(WebView *)sender { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf ("didDisplayInsecureContent\n"); } - (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf ("didRunInsecureContent\n"); } @end