<rdar://problem/
4564131> WebPluginDatabase setAdditionalWebPlugInPaths needs to be per WebView
Added some WebView SPI so that individual WebViews may have different plugin search paths. There are some
limitations with the approach taken here:
- JavaScript may only access the global plugin DB.
- When this SPI is in use, certain WebView methods may not give accurate results, such as +canShowMIMEType:.
- This only works for plugins referenced using the <object> or <embed> tags; plugins that reside in non-standard
file system locations may not be loaded directly into frames.
None of these issues are important to the client that needs this SPI. Rather than re-architect our entire
plugin database, I think it is better to simply accept these limitations for now.
* Plugins/WebPluginDatabase.h:
Added "plugInPaths" ivar, so different plugin databases can have different search paths.
* Plugins/WebPluginDatabase.m:
(+[WebPluginDatabase installedPlugins]):
Give the global plugin database the default plugin search paths.
(+[WebPluginDatabase setAdditionalWebPlugInPaths:]):
Removed static global; this method now sets the plugin paths on the global plugin database.
(-[WebPluginDatabase setPlugInPaths:]):
Setter method for plugin paths.
(-[WebPluginDatabase close]):
New method; called when the plugin database is no longer needed (when its WebView is being destroyed).
(-[WebPluginDatabase init]):
Don't refresh in -init, so that callers can set the DB's plugin path array before it refreshes.
(-[WebPluginDatabase dealloc]):
Moved here from near the bottom of the file. Release new ivar.
(-[WebPluginDatabase refresh]):
Use the plugInPaths ivar instead of calling pluginLocations().
Notify plugin packages when they are added to and removed from a plugin database. A plugin package will
unload itself when it is removed from all of its plugin databases.
The only really tricky thing here is that the global MIME <-> view class registrations are only modified
by the shared plugin DB.
(+[WebPluginDatabase _defaultPlugInPaths]):
Refactored from the old pluginLocations() function; returns the default set of plugin search paths.
* Plugins/WebBasePluginPackage.h:
* Plugins/WebBasePluginPackage.m:
(-[WebBasePluginPackage dealloc]):
Assert that this package has been removed from all of its containing plugin databases.
(-[WebBasePluginPackage finalize]):
ditto
(-[WebBasePluginPackage wasAddedToPluginDatabase:]):
Add plugin database to set.
(-[WebBasePluginPackage wasRemovedFromPluginDatabase:]):
Remove plugin database from set. If it was the last DB, then unload the plugin package.
* WebView/WebViewInternal.h:
Added instance methods to find the view class or plugin package, given a MIME type or file extension.
* WebView/WebViewPrivate.h:
Added SPI to set plugin search paths per WebView.
* WebView/WebView.m:
(-[WebView _viewClass:andRepresentationClass:forMIMEType:]):
New method; tries the global MIME <-> view map first; failing that, it checks the WebView's plugin DB.
(-[WebView _close]):
Close the plugin DB.
(-[WebView _setAdditionalWebPlugInPaths:]):
Create the plugin DB if necessary, and set its plugin paths.
(-[WebView _pluginForMIMEType:]):
Checks global plugin DB, falls back on WebView DB.
(-[WebView _pluginForExtension:]):
ditto
(-[WebView _isMIMETypeRegisteredAsPlugin:]):
ditto
* WebCoreSupport/WebFrameBridge.m:
(-[WebFrameBridge viewForPluginWithURL:attributeNames:attributeValues:MIMEType:DOMElement:loadManually:]):
Use new WebView instance methods to look for plugins.
(-[WebFrameBridge viewForJavaAppletWithFrame:attributeNames:attributeValues:baseURL:DOMElement:]):
ditto
(-[WebFrameBridge determineObjectFromMIMEType:URL:]):
ditto
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@14947
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2006-06-21 Tim Omernick <timo@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ <rdar://problem/4564131> WebPluginDatabase setAdditionalWebPlugInPaths needs to be per WebView
+
+ Added some WebView SPI so that individual WebViews may have different plugin search paths. There are some
+ limitations with the approach taken here:
+
+ - JavaScript may only access the global plugin DB.
+ - When this SPI is in use, certain WebView methods may not give accurate results, such as +canShowMIMEType:.
+ - This only works for plugins referenced using the <object> or <embed> tags; plugins that reside in non-standard
+ file system locations may not be loaded directly into frames.
+
+ None of these issues are important to the client that needs this SPI. Rather than re-architect our entire
+ plugin database, I think it is better to simply accept these limitations for now.
+
+ * Plugins/WebPluginDatabase.h:
+ Added "plugInPaths" ivar, so different plugin databases can have different search paths.
+ * Plugins/WebPluginDatabase.m:
+ (+[WebPluginDatabase installedPlugins]):
+ Give the global plugin database the default plugin search paths.
+ (+[WebPluginDatabase setAdditionalWebPlugInPaths:]):
+ Removed static global; this method now sets the plugin paths on the global plugin database.
+ (-[WebPluginDatabase setPlugInPaths:]):
+ Setter method for plugin paths.
+ (-[WebPluginDatabase close]):
+ New method; called when the plugin database is no longer needed (when its WebView is being destroyed).
+ (-[WebPluginDatabase init]):
+ Don't refresh in -init, so that callers can set the DB's plugin path array before it refreshes.
+ (-[WebPluginDatabase dealloc]):
+ Moved here from near the bottom of the file. Release new ivar.
+ (-[WebPluginDatabase refresh]):
+ Use the plugInPaths ivar instead of calling pluginLocations().
+ Notify plugin packages when they are added to and removed from a plugin database. A plugin package will
+ unload itself when it is removed from all of its plugin databases.
+ The only really tricky thing here is that the global MIME <-> view class registrations are only modified
+ by the shared plugin DB.
+ (+[WebPluginDatabase _defaultPlugInPaths]):
+ Refactored from the old pluginLocations() function; returns the default set of plugin search paths.
+
+ * Plugins/WebBasePluginPackage.h:
+ * Plugins/WebBasePluginPackage.m:
+ (-[WebBasePluginPackage dealloc]):
+ Assert that this package has been removed from all of its containing plugin databases.
+ (-[WebBasePluginPackage finalize]):
+ ditto
+ (-[WebBasePluginPackage wasAddedToPluginDatabase:]):
+ Add plugin database to set.
+ (-[WebBasePluginPackage wasRemovedFromPluginDatabase:]):
+ Remove plugin database from set. If it was the last DB, then unload the plugin package.
+
+ * WebView/WebViewInternal.h:
+ Added instance methods to find the view class or plugin package, given a MIME type or file extension.
+ * WebView/WebViewPrivate.h:
+ Added SPI to set plugin search paths per WebView.
+ * WebView/WebView.m:
+ (-[WebView _viewClass:andRepresentationClass:forMIMEType:]):
+ New method; tries the global MIME <-> view map first; failing that, it checks the WebView's plugin DB.
+ (-[WebView _close]):
+ Close the plugin DB.
+ (-[WebView _setAdditionalWebPlugInPaths:]):
+ Create the plugin DB if necessary, and set its plugin paths.
+ (-[WebView _pluginForMIMEType:]):
+ Checks global plugin DB, falls back on WebView DB.
+ (-[WebView _pluginForExtension:]):
+ ditto
+ (-[WebView _isMIMETypeRegisteredAsPlugin:]):
+ ditto
+
+ * WebCoreSupport/WebFrameBridge.m:
+ (-[WebFrameBridge viewForPluginWithURL:attributeNames:attributeValues:MIMEType:DOMElement:loadManually:]):
+ Use new WebView instance methods to look for plugins.
+ (-[WebFrameBridge viewForJavaAppletWithFrame:attributeNames:attributeValues:baseURL:DOMElement:]):
+ ditto
+ (-[WebFrameBridge determineObjectFromMIMEType:URL:]):
+ ditto
+
2006-06-20 Brady Eidson <beidson@apple.com>
Reviewed by Maciej
#import <WebCore/WebCoreViewFactory.h>
#import <WebKit/npfunctions.h>
+@class WebPluginDatabase;
+
@protocol WebPluginManualLoader
- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response;
- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data;
@interface WebBasePluginPackage : NSObject <WebCorePluginInfo>
{
+ NSMutableSet *pluginDatabases;
+
BOOL isLoaded;
NSString *name;
- (BOOL)isNativeLibraryData:(NSData *)data;
+- (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database;
+- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database;
+
@end
{
ASSERT(!isLoaded);
+ ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
+ [pluginDatabases release];
+
[name release];
[path release];
[pluginDescription release];
{
ASSERT(!isLoaded);
+ ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
+ [pluginDatabases release];
+
if (cfBundle)
CFRelease(cfBundle);
return YES;
}
+- (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database
+{
+ if (!pluginDatabases)
+ pluginDatabases = [[NSMutableSet alloc] init];
+
+ ASSERT(![pluginDatabases containsObject:database]);
+ [pluginDatabases addObject:database];
+}
+
+- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
+{
+ ASSERT(pluginDatabases);
+ ASSERT([pluginDatabases containsObject:database]);
+
+ [pluginDatabases removeObject:database];
+
+ if ([pluginDatabases count] == 0)
+ [self unload];
+}
+
@end
@implementation NSArray (WebPluginExtensions)
{
NSMutableSet *plugins;
NSMutableSet *registeredMIMETypes;
+ NSArray *plugInPaths;
}
+ (WebPluginDatabase *)installedPlugins;
- (void)refresh;
+- (void)setPlugInPaths:(NSArray *)newPaths;
+
+- (void)close;
+
@end
@interface NSObject (WebPlugInDatabase)
#import <WebKit/WebViewPrivate.h>
#import <WebKitSystemInterface.h>
+@interface WebPluginDatabase (Internal)
++ (NSArray *)_defaultPlugInPaths;
+@end
+
@implementation WebPluginDatabase
static WebPluginDatabase *database = nil;
+ (WebPluginDatabase *)installedPlugins
{
- if (!database)
+ if (!database) {
database = [[WebPluginDatabase alloc] init];
+ [database setPlugInPaths:[self _defaultPlugInPaths]];
+ [database refresh];
+ }
+
return database;
}
return [plugins allObjects];
}
-static NSArray *extensionPlugInPaths;
-
-+ (void)setAdditionalWebPlugInPaths:(NSArray *)a
++ (void)setAdditionalWebPlugInPaths:(NSArray *)additionalPaths
{
- if (a != extensionPlugInPaths) {
- [extensionPlugInPaths release];
- extensionPlugInPaths = [a copyWithZone:nil];
- }
+ NSMutableArray *newPlugInPaths = [[self _defaultPlugInPaths] mutableCopy];
+ [newPlugInPaths addObjectsFromArray:additionalPaths];
+ [[WebPluginDatabase installedPlugins] setPlugInPaths:newPlugInPaths];
+ [newPlugInPaths release];
}
-static NSArray *pluginLocations(void)
+- (void)setPlugInPaths:(NSArray *)newPaths
{
- // Plug-ins are found in order of precedence.
- // If there are duplicates, the first found plug-in is used.
- // For example, if there is a QuickTime.plugin in the users's home directory
- // that is used instead of the /Library/Internet Plug-ins version.
- // The purpose is to allow non-admin users to update their plug-ins.
- NSMutableArray *array = [NSMutableArray arrayWithCapacity:[extensionPlugInPaths count] + 3];
-
- if (extensionPlugInPaths)
- [array addObjectsFromArray:extensionPlugInPaths];
-
- [array addObject:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Internet Plug-Ins"]];
- [array addObject:@"/Library/Internet Plug-Ins"];
- [array addObject:[[NSBundle mainBundle] builtInPlugInsPath]];
+ if (plugInPaths == newPaths)
+ return;
- return array;
+ [plugInPaths release];
+ plugInPaths = [newPaths copy];
+}
+
+- (void)close
+{
+ [plugins makeObjectsPerformSelector:@selector(wasRemovedFromPluginDatabase:) withObject:self];
+ [plugins release];
+ plugins = nil;
}
- (id)init
{
- self = [super init];
- registeredMIMETypes = [[NSMutableSet alloc] init];
- [self refresh];
+ if (!(self = [super init]))
+ return nil;
+
+ registeredMIMETypes = [[NSMutableSet alloc] init];
+
return self;
}
+
+- (void)dealloc
+{
+ [plugInPaths release];
+ [plugins release];
+ [registeredMIMETypes release];
+ [super dealloc];
+}
+
- (void)refresh
{
- NSEnumerator *directoryEnumerator = [pluginLocations() objectEnumerator];
+ NSEnumerator *directoryEnumerator = [plugInPaths objectEnumerator];
NSMutableSet *uniqueFilenames = [[NSMutableArray alloc] init];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableSet *newPlugins = [[NSMutableSet alloc] init];
NSString *MIMEType;
while ((MIMEType = [MIMETypeEnumerator nextObject])) {
if ([registeredMIMETypes containsObject:MIMEType]) {
- [WebView _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType];
+ if (self == database)
+ [WebView _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType];
[registeredMIMETypes removeObject:MIMEType];
}
}
NSMutableSet *pluginsToUnload = [plugins mutableCopy];
[pluginsToUnload minusSet:newPlugins];
+ [newPlugins minusSet:plugins];
#if !LOG_DISABLED
- NSMutableSet *reallyNewPlugins = [newPlugins mutableCopy];
- [reallyNewPlugins minusSet:plugins];
- if ([reallyNewPlugins count] > 0) {
- LOG(Plugins, "New plugins:\n%@", reallyNewPlugins);
+ if ([newPlugins count] > 0) {
+ LOG(Plugins, "New plugins:\n%@", newPlugins);
}
if ([pluginsToUnload count] > 0) {
LOG(Plugins, "Removed plugins:\n%@", pluginsToUnload);
}
- [reallyNewPlugins release];
#endif
- [pluginsToUnload makeObjectsPerformSelector:@selector(unload)];
+ // Unload plugins
+ [pluginsToUnload makeObjectsPerformSelector:@selector(wasRemovedFromPluginDatabase:) withObject:self];
[plugins minusSet:pluginsToUnload];
- [plugins unionSet:newPlugins];
[pluginsToUnload release];
+
+ // Add new plugins
+ [plugins unionSet:newPlugins];
+ [newPlugins makeObjectsPerformSelector:@selector(wasAddedToPluginDatabase:) withObject:self];
[newPlugins release];
} else {
LOG(Plugins, "Plugin database initialization:\n%@", newPlugins);
plugins = newPlugins;
+ [newPlugins makeObjectsPerformSelector:@selector(wasAddedToPluginDatabase:) withObject:self];
}
// Build a list of MIME types.
// Don't allow the QT plug-in to override any types because it claims many that we can handle ourselves.
continue;
- [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType];
+ if (self == database)
+ [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType];
[registeredMIMETypes addObject:MIMEType];
}
}
return [registeredMIMETypes containsObject:MIMEType];
}
-- (void)dealloc
+@end
+
+@implementation WebPluginDatabase (Internal)
+
++ (NSArray *)_defaultPlugInPaths
{
- [plugins release];
- [registeredMIMETypes release];
- [super dealloc];
+ // Plug-ins are found in order of precedence.
+ // If there are duplicates, the first found plug-in is used.
+ // For example, if there is a QuickTime.plugin in the users's home directory
+ // that is used instead of the /Library/Internet Plug-ins version.
+ // The purpose is to allow non-admin users to update their plug-ins.
+ return [NSArray arrayWithObjects:
+ [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Internet Plug-Ins"],
+ @"/Library/Internet Plug-Ins",
+ [[NSBundle mainBundle] builtInPlugInsPath],
+ nil];
}
@end
}
if ([MIMEType length] != 0)
- pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
+ pluginPackage = [[self webView] _pluginForMIMEType:MIMEType];
else
MIMEType = nil;
NSString *extension = [[URL path] pathExtension];
if (!pluginPackage && [extension length] != 0) {
- pluginPackage = [[WebPluginDatabase installedPlugins] pluginForExtension:extension];
+ pluginPackage = [[self webView] _pluginForExtension:extension];
if (pluginPackage) {
NSString *newMIMEType = [pluginPackage MIMETypeForExtension:extension];
if ([newMIMEType length] != 0)
WebBasePluginPackage *pluginPackage;
NSView *view = nil;
- pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
+ pluginPackage = [[self webView] _pluginForMIMEType:MIMEType];
if (pluginPackage) {
if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) {
NSString *extension = [[URL path] pathExtension];
if ([extension length] > 0) {
MIMEType = WKGetMIMETypeForExtension(extension);
- if ([MIMEType length] == 0 && [[WebPluginDatabase installedPlugins] pluginForExtension:extension])
+ if ([MIMEType length] == 0 && [[self webView] _pluginForExtension:extension])
// If no MIME type is specified, use a plug-in if we have one that can handle the extension.
return ObjectElementPlugin;
}
if ([MIMEType length] == 0)
return ObjectElementFrame; // Go ahead and hope that we can display the content.
- if ([[WebPluginDatabase installedPlugins] isMIMETypeRegistered:MIMEType])
+ if ([[self webView] _isMIMETypeRegisteredAsPlugin:MIMEType])
return ObjectElementPlugin;
if ([WebFrameView _viewClassForMIMEType:MIMEType])
BOOL dashboardBehaviorAllowWheelScrolling;
BOOL selectWordBeforeMenuEvent;
+
+ WebPluginDatabase *pluginDatabase;
}
@end
return NO;
}
+- (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
+{
+ if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType])
+ return YES;
+
+ if (_private->pluginDatabase) {
+ WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
+ if (pluginPackage) {
+ if (vClass)
+ *vClass = [WebHTMLView class];
+ if (rClass)
+ *rClass = [WebHTMLRepresentation class];
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+ (void)_setAlwaysUseATSU:(BOOL)f
{
WebCoreSetAlwaysUseATSU(f);
[[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
_private->hasSpellCheckerDocumentTag = NO;
}
+
+ if (_private->pluginDatabase) {
+ [_private->pluginDatabase close];
+ [_private->pluginDatabase release];
+ _private->pluginDatabase = nil;
+ }
}
+ (NSString *)_MIMETypeForFile:(NSString *)path
WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == WebCoreScrollBarAlwaysOn;
}
+
+- (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
+{
+ if (!_private->pluginDatabase)
+ _private->pluginDatabase = [[WebPluginDatabase alloc] init];
+
+ [_private->pluginDatabase setPlugInPaths:newPaths];
+ [_private->pluginDatabase refresh];
+}
+
@end
return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
}
+- (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
+{
+ WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
+ if (pluginPackage)
+ return pluginPackage;
+
+ if (_private->pluginDatabase)
+ return [_private->pluginDatabase pluginForMIMEType:MIMEType];
+
+ return nil;
+}
+
+- (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
+{
+ WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForExtension:extension];
+ if (pluginPackage)
+ return pluginPackage;
+
+ if (_private->pluginDatabase)
+ return [_private->pluginDatabase pluginForExtension:extension];
+
+ return nil;
+}
+
+- (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
+{
+ if ([[WebPluginDatabase installedPlugins] isMIMETypeRegistered:MIMEType])
+ return YES;
+
+ if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
+ return YES;
+
+ return nil;
+}
+
+ (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
{
return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
#import "WebTypesInternal.h"
@class WebPageBridge;
+@class WebBasePluginPackage;
@interface WebView (WebViewEditingExtras)
- (BOOL)_interceptEditingKeyEvent:(NSEvent *)event;
- (void)_progressStarted:(WebFrame *)frame;
- (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame;
+ (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
+- (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
+ (NSString *)_MIMETypeForFile:(NSString *)path;
- (void)_downloadURL:(NSURL *)URL;
+ (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme;
- (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame;
- (void)_willChangeValueForKey:(NSString *)key;
- (void)_didChangeValueForKey:(NSString *)key;
+- (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType;
+- (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension;
+- (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType;
@end
*/
- (BOOL)alwaysShowHorizontalScroller;
+/*!
+ @method _setAdditionalWebPlugInPaths:
+ @abstract Sets additional plugin search paths for a specific WebView.
+ */
+- (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths;
+
@end
@interface WebView (WebViewPrintingPrivate)