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 <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