Bug 1700909 - [devtools] Migrate TabDescriptorFactory to LocalTabCommandsFactory. r=jdescottes

Also move iKnownTab to gDevTools.hasToolboxForTab as it feel more natural.

Differential Revision: https://phabricator.services.mozilla.com/D157943
This commit is contained in:
Alexandre Poirot 2022-09-29 14:43:25 +00:00
Родитель a0a5dd10cc
Коммит f72de72ca8
12 изменённых файлов: 112 добавлений и 128 удалений

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

@ -799,7 +799,7 @@ function addA11yPanelTestsTask(tests, uri, msg, options) {
* Resolves when the toolbox and tab have been destroyed and closed.
*/
async function closeTabToolboxAccessibility(tab = gBrowser.selectedTab) {
if (TabDescriptorFactory.isKnownTab(tab)) {
if (gDevTools.hasToolboxForTab(tab)) {
await gDevTools.closeToolboxForTab(tab);
}

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

@ -16,8 +16,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
loader.lazyRequireGetter(
this,
"TabDescriptorFactory",
"devtools/client/framework/tab-descriptor-factory",
"LocalTabCommandsFactory",
"devtools/client/framework/local-tab-commands-factory",
true
);
loader.lazyRequireGetter(
@ -604,18 +604,21 @@ DevTools.prototype = {
const openerTab = tab.ownerGlobal.gBrowser.getTabForBrowser(
tab.linkedBrowser.browsingContext.opener.embedderElement
);
const openerDescriptor = await TabDescriptorFactory.getDescriptorForTab(
const openerCommands = await LocalTabCommandsFactory.getCommandsForTab(
openerTab
);
if (this.getToolboxForDescriptor(openerDescriptor)) {
if (
openerCommands &&
this.getToolboxForDescriptor(openerCommands.descriptorFront)
) {
console.log(
"Can't open a toolbox for this document as this is debugged from its opener tab"
);
return null;
}
}
const descriptor = await TabDescriptorFactory.createDescriptorForTab(tab);
return this.showToolbox(descriptor, {
const commands = await LocalTabCommandsFactory.createCommandsForTab(tab);
return this.showToolbox(commands.descriptorFront, {
toolId,
hostType,
startTime,
@ -764,8 +767,8 @@ DevTools.prototype = {
* Returns null otherwise.
*/
async getToolboxForTab(tab) {
const descriptor = await TabDescriptorFactory.getDescriptorForTab(tab);
return this.getToolboxForDescriptor(descriptor);
const commands = await LocalTabCommandsFactory.getCommandsForTab(tab);
return commands && this.getToolboxForDescriptor(commands.descriptorFront);
},
/**
@ -776,8 +779,8 @@ DevTools.prototype = {
* - or after toolbox.destroy() resolved if a Toolbox was found
*/
async closeToolboxForTab(tab) {
const descriptor = await TabDescriptorFactory.getDescriptorForTab(tab);
const commands = await LocalTabCommandsFactory.getCommandsForTab(tab);
const descriptor = commands.descriptorFront;
let toolbox = await this._creatingToolboxes.get(descriptor);
if (!toolbox) {
toolbox = this._toolboxes.get(descriptor);

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

@ -0,0 +1,72 @@
/* 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";
loader.lazyRequireGetter(
this,
"CommandsFactory",
"devtools/shared/commands/commands-factory",
true
);
// Map of existing Commands objects, keyed by XULTab.
const commandsMap = new WeakMap();
/**
* Functions for creating unique Commands for Local Tabs.
*/
exports.LocalTabCommandsFactory = {
/**
* Create a unique commands object for the given tab.
*
* If a commands was already created by this factory for the provided tab,
* it will be returned and no new commands created.
*
* Otherwise, this will automatically:
* - spawn a DevToolsServer in the parent process,
* - create a DevToolsClient
* - connect the DevToolsClient to the DevToolsServer
* - call RootActor's `getTab` request to retrieve the WindowGlobalTargetActor's form
*
* @param {XULTab} tab
* The tab to use in creating a new commands.
*
* @return {Commands object} The commands object for the provided tab.
*/
async createCommandsForTab(tab) {
let commands = commandsMap.get(tab);
if (commands) {
// Keep in mind that commands can be either a promise
// or a commands object.
return commands;
}
const promise = CommandsFactory.forTab(tab);
// Immediately set the commands's promise in cache to prevent race
commandsMap.set(tab, promise);
commands = await promise;
// Then replace the promise with the commands object
commandsMap.set(tab, commands);
commands.descriptorFront.once("descriptor-destroyed", () => {
commandsMap.delete(tab);
});
return commands;
},
/**
* Retrieve an existing commands created by this factory for the provided
* tab. Returns null if no commands was created yet.
*
* @param {XULTab} tab
* The tab for which the commands should be retrieved
*/
async getCommandsForTab(tab) {
// commandsMap.get(tab) can either return an initialized commands, a promise
// which will resolve a commands, or null if no commands was ever created
// for this tab.
return commandsMap.get(tab);
},
};

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

@ -31,13 +31,13 @@ DevToolsModules(
"devtools-browser.js",
"devtools.js",
"enable-devtools-popup.js",
"local-tab-commands-factory.js",
"menu-item.js",
"menu.js",
"selection.js",
"source-map-url-service.js",
"store-provider.js",
"store.js",
"tab-descriptor-factory.js",
"toolbox-context-menu.js",
"toolbox-host-manager.js",
"toolbox-hosts.js",

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

@ -1,81 +0,0 @@
/* 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";
loader.lazyRequireGetter(
this,
"CommandsFactory",
"devtools/shared/commands/commands-factory",
true
);
// Map of existing Commands objects, keyed by XULTab.
const commandsMap = new WeakMap();
/**
* Functions for creating (local) Tab Target Descriptors
*/
exports.TabDescriptorFactory = {
/**
* Create a unique tab target descriptor for the given tab.
*
* If a descriptor was already created by this factory for the provided tab,
* it will be returned and no new descriptor created.
*
* Otherwise, this will automatically:
* - spawn a DevToolsServer in the parent process,
* - create a DevToolsClient
* - connect the DevToolsClient to the DevToolsServer
* - call RootActor's `getTab` request to retrieve the WindowGlobalTargetActor's form
*
* @param {XULTab} tab
* The tab to use in creating a new descriptor.
*
* @return {TabDescriptorFront} The tab descriptor for the provided tab.
*/
async createDescriptorForTab(tab) {
let commands = commandsMap.get(tab);
if (commands) {
commands = await commands;
return commands.descriptorFront;
}
const promise = CommandsFactory.forTab(tab);
// Immediately set the descriptor's promise in cache to prevent race
commandsMap.set(tab, promise);
commands = await promise;
// Then replace the promise with the descriptor object
commandsMap.set(tab, commands);
commands.descriptorFront.once("descriptor-destroyed", () => {
commandsMap.delete(tab);
});
return commands.descriptorFront;
},
/**
* Retrieve an existing descriptor created by this factory for the provided
* tab. Returns null if no descriptor was created yet.
*
* @param {XULTab} tab
* The tab for which the descriptor should be retrieved
*/
async getDescriptorForTab(tab) {
// commandsMap.get(tab) can either return initialized commands, a promise
// which will resolve a commands, or null if no commands was ever created
// for this tab.
const commands = await commandsMap.get(tab);
return commands?.descriptorFront;
},
/**
* This function allows us to ask if there is a known
* descriptor for a tab without creating a descriptor.
* @return true/false
*/
isKnownTab(tab) {
return commandsMap.has(tab);
},
};

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

@ -80,7 +80,7 @@ prefs =
[browser_source_map-pub-sub.js]
[browser_source_map-reload.js]
[browser_source_map-late-script.js]
[browser_tab_descriptor_factory.js]
[browser_tab_commands_factory.js]
[browser_tab_descriptor_fission.js]
[browser_target_from_url.js]
[browser_target_cached-front.js]

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

@ -3,9 +3,11 @@
"use strict";
// Test TabDescriptorFactory
// Test LocalTabCommandsFactory
const { createCommandsDictionary } = require("devtools/shared/commands/index");
const {
LocalTabCommandsFactory,
} = require("devtools/client/framework/local-tab-commands-factory");
add_task(async function() {
await testTabDescriptorWithURL("data:text/html;charset=utf-8,foo");
@ -19,32 +21,30 @@ async function testTabDescriptorWithURL(url) {
info(`Test TabDescriptor against url ${url}\n`);
const tab = await addTab(url);
const descriptor = await TabDescriptorFactory.createDescriptorForTab(tab);
is(descriptor.localTab, tab, "TabDescriptor's localTab is set correctly");
const commands = await LocalTabCommandsFactory.createCommandsForTab(tab);
is(
commands.descriptorFront.localTab,
tab,
"TabDescriptor's localTab is set correctly"
);
info(
"Calling a second time createDescriptorForTab with the same tab, will return the same descriptor"
"Calling a second time createCommandsForTab with the same tab, will return the same commands"
);
const secondDescriptor = await TabDescriptorFactory.createDescriptorForTab(
const secondCommands = await LocalTabCommandsFactory.createCommandsForTab(
tab
);
is(descriptor, secondDescriptor, "second descriptor is the same");
is(commands, secondCommands, "second commands is the same");
// We have to involve TargetCommand in order to have a function TabDescriptor.getTarget.
// With bug 1700909, all code should soon be migrated to use CommandsFactory instead of TabDescriptorFactory.
// Making this test irrelevant and this cryptic workaround useless.
const commands = await createCommandsDictionary(descriptor);
await commands.targetCommand.startListening();
info("Wait for descriptor's target");
const target = await descriptor.getTarget();
const target = await commands.descriptorFront.getTarget();
info("Call any method to ensure that each target works");
await target.logInPage("foo");
info("Destroy the descriptor");
await descriptor.destroy();
info("Destroy the command");
await commands.destroy();

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

@ -26,12 +26,6 @@ loader.lazyRequireGetter(
"devtools/client/shared/components/NotificationBox",
true
);
loader.lazyRequireGetter(
this,
"TabDescriptorFactory",
"devtools/client/framework/tab-descriptor-factory",
true
);
loader.lazyRequireGetter(
this,
"gDevTools",
@ -141,9 +135,8 @@ class ResponsiveUIManager {
*/
async recordTelemetryOpen(window, tab, options) {
// Track whether a toolbox was opened before RDM was opened.
const isKnownTab = TabDescriptorFactory.isKnownTab(tab);
let toolbox;
if (isKnownTab) {
if (gDevTools.hasToolboxForTab(tab)) {
toolbox = await gDevTools.getToolboxForTab(tab);
}
const hostType = toolbox ? toolbox.hostType : "none";
@ -211,9 +204,8 @@ class ResponsiveUIManager {
}
async recordTelemetryClose(window, tab) {
const isKnownTab = TabDescriptorFactory.isKnownTab(tab);
let toolbox;
if (isKnownTab) {
if (gDevTools.hasToolboxForTab(tab)) {
toolbox = await gDevTools.getToolboxForTab(tab);
}

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

@ -5,9 +5,6 @@
"use strict";
const { gDevTools } = require("devtools/client/framework/devtools");
const {
TabDescriptorFactory,
} = require("devtools/client/framework/tab-descriptor-factory");
/**
* Retrieve the most recent chrome window.
@ -62,7 +59,7 @@ exports.openContentLink = async function(url, options = {}) {
}
if (!options.triggeringPrincipal && top.gBrowser) {
const tab = top.gBrowser.selectedTab;
if (TabDescriptorFactory.isKnownTab(tab)) {
if (gDevTools.hasToolboxForTab(tab)) {
options.triggeringPrincipal = tab.linkedBrowser.contentPrincipal;
options.csp = tab.linkedBrowser.csp;
}

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

@ -62,9 +62,6 @@ const { loader, require } = ChromeUtils.import(
// and already expose Services as a global.
const { gDevTools } = require("devtools/client/framework/devtools");
const {
TabDescriptorFactory,
} = require("devtools/client/framework/tab-descriptor-factory");
const {
CommandsFactory,
} = require("devtools/shared/commands/commands-factory");
@ -1211,7 +1208,7 @@ async function openNewTabAndToolbox(url, toolId, hostType) {
* closed.
*/
async function closeTabAndToolbox(tab = gBrowser.selectedTab) {
if (TabDescriptorFactory.isKnownTab(tab)) {
if (gDevTools.hasToolboxForTab(tab)) {
await gDevTools.closeToolboxForTab(tab);
}

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

@ -53,6 +53,9 @@ Services.scriptloader.loadSubScript(
);
const { TableWidget } = require("devtools/client/shared/widgets/TableWidget");
const {
LocalTabCommandsFactory,
} = require("devtools/client/framework/local-tab-commands-factory");
const STORAGE_PREF = "devtools.storage.enabled";
const DOM_CACHE = "dom.caches.enabled";
const DUMPEMIT_PREF = "devtools.dump.emit";
@ -157,9 +160,10 @@ async function openTabAndSetupStorage(url, options = {}) {
var openStoragePanel = async function({ tab, descriptor, hostType } = {}) {
info("Opening the storage inspector");
if (!descriptor) {
descriptor = await TabDescriptorFactory.createDescriptorForTab(
const commands = await LocalTabCommandsFactory.createCommandsForTab(
tab || gBrowser.selectedTab
);
descriptor = commands.descriptorFront;
}
let storage, toolbox;

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

@ -996,7 +996,7 @@ class TargetCommand extends EventEmitter {
// TabDescriptor may emit the event with a null targetFront, interpret that as if the previous target
// has already been destroyed
if (targetFront) {
// Wait for the target to be destroyed so that TabDescriptorFactory clears its memoized target for this tab
// Wait for the target to be destroyed so that LocalTabCommandsFactory clears its memoized target for this tab
await targetFront.once("target-destroyed");
}