Source code
Revision control
Copy as Markdown
Other Tools
/* 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
import { RootBiDiModule } from "chrome://remote/content/webdriver-bidi/modules/RootBiDiModule.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowsingContextListener:
"chrome://remote/content/shared/listeners/BrowsingContextListener.sys.mjs",
ContextDescriptorType:
"chrome://remote/content/shared/messagehandler/MessageHandler.sys.mjs",
RootMessageHandler:
"chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs",
});
// Apply here only the emulations that will be initialized in the parent process,
// except from `viewport-overrides` which is handled separately.
const EMULATIONS_TO_APPLY = [
"locale-override",
"screen-orientation-override",
"screen-settings-override",
"timezone-override",
"user-agent-override",
];
/**
* Internal module to set the configuration on the newly created navigables.
*/
class _ConfigurationModule extends RootBiDiModule {
#configurationMap;
#contextListener;
constructor(messageHandler) {
super(messageHandler);
this.#contextListener = new lazy.BrowsingContextListener();
this.#contextListener.on("attached", this.#onContextAttached);
this.#contextListener.startListening();
// The configuration map, which maps an emulation to the settings
// that derived from session data when a browsing context is created
// to define which emulations have to be applied to this browsing context.
this.#configurationMap = {};
for (const emulation of EMULATIONS_TO_APPLY) {
this.#configurationMap[emulation] = {
[lazy.ContextDescriptorType.TopBrowsingContext]: null,
[lazy.ContextDescriptorType.UserContext]: null,
};
// User agent override also supports a global setting.
if (emulation === "user-agent-override") {
this.#configurationMap["user-agent-override"][
lazy.ContextDescriptorType.All
] = null;
}
}
}
destroy() {
this.#contextListener.stopListening();
this.#contextListener.off("attached", this.#onContextAttached);
this.#contextListener.destroy();
this.#configurationMap = null;
}
// For some emulations a value set per a browsing context overrides
// a value set per a user context or set globally. And a value set per
// a user context overrides a global value.
#findCorrectOverrideValue(configuration, type) {
const contextValue =
configuration[lazy.ContextDescriptorType.TopBrowsingContext];
const userContextValue =
configuration[lazy.ContextDescriptorType.UserContext];
const globalValue = configuration[lazy.ContextDescriptorType.All];
if (this.#isOfType(contextValue, type)) {
return contextValue;
}
if (this.#isOfType(userContextValue, type)) {
return userContextValue;
}
if (this.#isOfType(globalValue, type)) {
return globalValue;
}
return null;
}
/**
* Check if the provided value matches the provided type.
*
* @param {*} value
* The value to verify.
* @param {string} type
* The type to match.
*
* @returns {boolean}
* Returns `true` if the value type is the same as
* the provided type. `false`, otherwise.
* Also always returns `false` for `null`.
*/
#isOfType(value, type) {
return typeof value === type && value !== null;
}
#onContextAttached = async (eventName, data = {}) => {
const { browsingContext } = data;
// We have to apply configuration only to top-level browsing contexts.
if (browsingContext.parent) {
return;
}
const sessionDataItems =
this.messageHandler.sessionData.getSessionDataForContext(
"_configuration",
undefined,
browsingContext
);
const configurationMap = structuredClone(this.#configurationMap);
for (const { category, contextDescriptor, value } of sessionDataItems) {
if (!EMULATIONS_TO_APPLY.includes(category)) {
continue;
}
configurationMap[category][contextDescriptor.type] = value;
}
// For the following emulations on the previous step, we found session items
// that would apply an override for a browsing context, a user context, and in some cases globally.
// Now from these items we have to choose the one that would take precedence.
// The order is the user context item overrides the global one, and the browsing context overrides the user context item.
const localeOverride = this.#findCorrectOverrideValue(
configurationMap["locale-override"],
"string"
);
const screenOrientationOverride = this.#findCorrectOverrideValue(
configurationMap["screen-orientation-override"],
"object"
);
const screenSettingsOverride = this.#findCorrectOverrideValue(
configurationMap["screen-settings-override"],
"object"
);
const timezoneOverride = this.#findCorrectOverrideValue(
configurationMap["timezone-override"],
"string"
);
const userAgentOverride = this.#findCorrectOverrideValue(
configurationMap["user-agent-override"],
"string"
);
if (
localeOverride !== null ||
screenOrientationOverride !== null ||
screenSettingsOverride !== null ||
timezoneOverride !== null ||
userAgentOverride !== null
) {
await this.messageHandler.handleCommand({
moduleName: "emulation",
commandName: "_applyEmulationsToNewBrowsingContext",
destination: {
type: lazy.RootMessageHandler.type,
},
params: {
context: browsingContext,
localeOverride,
screenOrientationOverride,
screenSettingsOverride,
timezoneOverride,
userAgentOverride,
},
});
}
};
/**
* Internal commands
*/
_applySessionData() {}
}
export const _configuration = _ConfigurationModule;