webengine/osswebengine/WebKit/Plugins/WebPluginController.mm
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005, 2006 Apple Computer, 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 
       
    30 #import <WebKit/WebPluginController.h>
       
    31 
       
    32 #import <Foundation/NSURLRequest.h>
       
    33 #import <WebCore/Frame.h>
       
    34 #import <WebCore/FrameLoader.h>
       
    35 #import <WebCore/ResourceRequest.h>
       
    36 #import <WebCore/PlatformString.h>
       
    37 #import <WebCore/WebCoreFrameBridge.h>
       
    38 #import <WebCore/DocumentLoader.h>
       
    39 #import <WebKit/WebDataSourceInternal.h>
       
    40 #import <WebKit/WebFrameBridge.h>
       
    41 #import <WebKit/WebFrameInternal.h>
       
    42 #import <WebKit/WebFrameView.h>
       
    43 #import <WebKit/WebHTMLViewPrivate.h>
       
    44 #import <WebKit/WebKitErrorsPrivate.h>
       
    45 #import <WebKit/WebKitLogging.h>
       
    46 #import <WebKit/WebNSURLExtras.h>
       
    47 #import <WebKit/WebNSViewExtras.h>
       
    48 #import <WebKit/WebPlugin.h>
       
    49 #import <WebKit/WebPluginContainer.h>
       
    50 #import <WebKit/WebPluginContainerCheck.h>
       
    51 #import <WebKit/WebPluginPackage.h>
       
    52 #import <WebKit/WebPluginPrivate.h>
       
    53 #import <WebKit/WebPluginViewFactory.h>
       
    54 #import <WebKit/WebUIDelegate.h>
       
    55 #import <WebKit/WebViewInternal.h>
       
    56 
       
    57 using namespace WebCore;
       
    58 
       
    59 @interface NSView (PluginSecrets)
       
    60 - (void)setContainingWindow:(NSWindow *)w;
       
    61 @end
       
    62 
       
    63 // For compatibility only.
       
    64 @interface NSObject (OldPluginAPI)
       
    65 + (NSView *)pluginViewWithArguments:(NSDictionary *)arguments;
       
    66 @end
       
    67 
       
    68 @interface NSView (OldPluginAPI)
       
    69 - (void)pluginInitialize;
       
    70 - (void)pluginStart;
       
    71 - (void)pluginStop;
       
    72 - (void)pluginDestroy;
       
    73 @end
       
    74 
       
    75 static NSMutableSet *pluginViews = nil;
       
    76 
       
    77 @implementation WebPluginController
       
    78 
       
    79 + (NSView *)plugInViewWithArguments:(NSDictionary *)arguments fromPluginPackage:(WebPluginPackage *)pluginPackage
       
    80 {
       
    81     [pluginPackage load];
       
    82     Class viewFactory = [pluginPackage viewFactory];
       
    83     
       
    84     NSView *view = nil;
       
    85 
       
    86     if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
       
    87         KJS::JSLock::DropAllLocks dropAllLocks;
       
    88         view = [viewFactory plugInViewWithArguments:arguments];
       
    89     } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
       
    90         KJS::JSLock::DropAllLocks dropAllLocks;
       
    91         view = [viewFactory pluginViewWithArguments:arguments];
       
    92     }
       
    93     
       
    94     if (view == nil) {
       
    95         return nil;
       
    96     }
       
    97     
       
    98     if (pluginViews == nil) {
       
    99         pluginViews = [[NSMutableSet alloc] init];
       
   100     }
       
   101     [pluginViews addObject:view];
       
   102     
       
   103     return view;
       
   104 }
       
   105 
       
   106 + (BOOL)isPlugInView:(NSView *)view
       
   107 {
       
   108     return [pluginViews containsObject:view];
       
   109 }
       
   110 
       
   111 - (id)initWithDocumentView:(NSView *)view
       
   112 {
       
   113     [super init];
       
   114     _documentView = view;
       
   115     _views = [[NSMutableArray alloc] init];
       
   116     _checksInProgress = (NSMutableSet *)CFMakeCollectable(CFSetCreateMutable(NULL, 0, NULL));
       
   117     return self;
       
   118 }
       
   119 
       
   120 - (void)setDataSource:(WebDataSource *)dataSource
       
   121 {
       
   122     _dataSource = dataSource;    
       
   123 }
       
   124 
       
   125 - (void)dealloc
       
   126 {
       
   127     [_views release];
       
   128     [_checksInProgress release];
       
   129     [super dealloc];
       
   130 }
       
   131 
       
   132 - (void)startAllPlugins
       
   133 {
       
   134     if (_started)
       
   135         return;
       
   136     
       
   137     if ([_views count] > 0)
       
   138         LOG(Plugins, "starting WebKit plugins : %@", [_views description]);
       
   139     
       
   140     int i, count = [_views count];
       
   141     for (i = 0; i < count; i++) {
       
   142         id aView = [_views objectAtIndex:i];
       
   143         if ([aView respondsToSelector:@selector(webPlugInStart)]) {
       
   144             KJS::JSLock::DropAllLocks dropAllLocks;
       
   145             [aView webPlugInStart];
       
   146         } else if ([aView respondsToSelector:@selector(pluginStart)]) {
       
   147             KJS::JSLock::DropAllLocks dropAllLocks;
       
   148             [aView pluginStart];
       
   149         }
       
   150     }
       
   151     _started = YES;
       
   152 }
       
   153 
       
   154 - (void)stopAllPlugins
       
   155 {
       
   156     if (!_started)
       
   157         return;
       
   158 
       
   159     if ([_views count] > 0) {
       
   160         LOG(Plugins, "stopping WebKit plugins: %@", [_views description]);
       
   161     }
       
   162     
       
   163     int i, count = [_views count];
       
   164     for (i = 0; i < count; i++) {
       
   165         id aView = [_views objectAtIndex:i];
       
   166         if ([aView respondsToSelector:@selector(webPlugInStop)]) {
       
   167             KJS::JSLock::DropAllLocks dropAllLocks;
       
   168             [aView webPlugInStop];
       
   169         } else if ([aView respondsToSelector:@selector(pluginStop)]) {
       
   170             KJS::JSLock::DropAllLocks dropAllLocks;
       
   171             [aView pluginStop];
       
   172         }
       
   173     }
       
   174     _started = NO;
       
   175 }
       
   176 
       
   177 - (void)addPlugin:(NSView *)view
       
   178 {
       
   179     if (!_documentView) {
       
   180         LOG_ERROR("can't add a plug-in to a defunct WebPluginController");
       
   181         return;
       
   182     }
       
   183     
       
   184     if (![_views containsObject:view]) {
       
   185         [_views addObject:view];
       
   186         
       
   187         LOG(Plugins, "initializing plug-in %@", view);
       
   188         if ([view respondsToSelector:@selector(webPlugInInitialize)]) {
       
   189             KJS::JSLock::DropAllLocks dropAllLocks;
       
   190             [view webPlugInInitialize];
       
   191         } else if ([view respondsToSelector:@selector(pluginInitialize)]) {
       
   192             KJS::JSLock::DropAllLocks dropAllLocks;
       
   193             [view pluginInitialize];
       
   194         }
       
   195 
       
   196         if (_started) {
       
   197             LOG(Plugins, "starting plug-in %@", view);
       
   198             if ([view respondsToSelector:@selector(webPlugInStart)]) {
       
   199                 KJS::JSLock::DropAllLocks dropAllLocks;
       
   200                 [view webPlugInStart];
       
   201             } else if ([view respondsToSelector:@selector(pluginStart)]) {
       
   202                 KJS::JSLock::DropAllLocks dropAllLocks;
       
   203                 [view pluginStart];
       
   204             }
       
   205             
       
   206             if ([view respondsToSelector:@selector(setContainingWindow:)]) {
       
   207                 KJS::JSLock::DropAllLocks dropAllLocks;
       
   208                 [view setContainingWindow:[_documentView window]];
       
   209             }
       
   210         }
       
   211     }
       
   212 }
       
   213 
       
   214 - (void)destroyPlugin:(NSView *)view
       
   215 {
       
   216     if ([_views containsObject:view]) {
       
   217         if (_started) {
       
   218             if ([view respondsToSelector:@selector(webPlugInStop)]) {
       
   219                 KJS::JSLock::DropAllLocks dropAllLocks;
       
   220                 [view webPlugInStop];
       
   221             } else if ([view respondsToSelector:@selector(pluginStop)]) {
       
   222                 KJS::JSLock::DropAllLocks dropAllLocks;
       
   223                 [view pluginStop];
       
   224             }
       
   225         }
       
   226         
       
   227         if ([view respondsToSelector:@selector(webPlugInDestroy)]) {
       
   228             KJS::JSLock::DropAllLocks dropAllLocks;
       
   229             [view webPlugInDestroy];
       
   230         } else if ([view respondsToSelector:@selector(pluginDestroy)]) {
       
   231             KJS::JSLock::DropAllLocks dropAllLocks;
       
   232             [view pluginDestroy];
       
   233         }
       
   234         
       
   235         if (Frame* frame = core([self webFrame]))
       
   236             frame->cleanupScriptObjectsForPlugin(self);
       
   237         
       
   238         [pluginViews removeObject:view];
       
   239         [_views removeObject:view];
       
   240     }
       
   241 }
       
   242 
       
   243 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)checkIdentifier
       
   244 {
       
   245     [checkIdentifier cancel];
       
   246     [_checksInProgress removeObject:checkIdentifier];
       
   247 }
       
   248 
       
   249 static void cancelOutstandingCheck(const void *item, void *context)
       
   250 {
       
   251     [(id)item cancel];
       
   252 }
       
   253 
       
   254 - (void)_cancelOutstandingChecks
       
   255 {
       
   256     if (_checksInProgress) {
       
   257         CFSetApplyFunction((CFSetRef)_checksInProgress, cancelOutstandingCheck, NULL);
       
   258         [_checksInProgress release];
       
   259         _checksInProgress = nil;
       
   260     }
       
   261 }
       
   262 
       
   263 - (void)destroyAllPlugins
       
   264 {    
       
   265     [self stopAllPlugins];
       
   266 
       
   267     if ([_views count] > 0) {
       
   268         LOG(Plugins, "destroying WebKit plugins: %@", [_views description]);
       
   269     }
       
   270 
       
   271     [self _cancelOutstandingChecks];
       
   272     
       
   273     int i, count = [_views count];
       
   274     for (i = 0; i < count; i++) {
       
   275         id aView = [_views objectAtIndex:i];
       
   276         if ([aView respondsToSelector:@selector(webPlugInDestroy)]) {
       
   277             KJS::JSLock::DropAllLocks dropAllLocks;
       
   278             [aView webPlugInDestroy];
       
   279         } else if ([aView respondsToSelector:@selector(pluginDestroy)]) {
       
   280             KJS::JSLock::DropAllLocks dropAllLocks;
       
   281             [aView pluginDestroy];
       
   282         }
       
   283         
       
   284         if (Frame* frame = core([self webFrame]))
       
   285             frame->cleanupScriptObjectsForPlugin(self);
       
   286         
       
   287         [pluginViews removeObject:aView];
       
   288     }
       
   289     [_views makeObjectsPerformSelector:@selector(removeFromSuperviewWithoutNeedingDisplay)];
       
   290     [_views release];
       
   291     _views = nil;
       
   292 
       
   293     _documentView = nil;
       
   294 }
       
   295 
       
   296 - (id)_webPluginContainerCheckIfAllowedToLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target resultObject:(id)obj selector:(SEL)selector
       
   297 {
       
   298     WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:request target:target resultObject:obj selector:selector controller:self];
       
   299     [_checksInProgress addObject:check];
       
   300     [check start];
       
   301 
       
   302     return check;
       
   303 }
       
   304 
       
   305 - (void)webPlugInContainerLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target
       
   306 {
       
   307     if (!request) {
       
   308         LOG_ERROR("nil URL passed");
       
   309         return;
       
   310     }
       
   311     if (!_documentView) {
       
   312         LOG_ERROR("could not load URL %@ because plug-in has already been destroyed", request);
       
   313         return;
       
   314     }
       
   315     WebFrame *frame = [_dataSource webFrame];
       
   316     if (!frame) {
       
   317         LOG_ERROR("could not load URL %@ because plug-in has already been stopped", request);
       
   318         return;
       
   319     }
       
   320     if (!target) {
       
   321         target = @"_top";
       
   322     }
       
   323     NSString *JSString = [[request URL] _webkit_scriptIfJavaScriptURL];
       
   324     if (JSString) {
       
   325         if ([frame findFrameNamed:target] != frame) {
       
   326             LOG_ERROR("JavaScript requests can only be made on the frame that contains the plug-in");
       
   327             return;
       
   328         }
       
   329         [[frame _bridge] stringByEvaluatingJavaScriptFromString:JSString];
       
   330     } else {
       
   331         if (!request) {
       
   332             LOG_ERROR("could not load URL %@", [request URL]);
       
   333             return;
       
   334         }
       
   335         [frame _frameLoader]->load(request, target);
       
   336     }
       
   337 }
       
   338 
       
   339 // For compatibility only.
       
   340 - (void)showURL:(NSURL *)URL inFrame:(NSString *)target
       
   341 {
       
   342     [self webPlugInContainerLoadRequest:[NSURLRequest requestWithURL:URL] inFrame:target];
       
   343 }
       
   344 
       
   345 - (void)webPlugInContainerShowStatus:(NSString *)message
       
   346 {
       
   347     if (!message) {
       
   348         message = @"";
       
   349     }
       
   350     if (!_documentView) {
       
   351         LOG_ERROR("could not show status message (%@) because plug-in has already been destroyed", message);
       
   352         return;
       
   353     }
       
   354     WebView *v = [_dataSource _webView];
       
   355     [[v _UIDelegateForwarder] webView:v setStatusText:message];
       
   356 }
       
   357 
       
   358 // For compatibility only.
       
   359 - (void)showStatus:(NSString *)message
       
   360 {
       
   361     [self webPlugInContainerShowStatus:message];
       
   362 }
       
   363 
       
   364 - (NSColor *)webPlugInContainerSelectionColor
       
   365 {
       
   366     return [[_dataSource _bridge] selectionColor];
       
   367 }
       
   368 
       
   369 // For compatibility only.
       
   370 - (NSColor *)selectionColor
       
   371 {
       
   372     return [self webPlugInContainerSelectionColor];
       
   373 }
       
   374 
       
   375 - (WebFrame *)webFrame
       
   376 {
       
   377     return [_dataSource webFrame];
       
   378 }
       
   379 
       
   380 - (WebFrameBridge *)bridge
       
   381 {
       
   382     return [[self webFrame] _bridge];
       
   383 }
       
   384 
       
   385 - (WebView *)webView
       
   386 {
       
   387     return [[self webFrame] webView];
       
   388 }
       
   389 
       
   390 - (NSString *)URLPolicyCheckReferrer
       
   391 {
       
   392     NSURL *responseURL = [[[[self webFrame] _dataSource] response] URL];
       
   393     ASSERT(responseURL);
       
   394     return [responseURL _web_originalDataAsString];
       
   395 }
       
   396 
       
   397 - (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
       
   398 {    
       
   399     if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveResponse:)])
       
   400         [pluginView webPlugInMainResourceDidReceiveResponse:response];
       
   401     else {
       
   402         // Cancel the load since this plug-in does its own loading.
       
   403         // FIXME: See <rdar://problem/4258008> for a problem with this.
       
   404         NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
       
   405                                                         contentURL:[response URL]
       
   406                                                      pluginPageURL:nil
       
   407                                                         pluginName:nil // FIXME: Get this from somewhere
       
   408                                                           MIMEType:[response MIMEType]];
       
   409         [_dataSource _documentLoader]->cancelMainResourceLoad(error);
       
   410         [error release];
       
   411     }        
       
   412 }
       
   413 
       
   414 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
       
   415 {
       
   416     if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveData:)])
       
   417         [pluginView webPlugInMainResourceDidReceiveData:data];
       
   418 }
       
   419 
       
   420 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
       
   421 {
       
   422     if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFailWithError:)])
       
   423         [pluginView webPlugInMainResourceDidFailWithError:error];
       
   424 }
       
   425 
       
   426 - (void)pluginViewFinishedLoading:(NSView *)pluginView
       
   427 {
       
   428     if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFinishLoading)])
       
   429         [pluginView webPlugInMainResourceDidFinishLoading];
       
   430 }
       
   431 
       
   432 @end