no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / browser / actors / ClickHandlerChild.sys.mjs
blob2fa0a87df436adb0ca79cf000e5344f4925b034f
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
8 const lazy = {};
10 ChromeUtils.defineESModuleGetters(lazy, {
11   BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
12   E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
13 });
15 export class MiddleMousePasteHandlerChild extends JSWindowActorChild {
16   handleEvent(clickEvent) {
17     if (
18       clickEvent.defaultPrevented ||
19       clickEvent.button != 1 ||
20       MiddleMousePasteHandlerChild.autoscrollEnabled
21     ) {
22       return;
23     }
24     this.manager
25       .getActor("ClickHandler")
26       .handleClickEvent(
27         clickEvent,
28         /* is from middle mouse paste handler */ true
29       );
30   }
32   onProcessedClick(data) {
33     this.sendAsyncMessage("MiddleClickPaste", data);
34   }
37 XPCOMUtils.defineLazyPreferenceGetter(
38   MiddleMousePasteHandlerChild,
39   "autoscrollEnabled",
40   "general.autoScroll",
41   true
44 export class ClickHandlerChild extends JSWindowActorChild {
45   handleEvent(wrapperEvent) {
46     this.handleClickEvent(wrapperEvent.sourceEvent);
47   }
49   handleClickEvent(event, isFromMiddleMousePasteHandler = false) {
50     if (event.defaultPrevented || event.button == 2) {
51       return;
52     }
53     // Don't do anything on editable things, we shouldn't open links in
54     // contenteditables, and editor needs to possibly handle middlemouse paste
55     let composedTarget = event.composedTarget;
56     if (
57       composedTarget.isContentEditable ||
58       (composedTarget.ownerDocument &&
59         composedTarget.ownerDocument.designMode == "on") ||
60       ChromeUtils.getClassName(composedTarget) == "HTMLInputElement" ||
61       ChromeUtils.getClassName(composedTarget) == "HTMLTextAreaElement"
62     ) {
63       return;
64     }
66     let originalTarget = event.originalTarget;
67     let ownerDoc = originalTarget.ownerDocument;
68     if (!ownerDoc) {
69       return;
70     }
72     // Handle click events from about pages
73     if (event.button == 0) {
74       if (ownerDoc.documentURI.startsWith("about:blocked")) {
75         return;
76       }
77     }
79     // For untrusted events, require a valid transient user gesture activation.
80     if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
81       return;
82     }
84     let [href, node, principal] =
85       lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event);
87     let csp = ownerDoc.csp;
88     if (csp) {
89       csp = lazy.E10SUtils.serializeCSP(csp);
90     }
92     let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
93       Ci.nsIReferrerInfo
94     );
95     if (node) {
96       referrerInfo.initWithElement(node);
97     } else {
98       referrerInfo.initWithDocument(ownerDoc);
99     }
100     referrerInfo = lazy.E10SUtils.serializeReferrerInfo(referrerInfo);
102     let json = {
103       button: event.button,
104       shiftKey: event.shiftKey,
105       ctrlKey: event.ctrlKey,
106       metaKey: event.metaKey,
107       altKey: event.altKey,
108       href: null,
109       title: null,
110       csp,
111       referrerInfo,
112     };
114     if (href && !isFromMiddleMousePasteHandler) {
115       try {
116         Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
117           principal,
118           href
119         );
120       } catch (e) {
121         return;
122       }
124       if (
125         !event.isTrusted &&
126         lazy.BrowserUtils.whereToOpenLink(event) != "current"
127       ) {
128         // If we'll open the link, we want to consume the user gesture
129         // activation to ensure that we don't allow multiple links to open
130         // from one user gesture.
131         // Avoid doing so for links opened in the current tab, which get
132         // handled later, by gecko, as otherwise its popup blocker will stop
133         // the link from opening.
134         // We will do the same check (whereToOpenLink) again in the parent and
135         // avoid handling the click for such links... but we still need the
136         // click information in the parent because otherwise places link
137         // tracking breaks. (bug 1742894 tracks improving this.)
138         ownerDoc.consumeTransientUserGestureActivation();
139         // We don't care about the return value because we already checked that
140         // hasValidTransientUserGestureActivation was true earlier in this
141         // function.
142       }
144       json.href = href;
145       if (node) {
146         json.title = node.getAttribute("title");
147       }
149       if (
150         (ownerDoc.URL === "about:newtab" || ownerDoc.URL === "about:home") &&
151         node.dataset.isSponsoredLink === "true"
152       ) {
153         json.globalHistoryOptions = { triggeringSponsoredURL: href };
154       }
156       // If a link element is clicked with middle button, user wants to open
157       // the link somewhere rather than pasting clipboard content.  Therefore,
158       // when it's clicked with middle button, we should prevent multiple
159       // actions here to avoid leaking clipboard content unexpectedly.
160       // Note that whether the link will work actually or not does not matter
161       // because in this case, user does not intent to paste clipboard content.
162       // We also need to do this to prevent multiple tabs opening if there are
163       // nested link elements.
164       event.preventMultipleActions();
166       this.sendAsyncMessage("Content:Click", json);
167     }
169     // This might be middle mouse navigation, in which case pass this back:
170     if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
171       this.manager.getActor("MiddleMousePasteHandler").onProcessedClick(json);
172     }
173   }