PageDataChild.sys.mjs (3035B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; 6 7 const lazy = {}; 8 9 ChromeUtils.defineESModuleGetters(lazy, { 10 PageDataSchema: 11 "moz-src:///browser/components/pagedata/PageDataSchema.sys.mjs", 12 PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", 13 }); 14 15 // We defer any attempt to check for page data for a short time after a page 16 // loads to allow JS to operate. 17 XPCOMUtils.defineLazyPreferenceGetter( 18 lazy, 19 "READY_DELAY", 20 "browser.pagedata.readyDelay", 21 500 22 ); 23 24 /** 25 * The actor responsible for monitoring a page for page data. 26 */ 27 export class PageDataChild extends JSWindowActorChild { 28 #isContentWindowPrivate = true; 29 /** 30 * Used to debounce notifications about a page being ready. 31 * 32 * @type {Timer | null} 33 */ 34 #deferTimer = null; 35 36 /** 37 * Called when the actor is created for a new page. 38 */ 39 actorCreated() { 40 this.#isContentWindowPrivate = 41 lazy.PrivateBrowsingUtils.isContentWindowPrivate(this.contentWindow); 42 } 43 44 /** 45 * Called when the page is destroyed. 46 */ 47 didDestroy() { 48 if (this.#deferTimer) { 49 this.#deferTimer.cancel(); 50 } 51 } 52 53 /** 54 * Called when the page has signalled it is done loading. This signal is 55 * debounced by READY_DELAY. 56 */ 57 #deferReady() { 58 if (!this.#deferTimer) { 59 this.#deferTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 60 } 61 62 // If the timer was already running this re-starts it. 63 this.#deferTimer.initWithCallback( 64 () => { 65 this.#deferTimer = null; 66 this.sendAsyncMessage("PageData:DocumentReady", { 67 url: this.document.documentURI, 68 }); 69 }, 70 lazy.READY_DELAY, 71 Ci.nsITimer.TYPE_ONE_SHOT_LOW_PRIORITY 72 ); 73 } 74 75 /** 76 * Called when a message is received from the parent process. 77 * 78 * @param {ReceiveMessageArgument} msg 79 * The received message. 80 * 81 * @returns {Promise | undefined} 82 * A promise for the requested data or undefined if no data was requested. 83 */ 84 receiveMessage(msg) { 85 if (this.#isContentWindowPrivate) { 86 return undefined; 87 } 88 89 switch (msg.name) { 90 case "PageData:CheckLoaded": 91 // The service just started in the parent. Check if this document is 92 // already loaded. 93 if (this.document.readystate == "complete") { 94 this.#deferReady(); 95 } 96 break; 97 case "PageData:Collect": 98 return lazy.PageDataSchema.collectPageData(this.document); 99 } 100 101 return undefined; 102 } 103 104 /** 105 * DOM event handler. 106 * 107 * @param {Event} event 108 * The DOM event. 109 */ 110 handleEvent(event) { 111 if (this.#isContentWindowPrivate) { 112 return; 113 } 114 115 switch (event.type) { 116 case "DOMContentLoaded": 117 case "pageshow": 118 this.#deferReady(); 119 break; 120 } 121 } 122 }