Bug 1256339 - Fix up handling for touch-derived contextmenu events on desktop. r=mconley,jimm

This patch stops the widget code from passing along touch-derived contextmenu
events straight from Windows to Gecko, and instead lets the APZ gesture
detection code handle it. This allows the contextmenu event to be prevented
according to web standards, e.g. if the touchstart event is cancelled.

This changes to browser.js will affect both Linux and Windows, but the behaviour
implemented is in line with native Windows touch behaviour. We may want to
add an alternate codepath for Linux to better simulate "native" Linux behavior,
if there is such a thing for touch-derived contextmenu.

MozReview-Commit-ID: 18qzK15ic8E
This commit is contained in:
Kartikaya Gupta 2016-07-05 13:24:54 -04:00
parent eb0b1afe65
commit 570f040947
2 changed files with 44 additions and 1 deletions

View File

@ -81,7 +81,9 @@ addEventListener("blur", function(event) {
LoginManagerContent.onUsernameInput(event);
});
var gLastContextMenuEvent = null; // null or a WeakReference to a contextmenu event
var handleContentContextMenu = function (event) {
gLastContextMenuEvent = null;
let defaultPrevented = event.defaultPrevented;
if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
let plugin = null;
@ -96,8 +98,36 @@ var handleContentContextMenu = function (event) {
defaultPrevented = false;
}
if (defaultPrevented)
if (defaultPrevented) {
return;
}
if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
// If this was triggered by touch, then we don't want to show the actual
// context menu until we get the APZ:LongTapUp notification. However, we
// will need the |event| object when we get that notification, so we save
// it in a WeakReference. That way it won't leak things if we never get
// the APZ:LongTapUp notification (which is quite possible).
gLastContextMenuEvent = Cu.getWeakReference(event);
return;
}
// For non-touch-derived contextmenu events, we can handle it right away.
showContentContextMenu(event);
}
var showContentContextMenu = function (event) {
if (event == null) {
// If we weren't given an event, then this is being invoked from the
// APZ:LongTapUp observer, and the contextmenu event is stashed in
// gLastContextMenuEvent.
event = (gLastContextMenuEvent ? gLastContextMenuEvent.get() : null);
gLastContextMenuEvent = null;
if (event == null) {
// Still no event? We can't do anything, bail out.
return;
}
}
let addonInfo = {};
let subject = {
@ -215,6 +245,11 @@ Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService)
.addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
Services.obs.addObserver(showContentContextMenu, "APZ:LongTapUp", false);
addEventListener("unload", () => {
Services.obs.removeObserver(showContentContextMenu, "APZ:LongTapUp")
}, false);
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;

View File

@ -5144,6 +5144,14 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
case WM_CONTEXTMENU:
{
// If the context menu is brought up by a touch long-press, then
// the APZ code is responsble for dealing with this, so we don't
// need to do anything.
if (mAPZC && MOUSE_INPUT_SOURCE() == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
result = true;
break;
}
// if the context menu is brought up from the keyboard, |lParam|
// will be -1.
LPARAM pos;