summaryrefslogtreecommitdiffstats
path: root/mobile/android/chrome/geckoview/geckoview.js
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/chrome/geckoview/geckoview.js')
-rw-r--r--mobile/android/chrome/geckoview/geckoview.js934
1 files changed, 934 insertions, 0 deletions
diff --git a/mobile/android/chrome/geckoview/geckoview.js b/mobile/android/chrome/geckoview/geckoview.js
new file mode 100644
index 0000000000..69ca5e413f
--- /dev/null
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -0,0 +1,934 @@
+/* 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/. */
+
+"use strict";
+
+var { DelayedInit } = ChromeUtils.import(
+ "resource://gre/modules/DelayedInit.jsm"
+);
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ Blocklist: "resource://gre/modules/Blocklist.sys.mjs",
+ E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
+ EventDispatcher: "resource://gre/modules/Messaging.sys.mjs",
+ GeckoViewActorManager: "resource://gre/modules/GeckoViewActorManager.sys.mjs",
+ GeckoViewSettings: "resource://gre/modules/GeckoViewSettings.sys.mjs",
+ GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.sys.mjs",
+ RemoteSecuritySettings:
+ "resource://gre/modules/psm/RemoteSecuritySettings.sys.mjs",
+ SafeBrowsing: "resource://gre/modules/SafeBrowsing.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ HistogramStopwatch: "resource://gre/modules/GeckoViewTelemetry.jsm",
+ InitializationTracker: "resource://gre/modules/GeckoViewTelemetry.jsm",
+});
+
+XPCOMUtils.defineLazyGetter(this, "WindowEventDispatcher", () =>
+ EventDispatcher.for(window)
+);
+
+XPCOMUtils.defineLazyScriptGetter(
+ this,
+ "PrintUtils",
+ "chrome://global/content/printUtils.js"
+);
+
+// This file assumes `warn` and `debug` are imported into scope
+// by the child scripts.
+/* global debug, warn */
+
+/**
+ * ModuleManager creates and manages GeckoView modules. Each GeckoView module
+ * normally consists of a JSM module file with an optional content module file.
+ * The module file contains a class that extends GeckoViewModule, and the
+ * content module file contains a class that extends GeckoViewChildModule. A
+ * module usually pairs with a particular GeckoSessionHandler or delegate on the
+ * Java side, and automatically receives module lifetime events such as
+ * initialization, change in enabled state, and change in settings.
+ */
+var ModuleManager = {
+ get _initData() {
+ return window.arguments[0].QueryInterface(Ci.nsIAndroidView).initData;
+ },
+
+ init(aBrowser, aModules) {
+ const MODULES_INIT_PROBE = new HistogramStopwatch(
+ "GV_STARTUP_MODULES_MS",
+ aBrowser
+ );
+
+ MODULES_INIT_PROBE.start();
+
+ const initData = this._initData;
+ this._browser = aBrowser;
+ this._settings = initData.settings;
+ this._frozenSettings = Object.freeze(Object.assign({}, this._settings));
+
+ const self = this;
+ this._modules = new Map(
+ (function* () {
+ for (const module of aModules) {
+ yield [
+ module.name,
+ new ModuleInfo({
+ enabled: !!initData.modules[module.name],
+ manager: self,
+ ...module,
+ }),
+ ];
+ }
+ })()
+ );
+
+ window.document.documentElement.appendChild(aBrowser);
+
+ // By default all layers are discarded when a browser is set to inactive.
+ // GeckoView by default sets browsers to inactive every time they're not
+ // visible. To avoid flickering when changing tabs, we preserve layers for
+ // all loaded tabs.
+ aBrowser.preserveLayers(true);
+
+ WindowEventDispatcher.registerListener(this, [
+ "GeckoView:UpdateModuleState",
+ "GeckoView:UpdateInitData",
+ "GeckoView:UpdateSettings",
+ ]);
+
+ this.messageManager.addMessageListener(
+ "GeckoView:ContentModuleLoaded",
+ this
+ );
+
+ this._moduleByActorName = new Map();
+ this.forEach(module => {
+ module.onInit();
+ module.loadInitFrameScript();
+ for (const actorName of module.actorNames) {
+ this._moduleByActorName[actorName] = module;
+ }
+ });
+
+ window.addEventListener("unload", () => {
+ this.forEach(module => {
+ module.enabled = false;
+ module.onDestroy();
+ });
+
+ this._modules.clear();
+ });
+
+ MODULES_INIT_PROBE.finish();
+ },
+
+ onPrintWindow(aParams) {
+ if (!aParams.openWindowInfo.isForWindowDotPrint) {
+ return PrintUtils.handleStaticCloneCreatedForPrint(
+ aParams.openWindowInfo
+ );
+ }
+ const printActor = this.window.moduleManager.getActor(
+ "GeckoViewPrintDelegate"
+ );
+ // Prevents continually making new static browsers
+ if (printActor.browserStaticClone != null) {
+ throw new Error("A prior window.print is still in progress.");
+ }
+ const staticBrowser = PrintUtils.createParentBrowserForStaticClone(
+ aParams.openWindowInfo.parent,
+ aParams.openWindowInfo
+ );
+ printActor.browserStaticClone = staticBrowser;
+ printActor.printRequest();
+ return staticBrowser;
+ },
+
+ get window() {
+ return window;
+ },
+
+ get browser() {
+ return this._browser;
+ },
+
+ get messageManager() {
+ return this._browser.messageManager;
+ },
+
+ get eventDispatcher() {
+ return WindowEventDispatcher;
+ },
+
+ get settings() {
+ return this._frozenSettings;
+ },
+
+ forEach(aCallback) {
+ this._modules.forEach(aCallback, this);
+ },
+
+ getActor(aActorName) {
+ return this.browser.browsingContext.currentWindowGlobal?.getActor(
+ aActorName
+ );
+ },
+
+ // Ensures that session history has been flushed before changing remoteness
+ async prepareToChangeRemoteness() {
+ // Session state like history is maintained at the process level so we need
+ // to collect it and restore it in the other process when switching.
+ // TODO: This should go away when we migrate the history to the main
+ // process Bug 1507287.
+ const { history } = await this.getActor("GeckoViewContent").collectState();
+
+ // Ignore scroll and form data since we're navigating away from this page
+ // anyway
+ this.sessionState = { history };
+ },
+
+ willChangeBrowserRemoteness() {
+ debug`WillChangeBrowserRemoteness`;
+
+ // Now we're switching the remoteness.
+ this.disabledModules = [];
+ this.forEach(module => {
+ if (module.enabled && module.disableOnProcessSwitch) {
+ module.enabled = false;
+ this.disabledModules.push(module);
+ }
+ });
+
+ this.forEach(module => {
+ module.onDestroyBrowser();
+ });
+ },
+
+ didChangeBrowserRemoteness() {
+ debug`DidChangeBrowserRemoteness`;
+
+ this.forEach(module => {
+ if (module.impl) {
+ module.impl.onInitBrowser();
+ }
+ });
+
+ this.messageManager.addMessageListener(
+ "GeckoView:ContentModuleLoaded",
+ this
+ );
+
+ this.forEach(module => {
+ // We're attaching a new browser so we have to reload the frame scripts
+ module.loadInitFrameScript();
+ });
+
+ this.disabledModules.forEach(module => {
+ module.enabled = true;
+ });
+ this.disabledModules = null;
+ },
+
+ afterBrowserRemotenessChange(aSwitchId) {
+ const { sessionState } = this;
+ this.sessionState = null;
+
+ sessionState.switchId = aSwitchId;
+
+ this.getActor("GeckoViewContent").restoreState(sessionState);
+ this.browser.focus();
+
+ // Load was handled
+ return true;
+ },
+
+ _updateSettings(aSettings) {
+ Object.assign(this._settings, aSettings);
+ this._frozenSettings = Object.freeze(Object.assign({}, this._settings));
+
+ const windowType = aSettings.isPopup
+ ? "navigator:popup"
+ : "navigator:geckoview";
+ window.document.documentElement.setAttribute("windowtype", windowType);
+
+ this.forEach(module => {
+ if (module.impl) {
+ module.impl.onSettingsUpdate();
+ }
+ });
+ },
+
+ onMessageFromActor(aActorName, aMessage) {
+ this._moduleByActorName[aActorName].receiveMessage(aMessage);
+ },
+
+ onEvent(aEvent, aData, aCallback) {
+ debug`onEvent ${aEvent} ${aData}`;
+ switch (aEvent) {
+ case "GeckoView:UpdateModuleState": {
+ const module = this._modules.get(aData.module);
+ if (module) {
+ module.enabled = aData.enabled;
+ }
+ break;
+ }
+
+ case "GeckoView:UpdateInitData": {
+ // Replace all settings during a transfer.
+ const initData = this._initData;
+ this._updateSettings(initData.settings);
+
+ // Update module enabled states.
+ for (const name in initData.modules) {
+ const module = this._modules.get(name);
+ if (module) {
+ module.enabled = initData.modules[name];
+ }
+ }
+
+ // Notify child of the transfer.
+ this._browser.messageManager.sendAsyncMessage(aEvent);
+ break;
+ }
+
+ case "GeckoView:UpdateSettings": {
+ this._updateSettings(aData);
+ break;
+ }
+ }
+ },
+
+ receiveMessage(aMsg) {
+ debug`receiveMessage ${aMsg.name} ${aMsg.data}`;
+ switch (aMsg.name) {
+ case "GeckoView:ContentModuleLoaded": {
+ const module = this._modules.get(aMsg.data.module);
+ if (module) {
+ module.onContentModuleLoaded();
+ }
+ break;
+ }
+ }
+ },
+};
+
+/**
+ * ModuleInfo is the structure used by ModuleManager to represent individual
+ * modules. It is responsible for loading the module JSM file if necessary,
+ * and it acts as the intermediary between ModuleManager and the module
+ * object that extends GeckoViewModule.
+ */
+class ModuleInfo {
+ /**
+ * Create a ModuleInfo instance. See _loadPhase for phase object description.
+ *
+ * @param manager the ModuleManager instance.
+ * @param name Name of the module.
+ * @param enabled Enabled state of the module at startup.
+ * @param onInit Phase object for the init phase, when the window is created.
+ * @param onEnable Phase object for the enable phase, when the module is first
+ * enabled by setting a delegate in Java.
+ */
+ constructor({ manager, name, enabled, onInit, onEnable }) {
+ this._manager = manager;
+ this._name = name;
+
+ // We don't support having more than one main process script, so let's
+ // check that we're not accidentally defining two. We could support this if
+ // needed by making _impl an array for each phase impl.
+ if (onInit?.resource !== undefined && onEnable?.resource !== undefined) {
+ throw new Error(
+ "Only one main process script is allowed for each module."
+ );
+ }
+
+ this._impl = null;
+ this._contentModuleLoaded = false;
+ this._enabled = false;
+ // Only enable once we performed initialization.
+ this._enabledOnInit = enabled;
+
+ // For init, load resource _before_ initializing browser to support the
+ // onInitBrowser() override. However, load content module after initializing
+ // browser, because we don't have a message manager before then.
+ this._loadResource(onInit);
+ this._loadActors(onInit);
+ if (this._enabledOnInit) {
+ this._loadActors(onEnable);
+ }
+
+ this._onInitPhase = onInit;
+ this._onEnablePhase = onEnable;
+
+ const actorNames = [];
+ if (this._onInitPhase?.actors) {
+ actorNames.push(Object.keys(this._onInitPhase.actors));
+ }
+ if (this._onEnablePhase?.actors) {
+ actorNames.push(Object.keys(this._onEnablePhase.actors));
+ }
+ this._actorNames = Object.freeze(actorNames);
+ }
+
+ get actorNames() {
+ return this._actorNames;
+ }
+
+ onInit() {
+ if (this._impl) {
+ this._impl.onInit();
+ this._impl.onSettingsUpdate();
+ }
+
+ this.enabled = this._enabledOnInit;
+ }
+
+ /**
+ * Loads the onInit frame script
+ */
+ loadInitFrameScript() {
+ this._loadFrameScript(this._onInitPhase);
+ }
+
+ onDestroy() {
+ if (this._impl) {
+ this._impl.onDestroy();
+ }
+ }
+
+ /**
+ * Called before the browser is removed
+ */
+ onDestroyBrowser() {
+ if (this._impl) {
+ this._impl.onDestroyBrowser();
+ }
+ this._contentModuleLoaded = false;
+ }
+
+ _loadActors(aPhase) {
+ if (!aPhase || !aPhase.actors) {
+ return;
+ }
+
+ GeckoViewActorManager.addJSWindowActors(aPhase.actors);
+ }
+
+ /**
+ * Load resource according to a phase object that contains possible keys,
+ *
+ * "resource": specify the JSM resource to load for this module.
+ * "frameScript": specify a content JS frame script to load for this module.
+ */
+ _loadResource(aPhase) {
+ if (!aPhase || !aPhase.resource || this._impl) {
+ return;
+ }
+
+ const exports = ChromeUtils.importESModule(aPhase.resource);
+ this._impl = new exports[this._name](this);
+ }
+
+ /**
+ * Load frameScript according to a phase object that contains possible keys,
+ *
+ * "frameScript": specify a content JS frame script to load for this module.
+ */
+ _loadFrameScript(aPhase) {
+ if (!aPhase || !aPhase.frameScript || this._contentModuleLoaded) {
+ return;
+ }
+
+ if (this._impl) {
+ this._impl.onLoadContentModule();
+ }
+ this._manager.messageManager.loadFrameScript(aPhase.frameScript, true);
+ this._contentModuleLoaded = true;
+ }
+
+ get manager() {
+ return this._manager;
+ }
+
+ get disableOnProcessSwitch() {
+ // Only disable while process switching if it has a frameScript
+ return (
+ !!this._onInitPhase?.frameScript || !!this._onEnablePhase?.frameScript
+ );
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ get impl() {
+ return this._impl;
+ }
+
+ get enabled() {
+ return this._enabled;
+ }
+
+ set enabled(aEnabled) {
+ if (aEnabled === this._enabled) {
+ return;
+ }
+
+ if (!aEnabled && this._impl) {
+ this._impl.onDisable();
+ }
+
+ this._enabled = aEnabled;
+
+ if (aEnabled) {
+ this._loadResource(this._onEnablePhase);
+ this._loadFrameScript(this._onEnablePhase);
+ this._loadActors(this._onEnablePhase);
+ if (this._impl) {
+ this._impl.onEnable();
+ this._impl.onSettingsUpdate();
+ }
+ }
+
+ this._updateContentModuleState();
+ }
+
+ receiveMessage(aMessage) {
+ if (!this._impl) {
+ throw new Error(`No impl for message: ${aMessage.name}.`);
+ }
+
+ try {
+ this._impl.receiveMessage(aMessage);
+ } catch (error) {
+ warn`this._impl.receiveMessage failed ${aMessage.name}`;
+ throw error;
+ }
+ }
+
+ onContentModuleLoaded() {
+ this._updateContentModuleState();
+
+ if (this._impl) {
+ this._impl.onContentModuleLoaded();
+ }
+ }
+
+ _updateContentModuleState() {
+ this._manager.messageManager.sendAsyncMessage(
+ "GeckoView:UpdateModuleState",
+ {
+ module: this._name,
+ enabled: this.enabled,
+ }
+ );
+ }
+}
+
+function createBrowser() {
+ const browser = (window.browser = document.createXULElement("browser"));
+ // Identify this `<browser>` element uniquely to Marionette, devtools, etc.
+ // Use the JSM global to create the permanentKey, so that if the
+ // permanentKey is held by something after this window closes, it
+ // doesn't keep the window alive. See also Bug 1501789.
+ browser.permanentKey = new (Cu.getGlobalForObject(Services).Object)();
+
+ browser.setAttribute("nodefaultsrc", "true");
+ browser.setAttribute("type", "content");
+ browser.setAttribute("primary", "true");
+ browser.setAttribute("flex", "1");
+ browser.setAttribute("maychangeremoteness", "true");
+ browser.setAttribute("remote", "true");
+ browser.setAttribute("remoteType", E10SUtils.DEFAULT_REMOTE_TYPE);
+ browser.setAttribute("messagemanagergroup", "browsers");
+
+ // This is only needed for mochitests, so that they honor the
+ // prefers-color-scheme.content-override pref. GeckoView doesn't set this
+ // pref to anything other than the default value otherwise.
+ browser.setAttribute(
+ "style",
+ "color-scheme: env(-moz-content-preferred-color-scheme)"
+ );
+
+ return browser;
+}
+
+function InitLater(fn, object, name) {
+ return DelayedInit.schedule(fn, object, name, 15000 /* 15s max wait */);
+}
+
+function startup() {
+ GeckoViewUtils.initLogging("XUL", window);
+
+ const browser = createBrowser();
+ ModuleManager.init(browser, [
+ {
+ name: "GeckoViewContent",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewContent.sys.mjs",
+ actors: {
+ GeckoViewContent: {
+ parent: {
+ esModuleURI: "resource:///actors/GeckoViewContentParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/GeckoViewContentChild.sys.mjs",
+ events: {
+ mozcaretstatechanged: { capture: true, mozSystemGroup: true },
+ pageshow: { mozSystemGroup: true },
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ onEnable: {
+ actors: {
+ ContentDelegate: {
+ parent: {
+ esModuleURI: "resource:///actors/ContentDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/ContentDelegateChild.sys.mjs",
+ events: {
+ DOMContentLoaded: {},
+ DOMMetaViewportFitChanged: {},
+ "MozDOMFullscreen:Entered": {},
+ "MozDOMFullscreen:Exit": {},
+ "MozDOMFullscreen:Exited": {},
+ "MozDOMFullscreen:Request": {},
+ MozFirstContentfulPaint: {},
+ MozPaintStatusReset: {},
+ contextmenu: { capture: true },
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewNavigation",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewNavigation.sys.mjs",
+ },
+ },
+ {
+ name: "GeckoViewProcessHangMonitor",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewProcessHangMonitor.sys.mjs",
+ },
+ },
+ {
+ name: "GeckoViewProgress",
+ onEnable: {
+ resource: "resource://gre/modules/GeckoViewProgress.sys.mjs",
+ actors: {
+ ProgressDelegate: {
+ parent: {
+ esModuleURI: "resource:///actors/ProgressDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/ProgressDelegateChild.sys.mjs",
+ events: {
+ MozAfterPaint: { capture: false, mozSystemGroup: true },
+ DOMContentLoaded: { capture: false, mozSystemGroup: true },
+ pageshow: { capture: false, mozSystemGroup: true },
+ },
+ },
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewScroll",
+ onEnable: {
+ actors: {
+ ScrollDelegate: {
+ parent: {
+ esModuleURI: "resource:///actors/ScrollDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/ScrollDelegateChild.sys.mjs",
+ events: {
+ mozvisualscroll: { mozSystemGroup: true },
+ },
+ },
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewSelectionAction",
+ onEnable: {
+ resource: "resource://gre/modules/GeckoViewSelectionAction.sys.mjs",
+ actors: {
+ SelectionActionDelegate: {
+ parent: {
+ esModuleURI:
+ "resource:///actors/SelectionActionDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI:
+ "resource:///actors/SelectionActionDelegateChild.sys.mjs",
+ events: {
+ mozcaretstatechanged: { mozSystemGroup: true },
+ pagehide: { capture: true, mozSystemGroup: true },
+ deactivate: { mozSystemGroup: true },
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewSettings",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewSettings.sys.mjs",
+ actors: {
+ GeckoViewSettings: {
+ child: {
+ esModuleURI: "resource:///actors/GeckoViewSettingsChild.sys.mjs",
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewTab",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewTab.sys.mjs",
+ },
+ },
+ {
+ name: "GeckoViewContentBlocking",
+ onInit: {
+ resource: "resource://gre/modules/GeckoViewContentBlocking.sys.mjs",
+ },
+ },
+ {
+ name: "SessionStateAggregator",
+ onInit: {
+ frameScript: "chrome://geckoview/content/SessionStateAggregator.js",
+ },
+ },
+ {
+ name: "GeckoViewAutofill",
+ onInit: {
+ actors: {
+ GeckoViewAutoFill: {
+ parent: {
+ esModuleURI: "resource:///actors/GeckoViewAutoFillParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/GeckoViewAutoFillChild.sys.mjs",
+ events: {
+ DOMFormHasPassword: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ DOMInputPasswordAdded: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ pagehide: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ pageshow: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ focusin: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ focusout: {
+ mozSystemGroup: true,
+ capture: false,
+ },
+ "PasswordManager:ShowDoorhanger": {},
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewMediaControl",
+ onEnable: {
+ resource: "resource://gre/modules/GeckoViewMediaControl.sys.mjs",
+ actors: {
+ MediaControlDelegate: {
+ parent: {
+ esModuleURI:
+ "resource:///actors/MediaControlDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI:
+ "resource:///actors/MediaControlDelegateChild.sys.mjs",
+ events: {
+ "MozDOMFullscreen:Entered": {},
+ "MozDOMFullscreen:Exited": {},
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewAutocomplete",
+ onInit: {
+ actors: {
+ FormAutofill: {
+ parent: {
+ esModuleURI: "resource://autofill/FormAutofillParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource://autofill/FormAutofillChild.sys.mjs",
+ events: {
+ focusin: {},
+ DOMFormBeforeSubmit: {},
+ },
+ },
+ allFrames: true,
+ messageManagerGroups: ["browsers"],
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewPrompter",
+ onInit: {
+ actors: {
+ GeckoViewPrompter: {
+ parent: {
+ esModuleURI: "resource:///actors/GeckoViewPrompterParent.sys.mjs",
+ },
+ child: {
+ esModuleURI: "resource:///actors/GeckoViewPrompterChild.sys.mjs",
+ },
+ allFrames: true,
+ includeChrome: true,
+ },
+ },
+ },
+ },
+ {
+ name: "GeckoViewPrintDelegate",
+ onInit: {
+ actors: {
+ GeckoViewPrintDelegate: {
+ parent: {
+ esModuleURI:
+ "resource:///actors/GeckoViewPrintDelegateParent.sys.mjs",
+ },
+ child: {
+ esModuleURI:
+ "resource:///actors/GeckoViewPrintDelegateChild.sys.mjs",
+ },
+ allFrames: true,
+ },
+ },
+ },
+ },
+ ]);
+
+ if (!Services.appinfo.sessionHistoryInParent) {
+ browser.prepareToChangeRemoteness = () =>
+ ModuleManager.prepareToChangeRemoteness();
+ browser.afterChangeRemoteness = switchId =>
+ ModuleManager.afterBrowserRemotenessChange(switchId);
+ }
+
+ browser.addEventListener("WillChangeBrowserRemoteness", event =>
+ ModuleManager.willChangeBrowserRemoteness()
+ );
+
+ browser.addEventListener("DidChangeBrowserRemoteness", event =>
+ ModuleManager.didChangeBrowserRemoteness()
+ );
+
+ // Allows actors to access ModuleManager.
+ window.moduleManager = ModuleManager;
+
+ window.prompts = () => {
+ return window.ModuleManager.getActor("GeckoViewPrompter").getPrompts();
+ };
+
+ Services.tm.dispatchToMainThread(() => {
+ // This should always be the first thing we do here - any additional delayed
+ // initialisation tasks should be added between "browser-delayed-startup-finished"
+ // and "browser-idle-startup-tasks-finished".
+
+ // Bug 1496684: Various bits of platform stuff depend on this notification
+ // to learn when a browser window has finished its initial (chrome)
+ // initialisation, especially with regards to the very first window that is
+ // created. Therefore, GeckoView "windows" need to send this, too.
+ InitLater(() =>
+ Services.obs.notifyObservers(window, "browser-delayed-startup-finished")
+ );
+
+ // Let the extension code know it can start loading things that were delayed
+ // while GeckoView started up.
+ InitLater(() => {
+ Services.obs.notifyObservers(window, "extensions-late-startup");
+ });
+
+ InitLater(() => {
+ // TODO bug 1730026: this runs too often. It should run once.
+ RemoteSecuritySettings.init();
+ });
+
+ InitLater(() => {
+ // Initialize safe browsing module. This is required for content
+ // blocking features and manages blocklist downloads and updates.
+ SafeBrowsing.init();
+ });
+
+ InitLater(() => {
+ // It's enough to run this once to set up FOG.
+ // (See also bug 1730026.)
+ Services.fog.registerCustomPings();
+ });
+
+ InitLater(() => {
+ // Initialize the blocklist module.
+ // TODO bug 1730026: this runs too often. It should run once.
+ Blocklist.loadBlocklistAsync();
+ });
+
+ // This should always go last, since the idle tasks (except for the ones with
+ // timeouts) should execute in order. Note that this observer notification is
+ // not guaranteed to fire, since the window could close before we get here.
+
+ // This notification in particular signals the ScriptPreloader that we have
+ // finished startup, so it can now stop recording script usage and start
+ // updating the startup cache for faster script loading.
+ InitLater(() =>
+ Services.obs.notifyObservers(
+ window,
+ "browser-idle-startup-tasks-finished"
+ )
+ );
+ });
+
+ // Move focus to the content window at the end of startup,
+ // so things like text selection can work properly.
+ browser.focus();
+
+ InitializationTracker.onInitialized(performance.now());
+}