Home | History | Annotate | Download | only in mac
      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