Bug 1791785 - When dumping symbols never emit INLINE_ORIGIN directives with an empty...
[gecko.git] / browser / actors / ClickHandlerChild.jsm
blobcf274b210b7d44390e5f06e0eb83a79f2061f58e
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 var EXPORTED_SYMBOLS = ["ClickHandlerChild", "MiddleMousePasteHandlerChild"];
8 const { XPCOMUtils } = ChromeUtils.importESModule(
9   "resource://gre/modules/XPCOMUtils.sys.mjs"
12 const lazy = {};
14 ChromeUtils.defineModuleGetter(
15   lazy,
16   "PrivateBrowsingUtils",
17   "resource://gre/modules/PrivateBrowsingUtils.jsm"
19 ChromeUtils.defineModuleGetter(
20   lazy,
21   "WebNavigationFrames",
22   "resource://gre/modules/WebNavigationFrames.jsm"
24 ChromeUtils.defineModuleGetter(
25   lazy,
26   "E10SUtils",
27   "resource://gre/modules/E10SUtils.jsm"
30 ChromeUtils.defineModuleGetter(
31   lazy,
32   "BrowserUtils",
33   "resource://gre/modules/BrowserUtils.jsm"
36 class MiddleMousePasteHandlerChild extends JSWindowActorChild {
37   handleEvent(clickEvent) {
38     if (
39       clickEvent.defaultPrevented ||
40       clickEvent.button != 1 ||
41       MiddleMousePasteHandlerChild.autoscrollEnabled
42     ) {
43       return;
44     }
45     this.manager
46       .getActor("ClickHandler")
47       .handleClickEvent(
48         clickEvent,
49         /* is from middle mouse paste handler */ true
50       );
51   }
53   onProcessedClick(data) {
54     this.sendAsyncMessage("MiddleClickPaste", data);
55   }
58 XPCOMUtils.defineLazyPreferenceGetter(
59   MiddleMousePasteHandlerChild,
60   "autoscrollEnabled",
61   "general.autoScroll",
62   true
65 class ClickHandlerChild extends JSWindowActorChild {
66   handleEvent(wrapperEvent) {
67     this.handleClickEvent(wrapperEvent.sourceEvent);
68   }
70   handleClickEvent(event, isFromMiddleMousePasteHandler = false) {
71     if (event.defaultPrevented || event.button == 2) {
72       return;
73     }
74     // Don't do anything on editable things, we shouldn't open links in
75     // contenteditables, and editor needs to possibly handle middlemouse paste
76     let composedTarget = event.composedTarget;
77     if (
78       composedTarget.isContentEditable ||
79       (composedTarget.ownerDocument &&
80         composedTarget.ownerDocument.designMode == "on") ||
81       ChromeUtils.getClassName(composedTarget) == "HTMLInputElement" ||
82       ChromeUtils.getClassName(composedTarget) == "HTMLTextAreaElement"
83     ) {
84       return;
85     }
87     let originalTarget = event.originalTarget;
88     let ownerDoc = originalTarget.ownerDocument;
89     if (!ownerDoc) {
90       return;
91     }
93     // Handle click events from about pages
94     if (event.button == 0) {
95       if (ownerDoc.documentURI.startsWith("about:blocked")) {
96         return;
97       }
98     }
100     // For untrusted events, require a valid transient user gesture activation.
101     if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
102       return;
103     }
105     let [
106       href,
107       node,
108       principal,
109     ] = lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event);
111     let csp = ownerDoc.csp;
112     if (csp) {
113       csp = lazy.E10SUtils.serializeCSP(csp);
114     }
116     let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
117       Ci.nsIReferrerInfo
118     );
119     if (node) {
120       referrerInfo.initWithElement(node);
121     } else {
122       referrerInfo.initWithDocument(ownerDoc);
123     }
124     referrerInfo = lazy.E10SUtils.serializeReferrerInfo(referrerInfo);
125     let frameID = lazy.WebNavigationFrames.getFrameId(ownerDoc.defaultView);
127     let json = {
128       button: event.button,
129       shiftKey: event.shiftKey,
130       ctrlKey: event.ctrlKey,
131       metaKey: event.metaKey,
132       altKey: event.altKey,
133       href: null,
134       title: null,
135       frameID,
136       triggeringPrincipal: principal,
137       csp,
138       referrerInfo,
139       originAttributes: principal ? principal.originAttributes : {},
140       isContentWindowPrivate: lazy.PrivateBrowsingUtils.isContentWindowPrivate(
141         ownerDoc.defaultView
142       ),
143     };
145     if (href && !isFromMiddleMousePasteHandler) {
146       try {
147         Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
148           principal,
149           href
150         );
151       } catch (e) {
152         return;
153       }
155       if (
156         !event.isTrusted &&
157         lazy.BrowserUtils.whereToOpenLink(event) != "current"
158       ) {
159         // If we'll open the link, we want to consume the user gesture
160         // activation to ensure that we don't allow multiple links to open
161         // from one user gesture.
162         // Avoid doing so for links opened in the current tab, which get
163         // handled later, by gecko, as otherwise its popup blocker will stop
164         // the link from opening.
165         // We will do the same check (whereToOpenLink) again in the parent and
166         // avoid handling the click for such links... but we still need the
167         // click information in the parent because otherwise places link
168         // tracking breaks. (bug 1742894 tracks improving this.)
169         ownerDoc.consumeTransientUserGestureActivation();
170         // We don't care about the return value because we already checked that
171         // hasValidTransientUserGestureActivation was true earlier in this
172         // function.
173       }
175       json.href = href;
176       if (node) {
177         json.title = node.getAttribute("title");
178       }
180       json.originPrincipal = ownerDoc.nodePrincipal;
181       json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal;
182       json.triggeringPrincipal = ownerDoc.nodePrincipal;
184       if (
185         (ownerDoc.URL === "about:newtab" || ownerDoc.URL === "about:home") &&
186         node.dataset.isSponsoredLink === "true"
187       ) {
188         json.globalHistoryOptions = { triggeringSponsoredURL: href };
189       }
191       // If a link element is clicked with middle button, user wants to open
192       // the link somewhere rather than pasting clipboard content.  Therefore,
193       // when it's clicked with middle button, we should prevent multiple
194       // actions here to avoid leaking clipboard content unexpectedly.
195       // Note that whether the link will work actually or not does not matter
196       // because in this case, user does not intent to paste clipboard content.
197       // We also need to do this to prevent multiple tabs opening if there are
198       // nested link elements.
199       event.preventMultipleActions();
201       this.sendAsyncMessage("Content:Click", json);
202     }
204     // This might be middle mouse navigation, in which case pass this back:
205     if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
206       this.manager.getActor("MiddleMousePasteHandler").onProcessedClick(json);
207     }
208   }