forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			174 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
	
		
			5.5 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/. */
 | |
| 
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
 | |
|   E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
 | |
| });
 | |
| 
 | |
| export class MiddleMousePasteHandlerChild extends JSWindowActorChild {
 | |
|   handleEvent(clickEvent) {
 | |
|     if (
 | |
|       clickEvent.defaultPrevented ||
 | |
|       clickEvent.button != 1 ||
 | |
|       MiddleMousePasteHandlerChild.autoscrollEnabled
 | |
|     ) {
 | |
|       return;
 | |
|     }
 | |
|     this.manager
 | |
|       .getActor("ClickHandler")
 | |
|       .handleClickEvent(
 | |
|         clickEvent,
 | |
|         /* is from middle mouse paste handler */ true
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   onProcessedClick(data) {
 | |
|     this.sendAsyncMessage("MiddleClickPaste", data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(
 | |
|   MiddleMousePasteHandlerChild,
 | |
|   "autoscrollEnabled",
 | |
|   "general.autoScroll",
 | |
|   true
 | |
| );
 | |
| 
 | |
| export class ClickHandlerChild extends JSWindowActorChild {
 | |
|   handleEvent(wrapperEvent) {
 | |
|     this.handleClickEvent(wrapperEvent.sourceEvent);
 | |
|   }
 | |
| 
 | |
|   handleClickEvent(event, isFromMiddleMousePasteHandler = false) {
 | |
|     if (event.defaultPrevented || event.button == 2) {
 | |
|       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;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // For untrusted events, require a valid transient user gesture activation.
 | |
|     if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let [href, node, principal] =
 | |
|       lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event);
 | |
| 
 | |
|     let csp = ownerDoc.csp;
 | |
|     if (csp) {
 | |
|       csp = lazy.E10SUtils.serializeCSP(csp);
 | |
|     }
 | |
| 
 | |
|     let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
 | |
|       Ci.nsIReferrerInfo
 | |
|     );
 | |
|     if (node) {
 | |
|       referrerInfo.initWithElement(node);
 | |
|     } else {
 | |
|       referrerInfo.initWithDocument(ownerDoc);
 | |
|     }
 | |
|     referrerInfo = lazy.E10SUtils.serializeReferrerInfo(referrerInfo);
 | |
| 
 | |
|     let json = {
 | |
|       button: event.button,
 | |
|       shiftKey: event.shiftKey,
 | |
|       ctrlKey: event.ctrlKey,
 | |
|       metaKey: event.metaKey,
 | |
|       altKey: event.altKey,
 | |
|       href: null,
 | |
|       title: null,
 | |
|       csp,
 | |
|       referrerInfo,
 | |
|     };
 | |
| 
 | |
|     if (href && !isFromMiddleMousePasteHandler) {
 | |
|       try {
 | |
|         Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
 | |
|           principal,
 | |
|           href
 | |
|         );
 | |
|       } catch (e) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       if (
 | |
|         !event.isTrusted &&
 | |
|         lazy.BrowserUtils.whereToOpenLink(event) != "current"
 | |
|       ) {
 | |
|         // If we'll open the link, we want to consume the user gesture
 | |
|         // activation to ensure that we don't allow multiple links to open
 | |
|         // from one user gesture.
 | |
|         // Avoid doing so for links opened in the current tab, which get
 | |
|         // handled later, by gecko, as otherwise its popup blocker will stop
 | |
|         // the link from opening.
 | |
|         // We will do the same check (whereToOpenLink) again in the parent and
 | |
|         // avoid handling the click for such links... but we still need the
 | |
|         // click information in the parent because otherwise places link
 | |
|         // tracking breaks. (bug 1742894 tracks improving this.)
 | |
|         ownerDoc.consumeTransientUserGestureActivation();
 | |
|         // We don't care about the return value because we already checked that
 | |
|         // hasValidTransientUserGestureActivation was true earlier in this
 | |
|         // function.
 | |
|       }
 | |
| 
 | |
|       json.href = href;
 | |
|       if (node) {
 | |
|         json.title = node.getAttribute("title");
 | |
|       }
 | |
| 
 | |
|       if (
 | |
|         (ownerDoc.URL === "about:newtab" || ownerDoc.URL === "about:home") &&
 | |
|         node.dataset.isSponsoredLink === "true"
 | |
|       ) {
 | |
|         json.globalHistoryOptions = { triggeringSponsoredURL: href };
 | |
|       }
 | |
| 
 | |
|       // 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.
 | |
|       // We also need to do this to prevent multiple tabs opening if there are
 | |
|       // nested link elements.
 | |
|       event.preventMultipleActions();
 | |
| 
 | |
|       this.sendAsyncMessage("Content:Click", json);
 | |
|     }
 | |
| 
 | |
|     // This might be middle mouse navigation, in which case pass this back:
 | |
|     if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
 | |
|       this.manager.getActor("MiddleMousePasteHandler").onProcessedClick(json);
 | |
|     }
 | |
|   }
 | |
| }
 | 
