fune/browser/actors/ClickHandlerChild.jsm
Gijs Kruitbosch 550d651713 Bug 1716883 - fix autoscroll behaviour over various SVG elements, r=masayuki
This avoids starting autoscroll on SVG links, and on HTML links that
contain SVG, by sharing the code that browser's ClickHandlerChild uses
to detect links into BrowserUtils, and using that from AutoScrollChild
to determine if the click happened on top of a link. It also adds a
test so we avoid regressing this in future.

When running the test, I noticed an error from ClickHandlerParent
when the browser for which we receive a click has gone away, and
fixed it by adding a nullcheck and early return.

Differential Revision: https://phabricator.services.mozilla.com/D120024
2021-07-19 11:36:55 +00:00

144 lines
4.1 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.isTrusted ||
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;
}
}
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;
}
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);
}
}
}