mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 06:45:42 +00:00
f7af2c33b1
This commit does a couple of things: - move whereToOpenLink and getRootEvent implementations into BrowserUtils, so they can be used from the child process. - forward callers in utilityOverlay.js to the BrowserUtils ones (bug 1742889 will get rid of the forwarding and update all the callers; we might be able to get this and bug 1739929 into beta if risk is low enough, and touching a bunch of extra files really doesn't help with that) - move the lazy-load of BrowserUtils from browser.js to utilityOverlay.js This is safe because everywhere that loads browser.js also loads utilityOverlay.js. It's needed because there are some places that use utilityOverlay.js but not browser.js, and so now they need access to BrowserUtils.jsm. - use whereToOpenLink to determine if we should avoid consuming the transient user gesture activation in the child click handling code. - add an automated test based on the testcase in the bug. When working on this, I initially put the check using whereToOpenLink in the toplevel of the function, and then when I ran places test to check that I hadn't broken any places consumers of whereToOpenLink or getRootEvent, realized that I had broken `browser_markPageAsFollowedLink.js`, because it relies on "normal" (ie no modifier key, left button) link clicks making it to ClickHandlerParent.jsm . I filed bug 1742894 about this. I've not tried to fix that here, instead I've tried to ensure that paths through this function are as untouched as possible while still fixing bug 1739929 and bug 1742801. Differential Revision: https://phabricator.services.mozilla.com/D132102
169 lines
5.2 KiB
JavaScript
169 lines
5.2 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* 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/. */
|
|
|
|
var EXPORTED_SYMBOLS = ["ClickHandlerChild"];
|
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"PrivateBrowsingUtils",
|
|
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"WebNavigationFrames",
|
|
"resource://gre/modules/WebNavigationFrames.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"E10SUtils",
|
|
"resource://gre/modules/E10SUtils.jsm"
|
|
);
|
|
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"BrowserUtils",
|
|
"resource://gre/modules/BrowserUtils.jsm"
|
|
);
|
|
|
|
class ClickHandlerChild extends JSWindowActorChild {
|
|
handleEvent(event) {
|
|
if (
|
|
event.defaultPrevented ||
|
|
event.button == 2 ||
|
|
(event.type == "click" && event.button == 1)
|
|
) {
|
|
return;
|
|
}
|
|
// Don't do anything on editable things, we shouldn't open links in
|
|
// contenteditables, and editor needs to possibly handle middlemouse paste
|
|
let composedTarget = event.composedTarget;
|
|
if (
|
|
composedTarget.isContentEditable ||
|
|
(composedTarget.ownerDocument &&
|
|
composedTarget.ownerDocument.designMode == "on") ||
|
|
ChromeUtils.getClassName(composedTarget) == "HTMLInputElement" ||
|
|
ChromeUtils.getClassName(composedTarget) == "HTMLTextAreaElement"
|
|
) {
|
|
return;
|
|
}
|
|
|
|
let originalTarget = event.originalTarget;
|
|
let ownerDoc = originalTarget.ownerDocument;
|
|
if (!ownerDoc) {
|
|
return;
|
|
}
|
|
|
|
// Handle click events from about pages
|
|
if (event.button == 0) {
|
|
if (ownerDoc.documentURI.startsWith("about:blocked")) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// For untrusted events, require a valid transient user gesture activation.
|
|
if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
|
|
return;
|
|
}
|
|
|
|
let [href, node, principal] = BrowserUtils.hrefAndLinkNodeForClickEvent(
|
|
event
|
|
);
|
|
|
|
let csp = ownerDoc.csp;
|
|
if (csp) {
|
|
csp = E10SUtils.serializeCSP(csp);
|
|
}
|
|
|
|
let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
|
|
Ci.nsIReferrerInfo
|
|
);
|
|
if (node) {
|
|
referrerInfo.initWithElement(node);
|
|
} else {
|
|
referrerInfo.initWithDocument(ownerDoc);
|
|
}
|
|
referrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);
|
|
let frameID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
|
|
|
|
let json = {
|
|
button: event.button,
|
|
shiftKey: event.shiftKey,
|
|
ctrlKey: event.ctrlKey,
|
|
metaKey: event.metaKey,
|
|
altKey: event.altKey,
|
|
href: null,
|
|
title: null,
|
|
frameID,
|
|
triggeringPrincipal: principal,
|
|
csp,
|
|
referrerInfo,
|
|
originAttributes: principal ? principal.originAttributes : {},
|
|
isContentWindowPrivate: PrivateBrowsingUtils.isContentWindowPrivate(
|
|
ownerDoc.defaultView
|
|
),
|
|
};
|
|
|
|
if (href) {
|
|
try {
|
|
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
|
|
principal,
|
|
href
|
|
);
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
!event.isTrusted &&
|
|
BrowserUtils.whereToOpenLink(event) != "current"
|
|
) {
|
|
// If we'll open the link, we want to consume the user gesture
|
|
// activation to ensure that we don't allow multiple links to open
|
|
// from one user gesture.
|
|
// Avoid doing so for links opened in the current tab, which get
|
|
// handled later, by gecko, as otherwise its popup blocker will stop
|
|
// the link from opening.
|
|
// We will do the same check (whereToOpenLink) again in the parent and
|
|
// avoid handling the click for such links... but we still need the
|
|
// click information in the parent because otherwise places link
|
|
// tracking breaks. (bug 1742894 tracks improving this.)
|
|
ownerDoc.consumeTransientUserGestureActivation();
|
|
// We don't care about the return value because we already checked that
|
|
// hasValidTransientUserGestureActivation was true earlier in this
|
|
// function.
|
|
}
|
|
|
|
json.href = href;
|
|
if (node) {
|
|
json.title = node.getAttribute("title");
|
|
}
|
|
|
|
json.originPrincipal = ownerDoc.nodePrincipal;
|
|
json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal;
|
|
json.triggeringPrincipal = ownerDoc.nodePrincipal;
|
|
|
|
// If a link element is clicked with middle button, user wants to open
|
|
// the link somewhere rather than pasting clipboard content. Therefore,
|
|
// when it's clicked with middle button, we should prevent multiple
|
|
// actions here to avoid leaking clipboard content unexpectedly.
|
|
// Note that whether the link will work actually or not does not matter
|
|
// because in this case, user does not intent to paste clipboard content.
|
|
if (event.button === 1) {
|
|
event.preventMultipleActions();
|
|
}
|
|
|
|
this.sendAsyncMessage("Content:Click", json);
|
|
return;
|
|
}
|
|
|
|
// This might be middle mouse navigation.
|
|
if (event.button == 1) {
|
|
this.sendAsyncMessage("Content:Click", json);
|
|
}
|
|
}
|
|
}
|