Bug 516753 - Forward content context menu events to the parent. r=felipc

This commit is contained in:
David Keeler 2013-08-06 15:00:07 -07:00
parent da213913be
commit 9f7b825989
5 changed files with 87 additions and 23 deletions

View File

@ -38,7 +38,11 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) {
}
});
if (!Services.prefs.getBoolPref("browser.tabs.remote")) {
if (Services.prefs.getBoolPref("browser.tabs.remote")) {
addEventListener("contextmenu", function (event) {
sendAsyncMessage("contextmenu", {}, { event: event });
}, false);
} else {
addEventListener("DOMContentLoaded", function(event) {
LoginManagerContent.onContentLoaded(event);
});

View File

@ -4,6 +4,8 @@
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
var gContextMenuContentData = null;
function nsContextMenu(aXulMenu, aIsShift) {
this.shouldDisplay = true;
this.initMenu(aXulMenu, aIsShift);
@ -39,6 +41,7 @@ nsContextMenu.prototype = {
},
hiding: function CM_hiding() {
gContextMenuContentData = null;
InlineSpellCheckerUI.clearSuggestionsFromMenu();
InlineSpellCheckerUI.clearDictionaryListFromMenu();
InlineSpellCheckerUI.uninit();
@ -500,6 +503,15 @@ nsContextMenu.prototype = {
// Set various context menu attributes based on the state of the world.
setTarget: function (aNode, aRangeParent, aRangeOffset) {
// If gContextMenuContentData is not null, this event was forwarded from a
// child process, so use that information instead.
if (gContextMenuContentData) {
this.isRemote = true;
aNode = gContextMenuContentData.event.target;
} else {
this.isRemote = false;
}
const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
if (aNode.namespaceURI == xulNS ||
aNode.nodeType == Node.DOCUMENT_NODE ||
@ -539,11 +551,17 @@ nsContextMenu.prototype = {
// Remember the node that was clicked.
this.target = aNode;
this.browser = this.target.ownerDocument.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
// If this is a remote context menu event, use the information from
// gContextMenuContentData instead.
if (this.isRemote) {
this.browser = gContextMenuContentData.browser;
} else {
this.browser = this.target.ownerDocument.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
}
this.onSocial = !!this.browser.getAttribute("origin");
// Check if we are in a synthetic document (stand alone image, video, etc.).
@ -772,10 +790,22 @@ nsContextMenu.prototype = {
this.linkProtocol == "snews" );
},
_unremotePrincipal: function(aRemotePrincipal) {
if (this.isRemote) {
return Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getAppCodebasePrincipal(aRemotePrincipal.URI,
aRemotePrincipal.appId,
aRemotePrincipal.isInBrowserElement);
}
return aRemotePrincipal;
},
// Open linked-to URL in a new window.
openLink : function () {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
@ -784,7 +814,7 @@ nsContextMenu.prototype = {
// Open linked-to URL in a new private window.
openLinkInPrivateWindow : function () {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject,
@ -794,7 +824,7 @@ nsContextMenu.prototype = {
// Open linked-to URL in a new tab.
openLinkInTab: function() {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "tab",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
@ -803,7 +833,7 @@ nsContextMenu.prototype = {
// open URL in current tab
openLinkInCurrent: function() {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "current",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
@ -839,7 +869,8 @@ nsContextMenu.prototype = {
var doc = this.target.ownerDocument;
var frameURL = doc.location.href;
urlSecurityCheck(frameURL, this.browser.contentPrincipal,
urlSecurityCheck(frameURL,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var referrer = doc.referrer;
openUILinkIn(frameURL, "current", { disallowInheritPrincipal: true,
@ -902,7 +933,8 @@ nsContextMenu.prototype = {
viewImageDesc: function(e) {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.imageDescURL, this.browser.contentPrincipal,
urlSecurityCheck(this.imageDescURL,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
openUILink(this.imageDescURL, e, { disallowInheritPrincipal: true,
referrerURI: doc.documentURIObject });
@ -914,7 +946,7 @@ nsContextMenu.prototype = {
reloadImage: function(e) {
urlSecurityCheck(this.mediaURL,
this.browser.contentPrincipal,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
if (this.target instanceof Ci.nsIImageLoadingContent)
@ -930,7 +962,7 @@ nsContextMenu.prototype = {
else {
viewURL = this.mediaURL;
urlSecurityCheck(viewURL,
this.browser.contentPrincipal,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
}
@ -940,7 +972,8 @@ nsContextMenu.prototype = {
},
saveVideoFrameAsImage: function () {
urlSecurityCheck(this.mediaURL, this.browser.contentPrincipal,
urlSecurityCheck(this.mediaURL,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
let name = "";
try {
@ -973,7 +1006,7 @@ nsContextMenu.prototype = {
// Change current window to the URL of the background image.
viewBGImage: function(e) {
urlSecurityCheck(this.bgImageURL,
this.browser.contentPrincipal,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var doc = this.target.ownerDocument;
openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true,
@ -1007,8 +1040,9 @@ nsContextMenu.prototype = {
if (this.disableSetDesktopBackground())
return;
var doc = this.target.ownerDocument;
urlSecurityCheck(this.target.currentURI.spec,
this.target.ownerDocument.nodePrincipal);
this._unremotePrincipal(doc.nodePrincipal));
// Confirm since it's annoying if you hit this accidentally.
const kDesktopBackgroundURL =
@ -1185,7 +1219,7 @@ nsContextMenu.prototype = {
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
else
linkText = this.linkText();
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
this.saveHelper(this.linkURL, linkText, null, true, doc);
},
@ -1205,12 +1239,14 @@ nsContextMenu.prototype = {
true, false, doc.documentURIObject, doc);
}
else if (this.onImage) {
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
urlSecurityCheck(this.mediaURL,
this._unremotePrincipal(doc.nodePrincipal));
saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
false, doc.documentURIObject, doc);
}
else if (this.onVideo || this.onAudio) {
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
urlSecurityCheck(this.mediaURL,
this._unremotePrincipal(doc.nodePrincipal));
var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle";
this.saveHelper(this.mediaURL, null, dialogTitle, false, doc);
}

View File

@ -2908,6 +2908,16 @@
let titleChanged = this.setTabTitle(tab);
if (titleChanged && !tab.selected && !tab.hasAttribute("busy"))
tab.setAttribute("titlechanged", "true");
break;
case "contextmenu":
gContextMenuContentData = { event: aMessage.objects.event,
browser: browser };
let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
popup.openPopup(browser, "overlap",
gContextMenuContentData.event.clientX,
gContextMenuContentData.event.clientY,
true, false, null);
break;
}
]]></body>
</method>
@ -2957,8 +2967,10 @@
"-moz-default-background-color" :
Services.prefs.getCharPref("browser.display.background_color");
if (Services.prefs.getBoolPref("browser.tabs.remote"))
if (Services.prefs.getBoolPref("browser.tabs.remote")) {
messageManager.addMessageListener("DOMTitleChanged", this);
messageManager.addMessageListener("contextmenu", this);
}
]]>
</constructor>
@ -2993,8 +3005,10 @@
document.removeEventListener("keypress", this, false);
window.removeEventListener("sizemodechange", this, false);
if (Services.prefs.getBoolPref("browser.tabs.remote"))
if (Services.prefs.getBoolPref("browser.tabs.remote")) {
messageManager.removeMessageListener("DOMTitleChanged", this);
messageManager.removeMessageListener("contextmenu", this);
}
]]>
</destructor>

View File

@ -1585,6 +1585,7 @@ CrossProcessSafeEvent(const nsEvent& aEvent)
case NS_MOUSE_BUTTON_DOWN:
case NS_MOUSE_BUTTON_UP:
case NS_MOUSE_MOVE:
case NS_CONTEXTMENU:
return true;
default:
return false;

View File

@ -136,6 +136,16 @@ nsXULPopupListener::HandleEvent(nsIDOMEvent* aEvent)
}
}
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
if (!targetContent) {
return NS_OK;
}
if (targetContent->Tag() == nsGkAtoms::browser &&
targetContent->IsXUL() &&
nsEventStateManager::IsRemoteTarget(targetContent)) {
return NS_OK;
}
bool preventDefault;
mouseEvent->GetDefaultPrevented(&preventDefault);
if (preventDefault && targetNode && mIsContext) {
@ -180,7 +190,6 @@ nsXULPopupListener::HandleEvent(nsIDOMEvent* aEvent)
// If a menu item child was clicked on that leads to a popup needing
// to show, we know (guaranteed) that we're dealing with a menu or
// submenu of an already-showing popup. We don't need to do anything at all.
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
if (!mIsContext) {
nsIAtom *tag = targetContent ? targetContent->Tag() : nullptr;
if (tag == nsGkAtoms::menu || tag == nsGkAtoms::menuitem)