From c3eadf72fd384e445ea8b7ddaa62cd709cf7e04d Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Mon, 2 Apr 2012 13:49:56 -0700 Subject: [PATCH] Bug 711552 - Click to play plugins for desktop Firefox. r=felipe --- browser/app/profile/firefox.js | 2 + browser/base/content/browser.js | 83 ++++++++++++++++++- .../en-US/chrome/browser/browser.properties | 3 + browser/themes/gnomestripe/browser.css | 3 +- browser/themes/pinstripe/browser.css | 3 +- browser/themes/winstripe/browser.css | 3 +- .../en-US/chrome/mozapps/plugins/plugins.dtd | 4 +- .../mozapps/plugins/content/pluginProblem.xml | 5 +- .../plugins/content/pluginProblemContent.css | 1 + .../mozapps/plugins/pluginProblem.css | 9 ++ .../mozapps/plugins/pluginProblem.css | 17 ++++ 11 files changed, 125 insertions(+), 8 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index bc1f24a2125..0c40fc72d23 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -612,6 +612,8 @@ pref("plugins.hide_infobar_for_carbon_failure_plugin", false); pref("plugins.update.url", "https://www.mozilla.com/%LOCALE%/plugincheck/"); pref("plugins.update.notifyUser", false); +pref("plugins.click_to_play", false); + #ifdef XP_WIN pref("browser.preferences.instantApply", false); #else diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index e51dca0a642..71185f11b03 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -256,6 +256,12 @@ function pageShowEventHandlers(event) { if (event.originalTarget == content.document) { charsetLoadListener(event); XULBrowserWindow.asyncUpdateUI(); + + // The PluginClickToPlay events are not fired when navigating using the + // BF cache. |event.persisted| is true when the page is loaded from the + // BF cache, so this code reshows the notification if necessary. + if (event.persisted) + gPluginHandler.reshowClickToPlayNotification(); } } @@ -1428,6 +1434,7 @@ function prepareForStartup() { gBrowser.addEventListener("PluginBlocklisted", gPluginHandler, true); gBrowser.addEventListener("PluginOutdated", gPluginHandler, true); gBrowser.addEventListener("PluginDisabled", gPluginHandler, true); + gBrowser.addEventListener("PluginClickToPlay", gPluginHandler, true); gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true); #ifdef XP_MACOSX gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true); @@ -5188,8 +5195,13 @@ var TabsProgressListener = { onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI, aFlags) { // Filter out any sub-frame loads - if (aBrowser.contentWindow == aWebProgress.DOMWindow) + if (aBrowser.contentWindow == aWebProgress.DOMWindow) { + // initialize the click-to-play state + aBrowser._clickToPlayDoorhangerShown = false; + aBrowser._clickToPlayPluginsActivated = false; + FullZoom.onLocationChange(aLocationURI, false, aBrowser); + } }, onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) { @@ -7143,6 +7155,10 @@ var gPluginHandler = { self.pluginUnavailable(plugin, event.type); break; + case "PluginClickToPlay": + self._handleClickToPlayEvent(plugin); + break; + case "PluginDisabled": let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink"); self.addLinkClickCallback(manageLink, "managePlugins"); @@ -7150,13 +7166,29 @@ var gPluginHandler = { } // Hide the in-content UI if it's too big. The crashed plugin handler already did this. - if (event.type != "PluginCrashed") { + if (event.type != "PluginCrashed" && event.type != "PluginClickToPlay") { let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); if (self.isTooSmall(plugin, overlay)) overlay.style.visibility = "hidden"; } }, + activatePlugins: function PH_activatePlugins(aContentWindow) { + let browser = gBrowser.getBrowserForDocument(aContentWindow.document); + browser._clickToPlayPluginsActivated = true; + let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let plugins = cwu.plugins; + for (let plugin of plugins) { + let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (!objLoadingContent.activated) + objLoadingContent.playPlugin(); + } + let notification = PopupNotifications.getNotification("click-to-play-plugins", browser); + if (notification) + notification.remove(); + }, + newPluginInstalled : function(event) { // browser elements are anonymous so we can't just use target. var browser = event.originalTarget; @@ -7210,6 +7242,53 @@ var gPluginHandler = { openHelpLink("plugin-crashed", false); }, + // Event listener for click-to-play plugins. + _handleClickToPlayEvent: function PH_handleClickToPlayEvent(aPlugin) { + let doc = aPlugin.ownerDocument; + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + if (browser._clickToPlayPluginsActivated) { + let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent); + objLoadingContent.playPlugin(); + return; + } + + let overlay = doc.getAnonymousElementByAttribute(aPlugin, "class", "mainBox"); + overlay.addEventListener("click", function(aEvent) { + if (aEvent.button == 0 && aEvent.isTrusted) + gPluginHandler.activatePlugins(aEvent.target.ownerDocument.defaultView.top); + }, true); + + if (!browser._clickToPlayDoorhangerShown) + gPluginHandler._showClickToPlayNotification(browser); + }, + + reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() { + if (!Services.prefs.getBoolPref("plugins.click_to_play")) + return; + + let browser = gBrowser.selectedBrowser; + let contentWindow = browser.contentWindow; + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + if (cwu.plugins.length) + gPluginHandler._showClickToPlayNotification(browser); + }, + + _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser) { + aBrowser._clickToPlayDoorhangerShown = true; + let contentWindow = aBrowser.contentWindow; + let messageString = gNavigatorBundle.getString("activatePluginsMessage.message"); + let action = { + label: gNavigatorBundle.getString("activatePluginsMessage.label"), + accessKey: gNavigatorBundle.getString("activatePluginsMessage.accesskey"), + callback: function() { gPluginHandler.activatePlugins(contentWindow); } + }; + let options = { dismissed: true }; + PopupNotifications.show(aBrowser, "click-to-play-plugins", + messageString, "addons-notification-icon", + action, null, options); + }, + // event listener for missing/blocklisted/outdated/carbonFailure plugins. pluginUnavailable: function (plugin, eventType) { let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index df1537f2993..35ca7bfd3c7 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -115,6 +115,9 @@ crashedpluginsMessage.learnMore=Learn Moreā€¦ carbonFailurePluginsMessage.message=This page asks to use a plugin that can only run in 32-bit mode carbonFailurePluginsMessage.restartButton.label=Restart in 32-bit mode carbonFailurePluginsMessage.restartButton.accesskey=R +activatePluginsMessage.message=Would you like to activate the plugins on this page? +activatePluginsMessage.label=Activate plugins +activatePluginsMessage.accesskey=A # Sanitize # LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css index db06d784137..20e51c02698 100644 --- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -1191,7 +1191,8 @@ toolbar[iconsize="small"] #feed-button { .popup-notification-icon[popupid="addon-install-cancelled"], .popup-notification-icon[popupid="addon-install-blocked"], .popup-notification-icon[popupid="addon-install-failed"], -.popup-notification-icon[popupid="addon-install-complete"] { +.popup-notification-icon[popupid="addon-install-complete"], +.popup-notification-icon[popupid="click-to-play-plugins"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png); width: 32px; height: 32px; diff --git a/browser/themes/pinstripe/browser.css b/browser/themes/pinstripe/browser.css index 1bb67ff5722..5c14a502073 100644 --- a/browser/themes/pinstripe/browser.css +++ b/browser/themes/pinstripe/browser.css @@ -2378,7 +2378,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { .popup-notification-icon[popupid="addon-install-cancelled"], .popup-notification-icon[popupid="addon-install-blocked"], .popup-notification-icon[popupid="addon-install-failed"], -.popup-notification-icon[popupid="addon-install-complete"] { +.popup-notification-icon[popupid="addon-install-complete"], +.popup-notification-icon[popupid="click-to-play-plugins"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png); width: 32px; height: 32px; diff --git a/browser/themes/winstripe/browser.css b/browser/themes/winstripe/browser.css index ab4eb66fa86..4e8287a936e 100644 --- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -2249,7 +2249,8 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { .popup-notification-icon[popupid="addon-install-cancelled"], .popup-notification-icon[popupid="addon-install-blocked"], .popup-notification-icon[popupid="addon-install-failed"], -.popup-notification-icon[popupid="addon-install-complete"] { +.popup-notification-icon[popupid="addon-install-complete"], +.popup-notification-icon[popupid="click-to-play-plugins"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png); width: 32px; height: 32px; diff --git a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd index 8673940c5f2..a8fda4bb926 100644 --- a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd @@ -21,7 +21,9 @@ - + + + diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index b1b04ec381c..6afe01530e4 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -49,8 +49,8 @@ xmlns:html="http://www.w3.org/1999/xhtml"> - + @@ -58,7 +58,8 @@ &missingPlugin; - &clickToPlayPlugin; + &tapToPlayPlugin; + &clickToPlayPlugins; &disabledPlugin; &blockedPlugin.label; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index 3039718671e..59a3c053836 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -43,6 +43,7 @@ html|applet:not([height]), html|applet[height=""] { :-moz-type-unsupported .msgUnsupported, :-moz-handler-clicktoplay .msgClickToPlay, +:-moz-handler-clicktoplay .msgTapToPlay, :-moz-handler-disabled .msgDisabled, :-moz-handler-disabled .msgManagePlugins, :-moz-handler-blocked .msgBlocked, diff --git a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css index 0924145e869..30d27c1870d 100644 --- a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css @@ -60,6 +60,15 @@ html|a { text-shadow: rgba(0,0,0,0.8) 0 0 3.5px; } +:-moz-handler-clicktoplay, +.msgClickToPlay { + cursor: pointer; +} + +:-moz-handler-clicktoplay .msgTapToPlay { + display: none; +} + .submitStatus div { min-height: 19px; /* height of biggest line (with throbber) */ } diff --git a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css index 0924145e869..d577beb5024 100644 --- a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css @@ -60,6 +60,23 @@ html|a { text-shadow: rgba(0,0,0,0.8) 0 0 3.5px; } +:-moz-handler-clicktoplay, +.msgClickToPlay { + cursor: pointer; +} + +@media not all and (-moz-touch-enabled) { + :-moz-handler-clicktoplay .msgTapToPlay { + display: none; + } +} + +@media (-moz-touch-enabled) { + :-moz-handler-clicktoplay .msgClickToPlay { + display: none; + } +} + .submitStatus div { min-height: 19px; /* height of biggest line (with throbber) */ }