Bug 1916766 - Centralise HiddenBrowserManager into HiddenFrame.sys.mjs and make it a singleton. r=mossop

Differential Revision: https://phabricator.services.mozilla.com/D221061
This commit is contained in:
Mark Banner 2024-09-11 15:08:36 +00:00
Родитель 1a7df855ed
Коммит 72981bee50
3 изменённых файлов: 99 добавлений и 193 удалений

Просмотреть файл

@ -10,7 +10,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
HiddenFrame: "resource://gre/modules/HiddenFrame.sys.mjs",
HiddenBrowserManager: "resource://gre/modules/HiddenFrame.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "logConsole", function () {
@ -35,9 +35,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
const ALLOWED_SCHEMES = ["http", "https", "data", "blob"];
const BACKGROUND_WIDTH = 1024;
const BACKGROUND_HEIGHT = 768;
/**
* Shifts the first element out of the set.
*
@ -58,90 +55,6 @@ function shift(set) {
return value;
}
/**
* A manager for hidden browsers. Responsible for creating and destroying a
* hidden frame to hold them.
*/
class HiddenBrowserManager {
/**
* The hidden frame if one has been created.
*
* @type {HiddenFrame | null}
*/
#frame = null;
/**
* The number of hidden browser elements currently in use.
*
* @type {number}
*/
#browsers = 0;
/**
* Creates and returns a new hidden browser.
*
* @returns {Browser}
*/
async #acquireBrowser() {
this.#browsers++;
if (!this.#frame) {
this.#frame = new lazy.HiddenFrame();
}
let frame = await this.#frame.get();
let doc = frame.document;
let browser = doc.createXULElement("browser");
browser.setAttribute("remote", "true");
browser.setAttribute("type", "content");
browser.setAttribute(
"style",
`
width: ${BACKGROUND_WIDTH}px;
min-width: ${BACKGROUND_WIDTH}px;
height: ${BACKGROUND_HEIGHT}px;
min-height: ${BACKGROUND_HEIGHT}px;
`
);
browser.setAttribute("maychangeremoteness", "true");
doc.documentElement.appendChild(browser);
return browser;
}
/**
* Releases the given hidden browser.
*
* @param {Browser} browser
* The hidden browser element.
*/
#releaseBrowser(browser) {
browser.remove();
this.#browsers--;
if (this.#browsers == 0) {
this.#frame.destroy();
this.#frame = null;
}
}
/**
* Calls a callback function with a new hidden browser.
* This function will return whatever the callback function returns.
*
* @param {Callback} callback
* The callback function will be called with the browser element and may
* be asynchronous.
* @returns {T}
*/
async withHiddenBrowser(callback) {
let browser = await this.#acquireBrowser();
try {
return await callback(browser);
} finally {
this.#releaseBrowser(browser);
}
}
}
/**
* @typedef {object} CacheEntry
* An entry in the page data cache.
@ -293,13 +206,6 @@ export const PageDataService = new (class PageDataService extends EventEmitter {
*/
#userIsIdle = false;
/**
* A manager for hidden browsers.
*
* @type {HiddenBrowserManager}
*/
#browserManager = new HiddenBrowserManager();
/**
* A map of hidden browsers to a resolve function that should be passed the
* actor that was created for the browser.
@ -535,7 +441,7 @@ export const PageDataService = new (class PageDataService extends EventEmitter {
* Resolves to the found pagedata or null in case of error.
*/
async fetchPageData(url) {
return this.#browserManager.withHiddenBrowser(async browser => {
return lazy.HiddenBrowserManager.withHiddenBrowser(async browser => {
try {
let { promise, resolve } = Promise.withResolvers();
this.#backgroundBrowsers.set(browser, resolve);

Просмотреть файл

@ -6,7 +6,7 @@
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
HiddenFrame: "resource://gre/modules/HiddenFrame.sys.mjs",
HiddenBrowserManager: "resource://gre/modules/HiddenFrame.sys.mjs",
Preferences: "resource://gre/modules/Preferences.sys.mjs",
setTimeout: "resource://gre/modules/Timer.sys.mjs",
clearTimeout: "resource://gre/modules/Timer.sys.mjs",
@ -27,94 +27,6 @@ ChromeUtils.defineLazyGetter(lazy, "contentPrefs", () => {
);
});
const BACKGROUND_WIDTH = 1024;
const BACKGROUND_HEIGHT = 768;
/**
* A manager for hidden browsers. Responsible for creating and destroying a
* hidden frame to hold them.
* All of this is copied from PageDataService.sys.mjs
*/
class HiddenBrowserManager {
/**
* The hidden frame if one has been created.
*
* @type {HiddenFrame | null}
*/
#frame = null;
/**
* The number of hidden browser elements currently in use.
*
* @type {number}
*/
#browsers = 0;
/**
* Creates and returns a new hidden browser.
*
* @returns {Browser}
*/
async #acquireBrowser() {
this.#browsers++;
if (!this.#frame) {
this.#frame = new lazy.HiddenFrame();
}
let frame = await this.#frame.get();
let doc = frame.document;
let browser = doc.createXULElement("browser");
browser.setAttribute("remote", "true");
browser.setAttribute("type", "content");
browser.setAttribute(
"style",
`
width: ${BACKGROUND_WIDTH}px;
min-width: ${BACKGROUND_WIDTH}px;
height: ${BACKGROUND_HEIGHT}px;
min-height: ${BACKGROUND_HEIGHT}px;
`
);
browser.setAttribute("maychangeremoteness", "true");
doc.documentElement.appendChild(browser);
return browser;
}
/**
* Releases the given hidden browser.
*
* @param {Browser} browser
* The hidden browser element.
*/
#releaseBrowser(browser) {
browser.remove();
this.#browsers--;
if (this.#browsers == 0) {
this.#frame.destroy();
this.#frame = null;
}
}
/**
* Calls a callback function with a new hidden browser.
* This function will return whatever the callback function returns.
*
* @param {Callback} callback
* The callback function will be called with the browser element and may
* be asynchronous.
* @returns {T}
*/
async withHiddenBrowser(callback) {
let browser = await this.#acquireBrowser();
try {
return await callback(browser);
} finally {
this.#releaseBrowser(browser);
}
}
}
export class UserCharacteristicsPageService {
classId = Components.ID("{ce3e9659-e311-49fb-b18b-7f27c6659b23}");
QueryInterface = ChromeUtils.generateQI([
@ -124,13 +36,6 @@ export class UserCharacteristicsPageService {
_initialized = false;
_isParentProcess = false;
/**
* A manager for hidden browsers.
*
* @type {HiddenBrowserManager}
*/
_browserManager = new HiddenBrowserManager();
/**
* A map of hidden browsers to a resolve function that should be passed the
* actor that was created for the browser.
@ -178,7 +83,7 @@ export class UserCharacteristicsPageService {
remoteTypes: ["privilegedabout"],
});
return this._browserManager.withHiddenBrowser(async browser => {
return lazy.HiddenBrowserManager.withHiddenBrowser(async browser => {
lazy.console.debug(`In withHiddenBrowser`);
try {
let { promise, resolve } = Promise.withResolvers();

Просмотреть файл

@ -2,10 +2,21 @@
* 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/. */
/**
* This module contains `HiddenFrame`, a class which creates a windowless browser,
* and `HiddenBrowserManager` which is a singleton that can be used to manage
* creating and using multiple hidden frames.
*/
const XUL_PAGE = Services.io.newURI("chrome://global/content/win.xhtml");
const gAllHiddenFrames = new Set();
// The screen sizes to use for the background browser created by
// `HiddenBrowserManager`.
const BACKGROUND_WIDTH = 1024;
const BACKGROUND_HEIGHT = 768;
let cleanupRegistered = false;
function ensureCleanupRegistered() {
if (!cleanupRegistered) {
@ -121,3 +132,87 @@ export class HiddenFrame {
this.#browser.loadURI(XUL_PAGE, loadURIOptions);
}
}
/**
* A manager for hidden browsers. Responsible for creating and destroying a
* hidden frame to hold them.
*/
export const HiddenBrowserManager = new (class HiddenBrowserManager {
/**
* The hidden frame if one has been created.
*
* @type {HiddenFrame | null}
*/
#frame = null;
/**
* The number of hidden browser elements currently in use.
*
* @type {number}
*/
#browsers = 0;
/**
* Creates and returns a new hidden browser.
*
* @returns {Browser}
*/
async #acquireBrowser() {
this.#browsers++;
if (!this.#frame) {
this.#frame = new HiddenFrame();
}
let frame = await this.#frame.get();
let doc = frame.document;
let browser = doc.createXULElement("browser");
browser.setAttribute("remote", "true");
browser.setAttribute("type", "content");
browser.setAttribute(
"style",
`
width: ${BACKGROUND_WIDTH}px;
min-width: ${BACKGROUND_WIDTH}px;
height: ${BACKGROUND_HEIGHT}px;
min-height: ${BACKGROUND_HEIGHT}px;
`
);
browser.setAttribute("maychangeremoteness", "true");
doc.documentElement.appendChild(browser);
return browser;
}
/**
* Releases the given hidden browser.
*
* @param {Browser} browser
* The hidden browser element.
*/
#releaseBrowser(browser) {
browser.remove();
this.#browsers--;
if (this.#browsers == 0) {
this.#frame.destroy();
this.#frame = null;
}
}
/**
* Calls a callback function with a new hidden browser.
* This function will return whatever the callback function returns.
*
* @param {Callback} callback
* The callback function will be called with the browser element and may
* be asynchronous.
* @returns {T}
*/
async withHiddenBrowser(callback) {
let browser = await this.#acquireBrowser();
try {
return await callback(browser);
} finally {
this.#releaseBrowser(browser);
}
}
})();