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