Bug 1925425: Only consider -allow-content-analysis command line flag in nightly and...
[gecko.git] / browser / actors / ContextMenuParent.sys.mjs
bloba14da27f6a9be4d0343c4cced7e8edd114dce327
1 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
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   E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
12   FirefoxRelay: "resource://gre/modules/FirefoxRelay.sys.mjs",
13   WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.sys.mjs",
14 });
16 XPCOMUtils.defineLazyServiceGetters(lazy, {
17   BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"],
18 });
20 export class ContextMenuParent extends JSWindowActorParent {
21   receiveMessage(message) {
22     let browser = this.manager.rootFrameLoader.ownerElement;
23     let win = browser.ownerGlobal;
24     // It's possible that the <xul:browser> associated with this
25     // ContextMenu message doesn't belong to a window that actually
26     // loads nsContextMenu.js. In that case, try to find the chromeEventHandler,
27     // since that'll likely be the "top" <xul:browser>, and then use its window's
28     // nsContextMenu instance instead.
29     if (!win.nsContextMenu) {
30       let topBrowser = browser.ownerGlobal.docShell.chromeEventHandler;
31       win = topBrowser.ownerGlobal;
32     }
34     message.data.context.showRelay &&= lazy.FirefoxRelay.isEnabled;
36     this.#openContextMenu(message.data, win, browser);
37   }
39   hiding() {
40     try {
41       this.sendAsyncMessage("ContextMenu:Hiding", {});
42     } catch (e) {
43       // This will throw if the content goes away while the
44       // context menu is still open.
45     }
46   }
48   reloadFrame(targetIdentifier, forceReload) {
49     this.sendAsyncMessage("ContextMenu:ReloadFrame", {
50       targetIdentifier,
51       forceReload,
52     });
53   }
55   getImageText(targetIdentifier) {
56     return this.sendQuery("ContextMenu:GetImageText", {
57       targetIdentifier,
58     });
59   }
61   toggleRevealPassword(targetIdentifier) {
62     this.sendAsyncMessage("ContextMenu:ToggleRevealPassword", {
63       targetIdentifier,
64     });
65   }
67   async useRelayMask(targetIdentifier, origin) {
68     if (!origin) {
69       return;
70     }
72     const windowGlobal = this.manager.browsingContext.currentWindowGlobal;
73     const browser = windowGlobal.rootFrameLoader.ownerElement;
74     const emailMask = await lazy.FirefoxRelay.generateUsername(browser, origin);
75     if (emailMask) {
76       this.sendAsyncMessage("ContextMenu:UseRelayMask", {
77         targetIdentifier,
78         emailMask,
79       });
80     }
81   }
83   reloadImage(targetIdentifier) {
84     this.sendAsyncMessage("ContextMenu:ReloadImage", { targetIdentifier });
85   }
87   getFrameTitle(targetIdentifier) {
88     return this.sendQuery("ContextMenu:GetFrameTitle", { targetIdentifier });
89   }
91   mediaCommand(targetIdentifier, command, data) {
92     let windowGlobal = this.manager.browsingContext.currentWindowGlobal;
93     let browser = windowGlobal.rootFrameLoader.ownerElement;
94     let win = browser.ownerGlobal;
95     let windowUtils = win.windowUtils;
96     this.sendAsyncMessage("ContextMenu:MediaCommand", {
97       targetIdentifier,
98       command,
99       data,
100       handlingUserInput: windowUtils.isHandlingUserInput,
101     });
102   }
104   canvasToBlobURL(targetIdentifier) {
105     return this.sendQuery("ContextMenu:Canvas:ToBlobURL", { targetIdentifier });
106   }
108   saveVideoFrameAsImage(targetIdentifier) {
109     return this.sendQuery("ContextMenu:SaveVideoFrameAsImage", {
110       targetIdentifier,
111     });
112   }
114   setAsDesktopBackground(targetIdentifier) {
115     return this.sendQuery("ContextMenu:SetAsDesktopBackground", {
116       targetIdentifier,
117     });
118   }
120   getSearchFieldBookmarkData(targetIdentifier) {
121     return this.sendQuery("ContextMenu:SearchFieldBookmarkData", {
122       targetIdentifier,
123     });
124   }
126   /**
127    * Handles opening of the context menu for the appropraite browser.
128    *
129    * @param {object} data
130    *   The data for the context menu, received from the child.
131    * @param {DOMWindow} win
132    *   The window in which the context menu is to be opened.
133    * @param {Browser} browser
134    *   The browser the context menu is being opened for.
135    */
136   #openContextMenu(data, win, browser) {
137     if (lazy.BrowserHandler.kiosk) {
138       // Don't display context menus in kiosk mode
139       return;
140     }
141     let wgp = this.manager;
143     if (!wgp.isCurrentGlobal) {
144       // Don't display context menus for unloaded documents
145       return;
146     }
148     // NOTE: We don't use `wgp.documentURI` here as we want to use the failed
149     // channel URI in the case we have loaded an error page.
150     let documentURIObject = wgp.browsingContext.currentURI;
152     let frameReferrerInfo = data.frameReferrerInfo;
153     if (frameReferrerInfo) {
154       frameReferrerInfo =
155         lazy.E10SUtils.deserializeReferrerInfo(frameReferrerInfo);
156     }
158     let linkReferrerInfo = data.linkReferrerInfo;
159     if (linkReferrerInfo) {
160       linkReferrerInfo =
161         lazy.E10SUtils.deserializeReferrerInfo(linkReferrerInfo);
162     }
164     let frameID = lazy.WebNavigationFrames.getFrameId(wgp.browsingContext);
166     win.nsContextMenu.contentData = {
167       context: data.context,
168       browser,
169       actor: this,
170       editFlags: data.editFlags,
171       spellInfo: data.spellInfo,
172       principal: wgp.documentPrincipal,
173       storagePrincipal: wgp.documentStoragePrincipal,
174       documentURIObject,
175       docLocation: documentURIObject.spec,
176       charSet: data.charSet,
177       referrerInfo: lazy.E10SUtils.deserializeReferrerInfo(data.referrerInfo),
178       frameReferrerInfo,
179       linkReferrerInfo,
180       contentType: data.contentType,
181       contentDisposition: data.contentDisposition,
182       frameID,
183       frameOuterWindowID: frameID,
184       frameBrowsingContext: wgp.browsingContext,
185       selectionInfo: data.selectionInfo,
186       disableSetDesktopBackground: data.disableSetDesktopBackground,
187       showRelay: data.showRelay,
188       loginFillInfo: data.loginFillInfo,
189       userContextId: wgp.browsingContext.originAttributes.userContextId,
190       webExtContextData: data.webExtContextData,
191       cookieJarSettings: wgp.cookieJarSettings,
192     };
194     let popup = win.document.getElementById("contentAreaContextMenu");
195     let context = win.nsContextMenu.contentData.context;
197     // Fill in some values in the context from the WindowGlobalParent actor.
198     context.principal = wgp.documentPrincipal;
199     context.storagePrincipal = wgp.documentStoragePrincipal;
200     context.frameID = frameID;
201     context.frameOuterWindowID = wgp.outerWindowId;
202     context.frameBrowsingContextID = wgp.browsingContext.id;
204     // We don't have access to the original event here, as that happened in
205     // another process. Therefore we synthesize a new MouseEvent to propagate the
206     // inputSource to the subsequently triggered popupshowing event.
207     let newEvent = new PointerEvent("contextmenu", {
208       bubbles: true,
209       cancelable: true,
210       screenX: context.screenXDevPx / win.devicePixelRatio,
211       screenY: context.screenYDevPx / win.devicePixelRatio,
212       button: 2,
213       pointerType: (() => {
214         switch (context.inputSource) {
215           case MouseEvent.MOZ_SOURCE_MOUSE:
216             return "mouse";
217           case MouseEvent.MOZ_SOURCE_PEN:
218             return "pen";
219           case MouseEvent.MOZ_SOURCE_ERASER:
220             return "eraser";
221           case MouseEvent.MOZ_SOURCE_CURSOR:
222             return "cursor";
223           case MouseEvent.MOZ_SOURCE_TOUCH:
224             return "touch";
225           case MouseEvent.MOZ_SOURCE_KEYBOARD:
226             return "keyboard";
227           default:
228             return "";
229         }
230       })(),
231     });
232     popup.openPopupAtScreen(newEvent.screenX, newEvent.screenY, true, newEvent);
233   }