gecko/mobile/android/chrome/content/PluginHelper.js
Wes Kocher a5dcf6f444 Backed out 7 changesets (bug 406541, bug 738396, bug 852315, bug 971273, bug 971279) for various java/plugin-related failures on a CLOSED TREE
Backed out changeset 13cc8a7ee925 (bug 852315)
Backed out changeset 23dfc36f99d4 (bug 852315)
Backed out changeset fb56bd7c0feb (bug 406541)
Backed out changeset b24d1437c6f3 (bug 738396)
Backed out changeset 5028e1290b45 (bug 971279)
Backed out changeset 34ecdab0cfc2 (bug 971279)
Backed out changeset 95b4aa01923d (bug 971273)
2014-02-20 16:19:30 -08:00

299 lines
11 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var PluginHelper = {
showDoorHanger: function(aTab) {
if (!aTab.browser)
return;
// Even though we may not end up showing a doorhanger, this flag
// lets us know that we've tried to show a doorhanger.
aTab.shouldShowPluginDoorhanger = false;
let uri = aTab.browser.currentURI;
// If the user has previously set a plugins permission for this website,
// either play or don't play the plugins instead of showing a doorhanger.
let permValue = Services.perms.testPermission(uri, "plugins");
if (permValue != Services.perms.UNKNOWN_ACTION) {
if (permValue == Services.perms.ALLOW_ACTION)
PluginHelper.playAllPlugins(aTab.browser.contentWindow);
return;
}
let message = Strings.browser.formatStringFromName("clickToPlayPlugins.message2",
[uri.host], 1);
let buttons = [
{
label: Strings.browser.GetStringFromName("clickToPlayPlugins.activate"),
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked)
Services.perms.add(uri, "plugins", Ci.nsIPermissionManager.ALLOW_ACTION);
PluginHelper.playAllPlugins(aTab.browser.contentWindow);
}
},
{
label: Strings.browser.GetStringFromName("clickToPlayPlugins.dontActivate"),
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked)
Services.perms.add(uri, "plugins", Ci.nsIPermissionManager.DENY_ACTION);
// Other than that, do nothing
}
}
];
// Add a checkbox with a "Don't ask again" message if the uri contains a
// host. Adding a permanent exception will fail if host is not present.
let options = uri.host ? { checkbox: Strings.browser.GetStringFromName("clickToPlayPlugins.dontAskAgain") } : {};
NativeWindow.doorhanger.show(message, "ask-to-play-plugins", buttons, aTab.id, options);
},
delayAndShowDoorHanger: function(aTab) {
// To avoid showing the doorhanger if there are also visible plugin
// overlays on the page, delay showing the doorhanger to check if
// visible plugins get added in the near future.
if (!aTab.pluginDoorhangerTimeout) {
aTab.pluginDoorhangerTimeout = setTimeout(function() {
if (this.shouldShowPluginDoorhanger) {
PluginHelper.showDoorHanger(this);
}
}.bind(aTab), 500);
}
},
playAllPlugins: function(aContentWindow) {
let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// XXX not sure if we should enable plugins for the parent documents...
let plugins = cwu.plugins;
if (!plugins || !plugins.length)
return;
plugins.forEach(this.playPlugin);
},
playPlugin: function(plugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (!objLoadingContent.activated)
objLoadingContent.playPlugin();
},
stopPlayPreview: function(plugin, playPlugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (objLoadingContent.activated)
return;
if (playPlugin)
objLoadingContent.playPlugin();
else
objLoadingContent.cancelPlayPreview();
},
getPluginPreference: function getPluginPreference() {
let pluginDisable = Services.prefs.getBoolPref("plugin.disable");
if (pluginDisable)
return "0";
let state = Services.prefs.getIntPref("plugin.default.state");
return state == Ci.nsIPluginTag.STATE_CLICKTOPLAY ? "2" : "1";
},
setPluginPreference: function setPluginPreference(aValue) {
switch (aValue) {
case "0": // Enable Plugins = No
Services.prefs.setBoolPref("plugin.disable", true);
Services.prefs.clearUserPref("plugin.default.state");
break;
case "1": // Enable Plugins = Yes
Services.prefs.clearUserPref("plugin.disable");
Services.prefs.setIntPref("plugin.default.state", Ci.nsIPluginTag.STATE_ENABLED);
break;
case "2": // Enable Plugins = Tap to Play (default)
Services.prefs.clearUserPref("plugin.disable");
Services.prefs.clearUserPref("plugin.default.state");
break;
}
},
// Copied from /browser/base/content/browser.js
isTooSmall : function (plugin, overlay) {
// Is the <object>'s size too small to hold what we want to show?
let pluginRect = plugin.getBoundingClientRect();
// XXX bug 446693. The text-shadow on the submitted-report text at
// the bottom causes scrollHeight to be larger than it should be.
let overflows = (overlay.scrollWidth > pluginRect.width) ||
(overlay.scrollHeight - 5 > pluginRect.height);
return overflows;
},
getPluginMimeType: function (plugin) {
var tagMimetype;
if (plugin instanceof HTMLAppletElement) {
tagMimetype = "application/x-java-vm";
} else {
tagMimetype = plugin.QueryInterface(Components.interfaces.nsIObjectLoadingContent)
.actualType;
if (tagMimetype == "") {
tagMimetype = plugin.type;
}
}
return tagMimetype;
},
handlePluginBindingAttached: function (aTab, aEvent) {
let plugin = aEvent.target;
let doc = plugin.ownerDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
if (!overlay || overlay._bindingHandled) {
return;
}
overlay._bindingHandled = true;
let eventType = PluginHelper._getBindingType(plugin);
if (!eventType) {
// Not all bindings have handlers
return;
}
switch (eventType) {
case "PluginClickToPlay": {
// Check if plugins have already been activated for this page, or if
// the user has set a permission to always play plugins on the site
if (aTab.clickToPlayPluginsActivated ||
Services.perms.testPermission(aTab.browser.currentURI, "plugins") ==
Services.perms.ALLOW_ACTION) {
PluginHelper.playPlugin(plugin);
return;
}
// If the plugin is hidden, or if the overlay is too small, show a
// doorhanger notification
if (PluginHelper.isTooSmall(plugin, overlay)) {
PluginHelper.delayAndShowDoorHanger(aTab);
} else {
// There's a large enough visible overlay that we don't need to show
// the doorhanger.
aTab.shouldShowPluginDoorhanger = false;
overlay.classList.add("visible");
}
// Add click to play listener to the overlay
overlay.addEventListener("click", function(e) {
if (!e.isTrusted)
return;
e.preventDefault();
let win = e.target.ownerDocument.defaultView.top;
let tab = BrowserApp.getTabForWindow(win);
tab.clickToPlayPluginsActivated = true;
PluginHelper.playAllPlugins(win);
NativeWindow.doorhanger.hide("ask-to-play-plugins", tab.id);
}, true);
// Add handlers for over- and underflow in case the plugin gets resized
plugin.addEventListener("overflow", function(event) {
overlay.classList.remove("visible");
PluginHelper.delayAndShowDoorHanger(aTab);
});
plugin.addEventListener("underflow", function(event) {
// This is also triggered if only one dimension underflows,
// the other dimension might still overflow
if (!PluginHelper.isTooSmall(plugin, overlay)) {
overlay.classList.add("visible");
}
});
break;
}
case "PluginPlayPreview": {
let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let mimeType = PluginHelper.getPluginMimeType(plugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType);
if (!playPreviewInfo.ignoreCTP) {
// Check if plugins have already been activated for this page, or if
// the user has set a permission to always play plugins on the site
if (aTab.clickToPlayPluginsActivated ||
Services.perms.testPermission(aTab.browser.currentURI, "plugins") ==
Services.perms.ALLOW_ACTION) {
PluginHelper.playPlugin(plugin);
return;
}
// Always show door hanger for play preview plugins
PluginHelper.delayAndShowDoorHanger(aTab);
}
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
// lazy initialization of the iframe
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
}
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) {
if (!e.isTrusted)
return;
previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
let playPlugin = !aEvent.detail;
PluginHelper.stopPlayPreview(plugin, playPlugin);
// cleaning up: removes overlay iframe from the DOM
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (iframe)
previewContent.removeChild(iframe);
}, true);
break;
}
case "PluginNotFound": {
// On devices where we don't support Flash, there will be a
// "Learn More..." link in the missing plugin error message.
let learnMoreLink = doc.getAnonymousElementByAttribute(plugin, "class", "unsupportedLearnMoreLink");
let learnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
learnMoreUrl += "mobile-flash-unsupported";
learnMoreLink.href = learnMoreUrl;
overlay.classList.add("visible");
break;
}
}
},
// Helper to get the binding handler type from a plugin object
_getBindingType: function(plugin) {
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return null;
switch (plugin.pluginFallbackType) {
case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
return "PluginNotFound";
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
return "PluginClickToPlay";
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
return "PluginPlayPreview";
default:
// Not all states map to a handler
return null;
}
}
};