diff options
20 files changed, 126 insertions, 29 deletions
diff --git a/chrome/renderer/plugins/webview_plugin.cc b/chrome/renderer/plugins/webview_plugin.cc index 8e36f22..2b3b0d9 100644 --- a/chrome/renderer/plugins/webview_plugin.cc +++ b/chrome/renderer/plugins/webview_plugin.cc @@ -114,6 +114,10 @@ NPObject* WebViewPlugin::scriptableObject() { return NULL; } +struct _NPP* WebViewPlugin::pluginNPP() { + return NULL; +} + bool WebViewPlugin::getFormValue(WebString& value) { return false; } diff --git a/chrome/renderer/plugins/webview_plugin.h b/chrome/renderer/plugins/webview_plugin.h index 9033fb1..28e64c4 100644 --- a/chrome/renderer/plugins/webview_plugin.h +++ b/chrome/renderer/plugins/webview_plugin.h @@ -74,6 +74,8 @@ class WebViewPlugin : public WebKit::WebPlugin, virtual void destroy(); virtual NPObject* scriptableObject(); + virtual struct _NPP* pluginNPP(); + virtual bool getFormValue(WebKit::WebString& value); virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect); diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index d2756cb..a7c0c71 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc @@ -1138,6 +1138,10 @@ bool BrowserPlugin::initialize(WebPluginContainer* container) { if (!GetContentClient()->renderer()->AllowBrowserPlugin(container)) return false; + // Tell |container| to allow this plugin to use script objects. + npp_.reset(new NPP_t); + container->allowScriptObjects(); + bindings_.reset(new BrowserPluginBindings(this)); container_ = container; container_->setWantsWheelEvents(true); @@ -1181,6 +1185,12 @@ void BrowserPlugin::EnableCompositing(bool enable) { } void BrowserPlugin::destroy() { + // If the plugin was initialized then it has a valid |npp_| identifier, and + // the |container_| must clear references to the plugin's script objects. + DCHECK(!npp_ || container_); + if (container_) + container_->clearScriptObjects(); + // The BrowserPlugin's WebPluginContainer is deleted immediately after this // call returns, so let's not keep a reference to it around. g_plugin_container_map.Get().erase(container_); @@ -1203,6 +1213,10 @@ NPObject* BrowserPlugin::scriptableObject() { return browser_plugin_np_object; } +NPP BrowserPlugin::pluginNPP() { + return npp_.get(); +} + bool BrowserPlugin::supportsKeyboardFocus() const { return true; } diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index 3d7ee9a..10a48f7 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h @@ -174,6 +174,7 @@ class CONTENT_EXPORT BrowserPlugin : virtual bool initialize(WebKit::WebPluginContainer* container) OVERRIDE; virtual void destroy() OVERRIDE; virtual NPObject* scriptableObject() OVERRIDE; + virtual struct _NPP* pluginNPP() OVERRIDE; virtual bool supportsKeyboardFocus() const OVERRIDE; virtual bool canProcessDrag() const OVERRIDE; virtual void paint( @@ -441,6 +442,9 @@ class CONTENT_EXPORT BrowserPlugin : bool compositing_enabled_; scoped_refptr<BrowserPluginCompositingHelper> compositing_helper_; + // Used to identify the plugin to WebBindings. + scoped_ptr<struct _NPP> npp_; + // Weak factory used in v8 |MakeWeak| callback, since the v8 callback might // get called after BrowserPlugin has been destroyed. base::WeakPtrFactory<BrowserPlugin> weak_ptr_factory_; diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc index 9ded3f9..7857ed5 100644 --- a/content/renderer/browser_plugin/browser_plugin_bindings.cc +++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc @@ -817,7 +817,8 @@ BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance) np_object_(NULL), weak_ptr_factory_(this) { NPObject* obj = - WebBindings::createObject(NULL, &browser_plugin_message_class); + WebBindings::createObject(instance->pluginNPP(), + &browser_plugin_message_class); np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj); np_object_->message_channel = weak_ptr_factory_.GetWeakPtr(); diff --git a/content/renderer/webplugin_delegate_proxy.cc b/content/renderer/webplugin_delegate_proxy.cc index bc49803..6663239 100644 --- a/content/renderer/webplugin_delegate_proxy.cc +++ b/content/renderer/webplugin_delegate_proxy.cc @@ -212,6 +212,7 @@ WebPluginDelegateProxy::WebPluginDelegateProxy( mime_type_(mime_type), instance_id_(MSG_ROUTING_NONE), npobject_(NULL), + npp_(new NPP_t), sad_plugin_(NULL), invalidate_pending_(false), transparent_(false), @@ -743,6 +744,11 @@ NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() { return WebBindings::retainObject(npobject_); } +NPP WebPluginDelegateProxy::GetPluginNPP() { + // Return a dummy NPP for WebKit to use to identify this plugin. + return npp_.get(); +} + bool WebPluginDelegateProxy::GetFormValue(string16* value) { bool success = false; Send(new PluginMsg_GetFormValue(instance_id_, value, &success)); diff --git a/content/renderer/webplugin_delegate_proxy.h b/content/renderer/webplugin_delegate_proxy.h index 5ede581..f39d2ae 100644 --- a/content/renderer/webplugin_delegate_proxy.h +++ b/content/renderer/webplugin_delegate_proxy.h @@ -68,6 +68,7 @@ class WebPluginDelegateProxy const gfx::Rect& clip_rect) OVERRIDE; virtual void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect) OVERRIDE; virtual NPObject* GetPluginScriptableObject() OVERRIDE; + virtual struct _NPP* GetPluginNPP() OVERRIDE; virtual bool GetFormValue(string16* value) OVERRIDE; virtual void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id) OVERRIDE; @@ -266,6 +267,9 @@ class WebPluginDelegateProxy NPObject* npobject_; base::WeakPtr<NPObjectStub> window_script_object_; + // Dummy NPP used to uniquely identify this plugin. + scoped_ptr<NPP_t> npp_; + // Event passed in by the plugin process and is used to decide if messages // need to be pumped in the NPP_HandleEvent sync call. scoped_ptr<base::WaitableEvent> modal_loop_pump_messages_event_; diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc index 80d542d..e43df18 100644 --- a/webkit/glue/cpp_bound_class.cc +++ b/webkit/glue/cpp_bound_class.cc @@ -177,16 +177,13 @@ NPClass CppNPObject::np_class_ = { return obj->bound_class->SetProperty(ident, value); } -CppBoundClass::CppBoundClass() - : bound_to_frame_(false) { +CppBoundClass::CppBoundClass() : npp_(new NPP_t) { + WebBindings::registerObjectOwner(npp_.get()); } CppBoundClass::~CppBoundClass() { STLDeleteValues(&properties_); - - // Unregister ourselves if we were bound to a frame. - if (bound_to_frame_) - WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(self_variant_)); + WebBindings::unregisterObjectOwner(npp_.get()); } bool CppBoundClass::HasMethod(NPIdentifier ident) const { @@ -300,10 +297,10 @@ bool CppBoundClass::IsMethodRegistered(const std::string& name) const { CppVariant* CppBoundClass::GetAsCppVariant() { if (!self_variant_.isObject()) { - // Create an NPObject using our static NPClass. The first argument (a - // plugin's instance handle) is passed through to the allocate function - // directly, and we don't use it, so it's ok to be 0. - NPObject* np_obj = WebBindings::createObject(0, &CppNPObject::np_class_); + // Create an NPObject using our static NPClass. The first argument has type + // NPP, but is only used to track object ownership, so passing this is fine. + NPObject* np_obj = WebBindings::createObject( + npp_.get(), &CppNPObject::np_class_); CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); obj->bound_class = this; self_variant_.Set(np_obj); @@ -316,11 +313,11 @@ CppVariant* CppBoundClass::GetAsCppVariant() { void CppBoundClass::BindToJavascript(WebFrame* frame, const std::string& classname) { // BindToWindowObject will take its own reference to the NPObject, and clean - // up after itself. It will also (indirectly) register the object with V8, - // so we must remember this so we can unregister it when we're destroyed. + // up after itself. It will also (indirectly) register the object with V8, + // against an owner pointer we supply, so we must register that as an owner, + // and unregister when we teardown. frame->bindToWindowObject(ASCIIToUTF16(classname), NPVARIANT_TO_OBJECT(*GetAsCppVariant())); - bound_to_frame_ = true; } } // namespace webkit_glue diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h index 3d7427d..d62e2ef 100644 --- a/webkit/glue/cpp_bound_class.h +++ b/webkit/glue/cpp_bound_class.h @@ -133,9 +133,8 @@ class WEBKIT_GLUE_EXPORT CppBoundClass { // reference to this object, and it is released on deletion. CppVariant self_variant_; - // True if our np_object has been bound to a WebFrame, in which case it must - // be unregistered with V8 when we delete it. - bool bound_to_frame_; + // Dummy NPP to use to register as owner for NPObjects. + scoped_ptr<NPP_t> npp_; DISALLOW_COPY_AND_ASSIGN(CppBoundClass); }; diff --git a/webkit/plugins/npapi/webplugin_delegate.h b/webkit/plugins/npapi/webplugin_delegate.h index 43a3955..9f7fe0e 100644 --- a/webkit/plugins/npapi/webplugin_delegate.h +++ b/webkit/plugins/npapi/webplugin_delegate.h @@ -83,6 +83,9 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegate { // Gets the NPObject associated with the plugin for scripting. virtual NPObject* GetPluginScriptableObject() = 0; + // Gets the NPP instance uniquely identifying the plugin for its lifetime. + virtual struct _NPP* GetPluginNPP() = 0; + // Gets the form value associated with the plugin instance. // Returns false if the value is not available. virtual bool GetFormValue(base::string16* value) = 0; diff --git a/webkit/plugins/npapi/webplugin_delegate_impl.cc b/webkit/plugins/npapi/webplugin_delegate_impl.cc index 3c2587e9..831de3d 100644 --- a/webkit/plugins/npapi/webplugin_delegate_impl.cc +++ b/webkit/plugins/npapi/webplugin_delegate_impl.cc @@ -186,6 +186,10 @@ NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() { return instance_->GetPluginScriptableObject(); } +NPP WebPluginDelegateImpl::GetPluginNPP() { + return instance_->npp(); +} + bool WebPluginDelegateImpl::GetFormValue(base::string16* value) { return instance_->GetFormValue(value); } diff --git a/webkit/plugins/npapi/webplugin_delegate_impl.h b/webkit/plugins/npapi/webplugin_delegate_impl.h index 6755891..0101de7 100644 --- a/webkit/plugins/npapi/webplugin_delegate_impl.h +++ b/webkit/plugins/npapi/webplugin_delegate_impl.h @@ -112,6 +112,7 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate { virtual bool HandleInputEvent(const WebKit::WebInputEvent& event, WebCursor::CursorInfo* cursor_info) OVERRIDE; virtual NPObject* GetPluginScriptableObject() OVERRIDE; + virtual NPP GetPluginNPP() OVERRIDE; virtual bool GetFormValue(base::string16* value) OVERRIDE; virtual void DidFinishLoadWithReason(const GURL& url, NPReason reason, diff --git a/webkit/plugins/npapi/webplugin_impl.cc b/webkit/plugins/npapi/webplugin_impl.cc index 801ca91..e86f3d1 100644 --- a/webkit/plugins/npapi/webplugin_impl.cc +++ b/webkit/plugins/npapi/webplugin_impl.cc @@ -243,10 +243,15 @@ bool WebPluginImpl::initialize(WebPluginContainer* container) { if (!plugin_delegate) return false; + // Store the plugin's unique identifier, used by the container to track its + // script objects. + npp_ = plugin_delegate->GetPluginNPP(); + // Set the container before Initialize because the plugin may - // synchronously call NPN_GetValue to get its container during its - // initialization. + // synchronously call NPN_GetValue to get its container, or make calls + // passing script objects that need to be tracked, during initialization. SetContainer(container); + bool ok = plugin_delegate->Initialize( plugin_url_, arg_names_, arg_values_, this, load_manually_); if (!ok) { @@ -280,6 +285,10 @@ NPObject* WebPluginImpl::scriptableObject() { return delegate_->GetPluginScriptableObject(); } +NPP WebPluginImpl::pluginNPP() { + return npp_; +} + bool WebPluginImpl::getFormValue(WebKit::WebString& value) { if (!delegate_) return false; @@ -484,6 +493,7 @@ WebPluginImpl::WebPluginImpl( webframe_(webframe), delegate_(NULL), container_(NULL), + npp_(NULL), plugin_url_(params.url), load_manually_(params.loadManually), first_geometry_update_(true), @@ -1055,6 +1065,8 @@ void WebPluginImpl::SetContainer(WebPluginContainer* container) { if (!container) TearDownPluginInstance(NULL); container_ = container; + if (container_) + container_->allowScriptObjects(); } void WebPluginImpl::HandleURLRequest(const char* url, @@ -1333,19 +1345,32 @@ bool WebPluginImpl::ReinitializePluginForResponse( void WebPluginImpl::TearDownPluginInstance( WebURLLoader* loader_to_ignore) { - // The container maintains a list of JSObjects which are related to this - // plugin. Tell the frame we're gone so that it can invalidate all of - // those sub JSObjects. + // JavaScript garbage collection may cause plugin script object references to + // be retained long after the plugin is destroyed. Some plugins won't cope + // with their objects being released after they've been destroyed, and once + // we've actually unloaded the plugin the object's releaseobject() code may + // no longer be in memory. The container tracks the plugin's objects and lets + // us invalidate them, releasing the references to them held by the JavaScript + // runtime. if (container_) { container_->clearScriptObjects(); container_->setWebLayer(NULL); } + // Call PluginDestroyed() first to prevent the plugin from calling us back + // in the middle of tearing down the render tree. if (delegate_) { - // Call PluginDestroyed() first to prevent the plugin from calling us back - // in the middle of tearing down the render tree. + // The plugin may call into the browser and pass script objects even during + // teardown, so temporarily re-enable plugin script objects. + DCHECK(container_); + container_->allowScriptObjects(); + delegate_->PluginDestroyed(); delegate_ = NULL; + + // Invalidate any script objects created during teardown here, before the + // plugin might actually be unloaded. + container_->clearScriptObjects(); } // Cancel any pending requests because otherwise this deleted object will diff --git a/webkit/plugins/npapi/webplugin_impl.h b/webkit/plugins/npapi/webplugin_impl.h index 20917d0..7b6594b 100644 --- a/webkit/plugins/npapi/webplugin_impl.h +++ b/webkit/plugins/npapi/webplugin_impl.h @@ -75,6 +75,7 @@ class WEBKIT_PLUGINS_EXPORT WebPluginImpl : WebKit::WebPluginContainer* container); virtual void destroy(); virtual NPObject* scriptableObject(); + virtual struct _NPP* pluginNPP(); virtual bool getFormValue(WebKit::WebString& value); virtual void paint( WebKit::WebCanvas* canvas, const WebKit::WebRect& paint_rect); @@ -292,6 +293,9 @@ class WEBKIT_PLUGINS_EXPORT WebPluginImpl : // This is just a weak reference. WebKit::WebPluginContainer* container_; + // Unique identifier for this plugin, used to track script objects. + struct _NPP* npp_; + typedef std::map<WebPluginResourceClient*, webkit_glue::MultipartResponseDelegate*> MultiPartResponseHandlerMap; diff --git a/webkit/plugins/ppapi/message_channel.cc b/webkit/plugins/ppapi/message_channel.cc index e0e0a39..bbb3eb2 100644 --- a/webkit/plugins/ppapi/message_channel.cc +++ b/webkit/plugins/ppapi/message_channel.cc @@ -324,7 +324,8 @@ MessageChannel::MessageChannel(PluginInstance* instance) early_message_queue_state_(QUEUE_MESSAGES) { // Now create an NPObject for receiving calls to postMessage. This sets the // reference count to 1. We release it in the destructor. - NPObject* obj = WebBindings::createObject(NULL, &message_channel_class); + NPObject* obj = WebBindings::createObject(instance_->instanceNPP(), + &message_channel_class); DCHECK(obj); np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj); np_object_->message_channel = weak_ptr_factory_.GetWeakPtr(); diff --git a/webkit/plugins/ppapi/plugin_object.cc b/webkit/plugins/ppapi/plugin_object.cc index a5ef5fe..9b6a130 100644 --- a/webkit/plugins/ppapi/plugin_object.cc +++ b/webkit/plugins/ppapi/plugin_object.cc @@ -298,7 +298,8 @@ PP_Var PluginObject::Create(PluginInstance* instance, // WrapperClass_Allocated function which will have created an object wrapper // appropriate for this class (derived from NPObject). NPObjectWrapper* wrapper = static_cast<NPObjectWrapper*>( - WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class))); + WebBindings::createObject(instance->instanceNPP(), + const_cast<NPClass*>(&wrapper_class))); // This object will register itself both with the NPObject and with the // PluginModule. The NPObject will normally handle its lifetime, and it diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index 9368e29..4f7f050 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -437,17 +437,16 @@ PluginInstance::PluginInstance( selection_anchor_(0), pending_user_gesture_(0.0), document_loader_(NULL), - nacl_document_load_(false) { + nacl_document_load_(false), + npp_(new NPP_t) { pp_instance_ = HostGlobals::Get()->AddInstance(this); memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); DCHECK(delegate); module_->InstanceCreated(this); delegate_->InstanceCreated(this); - message_channel_.reset(new MessageChannel(this)); view_data_.is_page_visible = delegate->IsPageVisible(); - resource_creation_ = delegate_->CreateResourceCreationAPI(this); // TODO(bbudge) remove this when the trusted NaCl plugin has been removed. @@ -634,6 +633,8 @@ static void SetGPUHistogram(const ::ppapi::Preferences& prefs, bool PluginInstance::Initialize(const std::vector<std::string>& arg_names, const std::vector<std::string>& arg_values, bool full_frame) { + message_channel_.reset(new MessageChannel(this)); + full_frame_ = full_frame; UpdateTouchEventRequest(); @@ -2545,6 +2546,10 @@ bool PluginInstance::IsValidInstanceOf(PluginModule* module) { module == original_module_.get(); } +NPP PluginInstance::instanceNPP() { + return npp_.get(); +} + void PluginInstance::DoSetCursor(WebCursorInfo* cursor) { cursor_.reset(cursor); if (fullscreen_container_) { diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h index 07f3657..3053a8a 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.h +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -58,6 +58,7 @@ #include "webkit/plugins/webkit_plugins_export.h" struct PP_Point; +struct _NPP; class SkBitmap; class TransportDIB; @@ -502,6 +503,10 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // the given module. bool IsValidInstanceOf(PluginModule* module); + // Returns the plugin NPP identifier that this plugin will use to identify + // itself when making NPObject scripting calls to WebBindings. + struct _NPP* instanceNPP(); + private: friend class PpapiUnittest; @@ -834,6 +839,10 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // calls and handles PPB_ContentDecryptor_Private calls. scoped_ptr<ContentDecryptorDelegate> content_decryptor_delegate_; + // Dummy NPP value used when calling in to WebBindings, to allow the bindings + // to correctly track NPObjects belonging to this plugin instance. + scoped_ptr<struct _NPP> npp_; + friend class PpapiPluginInstanceTest; DISALLOW_COPY_AND_ASSIGN(PluginInstance); }; diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc index 30820fb..4ce9527 100644 --- a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc @@ -93,6 +93,9 @@ bool WebPluginImpl::initialize(WebPluginContainer* container) { if (!instance_) return false; + // Enable script objects for this plugin. + container->allowScriptObjects(); + bool success = instance_->Initialize(init_data_->arg_names, init_data_->arg_values, full_frame_); @@ -116,6 +119,9 @@ bool WebPluginImpl::initialize(WebPluginContainer* container) { } void WebPluginImpl::destroy() { + // Tell |container_| to clear references to this plugin's script objects. + container_->clearScriptObjects(); + if (instance_) { ::ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(instance_object_); instance_object_ = PP_MakeUndefined(); @@ -148,6 +154,10 @@ NPObject* WebPluginImpl::scriptableObject() { return message_channel_np_object; } +NPP WebPluginImpl::pluginNPP() { + return instance_->instanceNPP(); +} + bool WebPluginImpl::getFormValue(WebString& value) { return false; } diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.h b/webkit/plugins/ppapi/ppapi_webplugin_impl.h index 11bcf89..b8bbffe 100644 --- a/webkit/plugins/ppapi/ppapi_webplugin_impl.h +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.h @@ -16,6 +16,8 @@ #include "ui/gfx/rect.h" #include "webkit/plugins/webkit_plugins_export.h" +struct _NPP; + namespace WebKit { struct WebPluginParams; struct WebPrintParams; @@ -43,6 +45,7 @@ class WebPluginImpl : public WebKit::WebPlugin { virtual bool initialize(WebKit::WebPluginContainer* container); virtual void destroy(); virtual NPObject* scriptableObject(); + virtual struct _NPP* pluginNPP(); virtual bool getFormValue(WebKit::WebString& value); virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect); virtual void updateGeometry( |