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";
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",
16 XPCOMUtils.defineLazyServiceGetters(lazy, {
17 BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"],
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;
34 message.data.context.showRelay &&= lazy.FirefoxRelay.isEnabled;
36 this.#openContextMenu(message.data, win, browser);
41 this.sendAsyncMessage("ContextMenu:Hiding", {});
43 // This will throw if the content goes away while the
44 // context menu is still open.
48 reloadFrame(targetIdentifier, forceReload) {
49 this.sendAsyncMessage("ContextMenu:ReloadFrame", {
55 getImageText(targetIdentifier) {
56 return this.sendQuery("ContextMenu:GetImageText", {
61 toggleRevealPassword(targetIdentifier) {
62 this.sendAsyncMessage("ContextMenu:ToggleRevealPassword", {
67 async useRelayMask(targetIdentifier, origin) {
72 const windowGlobal = this.manager.browsingContext.currentWindowGlobal;
73 const browser = windowGlobal.rootFrameLoader.ownerElement;
74 const emailMask = await lazy.FirefoxRelay.generateUsername(browser, origin);
76 this.sendAsyncMessage("ContextMenu:UseRelayMask", {
83 reloadImage(targetIdentifier) {
84 this.sendAsyncMessage("ContextMenu:ReloadImage", { targetIdentifier });
87 getFrameTitle(targetIdentifier) {
88 return this.sendQuery("ContextMenu:GetFrameTitle", { targetIdentifier });
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", {
100 handlingUserInput: windowUtils.isHandlingUserInput,
104 canvasToBlobURL(targetIdentifier) {
105 return this.sendQuery("ContextMenu:Canvas:ToBlobURL", { targetIdentifier });
108 saveVideoFrameAsImage(targetIdentifier) {
109 return this.sendQuery("ContextMenu:SaveVideoFrameAsImage", {
114 setAsDesktopBackground(targetIdentifier) {
115 return this.sendQuery("ContextMenu:SetAsDesktopBackground", {
120 getSearchFieldBookmarkData(targetIdentifier) {
121 return this.sendQuery("ContextMenu:SearchFieldBookmarkData", {
127 * Handles opening of the context menu for the appropraite browser.
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.
136 #openContextMenu(data, win, browser) {
137 if (lazy.BrowserHandler.kiosk) {
138 // Don't display context menus in kiosk mode
141 let wgp = this.manager;
143 if (!wgp.isCurrentGlobal) {
144 // Don't display context menus for unloaded documents
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) {
155 lazy.E10SUtils.deserializeReferrerInfo(frameReferrerInfo);
158 let linkReferrerInfo = data.linkReferrerInfo;
159 if (linkReferrerInfo) {
161 lazy.E10SUtils.deserializeReferrerInfo(linkReferrerInfo);
164 let frameID = lazy.WebNavigationFrames.getFrameId(wgp.browsingContext);
166 win.nsContextMenu.contentData = {
167 context: data.context,
170 editFlags: data.editFlags,
171 spellInfo: data.spellInfo,
172 principal: wgp.documentPrincipal,
173 storagePrincipal: wgp.documentStoragePrincipal,
175 docLocation: documentURIObject.spec,
176 charSet: data.charSet,
177 referrerInfo: lazy.E10SUtils.deserializeReferrerInfo(data.referrerInfo),
180 contentType: data.contentType,
181 contentDisposition: data.contentDisposition,
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,
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", {
210 screenX: context.screenXDevPx / win.devicePixelRatio,
211 screenY: context.screenYDevPx / win.devicePixelRatio,
213 pointerType: (() => {
214 switch (context.inputSource) {
215 case MouseEvent.MOZ_SOURCE_MOUSE:
217 case MouseEvent.MOZ_SOURCE_PEN:
219 case MouseEvent.MOZ_SOURCE_ERASER:
221 case MouseEvent.MOZ_SOURCE_CURSOR:
223 case MouseEvent.MOZ_SOURCE_TOUCH:
225 case MouseEvent.MOZ_SOURCE_KEYBOARD:
232 popup.openPopupAtScreen(newEvent.screenX, newEvent.screenY, true, newEvent);