2009-02-13 Anders Carlsson <andersca@apple.com>
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Feb 2009 00:04:32 +0000 (00:04 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Feb 2009 00:04:32 +0000 (00:04 +0000)
        Reviewed by Kevin Decker.

        <rdar://problem/6584834> ESPN radio live stream link hangs Safari

        When a plug-in invokes JavaScript code that will destroy the plug-in, we need to
        defer destruction until we're done executing the script.

        * Plugins/Hosted/NetscapePluginHostProxy.mm:
        (WebKit::PluginDestroyDeferrer::PluginDestroyDeferrer):
        (WebKit::PluginDestroyDeferrer::~PluginDestroyDeferrer):
        Add a simple RAII object for deferring destruction of the plug-in instance.

        (WKPCEvaluate):
        (WKPCInvoke):
        (WKPCInvokeDefault):
        (WKPCConstruct):
        (WKPCGetProperty):
        (WKPCSetProperty):
        (WKPCRemoveProperty):
        (WKPCHasProperty):
        (WKPCHasMethod):
        Use the PluginDestroyDeferrer.

        * Plugins/Hosted/NetscapePluginInstanceProxy.h:
        (WebKit::NetscapePluginInstanceProxy::pluginID):
        Assert that the plug-in ID is not 0 here.

        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
        (WebKit::NetscapePluginInstanceProxy::NetscapePluginInstanceProxy):
        Initialize the call depth.

        (WebKit::NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy):
        Set the plug-in ID to 0 to aid debugging.

        (WebKit::NetscapePluginInstanceProxy::willCallPluginFunction):
        Increment the call depth.

        (WebKit::NetscapePluginInstanceProxy::didCallPluginFunction):
        Decrement the call depth, if it's 0 and we should stop the plug-in, do so.

        (WebKit::NetscapePluginInstanceProxy::shouldStop):
        If we're called this with a non-zero call depth, set shouldStopSoon to true.

        * Plugins/Hosted/WebHostedNetscapePluginView.mm:
        (-[WebHostedNetscapePluginView shouldStop]):
        Call the proxy.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@40996 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/mac/ChangeLog
WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm
WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h
WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm
WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm

index 565ff5dde999a4b03a183f2c1444fae29724722c..0d8b86116860795de6cc5b9df1dc46cd34ca3667 100644 (file)
@@ -1,3 +1,52 @@
+2009-02-13  Anders Carlsson  <andersca@apple.com>
+
+        Reviewed by Kevin Decker.
+
+        <rdar://problem/6584834> ESPN radio live stream link hangs Safari 
+
+        When a plug-in invokes JavaScript code that will destroy the plug-in, we need to
+        defer destruction until we're done executing the script.
+        
+        * Plugins/Hosted/NetscapePluginHostProxy.mm:
+        (WebKit::PluginDestroyDeferrer::PluginDestroyDeferrer):
+        (WebKit::PluginDestroyDeferrer::~PluginDestroyDeferrer):
+        Add a simple RAII object for deferring destruction of the plug-in instance.
+        
+        (WKPCEvaluate):
+        (WKPCInvoke):
+        (WKPCInvokeDefault):
+        (WKPCConstruct):
+        (WKPCGetProperty):
+        (WKPCSetProperty):
+        (WKPCRemoveProperty):
+        (WKPCHasProperty):
+        (WKPCHasMethod):
+        Use the PluginDestroyDeferrer.
+        
+        * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+        (WebKit::NetscapePluginInstanceProxy::pluginID):
+        Assert that the plug-in ID is not 0 here.
+        
+        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+        (WebKit::NetscapePluginInstanceProxy::NetscapePluginInstanceProxy):
+        Initialize the call depth.
+        
+        (WebKit::NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy):
+        Set the plug-in ID to 0 to aid debugging.
+        
+        (WebKit::NetscapePluginInstanceProxy::willCallPluginFunction):
+        Increment the call depth.
+        
+        (WebKit::NetscapePluginInstanceProxy::didCallPluginFunction):
+        Decrement the call depth, if it's 0 and we should stop the plug-in, do so.
+        
+        (WebKit::NetscapePluginInstanceProxy::shouldStop):
+        If we're called this with a non-zero call depth, set shouldStopSoon to true.
+        
+        * Plugins/Hosted/WebHostedNetscapePluginView.mm:
+        (-[WebHostedNetscapePluginView shouldStop]):
+        Call the proxy.
+
 2009-02-12  Brady Eidson  <beidson@apple.com>
 
         Reviewed by Kevin Decker
index 07d4208f22c698870f5c79a148d186914b27148e..082a468aa806580e1b0ec66daf8a0de0f79a3eb5 100644 (file)
@@ -51,6 +51,23 @@ using namespace WebCore;
 
 namespace WebKit {
 
+class PluginDestroyDeferrer {
+public:
+    PluginDestroyDeferrer(NetscapePluginInstanceProxy* proxy)
+        : m_proxy(proxy)
+    {
+        m_proxy->willCallPluginFunction();
+    }
+    
+    ~PluginDestroyDeferrer()
+    {
+        m_proxy->didCallPluginFunction();
+    }
+
+private:
+    NetscapePluginInstanceProxy* m_proxy;
+};
+
 typedef HashMap<mach_port_t, NetscapePluginHostProxy*> PluginProxyMap;
 static PluginProxyMap& pluginProxyMap()
 {
@@ -463,6 +480,8 @@ kern_return_t WKPCEvaluate(mach_port_t clientPort, uint32_t pluginID, uint32_t o
     if (!instanceProxy)
         return KERN_FAILURE;
 
+    PluginDestroyDeferrer deferrer(instanceProxy);
+    
     String script = String::fromUTF8WithLatin1Fallback(scriptData, scriptLength);
     
     data_t resultData;
@@ -512,6 +531,8 @@ kern_return_t WKPCInvoke(mach_port_t clientPort, uint32_t pluginID, uint32_t obj
     if (!instanceProxy)
         return KERN_FAILURE;
 
+    PluginDestroyDeferrer deferrer(instanceProxy);
+    
     IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
     if (!IdentifierRep::isValid(identifier)) {
         _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), false, 0, 0);
@@ -543,6 +564,8 @@ kern_return_t WKPCInvokeDefault(mach_port_t clientPort, uint32_t pluginID, uint3
     if (!instanceProxy)
         return KERN_FAILURE;
 
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     *returnValue = instanceProxy->invokeDefault(objectID, argumentsData, argumentsLength, *resultData, *resultLength);
     
     return KERN_SUCCESS;
@@ -560,6 +583,8 @@ kern_return_t WKPCConstruct(mach_port_t clientPort, uint32_t pluginID, uint32_t
     if (!instanceProxy)
         return KERN_FAILURE;
 
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     *returnValue = instanceProxy->construct(objectID, argumentsData, argumentsLength, *resultData, *resultLength);
     
     return KERN_SUCCESS;
@@ -579,6 +604,8 @@ kern_return_t WKPCGetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_
     if (!IdentifierRep::isValid(identifier))
         return KERN_FAILURE;
     
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     data_t resultData;
     mach_msg_type_number_t resultLength;
     boolean_t returnValue;
@@ -605,6 +632,8 @@ kern_return_t WKPCSetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_
     if (!instanceProxy)
         return KERN_FAILURE;
 
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
     if (!IdentifierRep::isValid(identifier))
         *returnValue = false;
@@ -628,6 +657,8 @@ kern_return_t WKPCRemoveProperty(mach_port_t clientPort, uint32_t pluginID, uint
     if (!instanceProxy)
         return KERN_FAILURE;
     
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
     if (!IdentifierRep::isValid(identifier))
         return KERN_FAILURE;
@@ -651,6 +682,8 @@ kern_return_t WKPCHasProperty(mach_port_t clientPort, uint32_t pluginID, uint32_
     if (!instanceProxy)
         return KERN_FAILURE;
     
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
     if (!IdentifierRep::isValid(identifier)) {
         _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), false);
@@ -679,6 +712,8 @@ kern_return_t WKPCHasMethod(mach_port_t clientPort, uint32_t pluginID, uint32_t
     if (!instanceProxy)
         return KERN_FAILURE;
     
+    PluginDestroyDeferrer deferrer(instanceProxy);
+
     IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
     if (!IdentifierRep::isValid(identifier)) {
         _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), false);
index 0a2a2ca527f392ec67ee94d503b20e9ed8e7bfcc..ded864224e7add070e14c05cb365d51973105e8f 100644 (file)
@@ -64,7 +64,12 @@ public:
     }
     ~NetscapePluginInstanceProxy();
     
-    uint32_t pluginID() const { return m_pluginID; }
+    uint32_t pluginID() const 
+    {
+        ASSERT(m_pluginID);
+        
+        return m_pluginID;
+    }
     uint32_t renderContextID() const { return m_renderContextID; }
     void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; }
     
@@ -123,6 +128,10 @@ public:
     
     void invalidate();
     
+    void willCallPluginFunction();
+    void didCallPluginFunction();
+    bool shouldStop();
+    
     // Reply structs
     struct Reply {
         enum Type {
@@ -258,6 +267,9 @@ private:
     
     typedef HashSet<ProxyInstance*> ProxyInstanceSet;
     ProxyInstanceSet m_instances;
+    
+    unsigned m_pluginFunctionCallDepth;
+    bool m_shouldStopSoon;
 };
     
 } // namespace WebKit
index 5869e1e4dab7937d6c1688cea86158df856b1dfc..65ae4e40ccbd66fed33dfdb0b9ddff3d014ed458 100644 (file)
@@ -97,6 +97,8 @@ NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy
     , m_useSoftwareRenderer(false)
     , m_waitingForReply(false)
     , m_objectIDCounter(0)
+    , m_pluginFunctionCallDepth(0)
+    , m_shouldStopSoon(false)
 {
     ASSERT(m_pluginView);
     
@@ -111,6 +113,8 @@ NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy
 NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy()
 {
     ASSERT(!m_pluginHostProxy);
+    
+    m_pluginID = 0;
 }
 
 void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect)
@@ -989,7 +993,35 @@ void NetscapePluginInstanceProxy::removeInstance(ProxyInstance* instance)
     
     m_instances.remove(instance);
 }
+void NetscapePluginInstanceProxy::willCallPluginFunction()
+{
+    m_pluginFunctionCallDepth++;
+}
+    
+void NetscapePluginInstanceProxy::didCallPluginFunction()
+{
+    ASSERT(m_pluginFunctionCallDepth > 0);
+    m_pluginFunctionCallDepth--;
+    
+    // If -stop was called while we were calling into a plug-in function, and we're no longer
+    // inside a plug-in function, stop now.
+    if (!m_pluginFunctionCallDepth && m_shouldStopSoon) {
+        m_shouldStopSoon = false;
+        [m_pluginView stop];
+    }
+}
     
+bool NetscapePluginInstanceProxy::shouldStop()
+{
+    if (m_pluginFunctionCallDepth) {
+        m_shouldStopSoon = true;
+        return false;
+    }
+    
+    return true;
+}
+
 } // namespace WebKit
 
 #endif // USE(PLUGIN_HOST_PROCESS)
index 42424d0fbbf47edda061e7a7313af772b2e74727..436d4caeea577a0a523857d7196efd5882bc3d78 100644 (file)
@@ -150,7 +150,10 @@ extern "C" {
 
 - (BOOL)shouldStop
 {
-    return YES;
+    if (!_proxy)
+        return YES;
+    
+    return _proxy->shouldStop();
 }
 
 - (void)destroyPlugin