1/* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#import "config.h" 30#import "DumpRenderTree.h" 31#import "FrameLoadDelegate.h" 32 33#import "AccessibilityController.h" 34#import "AppleScriptController.h" 35#import "EventSendingController.h" 36#import "GCController.h" 37#import "LayoutTestController.h" 38#import "NavigationController.h" 39#import "ObjCController.h" 40#import "ObjCPlugin.h" 41#import "ObjCPluginFunction.h" 42#import "PlainTextController.h" 43#import "TextInputController.h" 44#import "WorkQueue.h" 45#import "WorkQueueItem.h" 46#import <JavaScriptCore/JavaScriptCore.h> 47#import <WebKit/WebFramePrivate.h> 48#import <WebKit/WebHTMLViewPrivate.h> 49#import <WebKit/WebKit.h> 50#import <WebKit/WebNSURLExtras.h> 51#import <wtf/Assertions.h> 52 53@interface NSURLRequest (PrivateThingsWeShouldntReallyUse) 54+(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host; 55@end 56 57@interface NSURL (DRTExtras) 58- (NSString *)_drt_descriptionSuitableForTestResult; 59@end 60 61@interface NSError (DRTExtras) 62- (NSString *)_drt_descriptionSuitableForTestResult; 63@end 64 65@interface NSURLResponse (DRTExtras) 66- (NSString *)_drt_descriptionSuitableForTestResult; 67@end 68 69@interface NSURLRequest (DRTExtras) 70- (NSString *)_drt_descriptionSuitableForTestResult; 71@end 72 73@interface WebFrame (DRTExtras) 74- (NSString *)_drt_descriptionSuitableForTestResult; 75@end 76 77@implementation WebFrame (DRTExtras) 78- (NSString *)_drt_descriptionSuitableForTestResult 79{ 80 BOOL isMainFrame = (self == [[self webView] mainFrame]); 81 NSString *name = [self name]; 82 if (isMainFrame) { 83 if ([name length]) 84 return [NSString stringWithFormat:@"main frame \"%@\"", name]; 85 else 86 return @"main frame"; 87 } else { 88 if (name) 89 return [NSString stringWithFormat:@"frame \"%@\"", name]; 90 else 91 return @"frame (anonymous)"; 92 } 93} 94@end 95 96@implementation FrameLoadDelegate 97 98- (id)init 99{ 100 if ((self = [super init])) { 101 gcController = new GCController; 102 accessibilityController = new AccessibilityController; 103 } 104 return self; 105} 106 107- (void)dealloc 108{ 109 delete gcController; 110 delete accessibilityController; 111 [super dealloc]; 112} 113 114// Exec messages in the work queue until they're all done, or one of them starts a new load 115- (void)processWork:(id)dummy 116{ 117 // if another load started, then wait for it to complete. 118 if (topLoadingFrame) 119 return; 120 121 // if we finish all the commands, we're ready to dump state 122 if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) 123 dump(); 124} 125 126- (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource 127{ 128 if ([dataSource webFrame] == topLoadingFrame) { 129 topLoadingFrame = nil; 130 WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test 131 if (!gLayoutTestController->waitToDump()) { 132 if (WorkQueue::shared()->count()) 133 [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; 134 else 135 dump(); 136 } 137 } 138} 139 140- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame 141{ 142 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 143 NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 144 printf ("%s\n", [string UTF8String]); 145 } 146 147 ASSERT([frame provisionalDataSource]); 148 // Make sure we only set this once per test. If it gets cleared, and then set again, we might 149 // end up doing two dumps for one test. 150 if (!topLoadingFrame && !done) 151 topLoadingFrame = frame; 152 153 if (!done && gLayoutTestController->stopProvisionalFrameLoads()) { 154 NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]]; 155 printf ("%s\n", [string UTF8String]); 156 [frame stopLoading]; 157 } 158} 159 160- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame 161{ 162 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 163 NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 164 printf ("%s\n", [string UTF8String]); 165 } 166 167 ASSERT(![frame provisionalDataSource]); 168 ASSERT([frame dataSource]); 169 170 gLayoutTestController->setWindowIsKey(true); 171 NSView *documentView = [[mainFrame frameView] documentView]; 172 [[[mainFrame webView] window] makeFirstResponder:documentView]; 173} 174 175- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 176{ 177 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 178 NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; 179 printf ("%s\n", [string UTF8String]); 180 } 181 182 if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) { 183 NSURL *failedURL = [[error userInfo] objectForKey:@"NSErrorFailingURLKey"]; 184 [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[failedURL _web_hostString]]; 185 [frame loadRequest:[[[[frame provisionalDataSource] request] mutableCopy] autorelease]]; 186 return; 187 } 188 189 ASSERT([frame provisionalDataSource]); 190 [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]]; 191} 192 193- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame 194{ 195 ASSERT([frame dataSource]); 196 ASSERT(frame == [[frame dataSource] webFrame]); 197 198 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 199 NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 200 printf ("%s\n", [string UTF8String]); 201 } 202 203 // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed. 204 // After that is fixed, we will reenable painting after WebCore is done loading the document, 205 // and this call will no longer be needed. 206 if ([[sender mainFrame] isEqual:frame]) 207 [sender displayIfNeeded]; 208 [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]]; 209 [gNavigationController webView:sender didFinishLoadForFrame:frame]; 210} 211 212- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 213{ 214 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 215 NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; 216 printf ("%s\n", [string UTF8String]); 217 } 218 219 ASSERT(![frame provisionalDataSource]); 220 ASSERT([frame dataSource]); 221 222 [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]]; 223} 224 225- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject 226{ 227 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 228 NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; 229 printf ("%s\n", [string UTF8String]); 230 } 231 232 ASSERT_NOT_REACHED(); 233} 234 235- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)obj forFrame:(WebFrame *)frame 236{ 237 ASSERT(obj == [frame windowObject]); 238 ASSERT([obj JSObject] == JSContextGetGlobalObject([frame globalContext])); 239 240 // Make New-Style LayoutTestController 241 JSContextRef context = [frame globalContext]; 242 JSObjectRef globalObject = JSContextGetGlobalObject(context); 243 JSValueRef exception = 0; 244 245 ASSERT(gLayoutTestController); 246 gLayoutTestController->makeWindowObject(context, globalObject, &exception); 247 ASSERT(!exception); 248 249 gcController->makeWindowObject(context, globalObject, &exception); 250 ASSERT(!exception); 251 252 accessibilityController->makeWindowObject(context, globalObject, &exception); 253 ASSERT(!exception); 254 255 // Make Old-Style controllers 256 257 AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:sender]; 258 [obj setValue:asc forKey:@"appleScriptController"]; 259 [asc release]; 260 261 EventSendingController *esc = [[EventSendingController alloc] init]; 262 [obj setValue:esc forKey:@"eventSender"]; 263 [esc release]; 264 265 [obj setValue:gNavigationController forKey:@"navigationController"]; 266 267 ObjCController *occ = [[ObjCController alloc] init]; 268 [obj setValue:occ forKey:@"objCController"]; 269 [occ release]; 270 271 ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; 272 [obj setValue:plugin forKey:@"objCPlugin"]; 273 [plugin release]; 274 275 ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; 276 [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; 277 [pluginFunction release]; 278 279 [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"]; 280 281 TextInputController *tic = [[TextInputController alloc] initWithWebView:sender]; 282 [obj setValue:tic forKey:@"textInputController"]; 283 [tic release]; 284} 285 286- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame 287{ 288 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 289 NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; 290 printf ("%s\n", [string UTF8String]); 291 } 292 293 if (gLayoutTestController->dumpTitleChanges()) 294 printf("TITLE CHANGED: %s\n", [title UTF8String]); 295} 296 297- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame 298{ 299 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 300 NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 301 printf ("%s\n", [string UTF8String]); 302 } 303} 304 305- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame 306{ 307 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 308 NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]]; 309 printf ("%s\n", [string UTF8String]); 310 } 311} 312 313- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame 314{ 315 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 316 NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]]; 317 printf ("%s\n", [string UTF8String]); 318 } 319} 320 321- (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame 322{ 323 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 324 NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; 325 printf ("%s\n", [string UTF8String]); 326 } 327} 328 329- (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame 330{ 331 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 332 NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 333 printf ("%s\n", [string UTF8String]); 334 } else if (!done) { 335 unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount]; 336 if (pendingFrameUnloadEvents) { 337 NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents]; 338 printf ("%s\n", [string UTF8String]); 339 } 340 } 341} 342 343- (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame 344{ 345 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 346 NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; 347 printf ("%s\n", [string UTF8String]); 348 } 349} 350 351@end 352