diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index c05ddada5afa..bbcee11b0a85 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -113,6 +113,34 @@ var gPluginHandler = { true); }, + // Helper to get the binding handler type from a plugin object + _getBindingType : function(plugin) { + if (!(plugin instanceof Ci.nsIObjectLoadingContent)) + return; + + switch (plugin.pluginFallbackType) { + case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED: + return "PluginNotFound"; + case Ci.nsIObjectLoadingContent.PLUGIN_DISABLED: + return "PluginDisabled"; + case Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED: + return "PluginBlocklisted"; + case Ci.nsIObjectLoadingContent.PLUGIN_OUTDATED: + return "PluginOutdated"; + case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY: + return "PluginClickToPlay"; + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE: + return "PluginVulnerableUpdatable"; + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE: + return "PluginVulnerableNoUpdate"; + case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: + return "PluginPlayPreview"; + default: + // Not all states map to a handler + return; + } + }, + handleEvent : function(event) { let self = gPluginHandler; let plugin = event.target; @@ -122,10 +150,26 @@ var gPluginHandler = { if (!(plugin instanceof Ci.nsIObjectLoadingContent)) return; - // Force a style flush, so that we ensure our binding is attached. - plugin.clientTop; + let eventType = event.type; + if (eventType == "PluginBindingAttached") { + // The plugin binding fires this event when it is created. + // As an untrusted event, ensure that this object actually has a binding + // and make sure we don't handle it twice + let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); + if (!overlay || overlay._bindingHandled) { + return; + } + overlay._bindingHandled = true; - switch (event.type) { + // Lookup the handler for this binding + eventType = self._getBindingType(plugin); + if (!eventType) { + // Not all bindings have handlers + return; + } + } + + switch (eventType) { case "PluginCrashed": self.pluginInstanceCrashed(plugin, event); break; @@ -151,7 +195,7 @@ var gPluginHandler = { #ifdef XP_MACOSX case "npapi-carbon-event-model-failure": #endif - self.pluginUnavailable(plugin, event.type); + self.pluginUnavailable(plugin, eventType); break; case "PluginVulnerableUpdatable": @@ -167,9 +211,9 @@ var gPluginHandler = { let messageString = gNavigatorBundle.getFormattedString("PluginClickToPlay", [pluginName]); let overlayText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay"); overlayText.textContent = messageString; - if (event.type == "PluginVulnerableUpdatable" || - event.type == "PluginVulnerableNoUpdate") { - let vulnerabilityString = gNavigatorBundle.getString(event.type); + if (eventType == "PluginVulnerableUpdatable" || + eventType == "PluginVulnerableNoUpdate") { + let vulnerabilityString = gNavigatorBundle.getString(eventType); let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus"); vulnerabilityText.textContent = vulnerabilityString; } @@ -186,9 +230,8 @@ var gPluginHandler = { } // Hide the in-content UI if it's too big. The crashed plugin handler already did this. - if (event.type != "PluginCrashed") { + if (eventType != "PluginCrashed") { let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); - /* overlay might be null, so only operate on it if it exists */ if (overlay != null && self.isTooSmall(plugin, overlay)) overlay.style.visibility = "hidden"; } @@ -321,7 +364,6 @@ var gPluginHandler = { return; } - // The overlay is null if the XBL binding is not attached (element is display:none). if (overlay) { overlay.addEventListener("click", function(aEvent) { // Have to check that the target is not the link to update the plugin @@ -341,11 +383,6 @@ var gPluginHandler = { _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) { let doc = aPlugin.ownerDocument; let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent"); - if (!previewContent) { - // the XBL binding is not attached (element is display:none), fallback to click-to-play logic - gPluginHandler.stopPlayPreview(aPlugin, false); - return; - } let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; if (!iframe) { // lazy initialization of the iframe @@ -754,6 +791,9 @@ var gPluginHandler = { // // Configure the crashed-plugin placeholder. // + + // Force a layout flush so the binding is attached. + plugin.clientTop; let doc = plugin.ownerDocument; let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); let statusDiv = doc.getAnonymousElementByAttribute(plugin, "class", "submitStatus"); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 7be4c20c6a0b..10e7b7c2554b 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1012,15 +1012,11 @@ var gBrowserInit = { gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false); - gBrowser.addEventListener("PluginNotFound", gPluginHandler, true); - gBrowser.addEventListener("PluginCrashed", gPluginHandler, true); - gBrowser.addEventListener("PluginBlocklisted", gPluginHandler, true); - gBrowser.addEventListener("PluginOutdated", gPluginHandler, true); - gBrowser.addEventListener("PluginDisabled", gPluginHandler, true); - gBrowser.addEventListener("PluginClickToPlay", gPluginHandler, true); - gBrowser.addEventListener("PluginPlayPreview", gPluginHandler, true); - gBrowser.addEventListener("PluginVulnerableUpdatable", gPluginHandler, true); - gBrowser.addEventListener("PluginVulnerableNoUpdate", gPluginHandler, true); + // Note that the XBL binding is untrusted + gBrowser.addEventListener("PluginBindingAttached", gPluginHandler, true, true); + gBrowser.addEventListener("PluginCrashed", gPluginHandler, true); + gBrowser.addEventListener("PluginOutdated", gPluginHandler, true); + gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true); #ifdef XP_MACOSX gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true); diff --git a/browser/base/content/test/browser_pluginnotification.js b/browser/base/content/test/browser_pluginnotification.js index 0d4fe9722512..deb5176ba7d7 100644 --- a/browser/base/content/test/browser_pluginnotification.js +++ b/browser/base/content/test/browser_pluginnotification.js @@ -64,20 +64,22 @@ function test() { gBrowser.selectedTab = newTab; gTestBrowser = gBrowser.selectedBrowser; gTestBrowser.addEventListener("load", pageLoad, true); - gTestBrowser.addEventListener("PluginClickToPlay", handlePluginClickToPlay, true); + gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true); prepareTest(test1, gTestRoot + "plugin_unknown.html"); } function finishTest() { gTestBrowser.removeEventListener("load", pageLoad, true); - gTestBrowser.removeEventListener("PluginClickToPlay", handlePluginClickToPlay, true); + gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true); gBrowser.removeCurrentTab(); window.focus(); finish(); } -function handlePluginClickToPlay() { - gClickToPlayPluginActualEvents++; +function handleBindingAttached(evt) { + evt.target instanceof Ci.nsIObjectLoadingContent; + if (evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) + gClickToPlayPluginActualEvents++; } function pageLoad() { @@ -734,7 +736,7 @@ function test19f() { // "display: block" can be clicked to activate. function test20a() { var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); - ok(clickToPlayNotification, "Test 20a, Should have a click-to-play notification"); + ok(!clickToPlayNotification, "Test 20a, Should not have a click-to-play notification"); var doc = gTestBrowser.contentDocument; var plugin = doc.getElementById("plugin"); var mainBox = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); @@ -756,6 +758,8 @@ function test20a() { } function test20b() { + var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(clickToPlayNotification, "Test 20b, Should now have a click-to-play notification"); var doc = gTestBrowser.contentDocument; var plugin = doc.getElementById("plugin"); var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect(); diff --git a/browser/base/content/test/browser_pluginplaypreview.js b/browser/base/content/test/browser_pluginplaypreview.js index b8462680b1b5..427d0aff6c53 100644 --- a/browser/base/content/test/browser_pluginplaypreview.js +++ b/browser/base/content/test/browser_pluginplaypreview.js @@ -145,7 +145,7 @@ function test() { gBrowser.selectedTab = newTab; gTestBrowser = gBrowser.selectedBrowser; gTestBrowser.addEventListener("load", pageLoad, true); - gTestBrowser.addEventListener("PluginPlayPreview", handlePluginPlayPreview, true); + gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true); registerPlayPreview('application/x-test', 'about:'); prepareTest(test1a, gTestRoot + "plugin_test.html", 1); @@ -153,14 +153,16 @@ function test() { function finishTest() { gTestBrowser.removeEventListener("load", pageLoad, true); - gTestBrowser.removeEventListener("PluginPlayPreview", handlePluginPlayPreview, true); + gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true); gBrowser.removeCurrentTab(); window.focus(); finish(); } -function handlePluginPlayPreview() { - gPlayPreviewPluginActualEvents++; +function handleBindingAttached(evt) { + if (evt.target instanceof Ci.nsIObjectLoadingContent && + evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) + gPlayPreviewPluginActualEvents++; } function pageLoad() { diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index 7e2bf2027e18..f61cb484807d 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -58,5 +58,11 @@ + + + // Notify browser-plugins.js that we were attached + this.dispatchEvent(new CustomEvent("PluginBindingAttached")); + +