Bug 889788 - Plugin doorhanger breaks when plugins are dynamically removed from a page. This implements the short-term solution of hiding the plugin doorhanger when no more plugins are on the page (the better long-term solution will keep showing the UI and track all the plugins a page ever uses). This also implements a short-term solution when a user enables a plugin. Also bug 887088 - Short-term UI solution: when a user loads multiple tabs from a site and enables a plugin on one of them, the plugins are not enabled on other tabs but the "continue allowing" button does nothing. This patch makes the "Continue Allowing" button enable existing plugins of that type. r=jaws r=jschoenick

--HG--
extra : rebase_source : a60ae3259579ea63d51921dc3c70836da2d7ab3a
This commit is contained in:
Benjamin Smedberg 2013-07-19 10:02:48 -04:00
parent a309313cb4
commit c416701cd3
4 changed files with 68 additions and 35 deletions

View File

@ -217,14 +217,21 @@ var gPluginHandler = {
},
handleEvent : function(event) {
let plugin = event.target;
let doc = plugin.ownerDocument;
// We're expecting the target to be a plugin.
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
let plugin;
let doc;
let eventType = event.type;
if (eventType === "PluginRemoved") {
doc = event.target;
}
else {
plugin = event.target;
doc = plugin.ownerDocument;
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
}
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
@ -304,12 +311,13 @@ var gPluginHandler = {
break;
case "PluginInstantiated":
case "PluginRemoved":
this._showClickToPlayNotification(browser);
break;
}
// Hide the in-content UI if it's too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed") {
if (eventType != "PluginCrashed" && eventType != "PluginRemoved") {
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
if (overlay != null && this.isTooSmall(plugin, overlay))
overlay.style.visibility = "hidden";
@ -686,18 +694,12 @@ var gPluginHandler = {
switch (aNewState) {
case "allownow":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000;
break;
case "allowalways":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
expireTime = Date.now() +
@ -705,25 +707,28 @@ var gPluginHandler = {
break;
case "block":
if (aPluginInfo.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.PROMPT_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
expireTime = 0;
break;
// In case a plugin has already been allowed in another tab, the "continue allowing" button
// shouldn't change any permissions but should run the plugin-enablement code below.
case "continue":
break;
default:
Cu.reportError(Error("Unexpected plugin state: " + aNewState));
return;
}
let browser = aNotification.browser;
Services.perms.add(browser.currentURI, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState != "continue") {
Services.perms.add(browser.currentURI, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState == "block") {
return;
if (aNewState == "block") {
return;
}
}
// Manually activate the plugins that would have been automatically

View File

@ -755,6 +755,7 @@ var gBrowserInit = {
gBrowser.addEventListener("PluginCrashed", gPluginHandler, true);
gBrowser.addEventListener("PluginOutdated", gPluginHandler, true);
gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true);
gBrowser.addEventListener("PluginRemoved", gPluginHandler, true);
gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);

View File

@ -1574,12 +1574,19 @@
this.appendChild(item);
this._items.push(item);
}
if (this.notification.options.centerActions.length == 1) {
this._setState(this._states.SINGLE);
} else if (this.notification.options.primaryPlugin) {
this._setState(this._states.MULTI_COLLAPSED);
} else {
this._setState(this._states.MULTI_EXPANDED);
switch (this.notification.options.centerActions.length) {
case 0:
PopupNotifications._dismiss();
break;
case 1:
this._setState(this._states.SINGLE);
break;
default:
if (this.notification.options.primaryPlugin) {
this._setState(this._states.MULTI_COLLAPSED);
} else {
this._setState(this._states.MULTI_EXPANDED);
}
}
]]></constructor>
<method name="_setState">
@ -1645,7 +1652,7 @@
button2 = {
label: "pluginContinue.label",
accesskey: "pluginContinue.accesskey",
action: "_cancel",
action: "_singleContinue",
default: true
};
switch (action.blocklistState) {
@ -1819,6 +1826,14 @@
this._cancel();
]]></body>
</method>
<method name="_singleContinue">
<body><![CDATA[
gPluginHandler._updatePluginPermission(this.notification,
this.notification.options.centerActions[0],
"continue");
this._cancel();
]]></body>
</method>
<method name="_multiAccept">
<body><![CDATA[
for (let item of this._items) {

View File

@ -196,26 +196,36 @@ CheckPluginStopEvent::Run()
*/
class nsSimplePluginEvent : public nsRunnable {
public:
nsSimplePluginEvent(nsIContent* aContent, const nsAString &aEvent)
: mContent(aContent),
mEvent(aEvent)
{}
nsSimplePluginEvent(nsIContent* aTarget, const nsAString &aEvent)
: mTarget(aTarget)
, mDocument(aTarget->GetCurrentDoc())
, mEvent(aEvent)
{
}
nsSimplePluginEvent(nsIDocument* aTarget, const nsAString& aEvent)
: mTarget(aTarget)
, mDocument(aTarget)
, mEvent(aEvent)
{
}
~nsSimplePluginEvent() {}
NS_IMETHOD Run();
private:
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<nsISupports> mTarget;
nsCOMPtr<nsIDocument> mDocument;
nsString mEvent;
};
NS_IMETHODIMP
nsSimplePluginEvent::Run()
{
LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mContent.get(),
LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(),
mEvent.get()));
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
nsContentUtils::DispatchTrustedEvent(mDocument, mTarget,
mEvent, true, true);
return NS_OK;
}
@ -674,7 +684,9 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
/// would keep the docshell around, but trash the frameloader
UnloadObject();
}
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(thisContent->GetCurrentDoc(),
NS_LITERAL_STRING("PluginRemoved"));
NS_DispatchToCurrentThread(ev);
}
nsObjectLoadingContent::nsObjectLoadingContent()