From 934a08f28fdb0ff586036a0a837c4b1e0bf13408 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Tue, 17 Nov 2015 14:41:03 +0100 Subject: [PATCH] browser-plugin: Do not create a new object every time NPPVpluginScriptableNPObject is requested Merge PluginData and PluginObject structs into a single one and create the scriptable object associated to the plugin instance in NPP_New. Then, when NPPVpluginScriptableNPObject is requested we just return the scriptable object associated to the given instance. This caused the crashes in NPN_InvokeDefault with WebKit, since we had multiple scriptable objects for the same instance, but only one of those objects had the onchange listener installed. Firefox seems to cache the scriptable object for the instance and therefore NPPVpluginScriptableNPObject is requested only once. https://bugzilla.gnome.org/show_bug.cgi?id=737932 --- browser-plugin/browser-plugin.c | 306 ++++++++++++++++---------------- 1 file changed, 150 insertions(+), 156 deletions(-) diff --git a/browser-plugin/browser-plugin.c b/browser-plugin/browser-plugin.c index 50a7e1afe..c65711ec0 100644 --- a/browser-plugin/browser-plugin.c +++ b/browser-plugin/browser-plugin.c @@ -43,10 +43,6 @@ #define EXTENSION_DISABLE_VERSION_CHECK_KEY "disable-extension-version-validation" -typedef struct { - GDBusProxy *proxy; -} PluginData; - static NPNetscapeFuncs funcs; static inline gchar * @@ -145,125 +141,6 @@ check_origin_and_protocol (NPP instance) return ret; } -/* =============== public entry points =================== */ - -NPError -NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin) -{ - /* global initialization routine, called once when plugin - is loaded */ - - g_debug ("plugin loaded"); - - memcpy (&funcs, pfuncs, sizeof (funcs)); - - plugin->size = sizeof(NPPluginFuncs); - plugin->newp = NPP_New; - plugin->destroy = NPP_Destroy; - plugin->getvalue = NPP_GetValue; - plugin->setwindow = NPP_SetWindow; - plugin->event = NPP_HandleEvent; - - return NPERR_NO_ERROR; -} - -NPError -NP_Shutdown(void) -{ - return NPERR_NO_ERROR; -} - -const char* -NP_GetMIMEDescription(void) -{ - return PLUGIN_MIME_STRING; -} - -NPError -NP_GetValue(void *instance, - NPPVariable variable, - void *value) -{ - switch (variable) { - case NPPVpluginNameString: - *(char**)value = PLUGIN_NAME; - break; - case NPPVpluginDescriptionString: - *(char**)value = PLUGIN_DESCRIPTION; - break; - default: - ; - } - - return NPERR_NO_ERROR; -} - -NPError -NPP_New(NPMIMEType mimetype, - NPP instance, - uint16_t mode, - int16_t argc, - char **argn, - char **argv, - NPSavedData *saved) -{ - /* instance initialization function */ - PluginData *data; - GError *error = NULL; - - g_debug ("plugin created"); - - if (!check_origin_and_protocol (instance)) - return NPERR_GENERIC_ERROR; - - data = g_slice_new (PluginData); - instance->pdata = data; - - /* set windowless mode */ - funcs.setvalue(instance, NPPVpluginWindowBool, NULL); - - data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, /* interface info */ - "org.gnome.Shell", - "/org/gnome/Shell", - "org.gnome.Shell.Extensions", - NULL, /* GCancellable */ - &error); - if (!data->proxy) - { - /* ignore error if the shell is not running, otherwise warn */ - if (error->domain != G_DBUS_ERROR || - error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER) - { - g_warning ("Failed to set up Shell proxy: %s", error->message); - } - g_clear_error (&error); - return NPERR_GENERIC_ERROR; - } - - g_debug ("plugin created successfully"); - - return NPERR_NO_ERROR; -} - -NPError -NPP_Destroy(NPP instance, - NPSavedData **saved) -{ - /* instance finalization function */ - - PluginData *data = instance->pdata; - - g_debug ("plugin destroyed"); - - g_object_unref (data->proxy); - - g_slice_free (PluginData, data); - - return NPERR_NO_ERROR; -} - /* =================== scripting interface =================== */ typedef struct { @@ -348,45 +225,18 @@ static NPObject * plugin_object_allocate (NPP instance, NPClass *klass) { - PluginData *data = instance->pdata; - PluginObject *obj = g_slice_new0 (PluginObject); + PluginObject *obj = (PluginObject *) funcs.memalloc (sizeof (PluginObject)); + memset (obj, 0, sizeof (PluginObject)); obj->instance = instance; - obj->proxy = g_object_ref (data->proxy); - obj->settings = g_settings_new (SHELL_SCHEMA); - obj->signal_id = g_signal_connect (obj->proxy, "g-signal", - G_CALLBACK (on_shell_signal), obj); - obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION, - "org.gnome.Shell", - G_BUS_NAME_WATCHER_FLAGS_NONE, - on_shell_appeared, - NULL, - obj, - NULL); - - g_debug ("plugin object created"); - - return (NPObject*)obj; + return (NPObject*) obj; } static void plugin_object_deallocate (NPObject *npobj) { - PluginObject *obj = (PluginObject*)npobj; - - g_signal_handler_disconnect (obj->proxy, obj->signal_id); - g_object_unref (obj->proxy); - - if (obj->listener) - funcs.releaseobject (obj->listener); - - if (obj->watch_name_id) - g_bus_unwatch_name (obj->watch_name_id); - - g_debug ("plugin object destroyed"); - - g_slice_free (PluginObject, obj); + funcs.memfree (npobj); } static inline gboolean @@ -1037,6 +887,149 @@ init_methods_and_properties (void) onextension_changed_id = funcs.getstringidentifier ("onchange"); } +/* =============== public entry points =================== */ + +NPError +NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin) +{ + /* global initialization routine, called once when plugin + is loaded */ + + g_debug ("plugin loaded"); + + memcpy (&funcs, pfuncs, sizeof (funcs)); + + plugin->size = sizeof(NPPluginFuncs); + plugin->newp = NPP_New; + plugin->destroy = NPP_Destroy; + plugin->getvalue = NPP_GetValue; + plugin->setwindow = NPP_SetWindow; + plugin->event = NPP_HandleEvent; + + return NPERR_NO_ERROR; +} + +NPError +NP_Shutdown(void) +{ + return NPERR_NO_ERROR; +} + +const char* +NP_GetMIMEDescription(void) +{ + return PLUGIN_MIME_STRING; +} + +NPError +NP_GetValue(void *instance, + NPPVariable variable, + void *value) +{ + switch (variable) { + case NPPVpluginNameString: + *(char**)value = PLUGIN_NAME; + break; + case NPPVpluginDescriptionString: + *(char**)value = PLUGIN_DESCRIPTION; + break; + default: + ; + } + + return NPERR_NO_ERROR; +} + +NPError +NPP_New(NPMIMEType mimetype, + NPP instance, + uint16_t mode, + int16_t argc, + char **argn, + char **argv, + NPSavedData *saved) +{ + /* instance initialization function */ + PluginObject *obj; + GError *error = NULL; + + g_debug ("plugin created"); + + if (!check_origin_and_protocol (instance)) + return NPERR_GENERIC_ERROR; + + /* set windowless mode */ + funcs.setvalue(instance, NPPVpluginWindowBool, NULL); + + g_debug ("creating scriptable object"); + init_methods_and_properties (); + obj = (PluginObject *) funcs.createobject (instance, &plugin_class); + instance->pdata = obj; + + obj->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* interface info */ + "org.gnome.Shell", + "/org/gnome/Shell", + "org.gnome.Shell.Extensions", + NULL, /* GCancellable */ + &error); + if (!obj->proxy) + { + /* ignore error if the shell is not running, otherwise warn */ + if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) + { + g_warning ("Failed to set up Shell proxy: %s", error->message); + } + g_clear_error (&error); + return NPERR_GENERIC_ERROR; + } + + obj->settings = g_settings_new (SHELL_SCHEMA); + obj->signal_id = g_signal_connect (obj->proxy, "g-signal", + G_CALLBACK (on_shell_signal), obj); + obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + obj, + NULL); + + g_debug ("plugin created successfully"); + + return NPERR_NO_ERROR; +} + +NPError +NPP_Destroy(NPP instance, + NPSavedData **saved) +{ + /* instance finalization function */ + PluginObject *obj = (PluginObject *) instance->pdata; + + if (!obj) + return NPERR_INVALID_INSTANCE_ERROR; + + g_debug ("plugin destroyed"); + + g_signal_handler_disconnect (obj->proxy, obj->signal_id); + g_object_unref (obj->proxy); + + if (obj->listener) + funcs.releaseobject (obj->listener); + + if (obj->restart_listener) + funcs.releaseobject (obj->restart_listener); + + if (obj->watch_name_id) + g_bus_unwatch_name (obj->watch_name_id); + + funcs.releaseobject((NPObject *)obj); + + return NPERR_NO_ERROR; +} + NPError NPP_GetValue(NPP instance, NPPVariable variable, @@ -1047,9 +1040,10 @@ NPP_GetValue(NPP instance, switch (variable) { case NPPVpluginScriptableNPObject: g_debug ("creating scriptable object"); - init_methods_and_properties (); + if (!instance->pdata) + return NPERR_INVALID_INSTANCE_ERROR; - *(NPObject**)value = funcs.createobject (instance, &plugin_class); + *(NPObject**)value = instance->pdata; break; default: