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 <WebKit/WebScriptWorld.h> 52 #import <WebKit/WebSecurityOriginPrivate.h> 53 #import <wtf/Assertions.h> 54 55 @interface NSURL (DRTExtras) 56 - (NSString *)_drt_descriptionSuitableForTestResult; 57 @end 58 59 @interface NSError (DRTExtras) 60 - (NSString *)_drt_descriptionSuitableForTestResult; 61 @end 62 63 @interface NSURLResponse (DRTExtras) 64 - (NSString *)_drt_descriptionSuitableForTestResult; 65 @end 66 67 @interface NSURLRequest (DRTExtras) 68 - (NSString *)_drt_descriptionSuitableForTestResult; 69 @end 70 71 @interface WebFrame (DRTExtras) 72 - (NSString *)_drt_descriptionSuitableForTestResult; 73 @end 74 75 @implementation WebFrame (DRTExtras) 76 - (NSString *)_drt_descriptionSuitableForTestResult 77 { 78 BOOL isMainFrame = (self == [[self webView] mainFrame]); 79 NSString *name = [self name]; 80 if (isMainFrame) { 81 if ([name length]) 82 return [NSString stringWithFormat:@"main frame \"%@\"", name]; 83 else 84 return @"main frame"; 85 } else { 86 if (name) 87 return [NSString stringWithFormat:@"frame \"%@\"", name]; 88 else 89 return @"frame (anonymous)"; 90 } 91 } 92 @end 93 94 @implementation FrameLoadDelegate 95 96 - (id)init 97 { 98 if ((self = [super init])) { 99 gcController = new GCController; 100 accessibilityController = new AccessibilityController; 101 } 102 return self; 103 } 104 105 - (void)dealloc 106 { 107 delete gcController; 108 delete accessibilityController; 109 [super dealloc]; 110 } 111 112 // Exec messages in the work queue until they're all done, or one of them starts a new load 113 - (void)processWork:(id)dummy 114 { 115 // if another load started, then wait for it to complete. 116 if (topLoadingFrame) 117 return; 118 119 // if we finish all the commands, we're ready to dump state 120 if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) 121 dump(); 122 } 123 124 - (void)resetToConsistentState 125 { 126 accessibilityController->resetToConsistentState(); 127 } 128 129 - (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource 130 { 131 if ([dataSource webFrame] == topLoadingFrame) { 132 topLoadingFrame = nil; 133 WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test 134 if (!gLayoutTestController->waitToDump()) { 135 if (WorkQueue::shared()->count()) 136 [self performSelector:@selector(processWork:) withObject:nil afterDelay:0]; 137 else 138 dump(); 139 } 140 } 141 } 142 143 - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame 144 { 145 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 146 NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 147 printf ("%s\n", [string UTF8String]); 148 } 149 150 ASSERT([frame provisionalDataSource]); 151 // Make sure we only set this once per test. If it gets cleared, and then set again, we might 152 // end up doing two dumps for one test. 153 if (!topLoadingFrame && !done) 154 topLoadingFrame = frame; 155 156 if (!done && gLayoutTestController->stopProvisionalFrameLoads()) { 157 NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]]; 158 printf ("%s\n", [string UTF8String]); 159 [frame stopLoading]; 160 } 161 } 162 163 - (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame 164 { 165 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 166 NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 167 printf ("%s\n", [string UTF8String]); 168 } 169 170 ASSERT(![frame provisionalDataSource]); 171 ASSERT([frame dataSource]); 172 173 gLayoutTestController->setWindowIsKey(true); 174 NSView *documentView = [[mainFrame frameView] documentView]; 175 [[[mainFrame webView] window] makeFirstResponder:documentView]; 176 } 177 178 - (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 179 { 180 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 181 NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; 182 printf("%s\n", [string UTF8String]); 183 } 184 185 if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) { 186 // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL 187 // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree. 188 // 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 189 // to apply the workaround to. 190 ASSERT_NOT_REACHED(); 191 return; 192 } 193 194 ASSERT([frame provisionalDataSource]); 195 [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]]; 196 } 197 198 - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame 199 { 200 ASSERT([frame dataSource]); 201 ASSERT(frame == [[frame dataSource] webFrame]); 202 203 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 204 NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 205 printf ("%s\n", [string UTF8String]); 206 } 207 208 // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed. 209 // After that is fixed, we will reenable painting after WebCore is done loading the document, 210 // and this call will no longer be needed. 211 if ([[sender mainFrame] isEqual:frame]) 212 [sender displayIfNeeded]; 213 [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]]; 214 [gNavigationController webView:sender didFinishLoadForFrame:frame]; 215 } 216 217 - (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 218 { 219 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 220 NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]]; 221 printf ("%s\n", [string UTF8String]); 222 } 223 224 ASSERT(![frame provisionalDataSource]); 225 ASSERT([frame dataSource]); 226 227 [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]]; 228 } 229 230 - (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject 231 { 232 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 233 NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"]; 234 printf ("%s\n", [string UTF8String]); 235 } 236 237 ASSERT_NOT_REACHED(); 238 } 239 240 - (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame 241 { 242 // Make New-Style LayoutTestController 243 JSContextRef context = [frame globalContext]; 244 JSObjectRef globalObject = JSContextGetGlobalObject(context); 245 JSValueRef exception = 0; 246 247 ASSERT(gLayoutTestController); 248 gLayoutTestController->makeWindowObject(context, globalObject, &exception); 249 ASSERT(!exception); 250 251 gcController->makeWindowObject(context, globalObject, &exception); 252 ASSERT(!exception); 253 254 accessibilityController->makeWindowObject(context, globalObject, &exception); 255 ASSERT(!exception); 256 257 // Make Old-Style controllers 258 259 WebView *webView = [frame webView]; 260 WebScriptObject *obj = [frame windowObject]; 261 AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView]; 262 [obj setValue:asc forKey:@"appleScriptController"]; 263 [asc release]; 264 265 EventSendingController *esc = [[EventSendingController alloc] init]; 266 [obj setValue:esc forKey:@"eventSender"]; 267 [esc release]; 268 269 [obj setValue:gNavigationController forKey:@"navigationController"]; 270 271 ObjCController *occ = [[ObjCController alloc] init]; 272 [obj setValue:occ forKey:@"objCController"]; 273 [occ release]; 274 275 ObjCPlugin *plugin = [[ObjCPlugin alloc] init]; 276 [obj setValue:plugin forKey:@"objCPlugin"]; 277 [plugin release]; 278 279 ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init]; 280 [obj setValue:pluginFunction forKey:@"objCPluginFunction"]; 281 [pluginFunction release]; 282 283 [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"]; 284 285 TextInputController *tic = [[TextInputController alloc] initWithWebView:webView]; 286 [obj setValue:tic forKey:@"textInputController"]; 287 [tic release]; 288 } 289 290 - (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world 291 { 292 JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world]; 293 if (!ctx) 294 return; 295 296 JSObjectRef globalObject = JSContextGetGlobalObject(ctx); 297 if (!globalObject) 298 return; 299 300 JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); 301 } 302 303 - (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world 304 { 305 if (world == [WebScriptWorld standardWorld]) 306 [self didClearWindowObjectInStandardWorldForFrame:frame]; 307 else 308 [self didClearWindowObjectForFrame:frame inIsolatedWorld:world]; 309 } 310 311 - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame 312 { 313 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 314 NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title]; 315 printf ("%s\n", [string UTF8String]); 316 } 317 318 if (gLayoutTestController->dumpTitleChanges()) 319 printf("TITLE CHANGED: %s\n", [title UTF8String]); 320 } 321 322 - (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame 323 { 324 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 325 NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 326 printf ("%s\n", [string UTF8String]); 327 } 328 } 329 330 - (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame 331 { 332 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 333 NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]]; 334 printf ("%s\n", [string UTF8String]); 335 } 336 } 337 338 - (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame 339 { 340 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 341 NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]]; 342 printf ("%s\n", [string UTF8String]); 343 } 344 } 345 346 - (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame 347 { 348 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 349 NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]]; 350 printf ("%s\n", [string UTF8String]); 351 } 352 } 353 354 - (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame 355 { 356 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 357 NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]]; 358 printf ("%s\n", [string UTF8String]); 359 } else if (!done) { 360 unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount]; 361 if (pendingFrameUnloadEvents) { 362 NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents]; 363 printf ("%s\n", [string UTF8String]); 364 } 365 } 366 } 367 368 - (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame 369 { 370 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { 371 NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]]; 372 printf ("%s\n", [string UTF8String]); 373 } 374 } 375 376 - (void)webViewDidDisplayInsecureContent:(WebView *)sender 377 { 378 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) 379 printf ("didDisplayInsecureContent\n"); 380 } 381 382 - (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin 383 { 384 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) 385 printf ("didRunInsecureContent\n"); 386 } 387 388 @end 389