summaryrefslogtreecommitdiffstats
path: root/WebKit/mac/Plugins/WebPluginController.mm
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-04-27 16:31:00 +0100
committerSteve Block <steveblock@google.com>2010-05-11 14:42:12 +0100
commitdcc8cf2e65d1aa555cce12431a16547e66b469ee (patch)
tree92a8d65cd5383bca9749f5327fb5e440563926e6 /WebKit/mac/Plugins/WebPluginController.mm
parentccac38a6b48843126402088a309597e682f40fe6 (diff)
downloadexternal_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebKit/mac/Plugins/WebPluginController.mm')
-rw-r--r--WebKit/mac/Plugins/WebPluginController.mm107
1 files changed, 94 insertions, 13 deletions
diff --git a/WebKit/mac/Plugins/WebPluginController.mm b/WebKit/mac/Plugins/WebPluginController.mm
index 4343119..1c85862 100644
--- a/WebKit/mac/Plugins/WebPluginController.mm
+++ b/WebKit/mac/Plugins/WebPluginController.mm
@@ -36,6 +36,7 @@
#import "WebHTMLViewPrivate.h"
#import "WebKitErrorsPrivate.h"
#import "WebKitLogging.h"
+#import "WebNSObjectExtras.h"
#import "WebNSURLExtras.h"
#import "WebNSViewExtras.h"
#import "WebPlugin.h"
@@ -57,6 +58,7 @@
#import <WebCore/ResourceRequest.h>
#import <WebCore/ScriptController.h>
#import <WebCore/WebCoreURLResponse.h>
+#import <objc/objc-runtime.h>
#import <runtime/JSLock.h>
using namespace WebCore;
@@ -78,6 +80,10 @@ using namespace HTMLNames;
- (void)pluginDestroy;
@end
+static bool isKindOfClass(id, NSString* className);
+static void installFlip4MacPlugInWorkaroundIfNecessary();
+
+
static NSMutableSet *pluginViews = nil;
@implementation WebPluginController
@@ -209,7 +215,10 @@ static NSMutableSet *pluginViews = nil;
BOOL oldDefersCallbacks = [[self webView] defersCallbacks];
if (!oldDefersCallbacks)
[[self webView] setDefersCallbacks:YES];
-
+
+ if (isKindOfClass(view, @"WmvPlugin"))
+ installFlip4MacPlugInWorkaroundIfNecessary();
+
LOG(Plugins, "initializing plug-in %@", view);
if ([view respondsToSelector:@selector(webPlugInInitialize)]) {
JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
@@ -351,21 +360,11 @@ static void cancelOutstandingCheck(const void *item, void *context)
}
}
-// For compatibility only.
-- (void)showURL:(NSURL *)URL inFrame:(NSString *)target
-{
- [self webPlugInContainerLoadRequest:[NSURLRequest requestWithURL:URL] inFrame:target];
-}
-
- (void)webPlugInContainerShowStatus:(NSString *)message
{
- if (!message) {
+ if (!message)
message = @"";
- }
- if (!_documentView) {
- LOG_ERROR("could not show status message (%@) because plug-in has already been destroyed", message);
- return;
- }
+
WebView *v = [_dataSource _webView];
[[v _UIDelegateForwarder] webView:v setStatusText:message];
}
@@ -475,3 +474,85 @@ static WebCore::HTMLMediaElement* mediaProxyClient(DOMElement* element)
#endif
@end
+
+static bool isKindOfClass(id object, NSString *className)
+{
+ Class cls = NSClassFromString(className);
+
+ if (!cls)
+ return false;
+
+ return [object isKindOfClass:cls];
+}
+
+
+// Existing versions of the Flip4Mac WebKit plug-in have an object lifetime bug related to an NSAlert that is
+// used to notify the user about updates to the plug-in. This bug can result in Safari crashing if the page
+// containing the plug-in navigates while the alert is displayed (<rdar://problem/7313430>).
+//
+// The gist of the bug is thus: Flip4Mac sets an instance of the TSUpdateCheck class as the modal delegate of the
+// NSAlert instance. This TSUpdateCheck instance itself has a delegate. The delegate is set to the WmvPlugin
+// instance which is the NSView subclass that is exposed to WebKit as the plug-in view. Since this relationship
+// is that of delegates the TSUpdateCheck does not retain the WmvPlugin. This leads to a bug if the WmvPlugin
+// instance is destroyed before the TSUpdateCheck instance as the TSUpdateCheck instance will be left with a
+// pointer to a stale object. This will happen if a page containing the Flip4Mac plug-in triggers a navigation
+// while the update sheet is visible as the WmvPlugin instance is removed from the view hierarchy and there are
+// no other references to keep the object alive.
+//
+// We work around this bug by patching the following two messages:
+//
+// 1) -[NSAlert beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:]
+// 2) -[TSUpdateCheck alertDidEnd:returnCode:contextInfo:]
+//
+// Our override of 1) detects whether it is Flip4Mac's update sheet triggering the alert by checking whether the
+// modal delegate is an instance of TSUpdateCheck. If it is, it retains the modal delegate's delegate.
+//
+// Our override of 2) then autoreleases the delegate, balancing the retain we added in 1).
+//
+// These two overrides have the effect of ensuring that the WmvPlugin instance will always outlive the TSUpdateCheck
+// instance, preventing the TSUpdateCheck instance from accessing a stale delegate pointer and crashing the application.
+
+
+typedef void (*beginSheetModalForWindowIMP)(id, SEL, NSWindow *, id, SEL, void*);
+static beginSheetModalForWindowIMP original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_;
+
+typedef void (*alertDidEndIMP)(id, SEL, NSAlert *, NSInteger, void*);
+static alertDidEndIMP original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_;
+
+static void WebKit_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_(id object, SEL selector, NSAlert *alert, NSInteger returnCode, void* contextInfo)
+{
+ [[object delegate] autorelease];
+
+ original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_(object, selector, alert, returnCode, contextInfo);
+}
+
+static void WebKit_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(id object, SEL selector, NSWindow *window, id modalDelegate, SEL didEndSelector, void* contextInfo)
+{
+ if (isKindOfClass(modalDelegate, @"TSUpdateCheck"))
+ [[modalDelegate delegate] retain];
+
+ original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(object, selector, window, modalDelegate, didEndSelector, contextInfo);
+}
+
+static void installFlip4MacPlugInWorkaroundIfNecessary()
+{
+ static bool hasInstalledFlip4MacPlugInWorkaround;
+ if (!hasInstalledFlip4MacPlugInWorkaround) {
+ Class TSUpdateCheck = objc_lookUpClass("TSUpdateCheck");
+ if (!TSUpdateCheck)
+ return;
+
+ Method methodToPatch = class_getInstanceMethod(TSUpdateCheck, @selector(alertDidEnd:returnCode:contextInfo:));
+ if (!methodToPatch)
+ return;
+
+ IMP originalMethod = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(WebKit_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_));
+ original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_ = reinterpret_cast<alertDidEndIMP>(originalMethod);
+
+ methodToPatch = class_getInstanceMethod(objc_getRequiredClass("NSAlert"), @selector(beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:));
+ originalMethod = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(WebKit_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_));
+ original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_ = reinterpret_cast<beginSheetModalForWindowIMP>(originalMethod);
+
+ hasInstalledFlip4MacPlugInWorkaround = true;
+ }
+}