2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #import <WebKit/WebPluginController.h>
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/DocumentLoader.h>
38 #import <WebKit/WebDataSourceInternal.h>
39 #import <WebKit/WebFrameInternal.h>
40 #import <WebKit/WebFrameView.h>
41 #import <WebKit/WebHTMLViewPrivate.h>
42 #import <WebKit/WebKitErrorsPrivate.h>
43 #import <WebKit/WebKitLogging.h>
44 #import <WebKit/WebNSURLExtras.h>
45 #import <WebKit/WebNSViewExtras.h>
46 #import <WebKit/WebPlugin.h>
47 #import <WebKit/WebPluginContainer.h>
48 #import <WebKit/WebPluginContainerCheck.h>
49 #import <WebKit/WebPluginPackage.h>
50 #import <WebKit/WebPluginPrivate.h>
51 #import <WebKit/WebPluginViewFactory.h>
52 #import <WebKit/WebUIDelegate.h>
53 #import <WebKit/WebViewInternal.h>
55 using namespace WebCore;
57 @interface NSView (PluginSecrets)
58 - (void)setContainingWindow:(NSWindow *)w;
61 // For compatibility only.
62 @interface NSObject (OldPluginAPI)
63 + (NSView *)pluginViewWithArguments:(NSDictionary *)arguments;
66 @interface NSView (OldPluginAPI)
67 - (void)pluginInitialize;
70 - (void)pluginDestroy;
73 static NSMutableSet *pluginViews = nil;
75 @implementation WebPluginController
77 + (NSView *)plugInViewWithArguments:(NSDictionary *)arguments fromPluginPackage:(WebPluginPackage *)pluginPackage
80 Class viewFactory = [pluginPackage viewFactory];
84 if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
85 KJS::JSLock::DropAllLocks dropAllLocks;
86 view = [viewFactory plugInViewWithArguments:arguments];
87 } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
88 KJS::JSLock::DropAllLocks dropAllLocks;
89 view = [viewFactory pluginViewWithArguments:arguments];
96 if (pluginViews == nil) {
97 pluginViews = [[NSMutableSet alloc] init];
99 [pluginViews addObject:view];
104 + (BOOL)isPlugInView:(NSView *)view
106 return [pluginViews containsObject:view];
109 - (id)initWithDocumentView:(NSView *)view
112 _documentView = view;
113 _views = [[NSMutableArray alloc] init];
114 _checksInProgress = (NSMutableSet *)CFMakeCollectable(CFSetCreateMutable(NULL, 0, NULL));
118 - (void)setDataSource:(WebDataSource *)dataSource
120 _dataSource = dataSource;
126 [_checksInProgress release];
130 - (void)startAllPlugins
135 if ([_views count] > 0)
136 LOG(Plugins, "starting WebKit plugins : %@", [_views description]);
138 int i, count = [_views count];
139 for (i = 0; i < count; i++) {
140 id aView = [_views objectAtIndex:i];
141 if ([aView respondsToSelector:@selector(webPlugInStart)]) {
142 KJS::JSLock::DropAllLocks dropAllLocks;
143 [aView webPlugInStart];
144 } else if ([aView respondsToSelector:@selector(pluginStart)]) {
145 KJS::JSLock::DropAllLocks dropAllLocks;
152 - (void)stopAllPlugins
157 if ([_views count] > 0) {
158 LOG(Plugins, "stopping WebKit plugins: %@", [_views description]);
161 int i, count = [_views count];
162 for (i = 0; i < count; i++) {
163 id aView = [_views objectAtIndex:i];
164 if ([aView respondsToSelector:@selector(webPlugInStop)]) {
165 KJS::JSLock::DropAllLocks dropAllLocks;
166 [aView webPlugInStop];
167 } else if ([aView respondsToSelector:@selector(pluginStop)]) {
168 KJS::JSLock::DropAllLocks dropAllLocks;
175 - (void)addPlugin:(NSView *)view
177 if (!_documentView) {
178 LOG_ERROR("can't add a plug-in to a defunct WebPluginController");
182 if (![_views containsObject:view]) {
183 [_views addObject:view];
185 LOG(Plugins, "initializing plug-in %@", view);
186 if ([view respondsToSelector:@selector(webPlugInInitialize)]) {
187 KJS::JSLock::DropAllLocks dropAllLocks;
188 [view webPlugInInitialize];
189 } else if ([view respondsToSelector:@selector(pluginInitialize)]) {
190 KJS::JSLock::DropAllLocks dropAllLocks;
191 [view pluginInitialize];
195 LOG(Plugins, "starting plug-in %@", view);
196 if ([view respondsToSelector:@selector(webPlugInStart)]) {
197 KJS::JSLock::DropAllLocks dropAllLocks;
198 [view webPlugInStart];
199 } else if ([view respondsToSelector:@selector(pluginStart)]) {
200 KJS::JSLock::DropAllLocks dropAllLocks;
204 if ([view respondsToSelector:@selector(setContainingWindow:)]) {
205 KJS::JSLock::DropAllLocks dropAllLocks;
206 [view setContainingWindow:[_documentView window]];
212 - (void)destroyPlugin:(NSView *)view
214 if ([_views containsObject:view]) {
216 if ([view respondsToSelector:@selector(webPlugInStop)]) {
217 KJS::JSLock::DropAllLocks dropAllLocks;
218 [view webPlugInStop];
219 } else if ([view respondsToSelector:@selector(pluginStop)]) {
220 KJS::JSLock::DropAllLocks dropAllLocks;
225 if ([view respondsToSelector:@selector(webPlugInDestroy)]) {
226 KJS::JSLock::DropAllLocks dropAllLocks;
227 [view webPlugInDestroy];
228 } else if ([view respondsToSelector:@selector(pluginDestroy)]) {
229 KJS::JSLock::DropAllLocks dropAllLocks;
230 [view pluginDestroy];
233 if (Frame* frame = core([self webFrame]))
234 frame->cleanupScriptObjectsForPlugin(self);
236 [pluginViews removeObject:view];
237 [_views removeObject:view];
241 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)checkIdentifier
243 [checkIdentifier cancel];
244 [_checksInProgress removeObject:checkIdentifier];
247 static void cancelOutstandingCheck(const void *item, void *context)
252 - (void)_cancelOutstandingChecks
254 if (_checksInProgress) {
255 CFSetApplyFunction((CFSetRef)_checksInProgress, cancelOutstandingCheck, NULL);
256 [_checksInProgress release];
257 _checksInProgress = nil;
261 - (void)destroyAllPlugins
263 [self stopAllPlugins];
265 if ([_views count] > 0) {
266 LOG(Plugins, "destroying WebKit plugins: %@", [_views description]);
269 [self _cancelOutstandingChecks];
271 int i, count = [_views count];
272 for (i = 0; i < count; i++) {
273 id aView = [_views objectAtIndex:i];
274 if ([aView respondsToSelector:@selector(webPlugInDestroy)]) {
275 KJS::JSLock::DropAllLocks dropAllLocks;
276 [aView webPlugInDestroy];
277 } else if ([aView respondsToSelector:@selector(pluginDestroy)]) {
278 KJS::JSLock::DropAllLocks dropAllLocks;
279 [aView pluginDestroy];
282 if (Frame* frame = core([self webFrame]))
283 frame->cleanupScriptObjectsForPlugin(self);
285 [pluginViews removeObject:aView];
287 [_views makeObjectsPerformSelector:@selector(removeFromSuperviewWithoutNeedingDisplay)];
294 - (id)_webPluginContainerCheckIfAllowedToLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target resultObject:(id)obj selector:(SEL)selector
296 WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:request target:target resultObject:obj selector:selector controller:self];
297 [_checksInProgress addObject:check];
303 - (void)webPlugInContainerLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target
306 LOG_ERROR("nil URL passed");
309 if (!_documentView) {
310 LOG_ERROR("could not load URL %@ because plug-in has already been destroyed", request);
313 WebFrame *frame = [_dataSource webFrame];
315 LOG_ERROR("could not load URL %@ because plug-in has already been stopped", request);
321 NSString *JSString = [[request URL] _webkit_scriptIfJavaScriptURL];
323 if ([frame findFrameNamed:target] != frame) {
324 LOG_ERROR("JavaScript requests can only be made on the frame that contains the plug-in");
327 [frame _stringByEvaluatingJavaScriptFromString:JSString];
330 LOG_ERROR("could not load URL %@", [request URL]);
333 [frame _frameLoader]->load(request, target);
337 // For compatibility only.
338 - (void)showURL:(NSURL *)URL inFrame:(NSString *)target
340 [self webPlugInContainerLoadRequest:[NSURLRequest requestWithURL:URL] inFrame:target];
343 - (void)webPlugInContainerShowStatus:(NSString *)message
348 if (!_documentView) {
349 LOG_ERROR("could not show status message (%@) because plug-in has already been destroyed", message);
352 WebView *v = [_dataSource _webView];
353 [[v _UIDelegateForwarder] webView:v setStatusText:message];
356 // For compatibility only.
357 - (void)showStatus:(NSString *)message
359 [self webPlugInContainerShowStatus:message];
362 - (NSColor *)webPlugInContainerSelectionColor
365 if (Frame* frame = core([self webFrame]))
366 primary = frame->selectionController()->isFocusedAndActive();
367 return primary ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
370 // For compatibility only.
371 - (NSColor *)selectionColor
373 return [self webPlugInContainerSelectionColor];
376 - (WebFrame *)webFrame
378 return [_dataSource webFrame];
383 return [[self webFrame] webView];
386 - (NSString *)URLPolicyCheckReferrer
388 NSURL *responseURL = [[[[self webFrame] _dataSource] response] URL];
390 return [responseURL _web_originalDataAsString];
393 - (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
395 if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveResponse:)])
396 [pluginView webPlugInMainResourceDidReceiveResponse:response];
398 // Cancel the load since this plug-in does its own loading.
399 // FIXME: See <rdar://problem/4258008> for a problem with this.
400 NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
401 contentURL:[response URL]
403 pluginName:nil // FIXME: Get this from somewhere
404 MIMEType:[response MIMEType]];
405 [_dataSource _documentLoader]->cancelMainResourceLoad(error);
410 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
412 if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveData:)])
413 [pluginView webPlugInMainResourceDidReceiveData:data];
416 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
418 if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFailWithError:)])
419 [pluginView webPlugInMainResourceDidFailWithError:error];
422 - (void)pluginViewFinishedLoading:(NSView *)pluginView
424 if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFinishLoading)])
425 [pluginView webPlugInMainResourceDidFinishLoading];