Update On Tue Mar 29 20:30:19 CEST 2022

This commit is contained in:
github-action[bot] 2022-03-29 20:30:20 +02:00
parent b04421f0b7
commit 3360d722f7
204 changed files with 15043 additions and 22058 deletions

View file

@ -275,6 +275,11 @@ pref("browser.shell.setDefaultBrowserUserChoice", true);
// When setting the default browser on Windows 10 using the UserChoice
// registry keys, also try to set Firefox as the default PDF handler.
pref("browser.shell.setDefaultPDFHandler", false);
// When setting Firefox as the default PDF handler (subject to conditions
// above), only set Firefox as the default PDF handler when the existing handler
// is a known browser, and not when existing handler is another PDF handler such
// as Acrobat Reader or Nitro PDF.
pref("browser.shell.setDefaultPDFHandler.onlyReplaceBrowsers", true);
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Before After
Before After

View file

@ -92,7 +92,25 @@ const getEncodedKey = function getEncodedKey(extensionId, key) {
return `extension:${extensionId}:${key}`;
};
this.sessions = class extends ExtensionAPI {
this.sessions = class extends ExtensionAPIPersistent {
PERSISTENT_EVENTS = {
onChanged({ fire }) {
let observer = () => {
fire.async();
};
Services.obs.addObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
return {
unregister() {
Services.obs.removeObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
},
convert(_fire) {
fire = _fire;
},
};
},
};
getAPI(context) {
let { extension } = context;
@ -251,20 +269,9 @@ this.sessions = class extends ExtensionAPI {
onChanged: new EventManager({
context,
name: "sessions.onChanged",
register: fire => {
let observer = () => {
fire.async();
};
Services.obs.addObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
return () => {
Services.obs.removeObserver(
observer,
SS_ON_CLOSED_OBJECTS_CHANGED
);
};
},
module: "sessions",
event: "onChanged",
extensionApi: this,
}).api(),
},
};

View file

@ -191,3 +191,44 @@ add_task(async function test_sessions_restore() {
await extension.unload();
});
add_task(async function test_sessions_event_page() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.eventPages.enabled", true]],
});
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
applications: { gecko: { id: "eventpage@sessions" } },
permissions: ["sessions", "tabs"],
background: { persistent: false },
},
background() {
browser.sessions.onChanged.addListener(() => {
browser.test.sendMessage("changed");
});
browser.test.sendMessage("ready");
},
});
await extension.startup();
await extension.awaitMessage("ready");
// test events waken background
await extension.terminateBackground();
let win = await BrowserTestUtils.openNewBrowserWindow();
BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:config");
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
for (let url of ["about:robots", "about:mozilla"]) {
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, url);
}
await BrowserTestUtils.closeWindow(win);
await extension.awaitMessage("ready");
await extension.awaitMessage("changed");
ok(true, "persistent event woke background");
await extension.unload();
await SpecialPowers.popPrefEnv();
});

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const path = require("path");
const webpack = require("webpack");
const PATHS = {
// Where is the entry point for the unit tests?
@ -224,7 +225,16 @@ module.exports = function(config) {
resolve: {
extensions: [".js", ".jsx"],
modules: [PATHS.moduleResolveDirectory, "node_modules"],
fallback: {
stream: require.resolve("stream-browserify"),
buffer: require.resolve("buffer"),
},
},
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("development"),
}),
],
externals: {
// enzyme needs these for backwards compatibility with 0.13.
// see https://github.com/airbnb/enzyme/blob/master/docs/guides/webpack.md#using-enzyme-with-webpack

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@
"babel-loader": "8.2.3",
"babel-plugin-jsm-to-commonjs": "0.5.0",
"babel-plugin-jsm-to-esmodules": "0.6.0",
"buffer": "6.0.3",
"chai": "4.3.4",
"chai-json-schema": "1.5.1",
"enzyme": "3.11.0",
@ -55,8 +56,9 @@
"sass-lint": "1.13.1",
"shelljs": "0.8.4",
"sinon": "12.0.1",
"webpack": "4.41.6",
"webpack-cli": "4.5.0",
"stream-browserify": "3.0.0",
"webpack": "5.56.0",
"webpack-cli": "4.9.1",
"yamscripts": "0.1.0"
},
"engines": {
@ -80,9 +82,9 @@
},
"scripts": {
"bundle": "npm-run-all bundle:*",
"bundle:webpack": "webpack --config webpack.system-addon.config.js",
"bundle:webpack": "webpack-cli --config webpack.system-addon.config.js",
"bundle:css": "sass content-src/styles:css --no-source-map",
"bundle:welcomeBundle": "webpack --config webpack.aboutwelcome.config.js",
"bundle:welcomeBundle": "webpack-cli --config webpack.aboutwelcome.config.js",
"bundle:welcomeCss": "sass content-src/aboutwelcome:aboutwelcome/content --no-source-map",
"bundle:html": "rimraf prerendered && node ./bin/render-activity-stream-html.js",
"buildmc": "npm-run-all buildmc:*",

View file

@ -60,6 +60,9 @@ module.exports = (env = {}) => ({
resolve: {
extensions: [".js", ".jsx"],
modules: ["node_modules", "."],
fallback: {
stream: require.resolve("stream-browserify"),
},
},
externals: {
"prop-types": "PropTypes",

View file

@ -6,9 +6,9 @@
scripts:
# bundle: Build all assets for activity stream
bundle:
webpack: webpack --config webpack.system-addon.config.js
webpack: webpack-cli --config webpack.system-addon.config.js
css: sass content-src/styles:css --no-source-map
welcomeBundle: webpack --config webpack.aboutwelcome.config.js
welcomeBundle: webpack-cli --config webpack.aboutwelcome.config.js
welcomeCss: sass content-src/aboutwelcome:aboutwelcome/content --no-source-map
html: rimraf prerendered && node ./bin/render-activity-stream-html.js

View file

@ -2040,16 +2040,36 @@ body.theme_dark #stp_style_guide {
padding: 4px 8px;
transition: background-color 200ms ease-in-out;
}
body.theme_dark .stp_tag_picker .stp_tag_picker_tag {
background: #2B2A33;
color: #FBFBFB;
}
.stp_tag_picker .stp_tag_picker_tag_remove {
padding: 5px;
color: #5B5B66;
font-weight: 400;
}
body.theme_dark .stp_tag_picker .stp_tag_picker_tag_remove {
color: #8F8F9D;
}
.stp_tag_picker .stp_tag_picker_tag_duplicate {
background-color: #bbb;
}
body.theme_dark .stp_tag_picker .stp_tag_picker_tag_duplicate {
background-color: #666;
}
.stp_tag_picker .stp_tag_picker_input {
flex-grow: 1;
border: 1px solid #8F8F9D;
border-radius: 3px;
padding: 6px;
width: 100%;
}
body.theme_dark .stp_tag_picker .stp_tag_picker_input {
background: none;
color: #FBFBFB;
}
.stp_popular_topics {

View file

@ -26,19 +26,40 @@
margin-inline-end: 8px;
padding: 4px 8px;
transition: background-color 200ms ease-in-out;
@include theme_dark {
background: #2B2A33;
color: #FBFBFB;
}
}
.stp_tag_picker_tag_remove {
padding: 5px;
color: #5B5B66;
font-weight: 400;
@include theme_dark {
color: #8F8F9D;
}
}
.stp_tag_picker_tag_duplicate {
background-color: #bbb;
@include theme_dark {
background-color: #666;
}
}
.stp_tag_picker_input {
flex-grow: 1;
border: 1px solid #8F8F9D;
border-radius: 3px;
padding: 6px;
width: 100%;
@include theme_dark {
background: none;
color: #FBFBFB;
}
}
}

View file

@ -378,7 +378,12 @@ var pktUI = (function() {
pktUIMessaging.sendMessageToPanel(saveLinkMessageId, successResponse);
SaveToPocket.itemSaved();
if (item?.resolved_id && item?.resolved_id !== "0") {
if (
item?.resolved_id &&
item?.resolved_id !== "0" &&
NimbusFeatures.saveToPocket.getVariable("layoutRefresh") &&
!NimbusFeatures.saveToPocket.getVariable("hideRecentSaves")
) {
pktApi.getArticleInfo(item.resolved_url, {
success(data) {
pktUIMessaging.sendMessageToPanel("PKT_renderSavedStory", data);

View file

@ -49,8 +49,10 @@ var gSearchPane = {
window.addEventListener("dblclick", this);
Services.obs.addObserver(this, "browser-search-engine-modified");
Services.obs.addObserver(this, "intl:app-locales-changed");
window.addEventListener("unload", () => {
Services.obs.removeObserver(this, "browser-search-engine-modified");
Services.obs.removeObserver(this, "intl:app-locales-changed");
});
let suggestsPref = Preferences.get("browser.search.suggest.enabled");
@ -335,57 +337,78 @@ var gSearchPane = {
},
/**
* nsIObserver implementation. We observe the following:
*
* * browser-search-engine-modified: Update the default engine UI and engine
* tree view as appropriate when engine changes occur.
* Handle when the app locale is changed.
*/
observe(subject, topic, data) {
if (topic == "browser-search-engine-modified") {
let engine = subject;
engine.QueryInterface(Ci.nsISearchEngine);
switch (data) {
case "engine-added":
gEngineView._engineStore.addEngine(engine);
gEngineView.rowCountChanged(gEngineView.lastEngineIndex, 1);
async appLocalesChanged() {
await document.l10n.ready;
await gEngineView.loadL10nNames();
},
/**
* Update the default engine UI and engine tree view as appropriate when engine changes
* or locale changes occur.
*
* @param {Object} engine
* @param {string} data
*/
browserSearchEngineModified(engine, data) {
engine.QueryInterface(Ci.nsISearchEngine);
switch (data) {
case "engine-added":
gEngineView._engineStore.addEngine(engine);
gEngineView.rowCountChanged(gEngineView.lastEngineIndex, 1);
gSearchPane.buildDefaultEngineDropDowns();
break;
case "engine-changed":
gSearchPane.buildDefaultEngineDropDowns();
gEngineView._engineStore.updateEngine(engine);
gEngineView.invalidate();
break;
case "engine-removed":
gSearchPane.remove(engine);
break;
case "engine-default": {
// If the user is going through the drop down using up/down keys, the
// dropdown may still be open (eg. on Windows) when engine-default is
// fired, so rebuilding the list unconditionally would get in the way.
let selectedEngine = document.getElementById("defaultEngine")
.selectedItem.engine;
if (selectedEngine.name != engine.name) {
gSearchPane.buildDefaultEngineDropDowns();
break;
case "engine-changed":
gSearchPane.buildDefaultEngineDropDowns();
gEngineView._engineStore.updateEngine(engine);
gEngineView.invalidate();
break;
case "engine-removed":
gSearchPane.remove(engine);
break;
case "engine-default": {
}
break;
}
case "engine-default-private": {
if (
this._separatePrivateDefaultEnabledPref.value &&
this._separatePrivateDefaultPref.value
) {
// If the user is going through the drop down using up/down keys, the
// dropdown may still be open (eg. on Windows) when engine-default is
// fired, so rebuilding the list unconditionally would get in the way.
let selectedEngine = document.getElementById("defaultEngine")
const selectedEngine = document.getElementById("defaultPrivateEngine")
.selectedItem.engine;
if (selectedEngine.name != engine.name) {
gSearchPane.buildDefaultEngineDropDowns();
}
break;
}
case "engine-default-private": {
if (
this._separatePrivateDefaultEnabledPref.value &&
this._separatePrivateDefaultPref.value
) {
// If the user is going through the drop down using up/down keys, the
// dropdown may still be open (eg. on Windows) when engine-default is
// fired, so rebuilding the list unconditionally would get in the way.
const selectedEngine = document.getElementById(
"defaultPrivateEngine"
).selectedItem.engine;
if (selectedEngine.name != engine.name) {
gSearchPane.buildDefaultEngineDropDowns();
}
}
break;
}
break;
}
}
},
/**
* nsIObserver implementation.
*/
observe(subject, topic, data) {
switch (topic) {
case "intl:app-locales-changed": {
this.appLocalesChanged();
break;
}
case "browser-search-engine-modified": {
this.browserSearchEngineModified(subject, data);
break;
}
}
},
@ -461,10 +484,17 @@ var gSearchPane = {
remove(aEngine) {
let index = gEngineView._engineStore.removeEngine(aEngine);
if (!gEngineView.tree) {
// Only update the selection if it's visible in the UI.
return;
}
gEngineView.rowCountChanged(index, -1);
gEngineView.invalidate();
gEngineView.selection.select(Math.min(index, gEngineView.rowCount - 1));
gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
document.getElementById("engineList").focus();
},
@ -629,12 +659,9 @@ EngineStore.prototype = {
let engineToUpdate = this._engines.findIndex(
e => e.originalEngine == newEngine
);
if (engineToUpdate == -1) {
console.error("Could not find engine to update");
return;
if (engineToUpdate != -1) {
this.engines[engineToUpdate] = this._cloneEngine(newEngine);
}
this.engines[engineToUpdate] = this._cloneEngine(newEngine);
},
moveEngine(aEngine, aNewIndex) {
@ -729,31 +756,35 @@ function EngineView(aEngineStore) {
UrlbarPrefs.addObserver(this);
// This maps local shortcut sources to their l10n names. The names are needed
// by getCellText. Getting the names is async but getCellText is not, so we
// cache them here to retrieve them syncronously in getCellText.
this._localShortcutL10nNames = new Map();
document.l10n
.formatValues(
UrlbarUtils.LOCAL_SEARCH_MODES.map(mode => {
let name = UrlbarUtils.getResultSourceName(mode.source);
return { id: `urlbar-search-mode-${name}` };
})
)
.then(names => {
for (let { source } of UrlbarUtils.LOCAL_SEARCH_MODES) {
this._localShortcutL10nNames.set(source, names.shift());
}
// Invalidate the tree now that we have the names in case getCellText was
// called before name retrieval finished.
this.invalidate();
});
this.loadL10nNames();
}
EngineView.prototype = {
_engineStore: null,
tree: null,
loadL10nNames() {
// This maps local shortcut sources to their l10n names. The names are needed
// by getCellText. Getting the names is async but getCellText is not, so we
// cache them here to retrieve them syncronously in getCellText.
this._localShortcutL10nNames = new Map();
return document.l10n
.formatValues(
UrlbarUtils.LOCAL_SEARCH_MODES.map(mode => {
let name = UrlbarUtils.getResultSourceName(mode.source);
return { id: `urlbar-search-mode-${name}` };
})
)
.then(names => {
for (let { source } of UrlbarUtils.LOCAL_SEARCH_MODES) {
this._localShortcutL10nNames.set(source, names.shift());
}
// Invalidate the tree now that we have the names in case getCellText was
// called before name retrieval finished.
this.invalidate();
});
},
get lastEngineIndex() {
return this._engineStore.engines.length - 1;
},

View file

@ -27,6 +27,18 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIXREDirProvider"
);
XPCOMUtils.defineLazyGetter(this, "log", () => {
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
let consoleOptions = {
// tip: set maxLogLevel to "debug" and use log.debug() to create detailed
// messages during development. See LOG_LEVELS in Console.jsm for details.
maxLogLevel: "debug",
maxLogLevelPref: "browser.shell.loglevel",
prefix: "ShellService",
};
return new ConsoleAPI(consoleOptions);
});
/**
* Internal functionality to save and restore the docShell.allow* properties.
*/
@ -152,6 +164,72 @@ let ShellServiceInternal = {
return null;
},
/*
* Accommodate `setDefaultPDFHandlerOnlyReplaceBrowsers` feature.
* @return true if Firefox should set itself as default PDF handler, false
* otherwise.
*/
_shouldSetDefaultPDFHandler() {
if (
!NimbusFeatures.shellService.getVariable(
"setDefaultPDFHandlerOnlyReplaceBrowsers"
)
) {
return true;
}
const knownBrowserPrefixes = [
"AppXq0fevzme2pys62n3e0fbqa7peapykr8v", // Edge before Blink, per https://stackoverflow.com/a/32724723.
"Brave", // For "BraveFile".
"Chrome", // For "ChromeHTML".
"Firefox", // For "FirefoxHTML-*" or "FirefoxPDF-*". Need to take from other installations of Firefox!
"IE", // Best guess.
"MSEdge", // For "MSEdgePDF". Edgium.
"Opera", // For "OperaStable", presumably varying with channel.
"Yandex", // For "YandexPDF.IHKFKZEIOKEMR6BGF62QXCRIKM", presumably varying with installation.
];
let currentProgID = "";
try {
// Returns the empty string when no association is registered, in
// which case the prefix matching will fail and we'll set Firefox as
// the default PDF handler.
currentProgID = this.queryCurrentDefaultHandlerFor(".pdf");
} catch (e) {
// We only get an exception when something went really wrong. Fail
// safely: don't set Firefox as default PDF handler.
log.warn(
"Failed to queryCurrentDefaultHandlerFor: " +
"not setting Firefox as default PDF handler!"
);
return false;
}
if (currentProgID == "") {
log.debug(
`Current default PDF handler has no registered association; ` +
`should set as default PDF handler.`
);
return true;
}
let knownBrowserPrefix = knownBrowserPrefixes.find(it =>
currentProgID.startsWith(it)
);
if (knownBrowserPrefix) {
log.debug(
`Current default PDF handler progID matches known browser prefix: ` +
`'${knownBrowserPrefix}'; should set as default PDF handler.`
);
return true;
}
log.debug(
`Current default PDF handler progID does not match known browser prefix; ` +
`should not set as default PDF handler.`
);
return false;
},
/*
* Set the default browser through the UserChoice registry keys on Windows.
*
@ -166,6 +244,8 @@ let ShellServiceInternal = {
throw new Error("Windows-only");
}
log.info("Setting Firefox as default using UserChoice");
// We launch the WDBA to handle the registry writes, see
// SetDefaultBrowserUserChoice() in
// toolkit/mozapps/defaultagent/SetDefaultBrowser.cpp.
@ -190,7 +270,12 @@ let ShellServiceInternal = {
telemetryResult = "ErrLaunchExe";
const exeArgs = ["set-default-browser-user-choice", aumi];
if (NimbusFeatures.shellService.getVariable("setDefaultPDFHandler")) {
exeArgs.push(".pdf");
if (this._shouldSetDefaultPDFHandler()) {
log.info("Setting Firefox as default PDF handler");
exeArgs.push(".pdf");
} else {
log.info("Not setting Firefox as default PDF handler");
}
}
const exeProcess = await this._callExternalDefaultBrowserAgent({
arguments: exeArgs,

View file

@ -159,4 +159,15 @@ interface nsIWindowsShellService : nsISupports
* or protocol (like "https").
*/
boolean isDefaultHandlerFor(in AString aFileExtensionOrProtocol);
/*
* Return the Windows ProgID currently registered to handle the gven
* file extension (like ".pdf") or protocol (like "https").
*
* @return string ProgID, or "" when no association is registered.
* @throws NS_ERROR_FAILURE when the file extension or protocol
* cannot be determined.
*/
AString queryCurrentDefaultHandlerFor(in AString aFileExtensionOrProtocol);
};

View file

@ -242,6 +242,37 @@ nsWindowsShellService::IsDefaultHandlerFor(
return NS_OK;
}
NS_IMETHODIMP
nsWindowsShellService::QueryCurrentDefaultHandlerFor(
const nsAString& aFileExtensionOrProtocol, nsAString& aResult) {
aResult.Truncate();
RefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(
CLSID_ApplicationAssociationRegistration, nullptr, CLSCTX_INPROC,
IID_IApplicationAssociationRegistration, getter_AddRefs(pAAR));
if (FAILED(hr)) {
return NS_OK;
}
const nsString& flatClass = PromiseFlatString(aFileExtensionOrProtocol);
LPWSTR registeredApp;
bool isProtocol = flatClass.First() != L'.';
ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION;
hr = pAAR->QueryCurrentDefault(flatClass.get(), queryType, AL_EFFECTIVE,
&registeredApp);
if (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)) {
return NS_OK;
}
NS_ENSURE_HRESULT(hr, NS_ERROR_FAILURE);
aResult = registeredApp;
CoTaskMemFree(registeredApp);
return NS_OK;
}
nsresult nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI() {
IApplicationAssociationRegistrationUI* pAARUI;
HRESULT hr = CoCreateInstance(

View file

@ -29,9 +29,12 @@ const _userChoiceImpossibleTelemetryResultStub = sinon
// Ensure we don't fall back to a real implementation.
const setDefaultStub = sinon.stub();
const shellStub = sinon
.stub(ShellService, "shellService")
.value({ setDefaultBrowser: setDefaultStub });
// We'll dynamically update this as needed during the tests.
const queryCurrentDefaultHandlerForStub = sinon.stub();
const shellStub = sinon.stub(ShellService, "shellService").value({
setDefaultBrowser: setDefaultStub,
queryCurrentDefaultHandlerFor: queryCurrentDefaultHandlerForStub,
});
registerCleanupFunction(() => {
_callExternalDefaultBrowserAgentStub.restore();
@ -56,6 +59,7 @@ add_task(async function remoteEnableWithPDF() {
featureId: NimbusFeatures.shellService.featureId,
value: {
setDefaultBrowserUserChoice: true,
setDefaultPDFHandlerOnlyReplaceBrowsers: false,
setDefaultPDFHandler: true,
enabled: true,
},
@ -82,6 +86,65 @@ add_task(async function remoteEnableWithPDF() {
await doCleanup();
});
add_task(async function remoteEnableWithPDF_testOnlyReplaceBrowsers() {
let doCleanup = await ExperimentFakes.enrollWithRollout({
featureId: NimbusFeatures.shellService.featureId,
value: {
setDefaultBrowserUserChoice: true,
setDefaultPDFHandlerOnlyReplaceBrowsers: true,
setDefaultPDFHandler: true,
enabled: true,
},
});
Assert.equal(
NimbusFeatures.shellService.getVariable("setDefaultBrowserUserChoice"),
true
);
Assert.equal(
NimbusFeatures.shellService.getVariable("setDefaultPDFHandler"),
true
);
Assert.equal(
NimbusFeatures.shellService.getVariable(
"setDefaultPDFHandlerOnlyReplaceBrowsers"
),
true
);
const aumi = XreDirProvider.getInstallHash();
// We'll take the default from a missing association or a known browser.
for (let progId of ["", "MSEdgePDF"]) {
queryCurrentDefaultHandlerForStub.callsFake(() => progId);
_callExternalDefaultBrowserAgentStub.resetHistory();
ShellService.setDefaultBrowser();
Assert.ok(_callExternalDefaultBrowserAgentStub.called);
Assert.deepEqual(
_callExternalDefaultBrowserAgentStub.firstCall.args,
[{ arguments: ["set-default-browser-user-choice", aumi, ".pdf"] }],
`Will take default from missing association or known browser with ProgID '${progId}'`
);
}
// But not from a non-browser.
queryCurrentDefaultHandlerForStub.callsFake(() => "Acrobat.Document.DC");
_callExternalDefaultBrowserAgentStub.resetHistory();
ShellService.setDefaultBrowser();
Assert.ok(_callExternalDefaultBrowserAgentStub.called);
Assert.deepEqual(
_callExternalDefaultBrowserAgentStub.firstCall.args,
[{ arguments: ["set-default-browser-user-choice", aumi] }],
`Will not take default from non-browser`
);
await doCleanup();
});
add_task(async function remoteEnableWithoutPDF() {
let doCleanup = await ExperimentFakes.enrollWithRollout({
featureId: NimbusFeatures.shellService.featureId,

View file

@ -12,9 +12,7 @@ support-files =
head_cc.js
[browser_creditCard_doorhanger.js]
skip-if =
(!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
os == 'linux' && bits == 64 && !debug # Bug 1655600
skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
[browser_creditCard_dropdown_layout.js]
skip-if = ((os == "mac") || (os == 'linux') || (os == 'win'))
[browser_creditCard_fill_cancel_login.js]

View file

@ -1,209 +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/. */
/* globals log */
/* globals main, deviceInfo, catcher, communication, browser */
"use strict";
this.auth = (function() {
const exports = {};
let registrationInfo;
let initialized = false;
let authHeader = null;
let sentryPublicDSN = null;
let abTests = {};
let accountId = null;
const fetchStoredInfo = catcher.watchPromise(
browser.storage.local.get(["registrationInfo", "abTests"]).then(result => {
if (result.abTests) {
abTests = result.abTests;
}
if (result.registrationInfo) {
registrationInfo = result.registrationInfo;
}
})
);
function generateRegistrationInfo() {
const info = {
secret: crypto.randomUUID(),
registered: false,
};
return info;
}
function register() {
return new Promise((resolve, reject) => {
const registerUrl = main.getBackend() + "/api/register";
// TODO: replace xhr with Fetch #2261
const req = new XMLHttpRequest();
req.open("POST", registerUrl);
req.setRequestHeader("content-type", "application/json");
req.onload = catcher.watchFunction(() => {
if (req.status === 200) {
log.info("Registered login");
initialized = true;
saveAuthInfo(JSON.parse(req.responseText));
resolve(true);
} else {
log.warn("Error in response:", req.responseText);
const exc = new Error("Bad response: " + req.status);
exc.popupMessage = "LOGIN_ERROR";
reject(exc);
}
});
req.onerror = catcher.watchFunction(() => {
const exc = new Error("Error contacting server");
exc.popupMessage = "LOGIN_CONNECTION_ERROR";
reject(exc);
});
req.send(
JSON.stringify({
secret: registrationInfo.secret,
deviceInfo: JSON.stringify(deviceInfo()),
})
);
});
}
function login(options) {
const { ownershipCheck, noRegister } = options || {};
return new Promise((resolve, reject) => {
return fetchStoredInfo.then(() => {
if (!registrationInfo) {
registrationInfo = generateRegistrationInfo();
log.info("Generating new device authentication ID", registrationInfo);
browser.storage.local.set({ registrationInfo });
}
const loginUrl = main.getBackend() + "/api/login";
// TODO: replace xhr with Fetch #2261
const req = new XMLHttpRequest();
req.open("POST", loginUrl);
req.onload = catcher.watchFunction(() => {
if (req.status === 404) {
if (noRegister) {
resolve(false);
} else {
resolve(register());
}
} else if (req.status >= 300) {
log.warn("Error in response:", req.responseText);
const exc = new Error("Could not log in: " + req.status);
exc.popupMessage = "LOGIN_ERROR";
reject(exc);
} else if (req.status === 0) {
const error = new Error("Could not log in, server unavailable");
error.popupMessage = "LOGIN_CONNECTION_ERROR";
reject(error);
} else {
initialized = true;
const jsonResponse = JSON.parse(req.responseText);
log.info("Screenshots logged in");
saveAuthInfo(jsonResponse);
if (ownershipCheck) {
resolve({ isOwner: jsonResponse.isOwner });
} else {
resolve(true);
}
}
});
req.onerror = catcher.watchFunction(() => {
const exc = new Error("Connection failed");
exc.url = loginUrl;
exc.popupMessage = "CONNECTION_ERROR";
reject(exc);
});
req.setRequestHeader("content-type", "application/json");
req.send(
JSON.stringify({
secret: registrationInfo.secret,
deviceInfo: JSON.stringify(deviceInfo()),
ownershipCheck,
})
);
});
});
}
function saveAuthInfo(responseJson) {
accountId = responseJson.accountId;
if (responseJson.sentryPublicDSN) {
sentryPublicDSN = responseJson.sentryPublicDSN;
}
if (responseJson.authHeader) {
authHeader = responseJson.authHeader;
if (!registrationInfo.registered) {
registrationInfo.registered = true;
catcher.watchPromise(browser.storage.local.set({ registrationInfo }));
}
}
if (responseJson.abTests) {
abTests = responseJson.abTests;
catcher.watchPromise(browser.storage.local.set({ abTests }));
}
}
exports.maybeLogin = function() {
if (!registrationInfo) {
return Promise.resolve();
}
return exports.authHeaders();
};
exports.authHeaders = function() {
let initPromise = Promise.resolve();
if (!initialized) {
initPromise = login();
}
return initPromise.then(() => {
if (authHeader) {
return { "x-screenshots-auth": authHeader };
}
log.warn("No auth header available");
return {};
});
};
exports.getSentryPublicDSN = function() {
return sentryPublicDSN;
};
exports.getAbTests = function() {
return abTests;
};
exports.isRegistered = function() {
return registrationInfo && registrationInfo.registered;
};
communication.register("getAuthInfo", (sender, ownershipCheck) => {
return fetchStoredInfo.then(() => {
// If a device id was never generated, report back accordingly.
if (!registrationInfo) {
return null;
}
return exports.authHeaders().then(authHeaders => {
let info = registrationInfo;
if (info.registered) {
return login({ ownershipCheck }).then(result => {
return {
isOwner: result && result.isOwner,
accountId,
authHeaders,
};
});
}
info = Object.assign({ authHeaders }, info);
return info;
});
});
});
return exports;
})();

View file

@ -2,7 +2,7 @@
* 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/. */
/* globals browser, getStrings, selectorLoader, analytics, communication, catcher, log, auth, senderror, startBackground, blobConverters, startSelectionWithOnboarding */
/* globals browser, getStrings, selectorLoader, analytics, communication, catcher, log, senderror, startBackground, blobConverters, startSelectionWithOnboarding */
"use strict";

View file

@ -2,15 +2,13 @@
* 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/. */
/* globals startBackground, analytics, communication, Raven, catcher, auth, log, browser, getStrings */
/* globals startBackground, analytics, communication, catcher, log, browser, getStrings */
"use strict";
this.senderror = (function() {
const exports = {};
const manifest = browser.runtime.getManifest();
// Do not show an error more than every ERROR_TIME_LIMIT milliseconds:
const ERROR_TIME_LIMIT = 3000;
@ -101,13 +99,6 @@ this.senderror = (function() {
log.error("Telemetry disabled. Not sending critical error:", e);
return;
}
const dsn = auth.getSentryPublicDSN();
if (!dsn) {
return;
}
if (!Raven.isSetup()) {
Raven.config(dsn, { allowSecretKey: true }).install();
}
const exception = new Error(e.message);
exception.stack = e.multilineStack || e.stack || undefined;
@ -138,13 +129,6 @@ this.senderror = (function() {
}
}
rest.stack = exception.stack;
Raven.captureException(exception, {
logger: "addon",
tags: { category: e.popupMessage },
release: manifest.version,
message: exception.message,
extra: rest,
});
};
catcher.registerHandler(errorObj => {

View file

@ -51,9 +51,7 @@ this.startBackground = (function() {
"blobConverters.js",
"background/selectorLoader.js",
"background/communication.js",
"background/auth.js",
"background/senderror.js",
"build/raven.js",
"build/shot.js",
"build/thumbnailGenerator.js",
"background/analytics.js",

View file

@ -2,7 +2,7 @@
* 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/. */
/* globals browser, communication, getZoomFactor, shot, main, auth, catcher, analytics, blobConverters, thumbnailGenerator */
/* globals browser, communication, getZoomFactor, shot, main, catcher, analytics, blobConverters, thumbnailGenerator */
"use strict";

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,6 @@ FINAL_TARGET_FILES.features["screenshots@mozilla.org"] += [
FINAL_TARGET_FILES.features["screenshots@mozilla.org"]["background"] += [
"background/analytics.js",
"background/auth.js",
"background/communication.js",
"background/deviceInfo.js",
"background/main.js",
@ -38,7 +37,6 @@ FINAL_TARGET_FILES.features["screenshots@mozilla.org"]["background"] += [
FINAL_TARGET_FILES.features["screenshots@mozilla.org"]["build"] += [
"build/inlineSelectionCss.js",
"build/raven.js",
"build/selection.js",
"build/shot.js",
"build/thumbnailGenerator.js",

View file

@ -9,10 +9,6 @@
"use strict";
this.sitehelper = (function() {
// This gives us the content's copy of XMLHttpRequest, instead of the wrapped
// copy that this content script gets:
const ContentXMLHttpRequest = content.XMLHttpRequest;
catcher.registerHandler(errorObj => {
callBackground("reportError", errorObj);
});
@ -32,40 +28,6 @@ this.sitehelper = (function() {
document.dispatchEvent(new CustomEvent(name, { detail }));
}
/** Set the cookie, even if third-party cookies are disabled in this browser
(when they are disabled, login from the background page won't set cookies) */
function sendBackupCookieRequest(authHeaders) {
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1295660
// This bug would allow us to access window.content.XMLHttpRequest, and get
// a safer (not overridable by content) version of the object.
// This is a very minimal attempt to verify that the XMLHttpRequest object we got
// is legitimate. It is not a good test.
if (
Object.toString.apply(ContentXMLHttpRequest) !==
"function XMLHttpRequest() {\n [native code]\n}"
) {
console.warn("Insecure copy of XMLHttpRequest");
return;
}
const req = new ContentXMLHttpRequest();
req.open("POST", "/api/set-login-cookie");
for (const name in authHeaders) {
req.setRequestHeader(name, authHeaders[name]);
}
req.send("");
req.onload = () => {
if (req.status !== 200) {
console.warn(
"Attempt to set Screenshots cookie via /api/set-login-cookie failed:",
req.status,
req.statusText,
req.responseText
);
}
};
}
registerListener(
"delete-everything",
catcher.watchFunction(event => {
@ -73,25 +35,6 @@ this.sitehelper = (function() {
}, false)
);
registerListener(
"request-login",
catcher.watchFunction(event => {
const shotId = event.detail;
catcher.watchPromise(
callBackground("getAuthInfo", shotId || null).then(info => {
if (info) {
sendBackupCookieRequest(info.authHeaders);
sendCustomEvent("login-successful", {
accountId: info.accountId,
isOwner: info.isOwner,
backupCookieRequest: true,
});
}
})
);
})
);
registerListener(
"copy-to-clipboard",
catcher.watchFunction(event => {

View file

@ -321,7 +321,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "e5903e5aa5a3b9a35904075a525046ab5ad22aac"
"revision": "e01061abc6ab45f262b1f1ac299a57e7baa3ea6c"
},
"cy": {
"pin": false,
@ -339,7 +339,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "e46146d1d75fdf8c115c5addaecfa3249886a6a3"
"revision": "4eda4b2c9006f58705c2c48dbce7670c8362a75e"
},
"da": {
"pin": false,
@ -393,7 +393,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "ec31ac9f5d952ff06b5373c39dff01578cd1ebc2"
"revision": "fef470633391ed593758dfcdd50291eebfc35901"
},
"el": {
"pin": false,
@ -627,7 +627,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "7e19483c239bd713636a427a01bda65792e59def"
"revision": "2c4857dcfd49fd48d181e5f4ad71ad00ca94e29a"
},
"fr": {
"pin": false,
@ -645,7 +645,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "ef8d8783a939cb9b7d6c6725d018f19c176bbede"
"revision": "74a283448feb3a403d9fb742482b2217d05f6b91"
},
"fy-NL": {
"pin": false,
@ -663,7 +663,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "4d3f4cbce3958d765f213d4844b58c767a0827aa"
"revision": "4acc49b393a8d7924f1ebff0084af8452fcb37c1"
},
"ga-IE": {
"pin": false,
@ -735,7 +735,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "62fb5781adc823cc85199f9b7392f79971842167"
"revision": "b63fc77fa8a77d85975b2dd770c28542c092c644"
},
"gu-IN": {
"pin": false,
@ -825,7 +825,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "4e0e29d71d34a3170d6b827d6f58f023706f2247"
"revision": "aece2b7b4617114a5e79b418625b2b5a8cff81a8"
},
"hu": {
"pin": false,
@ -843,7 +843,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "a1f7e6b97ff7960b2998bd8b38e24273b43a4a4e"
"revision": "c2747df327b2aab392f70339efa1690e89978117"
},
"hy-AM": {
"pin": false,
@ -879,7 +879,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "8578eec469ca9369f292e30b82f5489f2a0435ec"
"revision": "840df2d0e1a37e8362598395e8e5b58f332fd519"
},
"ia": {
"pin": false,
@ -1317,7 +1317,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c98a12ea103a6f9b049a01110994943516a25721"
"revision": "fc3e36ce8db7e5c480f499efbb3e4b16ee320d59"
},
"nn-NO": {
"pin": false,
@ -1605,7 +1605,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "42026e4d19543344c8b5360e6523504164fb0a83"
"revision": "2c631ba6ab39c7b492c4e89019862d71afc4d98d"
},
"son": {
"pin": false,
@ -1749,7 +1749,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "8e871ebbf70026393d6b35b6a33434ecc4b2c065"
"revision": "73709e6fd2af93cb4d6a355c6f184d462fbff4a8"
},
"th": {
"pin": false,
@ -1767,7 +1767,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "8480cb6ec66c345881f958ee5559d960ff2562e3"
"revision": "a35e32face647327153b7ac9abf9c80294514a82"
},
"tl": {
"pin": false,
@ -1803,7 +1803,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "193c8b82478c1f8ac46ebed1371b5b67232514cd"
"revision": "68e0afd7c7342fb2550f0e94f551be1d0f4d8339"
},
"trs": {
"pin": false,
@ -1893,7 +1893,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "7a25bfbd29054b65289e20ee11b30ac5d9be3271"
"revision": "c3d81a82a79c226bcb9265beb78d180e1322e3d2"
},
"wo": {
"pin": false,

View file

@ -973,3 +973,32 @@
fun:_ZN9webrender8renderer8Renderer20update_texture_cache*
fun:_ZN9webrender8renderer8Renderer11render_impl*
}
# Suppression for a dynamic-atom leak apparently related to shutdown timing/race. See bug 1748520.
#
# 20 bytes in 1 blocks are definitely lost in loss record 3,754 of 20,244
# at 0x48397B5: malloc+117 (vg_replace_malloc.c:381)
# by 0x12CD30: moz_xmalloc+16 (checkouts/gecko/memory/mozalloc/mozalloc.cpp:52)
# by 0xAEE7F3C: nsDynamicAtom::Create(nsTSubstring<char16_t> const&, unsigned int)+140 (checkouts/gecko/xpcom/ds/nsAtomTable.cpp:90)
# by 0xAEE8DC9: nsAtomTable::Atomize(nsTSubstring<char> const&)+265 (checkouts/gecko/xpcom/ds/nsAtomTable.cpp:566)
# by 0xAFD5857: nsLanguageAtomService::LookupLanguage(nsTSubstring<char> const&)+87 (checkouts/gecko/intl/locale/nsLanguageAtomService.cpp:102)
# by 0xBCE209E: gfxFcPlatformFontList::TryLangForGroup(nsTSubstring<char> const&, nsAtom*, nsTSubstring<char>&, bool)+382 (checkouts/gecko/gfx/thebes/gfxFcPlatformFontList.cpp:2504)
# by 0xBCDD57E: gfxFcPlatformFontList::GetSampleLangForGroup(nsAtom*, nsTSubstring<char>&, bool)+734 (checkouts/gecko/gfx/thebes/gfxFcPlatformFontList.cpp:2569)
# by 0xBCE03A1: gfxFcPlatformFontList::FindGenericFamilies(nsPresContext*, nsTString<char> const&, nsAtom*)+113 (checkouts/gecko/gfx/thebes/gfxFcPlatformFontList.cpp:2299)
# by 0xBCE02F4: gfxFcPlatformFontList::GetDefaultFontForPlatform(nsPresContext*, gfxFontStyle const*, nsAtom*)+68 (checkouts/gecko/gfx/thebes/gfxFcPlatformFontList.cpp:1991)
# by 0xBD2E807: gfxPlatformFontList::GetDefaultFont(nsPresContext*, gfxFontStyle const*)+39 (checkouts/gecko/gfx/thebes/gfxPlatformFontList.cpp:2319)
# by 0xBD2CBBF: gfxPlatformFontList::InitFontList()+1279 (checkouts/gecko/gfx/thebes/gfxPlatformFontList.cpp:573)
# by 0xBD2C5C8: gfxPlatformFontList::Initialize(gfxPlatformFontList*)+72 (checkouts/gecko/gfx/thebes/gfxPlatformFontList.cpp:259)
# by 0xBCE8F8E: gfxPlatform::Init()+3070 (checkouts/gecko/gfx/thebes/gfxPlatform.cpp:963)
{
Bug 1748520
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:moz_xmalloc
fun:_ZN13nsDynamicAtom6Create*
fun:_ZN11nsAtomTable7Atomize*
fun:_ZN21nsLanguageAtomService14LookupLanguage*
...
fun:_ZN11gfxPlatform4InitEv
}

View file

@ -76,18 +76,17 @@ already_AddRefed<NullPrincipal> NullPrincipal::CreateWithoutOriginAttributes() {
return NullPrincipal::Create(OriginAttributes(), nullptr);
}
static void EscapePrecursorQuery(nsACString& aPrecursorQuery) {
void NullPrincipal::EscapePrecursorQuery(nsACString& aPrecursorQuery) {
// origins should not contain existing escape sequences, so set `esc_Forced`
// to force any `%` in the input to be escaped in addition to non-ascii,
// control characters and DEL.
nsCString modified;
if (NS_EscapeURLSpan(aPrecursorQuery, esc_OnlyNonASCII | esc_Forced,
modified)) {
if (NS_EscapeURLSpan(aPrecursorQuery, esc_Query | esc_Forced, modified)) {
aPrecursorQuery.Assign(std::move(modified));
}
}
static void UnescapePrecursorQuery(nsACString& aPrecursorQuery) {
void NullPrincipal::UnescapePrecursorQuery(nsACString& aPrecursorQuery) {
nsCString modified;
if (NS_UnescapeURL(aPrecursorQuery.BeginReading(), aPrecursorQuery.Length(),
/* aFlags */ 0, modified)) {

View file

@ -116,6 +116,10 @@ class NullPrincipal final : public BasePrincipal {
private:
FRIEND_TEST(OriginAttributes, NullPrincipal);
FRIEND_TEST(NullPrincipalPrecursor, EscapingRoundTrips);
static void EscapePrecursorQuery(nsACString& aPrecursorQuery);
static void UnescapePrecursorQuery(nsACString& aPrecursorQuery);
// If aIsFirstParty is true, this NullPrincipal will be initialized based on
// the aOriginAttributes with FirstPartyDomain set to a unique value. This

View file

@ -0,0 +1,55 @@
/* 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/. */
#include "gtest/gtest.h"
#include "mozilla/NullPrincipal.h"
#include "nsIURIMutator.h"
#include "nsPrintfCString.h"
namespace mozilla {
TEST(NullPrincipalPrecursor, EscapingRoundTrips)
{
nsTArray<nsCString> inputs;
inputs.AppendElements(mozilla::Span(std::array{
"mailbox:///dev/shm/tmp5wkt9ff_.mozrunner/Mail/Local%20Folders/secure-mail?number=5"_ns,
}));
// Add a string for every ASCII byte both escaped and unescaped.
for (uint8_t c = 0; c < 128; ++c) {
inputs.AppendElement(nsPrintfCString("%02X: %c", c, (char)c));
inputs.AppendElement(nsPrintfCString("%02X: %%%02X", c, c));
}
nsID dummyID{0xddf15eaf,
0x3837,
0x4678,
{0x80, 0x3b, 0x86, 0x86, 0xe8, 0x17, 0x66, 0x71}};
nsCOMPtr<nsIURI> baseURI = NullPrincipal::CreateURI(nullptr, &dummyID);
ASSERT_TRUE(baseURI);
for (auto& input : inputs) {
// First build an escaped version of the input string using
// `EscapePrecursorQuery`.
nsCString escaped(input);
NullPrincipal::EscapePrecursorQuery(escaped);
// Make sure that this escaped URI round-trips through a `moz-nullprincipal`
// URI's query without any additional escapes.
nsCOMPtr<nsIURI> clone;
EXPECT_TRUE(
NS_SUCCEEDED(NS_MutateURI(baseURI).SetQuery(escaped).Finalize(clone)));
nsCString query;
EXPECT_TRUE(NS_SUCCEEDED(clone->GetQuery(query)));
EXPECT_EQ(escaped, query);
// Try to unescape our escaped URI and make sure we recover the input
// string.
nsCString unescaped(escaped);
NullPrincipal::UnescapePrecursorQuery(unescaped);
EXPECT_EQ(input, unescaped);
}
}
} // namespace mozilla

View file

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
"TestNullPrincipalPrecursor.cpp",
"TestOriginAttributes.cpp",
"TestPrincipalAttributes.cpp",
"TestPrincipalSerialization.cpp",

View file

@ -766,7 +766,6 @@ system_headers = [
'SIOUX.h',
'size_t.h',
'smime.h',
'sndio.h',
'someincludefile.h',
'soundcard.h',
'Sound.h',
@ -1244,6 +1243,11 @@ if CONFIG['MOZ_JACK']:
'jack/statistics.h',
]
if CONFIG['MOZ_SNDIO']:
system_headers += [
'sndio.h',
]
if CONFIG['MOZ_SYSTEM_JPEG']:
system_headers += [
'jpeglib.h',

View file

@ -233,13 +233,6 @@ skip-if =
(os == 'linux' && (ccov || (!swgl && debug)))
os == "linux" && bits == 64 && debug # Bug 1732486
[browser_dbg-worker-scopes.js]
skip-if =
os == 'linux' && debug # Bug 1456013
ccov # Bug 1456013
os == 'linux' && asan # Bug 1559547
os == 'mac' # Bug 1607321
os == 'win' && os_version == '10.0' && bits == 64 # Bug 1607321
os == 'linux' && bits == 64 && !debug # Bug 1759502
[browser_dbg-event-handler.js]
[browser_dbg-event-breakpoints-fission.js]
[browser_dbg-event-breakpoints.js]

View file

@ -10,16 +10,13 @@ PromiseTestUtils.allowMatchingRejectionsGlobally(/Connection closed/);
// Test that unusual objects have their contents shown in worker thread scopes.
add_task(async function() {
const dbg = await initDebugger("doc-worker-scopes.html", "scopes-worker.js");
const workerSource = findSource(dbg, "scopes-worker.js");
await addBreakpoint(dbg, workerSource, 11);
await selectSource(dbg, "scopes-worker.js");
await addBreakpointViaGutter(dbg, 11);
await dbg.toolbox.target.waitForRequestsToSettle();
invokeInTab("startWorker");
await waitForPaused(dbg, "scopes-worker.js");
const onRemoved = waitForDispatch(dbg.store, "REMOVE_BREAKPOINT");
await removeBreakpoint(dbg, workerSource.id, 11);
await onRemoved;
await removeBreakpointViaGutter(dbg, 11);
// We should be paused at the first line of simple-worker.js
const workerSource2 = dbg.selectors.getSelectedSource();
assertPausedAtSourceAndLine(dbg, workerSource2.id, 11);
@ -97,3 +94,9 @@ function findNodeValue(dbg, text) {
}
}
}
async function removeBreakpointViaGutter(dbg, line) {
const onRemoved = waitForDispatch(dbg.store, "REMOVE_BREAKPOINT");
await clickGutter(dbg, line);
await onRemoved;
}

View file

@ -22,7 +22,7 @@ add_task(async function() {
private: true,
});
ok(PrivateBrowsingUtils.isWindowPrivate(privateWindow), "window is private");
const privateTab = await addTab(TEST_URL, privateWindow);
const privateTab = await addTab(TEST_URL, { window: privateWindow });
await openStoragePanel({ tab: privateTab });
await performAdd(["cookies", "http://test1.example.org"]);
await performAdd(["cookies", "http://test1.example.org"]);

File diff suppressed because one or more lines are too long

View file

@ -108,10 +108,6 @@ void BaseHistory::RegisterVisitedCallback(nsIURI* aURI, Link* aLink) {
// This will not catch a case where it is registered for two different URIs.
MOZ_DIAGNOSTIC_ASSERT(!links->mLinks.Contains(aLink),
"Already tracking this Link object!");
// FIXME(emilio): We should consider changing this (see the entry.Remove()
// call in NotifyVisitedInThisProcess).
MOZ_DIAGNOSTIC_ASSERT(links->mStatus != VisitedStatus::Visited,
"We don't keep tracking known-visited links");
links->mLinks.AppendElement(aLink);
@ -199,15 +195,6 @@ void BaseHistory::NotifyVisitedInThisProcess(nsIURI* aURI,
for (Link* link : links.mLinks.BackwardRange()) {
link->VisitedQueryFinished(visited);
}
// We never go from visited -> unvisited.
//
// FIXME(emilio): It seems unfortunate to remove a link to a visited uri and
// then re-add it to the document to trigger a new visited query. It shouldn't
// if we keep track of mStatus.
if (visited) {
entry.Remove();
}
}
void BaseHistory::SendPendingVisitedResultsToChildProcesses() {

View file

@ -113,6 +113,7 @@
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "mozilla/dom/Document.h"
#include "nsHTMLDocument.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIDOMWindow.h"
#include "nsIEditingSession.h"
@ -1655,91 +1656,132 @@ nsDocShell::ForceEncodingDetection() {
mForcedAutodetection = true;
LOGCHARSETMENU(("ENCODING_OVERRIDE_USED_AUTOMATIC"));
Telemetry::ScalarSet(Telemetry::ScalarID::ENCODING_OVERRIDE_USED_AUTOMATIC,
true);
nsIURI* url = doc->GetOriginalURI();
bool isFileURL = url && SchemeIsFile(url);
int32_t charsetSource = doc->GetDocumentCharacterSetSource();
auto encoding = doc->GetDocumentCharacterSet();
switch (charsetSource) {
case kCharsetFromInitialUserForcedAutoDetection:
case kCharsetFromFinalUserForcedAutoDetection:
LOGCHARSETMENU(("AutoOverridden"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::AutoOverridden);
break;
case kCharsetFromInitialAutoDetectionASCII:
// Deliberately no final version
LOGCHARSETMENU(("UnlabeledAscii"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::UnlabeledAscii);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
LOGCHARSETMENU(("UnlabeledNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::UnlabeledNonUtf8);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
LOGCHARSETMENU(("UnlabeledNonUtf8TLD"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::UnlabeledNonUtf8TLD);
break;
case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8:
LOGCHARSETMENU(("UnlabeledUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::UnlabeledUtf8);
break;
case kCharsetFromChannel:
if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("ChannelUtf8"));
// AsHTMLDocument is valid, because we called
// WillIgnoreCharsetOverride() above.
if (doc->AsHTMLDocument()->IsPlainText()) {
switch (charsetSource) {
case kCharsetFromInitialAutoDetectionASCII:
// Deliberately no final version
LOGCHARSETMENU(("TEXT:UnlabeledAscii"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::ChannelUtf8);
} else {
LOGCHARSETMENU(("ChannelNonUtf8"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::UnlabeledAscii);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::ChannelNonUtf8);
}
break;
case kCharsetFromXmlDeclaration:
case kCharsetFromMetaTag:
if (isFileURL) {
LOGCHARSETMENU(("LocalLabeled"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::
UnlabeledNonUtf8);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8TLD"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::LocalLabeled);
} else if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("MetaUtf8"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::
UnlabeledNonUtf8TLD);
break;
case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::MetaUtf8);
} else {
LOGCHARSETMENU(("MetaNonUtf8"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::UnlabeledUtf8);
break;
case kCharsetFromChannel:
if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("TEXT:ChannelUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::ChannelUtf8);
} else {
LOGCHARSETMENU(("TEXT:ChannelNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::
ChannelNonUtf8);
}
break;
default:
LOGCHARSETMENU(("TEXT:Bug"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::MetaNonUtf8);
}
break;
case kCharsetFromFinalAutoDetectionFile:
if (isFileURL) {
LOGCHARSETMENU(("LocalUnlabeled"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_TEXT::Bug);
break;
}
} else {
switch (charsetSource) {
case kCharsetFromInitialAutoDetectionASCII:
// Deliberately no final version
LOGCHARSETMENU(("HTML:UnlabeledAscii"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::LocalUnlabeled);
} else {
LOGCHARSETMENU(("Bug"));
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::UnlabeledAscii);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::Bug);
}
break;
default:
LOGCHARSETMENU(("Bug"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_2::Bug);
break;
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::
UnlabeledNonUtf8);
break;
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledNonUtf8TLD"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::
UnlabeledNonUtf8TLD);
break;
case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::UnlabeledUtf8);
break;
case kCharsetFromChannel:
if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("HTML:ChannelUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::ChannelUtf8);
} else {
LOGCHARSETMENU(("HTML:ChannelNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::
ChannelNonUtf8);
}
break;
case kCharsetFromXmlDeclaration:
case kCharsetFromMetaTag:
if (isFileURL) {
LOGCHARSETMENU(("HTML:LocalLabeled"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::LocalLabeled);
} else if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("HTML:MetaUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::InternalUtf8);
} else {
LOGCHARSETMENU(("HTML:MetaNonUtf8"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::
InternalNonUtf8);
}
break;
default:
LOGCHARSETMENU(("HTML:Bug"));
Telemetry::AccumulateCategorical(
Telemetry::LABELS_ENCODING_OVERRIDE_SITUATION_HTML::Bug);
break;
}
}
return NS_OK;
}

View file

@ -49,6 +49,8 @@ DocumentTimeline::DocumentTimeline(Document* aDocument,
if (mDocument) {
mDocument->Timelines().insertBack(this);
}
// Ensure mLastRefreshDriverTime is valid.
UpdateLastRefreshDriverTime();
}
DocumentTimeline::~DocumentTimeline() {
@ -97,6 +99,12 @@ bool DocumentTimeline::TracksWallclockTime() const {
}
TimeStamp DocumentTimeline::GetCurrentTimeStamp() const {
nsRefreshDriver* refreshDriver = GetRefreshDriver();
return refreshDriver ? refreshDriver->MostRecentRefresh()
: mLastRefreshDriverTime;
}
void DocumentTimeline::UpdateLastRefreshDriverTime() {
nsRefreshDriver* refreshDriver = GetRefreshDriver();
TimeStamp refreshTime =
refreshDriver ? refreshDriver->MostRecentRefresh() : TimeStamp();
@ -125,8 +133,6 @@ TimeStamp DocumentTimeline::GetCurrentTimeStamp() const {
if (!refreshTime.IsNull()) {
mLastRefreshDriverTime = refreshTime;
}
return result;
}
Nullable<TimeDuration> DocumentTimeline::ToTimelineTime(
@ -182,6 +188,7 @@ void DocumentTimeline::MostRecentRefreshTimeUpdated() {
}
void DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime) {
UpdateLastRefreshDriverTime();
MostRecentRefreshTimeUpdated();
}

View file

@ -68,6 +68,8 @@ class DocumentTimeline final : public AnimationTimeline,
Document* GetDocument() const override { return mDocument; }
void UpdateLastRefreshDriverTime();
bool IsMonotonicallyIncreasing() const override { return true; }
protected:
@ -83,7 +85,7 @@ class DocumentTimeline final : public AnimationTimeline,
// The most recently used refresh driver time. This is used in cases where
// we don't have a refresh driver (e.g. because we are in a display:none
// iframe).
mutable TimeStamp mLastRefreshDriverTime;
TimeStamp mLastRefreshDriverTime;
bool mIsObservingRefreshDriver;
TimeDuration mOriginTime;

View file

@ -579,8 +579,8 @@ void DOMIntersectionObserver::Update(Document* aDocument,
for (const auto side : mozilla::AllPhysicalSides()) {
nscoord basis = side == eSideTop || side == eSideBottom ? rootRect.Height()
: rootRect.Width();
rootMargin.Side(side) =
mRootMargin.Get(side).Resolve(basis, NSToCoordRoundWithClamp);
rootMargin.Side(side) = mRootMargin.Get(side).Resolve(
basis, static_cast<nscoord (*)(float)>(NSToCoordRoundWithClamp));
}
// 2. For each target in observers internal [[ObservationTargets]] slot,

View file

@ -13236,6 +13236,13 @@ void Document::SetNavigationTiming(nsDOMNavigationTiming* aTiming) {
if (!mLoadingTimeStamp.IsNull() && mTiming) {
mTiming->SetDOMLoadingTimeStamp(GetDocumentURI(), mLoadingTimeStamp);
}
// If there's already the DocumentTimeline instance, tell it since the
// DocumentTimeline is based on both the navigation start time stamp and the
// refresh driver timestamp.
if (mDocumentTimeline) {
mDocumentTimeline->UpdateLastRefreshDriverTime();
}
}
nsContentList* Document::ImageMapList() {

View file

@ -60,25 +60,17 @@ bool Link::ElementHasHref() const {
void Link::VisitedQueryFinished(bool aVisited) {
MOZ_ASSERT(mRegistered, "Setting the link state of an unregistered Link!");
MOZ_ASSERT(mState == State::Unvisited,
"Why would we want to know our visited state otherwise?");
auto newState = aVisited ? State::Visited : State::Unvisited;
// Set our current state as appropriate.
mState = newState;
// We will be no longer registered if we're visited, as it'd be pointless, we
// never transition from visited -> unvisited.
if (aVisited) {
mRegistered = false;
}
MOZ_ASSERT(LinkState() == NS_EVENT_STATE_VISITED ||
LinkState() == NS_EVENT_STATE_UNVISITED,
"Unexpected state obtained from LinkState()!");
// Tell the element to update its visited state
// Tell the element to update its visited state.
mElement->UpdateState(true);
if (StaticPrefs::layout_css_always_repaint_on_unvisited()) {

View file

@ -7785,6 +7785,21 @@ already_AddRefed<nsGlobalWindowInner> nsGlobalWindowInner::Create(
return window.forget();
}
JS::loader::ModuleLoaderBase* nsGlobalWindowInner::GetModuleLoader(
JSContext* aCx) {
Document* document = GetDocument();
if (!document) {
return nullptr;
}
ScriptLoader* loader = document->ScriptLoader();
if (!loader) {
return nullptr;
}
return loader->GetModuleLoader();
}
nsIURI* nsPIDOMWindowInner::GetDocumentURI() const {
return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
}

View file

@ -1340,6 +1340,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
mStorageAllowedReasonCache = 0;
}
virtual JS::loader::ModuleLoaderBase* GetModuleLoader(
JSContext* aCx) override;
private:
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;

View file

@ -48,6 +48,12 @@ class ServiceWorkerRegistrationDescriptor;
} // namespace dom
} // namespace mozilla
namespace JS {
namespace loader {
class ModuleLoaderBase;
} // namespace loader
} // namespace JS
/**
* See <https://developer.mozilla.org/en-US/docs/Glossary/Global_object>.
*/
@ -242,6 +248,14 @@ class nsIGlobalObject : public nsISupports,
*/
virtual uint32_t GetPrincipalHashValue() const { return 0; }
/**
* Get the module loader to use for this global, if any. By default this
* returns null.
*/
virtual JS::loader::ModuleLoaderBase* GetModuleLoader(JSContext* aCx) {
return nullptr;
}
protected:
virtual ~nsIGlobalObject();

View file

@ -1174,7 +1174,7 @@ void FormatUsageAuthority::AllowSizedTexFormat(GLenum sizedFormat,
if (usage->format->compression) {
MOZ_ASSERT(usage->isFilterable, "Compressed formats should be filterable.");
} else {
MOZ_ASSERT(usage->validUnpacks.size() && usage->idealUnpack,
MOZ_ASSERT(!usage->validUnpacks.empty() && usage->idealUnpack,
"AddTexUnpack() first.");
}
@ -1186,7 +1186,7 @@ void FormatUsageAuthority::AllowSizedTexFormat(GLenum sizedFormat,
void FormatUsageAuthority::AllowUnsizedTexFormat(const PackingInfo& pi,
const FormatUsageInfo* usage) {
MOZ_ASSERT(!usage->format->compression);
MOZ_ASSERT(usage->validUnpacks.size() && usage->idealUnpack,
MOZ_ASSERT(!usage->validUnpacks.empty() && usage->idealUnpack,
"AddTexUnpack() first.");
AlwaysInsert(mUnsizedTexFormatMap, pi, usage);

View file

@ -312,7 +312,7 @@ class BlobURLsReporter final : public nsIMemoryReporter {
// GetCurrentJSStack() hand out the JSContext it found.
JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
for (uint32_t i = 0; frame; ++i) {
while (frame) {
nsString fileNameUTF16;
frame->GetFilename(cx, fileNameUTF16);

View file

@ -675,7 +675,7 @@ bool nsHTMLDocument::WillIgnoreCharsetOverride() {
case kCharsetFromDocTypeDefault:
case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8:
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
case kCharsetFromParentFrame:
case kCharsetFromXmlDeclaration:

View file

@ -8,6 +8,7 @@
# include "AndroidDecoderModule.h"
#endif
#include "mozilla/AppShutdown.h"
#include "mozilla/DebugOnly.h"
#include "base/basictypes.h"
@ -52,6 +53,7 @@
#include "mozilla/ipc/URIUtils.h"
#include "gfxPlatform.h"
#include "gfxPlatformFontList.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/BasePrincipal.h"
@ -613,10 +615,6 @@ UniquePtr<SandboxBrokerPolicyFactory>
UniquePtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
#endif
// This is true when subprocess launching is enabled. This is the
// case between StartUp() and ShutDown().
static bool sCanLaunchSubprocesses;
// Set to true when the first content process gets created.
static bool sCreatedFirstContentProcess = false;
@ -664,11 +662,8 @@ ContentParent::MakePreallocProcess() {
/*static*/
void ContentParent::StartUp() {
// We could launch sub processes from content process
// FIXME Bug 1023701 - Stop using ContentParent static methods in
// child process
sCanLaunchSubprocesses = true;
if (!XRE_IsParentProcess()) {
return;
}
@ -696,7 +691,6 @@ void ContentParent::StartUp() {
void ContentParent::ShutDown() {
// No-op for now. We rely on normal process shutdown and
// ClearOnShutdown() to clean up our state.
sCanLaunchSubprocesses = false;
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
sSandboxBrokerPolicyFactory = nullptr;
@ -1453,7 +1447,7 @@ already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
"BrowsingContext must not have BrowserParent, or have previous "
"BrowserParent cleared");
if (!sCanLaunchSubprocesses) {
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
return nullptr;
}
@ -1850,8 +1844,7 @@ void ContentParent::AssertNotInPool() {
MOZ_RELEASE_ASSERT(
!sBrowserContentParents ||
!sBrowserContentParents->Contains(mRemoteType) ||
!sBrowserContentParents->Get(mRemoteType)->Contains(this) ||
!sCanLaunchSubprocesses); // aka in shutdown - avoid timing issues
!sBrowserContentParents->Get(mRemoteType)->Contains(this));
for (const auto& group : mGroups) {
MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
@ -2488,9 +2481,13 @@ void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
NS_WARNING("Shutdown has begun, we won't spawn any more child processes.");
return false;
}
if (!ContentProcessManager::GetSingleton()) {
NS_WARNING(
"Shutdown has begun, we shouldn't spawn any more child processes");
MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
return false;
}
@ -3537,36 +3534,48 @@ static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
static void InitClients() {
if (!sXPCOMShutdownClient) {
if (!sXPCOMShutdownClient &&
!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
nsresult rv;
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
nsCOMPtr<nsIAsyncShutdownClient> client;
rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
sXPCOMShutdownClient = client.forget();
ClearOnShutdown(&sXPCOMShutdownClient);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), "XPCOMShutdown shutdown blocker");
if (NS_SUCCEEDED(rv)) {
sXPCOMShutdownClient = client.forget();
ClearOnShutdown(&sXPCOMShutdownClient);
}
MOZ_ASSERT(sXPCOMShutdownClient);
rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
sProfileBeforeChangeClient = client.forget();
ClearOnShutdown(&sProfileBeforeChangeClient);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
"profileBeforeChange shutdown blocker");
if (NS_SUCCEEDED(rv)) {
sProfileBeforeChangeClient = client.forget();
ClearOnShutdown(&sProfileBeforeChangeClient);
}
MOZ_ASSERT(sProfileBeforeChangeClient);
}
}
void ContentParent::AddShutdownBlockers() {
InitClients();
sXPCOMShutdownClient->AddBlocker(
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
sProfileBeforeChangeClient->AddBlocker(
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
if (sXPCOMShutdownClient) {
sXPCOMShutdownClient->AddBlocker(
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
}
if (sProfileBeforeChangeClient) {
sProfileBeforeChangeClient->AddBlocker(
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
}
}
void ContentParent::RemoveShutdownBlockers() {
Unused << sXPCOMShutdownClient->RemoveBlocker(this);
Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
if (sXPCOMShutdownClient) {
Unused << sXPCOMShutdownClient->RemoveBlocker(this);
}
if (sProfileBeforeChangeClient) {
Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
}
}
NS_IMETHODIMP

View file

@ -6,6 +6,7 @@
#include "ContentProcessManager.h"
#include "ContentParent.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
@ -24,7 +25,8 @@ StaticAutoPtr<ContentProcessManager> ContentProcessManager::sSingleton;
ContentProcessManager* ContentProcessManager::GetSingleton() {
MOZ_ASSERT(XRE_IsParentProcess());
if (!sSingleton) {
if (!sSingleton &&
!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal)) {
sSingleton = new ContentProcessManager();
ClearOnShutdown(&sSingleton);
}

View file

@ -136,24 +136,26 @@ void BaseMediaResource::SetLoadInBackground(bool aLoadInBackground) {
} else {
loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
}
ModifyLoadFlags(loadFlags);
rv = ModifyLoadFlags(loadFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "ModifyLoadFlags() failed!");
}
}
void BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags) {
nsresult BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags) {
nsCOMPtr<nsILoadGroup> loadGroup;
nsresult rv = mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
MOZ_ASSERT(NS_SUCCEEDED(rv), "GetLoadGroup() failed!");
nsresult status;
mChannel->GetStatus(&status);
bool inLoadGroup = false;
if (loadGroup) {
nsresult status;
mChannel->GetStatus(&status);
rv = loadGroup->RemoveRequest(mChannel, nullptr, status);
if (NS_SUCCEEDED(rv)) {
inLoadGroup = true;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
inLoadGroup = true;
}
rv = mChannel->SetLoadFlags(aFlags);
@ -163,6 +165,8 @@ void BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags) {
rv = loadGroup->AddRequest(mChannel, nullptr);
MOZ_ASSERT(NS_SUCCEEDED(rv), "AddRequest() failed!");
}
return NS_OK;
}
} // namespace mozilla

View file

@ -127,7 +127,7 @@ class BaseMediaResource : public MediaResource,
// Set the request's load flags to aFlags. If the request is part of a
// load group, the request is removed from the group, the flags are set, and
// then the request is added back to the load group.
void ModifyLoadFlags(nsLoadFlags aFlags);
nsresult ModifyLoadFlags(nsLoadFlags aFlags);
RefPtr<MediaResourceCallback> mCallback;

View file

@ -339,7 +339,7 @@ nsresult ChannelMediaResource::OnStopRequest(nsIRequest* aRequest,
NS_ASSERTION(NS_SUCCEEDED(rv), "GetLoadFlags() failed!");
if (loadFlags & nsIRequest::LOAD_BACKGROUND) {
ModifyLoadFlags(loadFlags & ~nsIRequest::LOAD_BACKGROUND);
Unused << NS_WARN_IF(NS_FAILED(ModifyLoadFlags(loadFlags & ~nsIRequest::LOAD_BACKGROUND)));
}
// Note that aStatus might have succeeded --- this might be a normal close

View file

@ -80,15 +80,15 @@ class GraphRunner final : public Runnable {
// Monitor used for yielding mThread through Wait(), and scheduling mThread
// through Signal() from a GraphDriver.
Monitor mMonitor MOZ_UNANNOTATED;
Monitor mMonitor;
// The MediaTrackGraph we're running. Weakptr beecause this graph owns us and
// guarantees that our lifetime will not go beyond that of itself.
MediaTrackGraphImpl* const mGraph;
// State being handed over to the graph through OneIteration. Protected by
// mMonitor.
Maybe<IterationState> mIterationState;
Maybe<IterationState> mIterationState GUARDED_BY(mMonitor);
// Result from mGraph's OneIteration. Protected by mMonitor.
IterationResult mIterationResult;
IterationResult mIterationResult GUARDED_BY(mMonitor);
enum class ThreadState {
Wait, // Waiting for a message. This is the initial state.
@ -100,7 +100,7 @@ class GraphRunner final : public Runnable {
};
// Protected by mMonitor until set to Shutdown, after which this is not
// modified.
ThreadState mThreadState;
ThreadState mThreadState GUARDED_BY(mMonitor);
// The thread running mGraph. Set on construction, after other members are
// initialized. Cleared at the end of Shutdown().

View file

@ -1382,7 +1382,16 @@ auto MediaTrackGraphImpl::OneIterationImpl(GraphTime aStateTime,
// thread, and so the monitor need not be held to check mLifecycleState.
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
// graphs that have not started.
// While changes occur on mainthread, this assert confirms that
// this code shouldn't run if mainthread might be changing the state (to
// > LIFECYCLE_RUNNING)
// Ignore mutex warning: static during execution of the graph
PUSH_IGNORE_THREAD_SAFETY
MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING);
POP_THREAD_SAFETY
MOZ_ASSERT(OnGraphThread());
WebCore::DenormalDisabler disabler;
@ -2570,7 +2579,8 @@ bool SourceMediaTrack::PullNewData(GraphTime aDesiredUpToTime) {
*/
static void MoveToSegment(SourceMediaTrack* aTrack, MediaSegment* aIn,
MediaSegment* aOut, TrackTime aCurrentTime,
TrackTime aDesiredUpToTime) {
TrackTime aDesiredUpToTime)
REQUIRES(aTrack->GetMutex()) {
MOZ_ASSERT(aIn->GetType() == aOut->GetType());
MOZ_ASSERT(aOut->GetDuration() >= aCurrentTime);
MOZ_ASSERT(aDesiredUpToTime >= aCurrentTime);

View file

@ -667,9 +667,9 @@ class SourceMediaTrack : public MediaTrack {
// The value set here is applied in MoveToSegment so we can avoid the
// buffering delay in applying the change. See Bug 1443511.
void SetVolume(float aVolume);
float GetVolumeLocked();
float GetVolumeLocked() REQUIRES(mMutex);
Mutex& GetMutex() { return mMutex; }
Mutex& GetMutex() RETURN_CAPABILITY(mMutex) { return mMutex; }
friend class MediaTrackGraphImpl;
@ -702,7 +702,7 @@ class SourceMediaTrack : public MediaTrack {
bool NeedsMixing();
void ResampleAudioToGraphSampleRate(MediaSegment* aSegment);
void ResampleAudioToGraphSampleRate(MediaSegment* aSegment) REQUIRES(mMutex);
void AddDirectListenerImpl(
already_AddRefed<DirectMediaTrackListener> aListener) override;
@ -714,7 +714,7 @@ class SourceMediaTrack : public MediaTrack {
* from AppendData on the thread providing the data, and will call
* the Listeners on this thread.
*/
void NotifyDirectConsumers(MediaSegment* aSegment);
void NotifyDirectConsumers(MediaSegment* aSegment) REQUIRES(mMutex);
void OnGraphThreadDone() override {
MutexAutoLock lock(mMutex);
@ -733,11 +733,12 @@ class SourceMediaTrack : public MediaTrack {
// This must be acquired *before* MediaTrackGraphImpl's lock, if they are
// held together.
Mutex mMutex MOZ_UNANNOTATED;
Mutex mMutex;
// protected by mMutex
float mVolume = 1.0;
UniquePtr<TrackData> mUpdateTrack;
nsTArray<RefPtr<DirectMediaTrackListener>> mDirectTrackListeners;
float mVolume GUARDED_BY(mMutex) = 1.0;
UniquePtr<TrackData> mUpdateTrack GUARDED_BY(mMutex);
nsTArray<RefPtr<DirectMediaTrackListener>> mDirectTrackListeners
GUARDED_BY(mMutex);
};
/**

View file

@ -167,7 +167,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
/**
* Called to apply a TrackUpdate to its track.
*/
void ApplyTrackUpdate(TrackUpdate* aUpdate);
void ApplyTrackUpdate(TrackUpdate* aUpdate) REQUIRES(mMonitor);
/**
* Append a ControlMessage to the message queue. This queue is drained
* during RunInStableState; the messages will run on the graph thread.
@ -258,12 +258,12 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* mMonitor must be held.
* See EnsureRunInStableState
*/
void EnsureStableStateEventPosted();
void EnsureStableStateEventPosted() REQUIRES(mMonitor);
/**
* Generate messages to the main thread to update it for all state changes.
* mMonitor must be held.
*/
void PrepareUpdatesToMainThreadState(bool aFinalUpdate);
void PrepareUpdatesToMainThreadState(bool aFinalUpdate) REQUIRES(mMonitor);
/**
* If we are rendering in non-realtime mode, we don't want to send messages to
* the main thread at each iteration for performance reasons. We instead
@ -297,7 +297,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
*/
void UpdateGraph(GraphTime aEndBlockingDecisions);
void SwapMessageQueues() {
void SwapMessageQueues() REQUIRES(mMonitor) {
MOZ_ASSERT(OnGraphThreadOrNotRunning());
mMonitor.AssertCurrentThreadOwns();
MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
@ -528,7 +528,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
/**
* Not safe to call off the MediaTrackGraph thread unless monitor is held!
*/
GraphDriver* CurrentDriver() const {
GraphDriver* CurrentDriver() const NO_THREAD_SAFETY_ANALYSIS {
#ifdef DEBUG
if (!OnGraphThreadOrNotRunning()) {
mMonitor.AssertCurrentThreadOwns();
@ -767,7 +767,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
// not safe to just grab mMonitor from some thread and start monkeying with
// the graph. Instead, communicate with the graph thread using provided
// mechanisms such as the ControlMessage queue.
Monitor mMonitor MOZ_UNANNOTATED;
Monitor mMonitor;
// Data guarded by mMonitor (must always be accessed with mMonitor held,
// regardless of the value of mLifecycleState).
@ -775,11 +775,11 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
/**
* State to copy to main thread
*/
nsTArray<TrackUpdate> mTrackUpdates;
nsTArray<TrackUpdate> mTrackUpdates GUARDED_BY(mMonitor);
/**
* Runnables to run after the next update to main thread state.
*/
nsTArray<nsCOMPtr<nsIRunnable>> mUpdateRunnables;
nsTArray<nsCOMPtr<nsIRunnable>> mUpdateRunnables GUARDED_BY(mMonitor);
/**
* A list of batches of messages to process. Each batch is processed
* as an atomic unit.
@ -793,10 +793,10 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* Message queue in which the main thread appends messages.
* Access guarded by mMonitor.
*/
nsTArray<MessageBlock> mBackMessageQueue;
nsTArray<MessageBlock> mBackMessageQueue GUARDED_BY(mMonitor);
/* True if there will messages to process if we swap the message queues. */
bool MessagesQueued() const {
bool MessagesQueued() const REQUIRES(mMonitor) {
mMonitor.AssertCurrentThreadOwns();
return !mBackMessageQueue.IsEmpty();
}
@ -850,8 +850,8 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP occur on the graph thread at
* the end of an iteration. All other transitions occur on the main thread.
*/
LifecycleState mLifecycleState;
LifecycleState& LifecycleStateRef() {
LifecycleState mLifecycleState GUARDED_BY(mMonitor);
LifecycleState& LifecycleStateRef() NO_THREAD_SAFETY_ANALYSIS {
#if DEBUG
if (mGraphDriverRunning) {
mMonitor.AssertCurrentThreadOwns();
@ -861,7 +861,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
#endif
return mLifecycleState;
}
const LifecycleState& LifecycleStateRef() const {
const LifecycleState& LifecycleStateRef() const NO_THREAD_SAFETY_ANALYSIS {
#if DEBUG
if (mGraphDriverRunning) {
mMonitor.AssertCurrentThreadOwns();
@ -887,7 +887,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* forced) has commenced. Set on the main thread under mMonitor and read on
* the graph thread under mMonitor.
**/
bool mInterruptJSCalled = false;
bool mInterruptJSCalled GUARDED_BY(mMonitor) = false;
/**
* Remove this blocker to unblock shutdown.
@ -900,7 +900,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* RunInStableState() and the event hasn't run yet.
* Accessed on both main and MTG thread, mMonitor must be held.
*/
bool mPostedRunInStableStateEvent;
bool mPostedRunInStableStateEvent GUARDED_BY(mMonitor);
/**
* The JSContext of the graph thread. Set under mMonitor on only the graph
@ -908,7 +908,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* the thread is about to exit. Read under mMonitor on the main thread to
* interrupt running JS for forced shutdown.
**/
JSContext* mJSContext = nullptr;
JSContext* mJSContext GUARDED_BY(mMonitor) = nullptr;
// Main thread only
@ -999,7 +999,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* Set based on mProcessedTime at end of iteration.
* Read by stable state runnable on main thread. Protected by mMonitor.
*/
GraphTime mNextMainThreadGraphTime = 0;
GraphTime mNextMainThreadGraphTime GUARDED_BY(mMonitor) = 0;
/**
* Cached audio output latency, in seconds. Main thread only. This is reset

View file

@ -21,17 +21,16 @@ static const int64_t gEndOffsets[] = {501, 772, 1244, 1380, 1543, 2015};
TEST(WebMBuffered, BasicTests)
{
ReentrantMonitor dummy MOZ_UNANNOTATED("dummy");
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
parser.Append(nullptr, 0, mapping, dummy);
parser.Append(nullptr, 0, mapping);
EXPECT_TRUE(mapping.IsEmpty());
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, 0);
unsigned char buf[] = {0x1a, 0x45, 0xdf, 0xa3};
parser.Append(buf, ArrayLength(buf), mapping, dummy);
parser.Append(buf, ArrayLength(buf), mapping);
EXPECT_TRUE(mapping.IsEmpty());
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, 4);
@ -60,14 +59,13 @@ static void ReadFile(const char* aPath, nsTArray<uint8_t>& aBuffer) {
TEST(WebMBuffered, RealData)
{
ReentrantMonitor dummy MOZ_UNANNOTATED("dummy");
WebMBufferedParser parser(0);
nsTArray<uint8_t> webmData;
ReadFile("test.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
parser.Append(webmData.Elements(), webmData.Length(), mapping, dummy);
parser.Append(webmData.Elements(), webmData.Length(), mapping);
EXPECT_EQ(mapping.Length(), 6u);
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length()));
@ -82,7 +80,6 @@ TEST(WebMBuffered, RealData)
TEST(WebMBuffered, RealDataAppend)
{
ReentrantMonitor dummy MOZ_UNANNOTATED("dummy");
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
@ -92,7 +89,7 @@ TEST(WebMBuffered, RealDataAppend)
uint32_t arrayEntries = mapping.Length();
size_t offset = 0;
while (offset < webmData.Length()) {
parser.Append(webmData.Elements() + offset, 1, mapping, dummy);
parser.Append(webmData.Elements() + offset, 1, mapping);
offset += 1;
EXPECT_EQ(parser.mCurrentOffset, int64_t(offset));
if (mapping.Length() != arrayEntries) {

View file

@ -116,9 +116,7 @@ class WebMContainerParser
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
ReentrantMonitor dummy MOZ_ANNOTATED("dummy");
bool result =
parser.Append(aData.Elements(), aData.Length(), mapping, dummy);
bool result = parser.Append(aData.Elements(), aData.Length(), mapping);
if (!result) {
return MediaResult(NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid webm content"));
@ -134,10 +132,8 @@ class WebMContainerParser
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
ReentrantMonitor dummy MOZ_ANNOTATED("dummy");
parser.AppendMediaSegmentOnly();
bool result =
parser.Append(aData.Elements(), aData.Length(), mapping, dummy);
bool result = parser.Append(aData.Elements(), aData.Length(), mapping);
if (!result) {
return MediaResult(NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid webm content"));
@ -182,8 +178,7 @@ class WebMContainerParser
nsTArray<WebMTimeDataOffset> mapping;
mapping.AppendElements(mOverlappedMapping);
mOverlappedMapping.Clear();
ReentrantMonitor dummy MOZ_ANNOTATED("dummy");
mParser.Append(aData.Elements(), aData.Length(), mapping, dummy);
mParser.Append(aData.Elements(), aData.Length(), mapping);
if (mResource) {
mResource->AppendData(aData);
}

View file

@ -180,8 +180,12 @@ FFmpegLibWrapper::LinkResult FFmpegLibWrapper::Link() {
AV_FUNC(av_buffer_create,
(AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 |
AV_FUNC_AVUTIL_58 | AV_FUNC_AVUTIL_59))
AV_FUNC_OPTION(av_frame_get_colorspace, AV_FUNC_AVUTIL_ALL)
AV_FUNC_OPTION(av_frame_get_color_range, AV_FUNC_AVUTIL_ALL)
AV_FUNC_OPTION(av_frame_get_colorspace,
AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 |
AV_FUNC_AVUTIL_58)
AV_FUNC_OPTION(av_frame_get_color_range,
AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 |
AV_FUNC_AVUTIL_58)
#ifdef MOZ_WAYLAND
AV_FUNC_OPTION_SILENT(avcodec_get_hw_config, AV_FUNC_58 | AV_FUNC_59)

View file

@ -570,6 +570,7 @@ FFmpegVideoDecoder<LIBAV_VER>::AllocateTextureClientForImage(
data.mColorRange = aCodecContext->color_range == AVCOL_RANGE_JPEG
? gfx::ColorRange::FULL
: gfx::ColorRange::LIMITED;
FFMPEG_LOGV(
"Created plane data, YSize=(%d, %d), CbCrSize=(%d, %d), "
"CroppedYSize=(%d, %d), CroppedCbCrSize=(%d, %d), ColorDepth=%hhu",
@ -805,7 +806,7 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
# ifdef MOZ_WAYLAND_USE_VAAPI
// Create VideoFramePool in case we need it.
if (!mVideoFramePool && mEnableHardwareDecoding) {
mVideoFramePool = MakeUnique<VideoFramePool>();
mVideoFramePool = MakeUnique<VideoFramePool<LIBAV_VER>>();
}
// Release unused VA-API surfaces before avcodec_receive_frame() as
@ -922,25 +923,43 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
}
gfx::YUVColorSpace FFmpegVideoDecoder<LIBAV_VER>::GetFrameColorSpace() const {
AVColorSpace colorSpace = AVCOL_SPC_UNSPECIFIED;
#if LIBAVCODEC_VERSION_MAJOR > 58
colorSpace = mFrame->colorspace;
#else
if (mLib->av_frame_get_colorspace) {
switch (mLib->av_frame_get_colorspace(mFrame)) {
#if LIBAVCODEC_VERSION_MAJOR >= 55
case AVCOL_SPC_BT2020_NCL:
case AVCOL_SPC_BT2020_CL:
return gfx::YUVColorSpace::BT2020;
#endif
case AVCOL_SPC_BT709:
return gfx::YUVColorSpace::BT709;
case AVCOL_SPC_SMPTE170M:
case AVCOL_SPC_BT470BG:
return gfx::YUVColorSpace::BT601;
case AVCOL_SPC_RGB:
return gfx::YUVColorSpace::Identity;
default:
break;
}
colorSpace = (AVColorSpace)mLib->av_frame_get_colorspace(mFrame);
}
return DefaultColorSpace({mFrame->width, mFrame->height});
#endif
switch (colorSpace) {
#if LIBAVCODEC_VERSION_MAJOR >= 55
case AVCOL_SPC_BT2020_NCL:
case AVCOL_SPC_BT2020_CL:
return gfx::YUVColorSpace::BT2020;
#endif
case AVCOL_SPC_BT709:
return gfx::YUVColorSpace::BT709;
case AVCOL_SPC_SMPTE170M:
case AVCOL_SPC_BT470BG:
return gfx::YUVColorSpace::BT601;
case AVCOL_SPC_RGB:
return gfx::YUVColorSpace::Identity;
default:
return DefaultColorSpace({mFrame->width, mFrame->height});
}
}
gfx::ColorRange FFmpegVideoDecoder<LIBAV_VER>::GetFrameColorRange() const {
AVColorRange range = AVCOL_RANGE_UNSPECIFIED;
#if LIBAVCODEC_VERSION_MAJOR > 58
range = mFrame->color_range;
#else
if (mLib->av_frame_get_color_range) {
range = (AVColorRange)mLib->av_frame_get_color_range(mFrame);
}
#endif
return range == AVCOL_RANGE_JPEG ? gfx::ColorRange::FULL
: gfx::ColorRange::LIMITED;
}
MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImage(
@ -1015,12 +1034,7 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImage(
#endif
}
b.mYUVColorSpace = GetFrameColorSpace();
if (mLib->av_frame_get_color_range) {
auto range = mLib->av_frame_get_color_range(mFrame);
b.mColorRange = range == AVCOL_RANGE_JPEG ? gfx::ColorRange::FULL
: gfx::ColorRange::LIMITED;
}
b.mColorRange = GetFrameColorRange();
RefPtr<VideoData> v;
#ifdef CUSTOMIZED_BUFFER_ALLOCATION
@ -1090,13 +1104,7 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImageVAAPI(
RESULT_DETAIL("VAAPI dmabuf allocation error"));
}
surface->SetYUVColorSpace(GetFrameColorSpace());
if (mLib->av_frame_get_color_range) {
auto range = mLib->av_frame_get_color_range(mFrame);
surface->SetColorRange(range == AVCOL_RANGE_JPEG
? gfx::ColorRange::FULL
: gfx::ColorRange::LIMITED);
}
surface->SetColorRange(GetFrameColorRange());
RefPtr<VideoData> vp = VideoData::CreateFromImage(
mInfo.mDisplay, aOffset, TimeUnit::FromMicroseconds(aPts),

View file

@ -16,6 +16,9 @@
#if LIBAVCODEC_VERSION_MAJOR >= 57 && LIBAVUTIL_VERSION_MAJOR >= 56
# include "mozilla/layers/TextureClient.h"
#endif
#ifdef MOZ_WAYLAND_USE_VAAPI
# include "FFmpegVideoFramePool.h"
#endif
struct _VADRMPRIMESurfaceDescriptor;
typedef struct _VADRMPRIMESurfaceDescriptor VADRMPRIMESurfaceDescriptor;
@ -23,7 +26,6 @@ typedef struct _VADRMPRIMESurfaceDescriptor VADRMPRIMESurfaceDescriptor;
namespace mozilla {
class ImageBufferWrapper;
class VideoFramePool;
template <int V>
class FFmpegVideoDecoder : public FFmpegDataDecoder<V> {};
@ -96,6 +98,7 @@ class FFmpegVideoDecoder<LIBAV_VER>
#endif
}
gfx::YUVColorSpace GetFrameColorSpace() const;
gfx::ColorRange GetFrameColorRange() const;
MediaResult CreateImage(int64_t aOffset, int64_t aPts, int64_t aDuration,
MediaDataDecoder::DecodedData& aResults) const;
@ -135,7 +138,7 @@ class FFmpegVideoDecoder<LIBAV_VER>
AVBufferRef* mVAAPIDeviceContext;
bool mEnableHardwareDecoding;
VADisplay mDisplay;
UniquePtr<VideoFramePool> mVideoFramePool;
UniquePtr<VideoFramePool<LIBAV_VER>> mVideoFramePool;
static nsTArray<AVCodecID> mAcceleratedFormats;
#endif
RefPtr<KnowsCompositor> mImageAllocator;

View file

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FFmpegVideoFramePool.h"
#include "PlatformDecoderModule.h"
#include "FFmpegLog.h"
#include "mozilla/widget/DMABufLibWrapper.h"
#include "libavutil/pixfmt.h"
@ -15,11 +16,11 @@
namespace mozilla {
RefPtr<layers::Image> VideoFrameSurfaceVAAPI::GetAsImage() {
RefPtr<layers::Image> VideoFrameSurface<LIBAV_VER>::GetAsImage() {
return new layers::DMABUFSurfaceImage(mSurface);
}
VideoFrameSurfaceVAAPI::VideoFrameSurfaceVAAPI(DMABufSurface* aSurface)
VideoFrameSurface<LIBAV_VER>::VideoFrameSurface(DMABufSurface* aSurface)
: mSurface(aSurface),
mLib(nullptr),
mAVHWDeviceContext(nullptr),
@ -30,22 +31,22 @@ VideoFrameSurfaceVAAPI::VideoFrameSurfaceVAAPI(DMABufSurface* aSurface)
MOZ_ASSERT(mSurface);
MOZ_RELEASE_ASSERT(mSurface->GetAsDMABufSurfaceYUV());
mSurface->GlobalRefCountCreate();
FFMPEG_LOG("VideoFrameSurfaceVAAPI: creating surface UID = %d",
FFMPEG_LOG("VideoFrameSurface: creating surface UID = %d",
mSurface->GetUID());
}
void VideoFrameSurfaceVAAPI::LockVAAPIData(AVCodecContext* aAVCodecContext,
AVFrame* aAVFrame,
FFmpegLibWrapper* aLib) {
FFMPEG_LOG("VideoFrameSurfaceVAAPI: VAAPI locking dmabuf surface UID = %d",
void VideoFrameSurface<LIBAV_VER>::LockVAAPIData(
AVCodecContext* aAVCodecContext, AVFrame* aAVFrame,
FFmpegLibWrapper* aLib) {
FFMPEG_LOG("VideoFrameSurface: VAAPI locking dmabuf surface UID = %d",
mSurface->GetUID());
mLib = aLib;
mAVHWDeviceContext = aLib->av_buffer_ref(aAVCodecContext->hw_device_ctx);
mHWAVBuffer = aLib->av_buffer_ref(aAVFrame->buf[0]);
}
void VideoFrameSurfaceVAAPI::ReleaseVAAPIData(bool aForFrameRecycle) {
FFMPEG_LOG("VideoFrameSurfaceVAAPI: VAAPI releasing dmabuf surface UID = %d",
void VideoFrameSurface<LIBAV_VER>::ReleaseVAAPIData(bool aForFrameRecycle) {
FFMPEG_LOG("VideoFrameSurface: VAAPI releasing dmabuf surface UID = %d",
mSurface->GetUID());
// It's possible to unref GPU data while IsUsed() is still set.
@ -67,43 +68,44 @@ void VideoFrameSurfaceVAAPI::ReleaseVAAPIData(bool aForFrameRecycle) {
}
}
VideoFrameSurfaceVAAPI::~VideoFrameSurfaceVAAPI() {
FFMPEG_LOG("VideoFrameSurfaceVAAPI: deleting dmabuf surface UID = %d",
VideoFrameSurface<LIBAV_VER>::~VideoFrameSurface() {
FFMPEG_LOG("VideoFrameSurface: deleting dmabuf surface UID = %d",
mSurface->GetUID());
// We're about to quit, no need to recycle the frames.
ReleaseVAAPIData(/* aForFrameRecycle */ false);
}
VideoFramePool::VideoFramePool() : mSurfaceLock("VideoFramePoolSurfaceLock") {}
VideoFramePool<LIBAV_VER>::VideoFramePool()
: mSurfaceLock("VideoFramePoolSurfaceLock") {}
VideoFramePool::~VideoFramePool() {
VideoFramePool<LIBAV_VER>::~VideoFramePool() {
MutexAutoLock lock(mSurfaceLock);
mDMABufSurfaces.Clear();
}
void VideoFramePool::ReleaseUnusedVAAPIFrames() {
void VideoFramePool<LIBAV_VER>::ReleaseUnusedVAAPIFrames() {
MutexAutoLock lock(mSurfaceLock);
for (const auto& surface : mDMABufSurfaces) {
auto* vaapiSurface = surface->AsVideoFrameSurfaceVAAPI();
if (!vaapiSurface->IsUsed()) {
vaapiSurface->ReleaseVAAPIData();
if (!surface->IsUsed()) {
surface->ReleaseVAAPIData();
}
}
}
RefPtr<VideoFrameSurface> VideoFramePool::GetFreeVideoFrameSurface() {
RefPtr<VideoFrameSurface<LIBAV_VER>>
VideoFramePool<LIBAV_VER>::GetFreeVideoFrameSurface() {
for (auto& surface : mDMABufSurfaces) {
if (surface->IsUsed()) {
continue;
}
auto* vaapiSurface = surface->AsVideoFrameSurfaceVAAPI();
vaapiSurface->ReleaseVAAPIData();
surface->ReleaseVAAPIData();
return surface;
}
return nullptr;
}
RefPtr<VideoFrameSurface> VideoFramePool::GetVideoFrameSurface(
RefPtr<VideoFrameSurface<LIBAV_VER>>
VideoFramePool<LIBAV_VER>::GetVideoFrameSurface(
VADRMPRIMESurfaceDescriptor& aVaDesc, AVCodecContext* aAVCodecContext,
AVFrame* aAVFrame, FFmpegLibWrapper* aLib) {
if (aVaDesc.fourcc != VA_FOURCC_NV12 && aVaDesc.fourcc != VA_FOURCC_YV12 &&
@ -113,7 +115,8 @@ RefPtr<VideoFrameSurface> VideoFramePool::GetVideoFrameSurface(
}
MutexAutoLock lock(mSurfaceLock);
RefPtr<VideoFrameSurface> videoSurface = GetFreeVideoFrameSurface();
RefPtr<VideoFrameSurface<LIBAV_VER>> videoSurface =
GetFreeVideoFrameSurface();
if (!videoSurface) {
RefPtr<DMABufSurfaceYUV> surface =
DMABufSurfaceYUV::CreateYUVSurface(aVaDesc);
@ -121,7 +124,8 @@ RefPtr<VideoFrameSurface> VideoFramePool::GetVideoFrameSurface(
return nullptr;
}
FFMPEG_LOG("Created new VA-API DMABufSurface UID = %d", surface->GetUID());
RefPtr<VideoFrameSurfaceVAAPI> surf = new VideoFrameSurfaceVAAPI(surface);
RefPtr<VideoFrameSurface<LIBAV_VER>> surf =
new VideoFrameSurface<LIBAV_VER>(surface);
if (!mTextureCreationWorks) {
mTextureCreationWorks = Some(surface->VerifyTextureCreation());
}
@ -138,11 +142,8 @@ RefPtr<VideoFrameSurface> VideoFramePool::GetVideoFrameSurface(
}
FFMPEG_LOG("Reusing VA-API DMABufSurface UID = %d", surface->GetUID());
}
auto* vaapiSurface = videoSurface->AsVideoFrameSurfaceVAAPI();
vaapiSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib);
vaapiSurface->MarkAsUsed();
videoSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib);
videoSurface->MarkAsUsed();
return videoSurface;
}

View file

@ -7,8 +7,9 @@
#ifndef __FFmpegVideoFramePool_h__
#define __FFmpegVideoFramePool_h__
#include "FFmpegVideoDecoder.h"
#include "FFmpegLibWrapper.h"
#include "FFmpegLibs.h"
#include "FFmpegLog.h"
#include "mozilla/layers/DMABUFSurfaceImage.h"
#include "mozilla/widget/DMABufLibWrapper.h"
@ -16,43 +17,16 @@
namespace mozilla {
class VideoFramePool;
class VideoFrameSurfaceVAAPI;
class VideoFrameSurface {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoFrameSurface)
VideoFrameSurface() = default;
virtual VideoFrameSurfaceVAAPI* AsVideoFrameSurfaceVAAPI() { return nullptr; }
virtual void SetYUVColorSpace(gfx::YUVColorSpace aColorSpace) = 0;
virtual void SetColorRange(gfx::ColorRange aColorRange) = 0;
virtual RefPtr<DMABufSurfaceYUV> GetDMABufSurface() { return nullptr; };
virtual RefPtr<layers::Image> GetAsImage() = 0;
// Don't allow VideoFrameSurface plain copy as it leads to
// unexpected DMABufSurface/HW buffer releases and we don't want to
// deep copy them.
VideoFrameSurface(const VideoFrameSurface&) = delete;
const VideoFrameSurface& operator=(VideoFrameSurface const&) = delete;
protected:
virtual ~VideoFrameSurface(){};
};
// VideoFrameSurfaceVAAPI holds a reference to GPU data with a video frame.
// VideoFrameSurface holds a reference to GPU data with a video frame.
//
// Actual GPU pixel data are stored at DMABufSurface and
// DMABufSurface is passed to gecko GL rendering pipeline via.
// DMABUFSurfaceImage.
//
// VideoFrameSurfaceVAAPI can optionally hold VA-API ffmpeg related data to keep
// VideoFrameSurface can optionally hold VA-API ffmpeg related data to keep
// GPU data locked untill we need them.
//
// VideoFrameSurfaceVAAPI is used for both HW accelerated video decoding
// VideoFrameSurface is used for both HW accelerated video decoding
// (VA-API) and ffmpeg SW decoding.
//
// VA-API scenario
@ -72,13 +46,24 @@ class VideoFrameSurface {
// Unfortunately there isn't any obvious way how to mark particular VASurface
// as used. The best we can do is to hold a reference to particular AVBuffer
// from decoded AVFrame and AVHWFramesContext which owns the AVBuffer.
class VideoFrameSurfaceVAAPI final : public VideoFrameSurface {
friend class VideoFramePool;
template <int V>
class VideoFrameSurface {};
template <>
class VideoFrameSurface<LIBAV_VER>;
template <int V>
class VideoFramePool {};
template <>
class VideoFramePool<LIBAV_VER>;
template <>
class VideoFrameSurface<LIBAV_VER> {
friend class VideoFramePool<LIBAV_VER>;
public:
explicit VideoFrameSurfaceVAAPI(DMABufSurface* aSurface);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoFrameSurface)
VideoFrameSurfaceVAAPI* AsVideoFrameSurfaceVAAPI() final { return this; }
explicit VideoFrameSurface(DMABufSurface* aSurface);
void SetYUVColorSpace(mozilla::gfx::YUVColorSpace aColorSpace) {
mSurface->GetAsDMABufSurfaceYUV()->SetYUVColorSpace(aColorSpace);
@ -93,6 +78,12 @@ class VideoFrameSurfaceVAAPI final : public VideoFrameSurface {
RefPtr<layers::Image> GetAsImage();
// Don't allow VideoFrameSurface plain copy as it leads to
// unexpected DMABufSurface/HW buffer releases and we don't want to
// deep copy them.
VideoFrameSurface(const VideoFrameSurface&) = delete;
const VideoFrameSurface& operator=(VideoFrameSurface const&) = delete;
protected:
// Lock VAAPI related data
void LockVAAPIData(AVCodecContext* aAVCodecContext, AVFrame* aAVFrame,
@ -107,7 +98,7 @@ class VideoFrameSurfaceVAAPI final : public VideoFrameSurface {
void MarkAsUsed() { mSurface->GlobalRefAdd(); }
private:
virtual ~VideoFrameSurfaceVAAPI();
virtual ~VideoFrameSurface();
const RefPtr<DMABufSurface> mSurface;
const FFmpegLibWrapper* mLib;
@ -116,23 +107,24 @@ class VideoFrameSurfaceVAAPI final : public VideoFrameSurface {
};
// VideoFramePool class is thread-safe.
class VideoFramePool final {
template <>
class VideoFramePool<LIBAV_VER> {
public:
VideoFramePool();
~VideoFramePool();
RefPtr<VideoFrameSurface> GetVideoFrameSurface(
RefPtr<VideoFrameSurface<LIBAV_VER>> GetVideoFrameSurface(
VADRMPRIMESurfaceDescriptor& aVaDesc, AVCodecContext* aAVCodecContext,
AVFrame* aAVFrame, FFmpegLibWrapper* aLib);
void ReleaseUnusedVAAPIFrames();
private:
RefPtr<VideoFrameSurface> GetFreeVideoFrameSurface();
RefPtr<VideoFrameSurface<LIBAV_VER>> GetFreeVideoFrameSurface();
private:
// Protect mDMABufSurfaces pool access
Mutex mSurfaceLock MOZ_UNANNOTATED;
nsTArray<RefPtr<VideoFrameSurfaceVAAPI>> mDMABufSurfaces;
nsTArray<RefPtr<VideoFrameSurface<LIBAV_VER>>> mDMABufSurfaces;
// We may fail to create texture over DMABuf memory due to driver bugs so
// check that before we export first DMABuf video frame.
Maybe<bool> mTextureCreationWorks;

View file

@ -30,6 +30,9 @@ if CONFIG['MOZ_WAYLAND']:
CXXFLAGS += CONFIG['MOZ_GTK3_CFLAGS']
DEFINES['MOZ_WAYLAND_USE_VAAPI'] = 1
USE_LIBS += ['mozva']
UNIFIED_SOURCES += [
'../FFmpegVideoFramePool.cpp',
]
include("/ipc/chromium/chromium-config.mozbuild")

View file

@ -30,6 +30,9 @@ if CONFIG["MOZ_WAYLAND"]:
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
DEFINES["MOZ_WAYLAND_USE_VAAPI"] = 1
USE_LIBS += ["mozva"]
UNIFIED_SOURCES += [
"../FFmpegVideoFramePool.cpp",
]
include("/ipc/chromium/chromium-config.mozbuild")

View file

@ -16,7 +16,6 @@
#include "MediaInfo.h"
#include "PDMFactory.h"
#include "VPXDecoder.h"
#include "AOMDecoder.h"
#include "WMF.h"
#include "WMFAudioMFTManager.h"
#include "WMFMediaDataDecoder.h"
@ -36,6 +35,10 @@
#include "nsWindowsHelpers.h"
#include "prsystem.h"
#ifdef MOZ_AV1
# include "AOMDecoder.h"
#endif
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {
@ -341,9 +344,11 @@ bool WMFDecoderModule::Supports(const SupportDecoderParams& aParams,
return true;
}
#ifdef MOZ_AV1
if (AOMDecoder::IsAV1(trackInfo.mMimeType) && WMFDecoderModule::HasAV1()) {
return true;
}
#endif
// Some unsupported codec.
return false;

View file

@ -18,7 +18,6 @@
#include "MediaInfo.h"
#include "MediaTelemetryConstants.h"
#include "VPXDecoder.h"
#include "AOMDecoder.h"
#include "VideoUtils.h"
#include "WMFDecoderModule.h"
#include "WMFUtils.h"
@ -40,6 +39,10 @@
#include "nsThreadUtils.h"
#include "nsWindowsHelpers.h"
#ifdef MOZ_AV1
# include "AOMDecoder.h"
#endif
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
using mozilla::layers::Image;
@ -155,8 +158,10 @@ WMFVideoMFTManager::WMFVideoMFTManager(
mStreamType = VP8;
} else if (VPXDecoder::IsVP9(aConfig.mMimeType)) {
mStreamType = VP9;
#ifdef MOZ_AV1
} else if (AOMDecoder::IsAV1(aConfig.mMimeType)) {
mStreamType = AV1;
#endif
} else {
mStreamType = Unknown;
}

View file

@ -135,6 +135,7 @@ MOZ_DEFINE_MALLOC_SIZE_OF(AudioBufferMemoryTrackerMallocSizeOf)
NS_IMETHODIMP
AudioBufferMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool) {
StaticMutexAutoLock lock(sMutex);
const size_t amount =
std::accumulate(mBuffers.cbegin(), mBuffers.cend(), size_t(0),
[](size_t val, const AudioBuffer* buffer) {

View file

@ -37,8 +37,7 @@ static uint32_t VIntLength(unsigned char aFirstByte, uint32_t* aMask) {
}
bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping,
ReentrantMonitor& aReentrantMonitor) {
nsTArray<WebMTimeDataOffset>& aMapping) {
static const uint32_t EBML_ID = 0x1a45dfa3;
static const uint32_t SEGMENT_ID = 0x18538067;
static const uint32_t SEGINFO_ID = 0x1549a966;
@ -197,7 +196,6 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
// It's possible we've parsed this data before, so avoid inserting
// duplicate WebMTimeDataOffset entries.
{
ReentrantMonitorAutoEnter mon(aReentrantMonitor);
int64_t endOffset = mBlockOffset + mBlockSize +
mElement.mID.mLength + mElement.mSize.mLength;
uint32_t idx = aMapping.IndexOfFirstElementGt(endOffset);
@ -315,7 +313,7 @@ bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset,
int64_t aEndOffset,
uint64_t* aStartTime,
uint64_t* aEndTime) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
// Find the first WebMTimeDataOffset at or after aStartOffset.
uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset - 1,
@ -362,7 +360,7 @@ bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset,
}
bool WebMBufferedState::GetOffsetForTime(uint64_t aTime, int64_t* aOffset) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
if (mTimeMapping.IsEmpty()) {
return false;
@ -413,7 +411,10 @@ void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer,
}
}
mRangeParsers[idx].Append(aBuffer, aLength, mTimeMapping, mReentrantMonitor);
{
MutexAutoLock lock(mMutex);
mRangeParsers[idx].Append(aBuffer, aLength, mTimeMapping);
}
// Merge parsers with overlapping regions and clean up the remnants.
uint32_t i = 0;
@ -431,12 +432,12 @@ void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer,
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
mLastBlockOffset = mRangeParsers.LastElement().mBlockEndOffset;
}
void WebMBufferedState::Reset() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
mRangeParsers.Clear();
mTimeMapping.Clear();
}
@ -499,13 +500,13 @@ int64_t WebMBufferedState::GetInitEndOffset() {
}
int64_t WebMBufferedState::GetLastBlockOffset() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
return mLastBlockOffset;
}
bool WebMBufferedState::GetStartTime(uint64_t* aTime) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
if (mTimeMapping.IsEmpty()) {
return false;
@ -522,7 +523,7 @@ bool WebMBufferedState::GetStartTime(uint64_t* aTime) {
bool WebMBufferedState::GetNextKeyframeTime(uint64_t aTime,
uint64_t* aKeyframeTime) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MutexAutoLock lock(mMutex);
int64_t offset = 0;
bool rv = GetOffsetForTime(aTime, &offset);
if (!rv) {

View file

@ -8,7 +8,7 @@
# include "nsISupportsImpl.h"
# include "nsTArray.h"
# include "mozilla/ReentrantMonitor.h"
# include "mozilla/Mutex.h"
# include "MediaResource.h"
namespace mozilla {
@ -88,12 +88,10 @@ struct WebMBufferedParser {
}
// Steps the parser through aLength bytes of data. Always consumes
// aLength bytes. Updates mCurrentOffset before returning. Acquires
// aReentrantMonitor before using aMapping.
// aLength bytes. Updates mCurrentOffset before returning.
// Returns false if an error was encountered.
bool Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping,
ReentrantMonitor& aReentrantMonitor);
nsTArray<WebMTimeDataOffset>& aMapping);
bool operator==(int64_t aOffset) const { return mCurrentOffset == aOffset; }
@ -263,8 +261,7 @@ class WebMBufferedState final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState)
public:
WebMBufferedState()
: mReentrantMonitor("WebMBufferedState"), mLastBlockOffset(-1) {
WebMBufferedState() : mMutex("WebMBufferedState"), mLastBlockOffset(-1) {
MOZ_COUNT_CTOR(WebMBufferedState);
}
@ -298,13 +295,13 @@ class WebMBufferedState final {
MOZ_COUNTED_DTOR(WebMBufferedState)
// Synchronizes access to the mTimeMapping array and mLastBlockOffset.
ReentrantMonitor mReentrantMonitor MOZ_UNANNOTATED;
Mutex mMutex;
// Sorted (by offset) map of data offsets to timecodes. Populated
// on the main thread as data is received and parsed by WebMBufferedParsers.
nsTArray<WebMTimeDataOffset> mTimeMapping;
nsTArray<WebMTimeDataOffset> mTimeMapping GUARDED_BY(mMutex);
// The last complete block parsed. -1 if not set.
int64_t mLastBlockOffset;
int64_t mLastBlockOffset GUARDED_BY(mMutex);
// Sorted (by offset) live parser instances. Main thread only.
nsTArray<WebMBufferedParser> mRangeParsers;

View file

@ -28,7 +28,6 @@
#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
#include "nsGlobalWindowInner.h"
#include "nsIPrincipal.h"
#include "mozilla/LoadInfo.h"
@ -45,321 +44,35 @@ namespace mozilla::dom {
#define LOG_ENABLED() \
MOZ_LOG_TEST(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug)
//////////////////////////////////////////////////////////////
// DOM module loader Helpers
//////////////////////////////////////////////////////////////
static ScriptLoader* GetCurrentScriptLoader(JSContext* aCx) {
auto reportError = mozilla::MakeScopeExit([aCx]() {
JS_ReportErrorASCII(aCx, "No ScriptLoader found for the current context");
});
JS::Rooted<JSObject*> object(aCx, JS::CurrentGlobalOrNull(aCx));
if (!object) {
return nullptr;
}
nsIGlobalObject* global = xpc::NativeGlobal(object);
if (!global) {
return nullptr;
}
nsGlobalWindowInner* innerWindow = nullptr;
if (nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global)) {
innerWindow = nsGlobalWindowInner::Cast(win);
} else {
innerWindow = xpc::SandboxWindowOrNull(object, aCx);
}
if (!innerWindow) {
return nullptr;
}
Document* document = innerWindow->GetDocument();
if (!document) {
return nullptr;
}
ScriptLoader* loader = document->ScriptLoader();
if (!loader) {
return nullptr;
}
reportError.release();
return loader;
}
static LoadedScript* GetLoadedScriptOrNull(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate) {
if (aReferencingPrivate.isUndefined()) {
return nullptr;
}
auto* script = static_cast<LoadedScript*>(aReferencingPrivate.toPrivate());
if (script->IsEventScript()) {
return nullptr;
}
MOZ_ASSERT_IF(
script->IsModuleScript(),
JS::GetModulePrivate(script->AsModuleScript()->ModuleRecord()) ==
aReferencingPrivate);
return script;
}
//////////////////////////////////////////////////////////////
// DOM module loader Host Hooks
//////////////////////////////////////////////////////////////
bool HostGetSupportedImportAssertions(JSContext* aCx,
JS::ImportAssertionVector& aValues) {
MOZ_ASSERT(aValues.empty());
if (!aValues.reserve(1)) {
JS_ReportOutOfMemory(aCx);
return false;
}
aValues.infallibleAppend(JS::ImportAssertion::Type);
return true;
}
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, moduleRequest)
/**
* Implement the HostResolveImportedModule abstract operation.
*
* Resolve a module specifier string and look this up in the module
* map, returning the result. This is only called for previously
* loaded modules and always succeeds.
*
* @param aReferencingPrivate A JS::Value which is either undefined
* or contains a LoadedScript private pointer.
* @param aModuleRequest A module request object.
* @returns module This is set to the module found.
*/
JSObject* HostResolveImportedModule(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest) {
JS::Rooted<JSObject*> module(aCx);
{
// LoadedScript should only live in this block, otherwise it will be a GC
// hazard
RefPtr<LoadedScript> script(
GetLoadedScriptOrNull(aCx, aReferencingPrivate));
JS::Rooted<JSString*> specifierString(
aCx, JS::GetModuleRequestSpecifier(aCx, aModuleRequest));
if (!specifierString) {
return nullptr;
}
// Let url be the result of resolving a module specifier given referencing
// module script and specifier.
nsAutoJSString string;
if (!string.init(aCx, specifierString)) {
return nullptr;
}
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
if (!loader) {
return nullptr;
}
nsCOMPtr<nsIURI> uri =
ModuleLoaderBase::ResolveModuleSpecifier(loader, script, string);
// This cannot fail because resolving a module specifier must have been
// previously successful with these same two arguments.
MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
// Use sandboxed global when doing a WebExtension content-script load.
nsCOMPtr<nsIGlobalObject> global;
if (BasePrincipal::Cast(nsContentUtils::SubjectPrincipal(aCx))
->ContentScriptAddonPolicy()) {
global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
MOZ_ASSERT(
xpc::IsWebExtensionContentScriptSandbox(global->GetGlobalJSObject()));
}
// Let resolved module script be moduleMap[url]. (This entry must exist for
// us to have gotten to this point.)
ModuleScript* ms = loader->GetModuleLoader()->GetFetchedModule(uri, global);
MOZ_ASSERT(ms, "Resolved module not found in module map");
MOZ_ASSERT(!ms->HasParseError());
MOZ_ASSERT(ms->ModuleRecord());
module.set(ms->ModuleRecord());
}
return module;
}
bool HostPopulateImportMeta(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aMetaObject) {
RefPtr<ModuleScript> script =
static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(script->IsModuleScript());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
aReferencingPrivate);
nsAutoCString url;
MOZ_DIAGNOSTIC_ASSERT(script->BaseURL());
MOZ_ALWAYS_SUCCEEDS(script->BaseURL()->GetAsciiSpec(url));
JS::Rooted<JSString*> urlString(aCx, JS_NewStringCopyZ(aCx, url.get()));
if (!urlString) {
JS_ReportOutOfMemory(aCx);
return false;
}
return JS_DefineProperty(aCx, aMetaObject, "url", urlString,
JSPROP_ENUMERATE);
}
bool HostImportModuleDynamically(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest,
JS::Handle<JSObject*> aPromise) {
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
JS::Rooted<JSString*> specifierString(
aCx, JS::GetModuleRequestSpecifier(aCx, aModuleRequest));
if (!specifierString) {
return false;
}
// Attempt to resolve the module specifier.
nsAutoJSString specifier;
if (!specifier.init(aCx, specifierString)) {
return false;
}
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
if (!loader) {
return false;
}
nsCOMPtr<nsIURI> uri =
ModuleLoaderBase::ResolveModuleSpecifier(loader, script, specifier);
if (!uri) {
JS::Rooted<JS::Value> error(aCx);
nsresult rv = ModuleLoaderBase::HandleResolveFailure(aCx, script, specifier,
0, 0, &error);
if (NS_FAILED(rv)) {
JS_ReportOutOfMemory(aCx);
return false;
}
JS_SetPendingException(aCx, error);
return false;
}
// Create a new top-level load request.
RefPtr<ScriptFetchOptions> options;
nsIURI* baseURL = nullptr;
nsCOMPtr<Element> element;
RefPtr<ScriptLoadContext> context;
if (script) {
options = script->GetFetchOptions();
baseURL = script->BaseURL();
nsCOMPtr<Element> element = script->GetScriptElement();
context = new ScriptLoadContext(element);
} else {
// We don't have a referencing script so fall back on using
// options from the document. This can happen when the user
// triggers an inline event handler, as there is no active script
// there.
Document* document = loader->GetDocument();
// Use the document's principal for all loads, except WebExtension
// content-scripts.
// Only remember the global for content-scripts as well.
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipal(aCx);
nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
if (!BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()) {
principal = document->NodePrincipal();
MOZ_ASSERT(global);
global = nullptr; // Null global is the usual case for most loads.
} else {
MOZ_ASSERT(
xpc::IsWebExtensionContentScriptSandbox(global->GetGlobalJSObject()));
}
options = new ScriptFetchOptions(
mozilla::CORS_NONE, document->GetReferrerPolicy(), principal, global);
baseURL = document->GetDocBaseURI();
context = new ScriptLoadContext(nullptr);
}
RefPtr<ModuleLoadRequest> request = ModuleLoader::CreateDynamicImport(
uri, options, baseURL, context, loader, aReferencingPrivate,
specifierString, aPromise);
loader->GetModuleLoader()->StartDynamicImport(request);
return true;
}
void DynamicImportPrefChangedCallback(const char* aPrefName, void* aClosure) {
bool enabled = Preferences::GetBool(aPrefName);
JS::ModuleDynamicImportHook hook =
enabled ? HostImportModuleDynamically : nullptr;
AutoJSAPI jsapi;
jsapi.Init();
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
JS::SetModuleDynamicImportHook(rt, hook);
}
//////////////////////////////////////////////////////////////
// DOM module loader
//////////////////////////////////////////////////////////////
ModuleLoader::ModuleLoader(ScriptLoader* aLoader) : ModuleLoaderBase(aLoader) {
EnsureModuleHooksInitialized();
}
void ModuleLoader::EnsureModuleHooksInitialized() {
AutoJSAPI jsapi;
jsapi.Init();
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
if (JS::GetModuleResolveHook(rt)) {
return;
}
JS::SetModuleResolveHook(rt, HostResolveImportedModule);
JS::SetModuleMetadataHook(rt, HostPopulateImportMeta);
JS::SetScriptPrivateReferenceHooks(rt, HostAddRefTopLevelScript,
HostReleaseTopLevelScript);
JS::SetSupportedAssertionsHook(rt, HostGetSupportedImportAssertions);
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
"javascript.options.dynamicImport",
(void*)nullptr);
}
ModuleLoader::ModuleLoader(ScriptLoader* aLoader) : ModuleLoaderBase(aLoader) {}
ScriptLoader* ModuleLoader::GetScriptLoader() {
return static_cast<ScriptLoader*>(mLoader.get());
}
nsresult ModuleLoader::StartModuleLoad(ScriptLoadRequest* aRequest) {
return StartModuleLoadImpl(aRequest, RestartRequest::No);
}
nsresult ModuleLoader::RestartModuleLoad(ScriptLoadRequest* aRequest) {
return StartModuleLoadImpl(aRequest, RestartRequest::Yes);
}
nsresult ModuleLoader::StartModuleLoadImpl(ScriptLoadRequest* aRequest,
RestartRequest aRestart) {
MOZ_ASSERT(aRequest->IsFetching());
NS_ENSURE_TRUE(GetScriptLoader()->GetDocument(), NS_ERROR_NULL_POINTER);
aRequest->SetUnknownDataType();
bool ModuleLoader::CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) {
if (!GetScriptLoader()->GetDocument()) {
*aRvOut = NS_ERROR_NULL_POINTER;
return false;
}
// If this document is sandboxed without 'allow-scripts', abort.
if (GetScriptLoader()->GetDocument()->HasScriptsBlockedBySandbox()) {
return NS_OK;
*aRvOut = NS_OK;
return false;
}
// To prevent dynamic code execution, content scripts can only
// load moz-extension URLs.
nsCOMPtr<nsIPrincipal> principal = aRequest->TriggeringPrincipal();
if (BasePrincipal::Cast(principal)->ContentScriptAddonPolicy() &&
!aRequest->mURI->SchemeIs("moz-extension")) {
*aRvOut = NS_ERROR_DOM_WEBEXT_CONTENT_SCRIPT_URI;
return false;
}
if (LOG_ENABLED()) {
@ -369,37 +82,10 @@ nsresult ModuleLoader::StartModuleLoadImpl(ScriptLoadRequest* aRequest,
url.get()));
}
// To prevent dynamic code execution, content scripts can only
// load moz-extension URLs.
nsCOMPtr<nsIPrincipal> principal = aRequest->TriggeringPrincipal();
if (BasePrincipal::Cast(principal)->ContentScriptAddonPolicy() &&
!aRequest->mURI->SchemeIs("moz-extension")) {
return NS_ERROR_DOM_WEBEXT_CONTENT_SCRIPT_URI;
}
// Check whether the module has been fetched or is currently being fetched,
// and if so wait for it rather than starting a new fetch.
ModuleLoadRequest* request = aRequest->AsModuleRequest();
// If we're restarting the request, the module should already be in the
// "fetching" map.
MOZ_ASSERT_IF(
aRestart == RestartRequest::Yes,
IsModuleFetching(request->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal()));
if (aRestart == RestartRequest::No &&
ModuleMapContainsURL(request->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal())) {
LOG(("ScriptLoadRequest (%p): Waiting for module fetch", aRequest));
WaitForModuleFetch(request->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal())
->Then(GetMainThreadSerialEventTarget(), __func__, request,
&ModuleLoadRequest::ModuleLoaded,
&ModuleLoadRequest::LoadFailed);
return NS_OK;
}
return true;
}
nsresult ModuleLoader::StartFetch(ModuleLoadRequest* aRequest) {
nsSecurityFlags securityFlags;
// According to the spec, module scripts have different behaviour to classic
@ -423,14 +109,8 @@ nsresult ModuleLoader::StartModuleLoadImpl(ScriptLoadRequest* aRequest,
// Delegate Shared Behavior to base ScriptLoader
nsresult rv = GetScriptLoader()->StartLoadInternal(aRequest, securityFlags);
NS_ENSURE_SUCCESS(rv, rv);
// We successfully started fetching a module so put its URL in the module
// map and mark it as fetching.
if (aRestart == RestartRequest::No) {
SetModuleFetchStarted(aRequest->AsModuleRequest());
}
LOG(("ScriptLoadRequest (%p): Start fetching module", aRequest));
return NS_OK;
@ -558,7 +238,6 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateTopLevel(
return request.forget();
}
/* static */
already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) {
RefPtr<ScriptLoadContext> newContext =
@ -577,23 +256,56 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateStaticImport(
return request.forget();
}
/* static */
already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateDynamicImport(
nsIURI* aURI, ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
ScriptLoadContext* aContext, ScriptLoader* aLoader,
JSContext* aCx, nsIURI* aURI, LoadedScript* aMaybeActiveScript,
JS::Handle<JS::Value> aReferencingPrivate, JS::Handle<JSString*> aSpecifier,
JS::Handle<JSObject*> aPromise) {
MOZ_ASSERT(aSpecifier);
MOZ_ASSERT(aPromise);
aContext->mIsInline = false;
aContext->mScriptMode = ScriptLoadContext::ScriptMode::eAsync;
RefPtr<ScriptFetchOptions> options;
nsIURI* baseURL = nullptr;
RefPtr<ScriptLoadContext> context;
if (aMaybeActiveScript) {
options = aMaybeActiveScript->GetFetchOptions();
baseURL = aMaybeActiveScript->BaseURL();
nsCOMPtr<Element> element = aMaybeActiveScript->GetScriptElement();
context = new ScriptLoadContext(element);
} else {
// We don't have a referencing script so fall back on using
// options from the document. This can happen when the user
// triggers an inline event handler, as there is no active script
// there.
Document* document = GetScriptLoader()->GetDocument();
// Use the document's principal for all loads, except WebExtension
// content-scripts.
// Only remember the global for content-scripts as well.
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipal(aCx);
nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
if (!BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()) {
principal = document->NodePrincipal();
MOZ_ASSERT(global);
global = nullptr; // Null global is the usual case for most loads.
} else {
MOZ_ASSERT(
xpc::IsWebExtensionContentScriptSandbox(global->GetGlobalJSObject()));
}
options = new ScriptFetchOptions(
mozilla::CORS_NONE, document->GetReferrerPolicy(), principal, global);
baseURL = document->GetDocBaseURI();
context = new ScriptLoadContext(nullptr);
}
context->mIsInline = false;
context->mScriptMode = ScriptLoadContext::ScriptMode::eAsync;
RefPtr<ModuleLoadRequest> request = new ModuleLoadRequest(
aURI, aFetchOptions, SRIMetadata(), aBaseURL, aContext, true,
aURI, options, SRIMetadata(), baseURL, context, true,
/* is top level */ true, /* is dynamic import */
aLoader->GetModuleLoader(),
ModuleLoadRequest::NewVisitedSetForTopLevelImport(aURI), nullptr);
this, ModuleLoadRequest::NewVisitedSetForTopLevelImport(aURI), nullptr);
request->mDynamicReferencingPrivate = aReferencingPrivate;
request->mDynamicSpecifier = aSpecifier;

View file

@ -44,23 +44,10 @@ class ModuleLoader final : public JS::loader::ModuleLoaderBase {
ScriptLoader* GetScriptLoader();
// Methods that must be overwritten by an extending class
void EnsureModuleHooksInitialized() override;
bool CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) override;
/**
* Start a load for a module script URI.
* Sets up the necessary security flags before calling StartLoadInternal.
* Short-circuits if the module is already being loaded.
*/
nsresult StartModuleLoad(ScriptLoadRequest* aRequest) override;
nsresult RestartModuleLoad(ScriptLoadRequest* aRequest) override;
nsresult StartFetch(ModuleLoadRequest* aRequest) override;
private:
enum class RestartRequest { No, Yes };
nsresult StartModuleLoadImpl(ScriptLoadRequest* aRequest,
RestartRequest aRestart);
public:
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) override;
nsresult CompileOrFinishModuleScript(
@ -78,12 +65,12 @@ class ModuleLoader final : public JS::loader::ModuleLoaderBase {
already_AddRefed<ModuleLoadRequest> CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) override;
// Create a module load request for dynamic module import.
static already_AddRefed<ModuleLoadRequest> CreateDynamicImport(
nsIURI* aURI, ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
ScriptLoadContext* aContext, ScriptLoader* aLoader,
// Create a module load request for a dynamic module import.
already_AddRefed<ModuleLoadRequest> CreateDynamicImport(
JSContext* aCx, nsIURI* aURI, LoadedScript* aMaybeActiveScript,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise);
JS::Handle<JSString*> aSpecifier,
JS::Handle<JSObject*> aPromise) override;
};
} // namespace dom

View file

@ -490,7 +490,7 @@ nsresult ScriptLoader::RestartLoad(ScriptLoadRequest* aRequest) {
aRequest->mFetchSourceOnly = true;
nsresult rv;
if (aRequest->IsModuleRequest()) {
rv = mModuleLoader->RestartModuleLoad(aRequest);
rv = mModuleLoader->RestartModuleLoad(aRequest->AsModuleRequest());
} else {
rv = StartLoad(aRequest);
}
@ -504,8 +504,11 @@ nsresult ScriptLoader::RestartLoad(ScriptLoadRequest* aRequest) {
}
nsresult ScriptLoader::StartLoad(ScriptLoadRequest* aRequest) {
return aRequest->IsModuleRequest() ? mModuleLoader->StartModuleLoad(aRequest)
: StartClassicLoad(aRequest);
if (aRequest->IsModuleRequest()) {
return mModuleLoader->StartModuleLoad(aRequest->AsModuleRequest());
}
return StartClassicLoad(aRequest);
}
nsresult ScriptLoader::StartClassicLoad(ScriptLoadRequest* aRequest) {

View file

@ -21,11 +21,9 @@ class CompositorWidget;
} // namespace widget
namespace gl {
RefPtr<GLLibraryEGL> DefaultEglLibrary(nsACString* const out_failureId);
inline std::shared_ptr<EglDisplay> DefaultEglDisplay(
nsACString* const out_failureId) {
const auto lib = DefaultEglLibrary(out_failureId);
const auto lib = GLLibraryEGL::Get(out_failureId);
if (!lib) {
return nullptr;
}

View file

@ -237,7 +237,7 @@ class GLContextEGLFactory {
already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) {
nsCString failureId;
const auto lib = gl::DefaultEglLibrary(&failureId);
const auto lib = GLLibraryEGL::Get(&failureId);
if (!lib) {
gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get();
return nullptr;
@ -1211,30 +1211,7 @@ GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; }
// -
static StaticMutex sMutex MOZ_UNANNOTATED;
static StaticRefPtr<GLLibraryEGL> gDefaultEglLibrary;
RefPtr<GLLibraryEGL> DefaultEglLibrary(nsACString* const out_failureId) {
StaticMutexAutoLock lock(sMutex);
if (!gDefaultEglLibrary) {
gDefaultEglLibrary = GLLibraryEGL::Create(out_failureId);
if (!gDefaultEglLibrary) {
NS_WARNING("GLLibraryEGL::Create failed");
}
}
return gDefaultEglLibrary.get();
}
// -
/*static*/
void GLContextProviderEGL::Shutdown() {
StaticMutexAutoLock lock(sMutex);
if (!gDefaultEglLibrary) {
return;
}
gDefaultEglLibrary = nullptr;
}
/*static*/ void GLContextProviderEGL::Shutdown() { GLLibraryEGL::Shutdown(); }
} /* namespace gl */
} /* namespace mozilla */

View file

@ -48,6 +48,9 @@
namespace mozilla {
namespace gl {
StaticMutex GLLibraryEGL::sMutex;
StaticRefPtr<GLLibraryEGL> GLLibraryEGL::sInstance;
// should match the order of EGLExtensions, and be null-terminated.
static const char* sEGLLibraryExtensionNames[] = {
"EGL_ANDROID_get_native_client_buffer", "EGL_ANGLE_device_creation",
@ -140,15 +143,17 @@ static PRLibrary* LoadLibraryForEGLOnWindows(const nsAString& filename) {
#endif // XP_WIN
static std::shared_ptr<EglDisplay> GetAndInitDisplay(GLLibraryEGL& egl,
void* displayType) {
static std::shared_ptr<EglDisplay> GetAndInitDisplay(
GLLibraryEGL& egl, void* displayType,
const StaticMutexAutoLock& aProofOfLock) {
const auto display = egl.fGetDisplay(displayType);
if (!display) return nullptr;
return EglDisplay::Create(egl, display, false);
return EglDisplay::Create(egl, display, false, aProofOfLock);
}
static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay(GLLibraryEGL& egl,
void* displayType) {
static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay(
GLLibraryEGL& egl, void* displayType,
const StaticMutexAutoLock& aProofOfLock) {
const EGLAttrib attrib_list[] = {
LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
@ -167,11 +172,12 @@ static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay(GLLibraryEGL& egl,
return nullptr;
}
return EglDisplay::Create(egl, display, true);
return EglDisplay::Create(egl, display, true, aProofOfLock);
}
std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
ID3D11Device* const d3d11Device) {
StaticMutexAutoLock lock(sMutex);
EGLDeviceEXT eglDevice =
fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE, d3d11Device, nullptr);
if (!eglDevice) {
@ -199,7 +205,7 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
return nullptr;
}
const auto ret = EglDisplay::Create(*this, display, false);
const auto ret = EglDisplay::Create(*this, display, false, lock);
if (!ret) {
const EGLint err = fGetError();
@ -263,7 +269,8 @@ class AngleErrorReporting {
AngleErrorReporting gAngleErrorReporter;
static std::shared_ptr<EglDisplay> GetAndInitDisplayForAccelANGLE(
GLLibraryEGL& egl, nsACString* const out_failureId) {
GLLibraryEGL& egl, nsACString* const out_failureId,
const StaticMutexAutoLock& aProofOfLock) {
gfx::FeatureState& d3d11ANGLE =
gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE);
@ -285,16 +292,18 @@ static std::shared_ptr<EglDisplay> GetAndInitDisplayForAccelANGLE(
});
if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE)) {
return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE,
aProofOfLock);
}
std::shared_ptr<EglDisplay> ret;
if (d3d11ANGLE.IsEnabled()) {
ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE,
aProofOfLock);
}
if (!ret) {
ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY);
ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY, aProofOfLock);
}
if (!ret && out_failureId->IsEmpty()) {
@ -326,12 +335,20 @@ Maybe<SymbolLoader> GLLibraryEGL::GetSymbolLoader() const {
// -
/* static */
RefPtr<GLLibraryEGL> GLLibraryEGL::Create(nsACString* const out_failureId) {
RefPtr<GLLibraryEGL> ret = new GLLibraryEGL;
if (!ret->Init(out_failureId)) {
return nullptr;
RefPtr<GLLibraryEGL> GLLibraryEGL::Get(nsACString* const out_failureId) {
StaticMutexAutoLock lock(sMutex);
if (!sInstance) {
sInstance = new GLLibraryEGL;
if (NS_WARN_IF(!sInstance->Init(out_failureId))) {
sInstance = nullptr;
}
}
return ret;
return sInstance;
}
/* static */ void GLLibraryEGL::Shutdown() {
StaticMutexAutoLock lock(sMutex);
sInstance = nullptr;
}
bool GLLibraryEGL::Init(nsACString* const out_failureId) {
@ -640,9 +657,9 @@ static void MarkExtensions(const char* rawExtString, bool shouldDumpExts,
// -
// static
std::shared_ptr<EglDisplay> EglDisplay::Create(GLLibraryEGL& lib,
const EGLDisplay display,
const bool isWarp) {
std::shared_ptr<EglDisplay> EglDisplay::Create(
GLLibraryEGL& lib, const EGLDisplay display, const bool isWarp,
const StaticMutexAutoLock& aProofOfLock) {
// Retrieve the EglDisplay if it already exists
{
const auto itr = lib.mActiveDisplays.find(display);
@ -710,6 +727,7 @@ EglDisplay::EglDisplay(const PrivateUseOnly&, GLLibraryEGL& lib,
}
EglDisplay::~EglDisplay() {
StaticMutexAutoLock lock(GLLibraryEGL::sMutex);
fTerminate();
mLib->mActiveDisplays.erase(mDisplay);
}
@ -718,16 +736,24 @@ EglDisplay::~EglDisplay() {
std::shared_ptr<EglDisplay> GLLibraryEGL::DefaultDisplay(
nsACString* const out_failureId) {
StaticMutexAutoLock lock(sMutex);
auto ret = mDefaultDisplay.lock();
if (ret) return ret;
ret = CreateDisplay(false, out_failureId);
ret = CreateDisplayLocked(false, out_failureId, lock);
mDefaultDisplay = ret;
return ret;
}
std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
const bool forceAccel, nsACString* const out_failureId) {
StaticMutexAutoLock lock(sMutex);
return CreateDisplayLocked(forceAccel, out_failureId, lock);
}
std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplayLocked(
const bool forceAccel, nsACString* const out_failureId,
const StaticMutexAutoLock& aProofOfLock) {
std::shared_ptr<EglDisplay> ret;
if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)) {
@ -747,7 +773,7 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
// Hardware accelerated ANGLE path (supported or force accel)
if (shouldTryAccel) {
ret = GetAndInitDisplayForAccelANGLE(*this, out_failureId);
ret = GetAndInitDisplayForAccelANGLE(*this, out_failureId, aProofOfLock);
}
// Report the acceleration status to telemetry
@ -766,7 +792,7 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
// Fallback to a WARP display if ANGLE fails, or if WARP is forced
if (!ret && shouldTryWARP) {
ret = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY);
ret = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY, aProofOfLock);
if (!ret) {
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WARP_FALLBACK"_ns;
@ -788,7 +814,7 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
}
}
#endif
ret = GetAndInitDisplay(*this, nativeDisplay);
ret = GetAndInitDisplay(*this, nativeDisplay, aProofOfLock);
}
if (!ret) {

View file

@ -13,6 +13,8 @@
#include "mozilla/EnumTypeTraits.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "nsISupports.h"
#include "prlink.h"
@ -125,14 +127,22 @@ class GLLibraryEGL final {
std::unordered_map<EGLDisplay, std::weak_ptr<EglDisplay>> mActiveDisplays;
public:
static RefPtr<GLLibraryEGL> Create(nsACString* const out_failureId);
static RefPtr<GLLibraryEGL> Get(nsACString* const out_failureId);
static void Shutdown();
private:
~GLLibraryEGL() = default;
static StaticMutex sMutex;
static StaticRefPtr<GLLibraryEGL> sInstance GUARDED_BY(sMutex);
bool Init(nsACString* const out_failureId);
void InitLibExtensions();
std::shared_ptr<EglDisplay> CreateDisplayLocked(
bool forceAccel, nsACString* const out_failureId,
const StaticMutexAutoLock& aProofOfLock);
public:
Maybe<SymbolLoader> GetSymbolLoader() const;
@ -599,8 +609,9 @@ class EglDisplay final {
struct PrivateUseOnly final {};
public:
static std::shared_ptr<EglDisplay> Create(GLLibraryEGL&, EGLDisplay,
bool isWarp);
static std::shared_ptr<EglDisplay> Create(
GLLibraryEGL&, EGLDisplay, bool isWarp,
const StaticMutexAutoLock& aProofOfLock);
// Only `public` for make_shared.
EglDisplay(const PrivateUseOnly&, GLLibraryEGL&, EGLDisplay, bool isWarp);

View file

@ -82,8 +82,6 @@ class APZSampler {
const LayersId& aLayersId,
const ScrollableLayerGuid::ViewID& aScrollId) const;
ScreenMargin GetGeckoFixedLayerMargins() const;
/**
* This can be used to assert that the current thread is the
* sampler thread (which samples the async transform).

View file

@ -2941,11 +2941,6 @@ already_AddRefed<AsyncPanZoomController> APZCTreeManager::FindZoomableApzc(
return GetZoomableTarget(aStart, aStart);
}
ScreenMargin APZCTreeManager::GetGeckoFixedLayerMargins() const {
RecursiveMutexAutoLock lock(mTreeLock);
return mGeckoFixedLayerMargins;
}
ScreenMargin APZCTreeManager::GetCompositorFixedLayerMargins() const {
RecursiveMutexAutoLock lock(mTreeLock);
return mCompositorFixedLayerMargins;

View file

@ -558,8 +558,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
already_AddRefed<AsyncPanZoomController> FindZoomableApzc(
AsyncPanZoomController* aStart) const;
ScreenMargin GetGeckoFixedLayerMargins() const;
ScreenMargin GetCompositorFixedLayerMargins() const;
APZScrollGeneration NewAPZScrollGeneration() {

View file

@ -122,13 +122,6 @@ AsyncTransform APZSampler::GetCurrentAsyncTransform(
aComponents);
}
ScreenMargin APZSampler::GetGeckoFixedLayerMargins() const {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
AssertOnSamplerThread();
return mApz->GetGeckoFixedLayerMargins();
}
ParentLayerRect APZSampler::GetCompositionBounds(
const LayersId& aLayersId,
const ScrollableLayerGuid::ViewID& aScrollId) const {

View file

@ -76,7 +76,12 @@ async function test() {
// Now we turn the "simple" clip-path that WR can handle into a more complex
// one that needs a mask. Then run the checks again; the expected results for
// WR are slightly different
document.getElementById("clipped").style.clipPath = "polygon(50px 200px, 75px 75px, 200px 50px, 350px 200px, 200px 350px)";
document.getElementById("clipped").style.clipPath = "polygon(" +
"50px 200px, 75px 75px, 200px 50px, 205px 55px, 210px 50px, " +
"215px 55px, 220px 50px, 225px 55px, 230px 50px, 235px 55px, " +
"240px 50px, 245px 55px, 250px 50px, 255px 55px, 260px 50px, " +
"265px 55px, 270px 50px, 275px 55px, 280px 50px, 350px 200px, " +
"200px 350px)";
await promiseApzFlushedRepaints();
checkHitResult(hitTest({ x: 10, y: 10 }),

View file

@ -161,7 +161,8 @@ void CompositorVsyncScheduler::ScheduleComposition(wr::RenderReasons aReasons) {
// through the main thread of the UI process. It's possible that
// we're blocking there waiting on a composite, so schedule an initial
// one now to get things started.
PostCompositeTask(vsyncEvent, aReasons);
PostCompositeTask(vsyncEvent,
aReasons | wr::RenderReasons::START_OBSERVING_VSYNC);
} else {
mRendersDelayedByVsyncReasons = aReasons;
}

View file

@ -1590,7 +1590,8 @@ void WebRenderBridgeParent::FlushFrameGeneration(wr::RenderReasons aReasons) {
mCompositorScheduler->CancelCurrentCompositeTask();
// Update timestamp of scheduler for APZ and animation.
mCompositorScheduler->UpdateLastComposeTime();
MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true, aReasons);
MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true,
aReasons | wr::RenderReasons::FLUSH);
}
}
@ -2181,7 +2182,8 @@ void WebRenderBridgeParent::CompositeIfNeeded() {
if (mSkippedComposite) {
mSkippedComposite = false;
if (mCompositorScheduler) {
mCompositorScheduler->ScheduleComposition(mSkippedCompositeReasons);
mCompositorScheduler->ScheduleComposition(
mSkippedCompositeReasons | RenderReasons::SKIPPED_COMPOSITE);
}
mSkippedCompositeReasons = wr::RenderReasons::NONE;
}
@ -2217,7 +2219,7 @@ void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
if (paused || !mReceivedDisplayList) {
ResetPreviousSampleTime();
mCompositionOpportunityId = mCompositionOpportunityId.Next();
PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS,
PROFILER_MARKER_TEXT("Discarded composite", GRAPHICS,
MarkerInnerWindowId(innerWindowId),
paused ? "Paused"_ns : "No display list"_ns);
return;
@ -2301,11 +2303,16 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
// Trigger another CompositeToTarget() call because there might be another
// frame that we want to generate after this one.
// It will check if we actually want to generate the frame or not.
mCompositorScheduler->ScheduleComposition(aReasons);
mCompositorScheduler->ScheduleComposition(
wr::RenderReasons::ASYNC_IMAGE_COMPOSITE_UNTIL);
}
bool generateFrame = mAsyncImageManager->GetAndResetWillGenerateFrame() ||
!fastTxn.IsEmpty() || aForceGenerateFrame;
bool generateFrame = !fastTxn.IsEmpty() || aForceGenerateFrame;
if (mAsyncImageManager->GetAndResetWillGenerateFrame()) {
aReasons |= wr::RenderReasons::ASYNC_IMAGE;
generateFrame = true;
}
if (!generateFrame) {
// Could skip generating frame now.

View file

@ -25,26 +25,10 @@
* 96dpi as possible.
*/
// This controls whether we're using integers or floats for coordinates. We
// want to eventually use floats.
//#define NS_COORD_IS_FLOAT
#ifdef NS_COORD_IS_FLOAT
typedef float nscoord;
# define nscoord_MAX (mozilla::PositiveInfinity<float>())
#else
typedef int32_t nscoord;
# define nscoord_MAX nscoord((1 << 30) - 1)
#endif
#define nscoord_MAX nscoord((1 << 30) - 1)
#define nscoord_MIN (-nscoord_MAX)
inline void VERIFY_COORD(nscoord aCoord) {
#ifdef NS_COORD_IS_FLOAT
NS_ASSERTION(floorf(aCoord) == aCoord, "Coords cannot have fractions");
#endif
}
namespace mozilla {
struct AppUnit {};
@ -104,22 +88,13 @@ using AuCoord64 = detail::AuCoordImpl<int64_t>;
* return the remainder.
*/
inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient) {
#ifdef NS_COORD_IS_FLOAT
*aQuotient = aSpace / aN;
return 0.0f;
#else
div_t result = div(aSpace, aN);
*aQuotient = nscoord(result.quot);
return nscoord(result.rem);
#endif
}
inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
#ifdef NS_COORD_IS_FLOAT
return (aMult1 * aMult2 / aDiv);
#else
return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
#endif
}
inline nscoord NSToCoordRound(float aValue) {
@ -141,7 +116,6 @@ inline nscoord NSToCoordRound(double aValue) {
}
inline nscoord NSToCoordRoundWithClamp(float aValue) {
#ifndef NS_COORD_IS_FLOAT
// Bounds-check before converting out of float, to avoid overflow
if (aValue >= float(nscoord_MAX)) {
return nscoord_MAX;
@ -149,7 +123,17 @@ inline nscoord NSToCoordRoundWithClamp(float aValue) {
if (aValue <= float(nscoord_MIN)) {
return nscoord_MIN;
}
#endif
return NSToCoordRound(aValue);
}
inline nscoord NSToCoordRoundWithClamp(double aValue) {
// Bounds-check before converting out of double, to avoid overflow
if (aValue >= double(nscoord_MAX)) {
return nscoord_MAX;
}
if (aValue <= double(nscoord_MIN)) {
return nscoord_MIN;
}
return NSToCoordRound(aValue);
}
@ -161,20 +145,15 @@ inline nscoord NSToCoordRoundWithClamp(float aValue) {
*/
inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
bool requireNotNegative) {
VERIFY_COORD(aCoord);
if (requireNotNegative) {
MOZ_ASSERT(aScale >= 0.0f,
"negative scaling factors must be handled manually");
}
#ifdef NS_COORD_IS_FLOAT
return floorf(aCoord * aScale);
#else
float product = aCoord * aScale;
if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
return NSToCoordRoundWithClamp(
std::min<float>((float)nscoord_MAX, product));
return NSToCoordRoundWithClamp(std::max<float>((float)nscoord_MIN, product));
#endif
}
/**
@ -200,19 +179,8 @@ inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
* Returns a + b, capping the sum to nscoord_MAX.
*
* This function assumes that neither argument is nscoord_MIN.
*
* Note: If/when we start using floats for nscoords, this function won't be as
* necessary. Normal float addition correctly handles adding with infinity,
* assuming we aren't adding nscoord_MIN. (-infinity)
*/
inline nscoord NSCoordSaturatingAdd(nscoord a, nscoord b) {
VERIFY_COORD(a);
VERIFY_COORD(b);
#ifdef NS_COORD_IS_FLOAT
// Float math correctly handles a+b, given that neither is -infinity.
return a + b;
#else
if (a == nscoord_MAX || b == nscoord_MAX) {
// infinity + anything = anything + infinity = infinity
return nscoord_MAX;
@ -221,7 +189,6 @@ inline nscoord NSCoordSaturatingAdd(nscoord a, nscoord b) {
// Cap the result, just in case we're dealing with numbers near nscoord_MAX
return std::min(nscoord_MAX, a + b);
}
#endif
}
/**
@ -234,17 +201,9 @@ inline nscoord NSCoordSaturatingAdd(nscoord a, nscoord b) {
* b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
* c) infinity - N -> infinity
* d) N1 - N2 -> N1 - N2
*
* Note: For float nscoords, cases (c) and (d) are handled by normal float
* math. We still need to explicitly specify the behavior for cases (a)
* and (b), though. (Under normal float math, those cases would return NaN
* and -infinity, respectively.)
*/
inline nscoord NSCoordSaturatingSubtract(nscoord a, nscoord b,
nscoord infMinusInfResult) {
VERIFY_COORD(a);
VERIFY_COORD(b);
if (b == nscoord_MAX) {
if (a == nscoord_MAX) {
// case (a)
@ -254,10 +213,6 @@ inline nscoord NSCoordSaturatingSubtract(nscoord a, nscoord b,
return 0;
}
} else {
#ifdef NS_COORD_IS_FLOAT
// case (c) and (d) for floats. (float math handles both)
return a - b;
#else
if (a == nscoord_MAX) {
// case (c) for integers
return nscoord_MAX;
@ -266,17 +221,10 @@ inline nscoord NSCoordSaturatingSubtract(nscoord a, nscoord b,
// Cap the result, in case we're dealing with numbers near nscoord_MAX
return std::min(nscoord_MAX, a - b);
}
#endif
}
}
inline float NSCoordToFloat(nscoord aCoord) {
VERIFY_COORD(aCoord);
#ifdef NS_COORD_IS_FLOAT
NS_ASSERTION(!mozilla::IsNaN(aCoord), "NaN encountered in float conversion");
#endif
return (float)aCoord;
}
inline float NSCoordToFloat(nscoord aCoord) { return (float)aCoord; }
/*
* Coord Rounding Functions
@ -286,7 +234,6 @@ inline nscoord NSToCoordFloor(float aValue) { return nscoord(floorf(aValue)); }
inline nscoord NSToCoordFloor(double aValue) { return nscoord(floor(aValue)); }
inline nscoord NSToCoordFloorClamped(float aValue) {
#ifndef NS_COORD_IS_FLOAT
// Bounds-check before converting out of float, to avoid overflow
if (aValue >= float(nscoord_MAX)) {
return nscoord_MAX;
@ -294,7 +241,6 @@ inline nscoord NSToCoordFloorClamped(float aValue) {
if (aValue <= float(nscoord_MIN)) {
return nscoord_MIN;
}
#endif
return NSToCoordFloor(aValue);
}
@ -303,7 +249,6 @@ inline nscoord NSToCoordCeil(float aValue) { return nscoord(ceilf(aValue)); }
inline nscoord NSToCoordCeil(double aValue) { return nscoord(ceil(aValue)); }
inline nscoord NSToCoordCeilClamped(double aValue) {
#ifndef NS_COORD_IS_FLOAT
// Bounds-check before converting out of double, to avoid overflow
if (aValue >= nscoord_MAX) {
return nscoord_MAX;
@ -311,7 +256,6 @@ inline nscoord NSToCoordCeilClamped(double aValue) {
if (aValue <= nscoord_MIN) {
return nscoord_MIN;
}
#endif
return NSToCoordCeil(aValue);
}
@ -332,7 +276,6 @@ inline nscoord NSToCoordTrunc(double aValue) {
}
inline nscoord NSToCoordTruncClamped(float aValue) {
#ifndef NS_COORD_IS_FLOAT
// Bounds-check before converting out of float, to avoid overflow
if (aValue >= float(nscoord_MAX)) {
return nscoord_MAX;
@ -340,12 +283,10 @@ inline nscoord NSToCoordTruncClamped(float aValue) {
if (aValue <= float(nscoord_MIN)) {
return nscoord_MIN;
}
#endif
return NSToCoordTrunc(aValue);
}
inline nscoord NSToCoordTruncClamped(double aValue) {
#ifndef NS_COORD_IS_FLOAT
// Bounds-check before converting out of double, to avoid overflow
if (aValue >= float(nscoord_MAX)) {
return nscoord_MAX;
@ -353,7 +294,6 @@ inline nscoord NSToCoordTruncClamped(double aValue) {
if (aValue <= float(nscoord_MIN)) {
return nscoord_MIN;
}
#endif
return NSToCoordTrunc(aValue);
}
@ -384,7 +324,6 @@ inline nscoord NSIntPixelsToAppUnits(int32_t aPixels,
// The cast to nscoord makes sure we don't overflow if we ever change
// nscoord to float
nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
VERIFY_COORD(r);
return r;
}

View file

@ -22,13 +22,9 @@ const mozilla::gfx::IntRect& GetMaxSizedIntRect() {
}
bool nsRect::Overflows() const {
#ifdef NS_COORD_IS_FLOAT
return false;
#else
mozilla::CheckedInt<int32_t> xMost = this->x;
xMost += this->width;
mozilla::CheckedInt<int32_t> yMost = this->y;
yMost += this->height;
return !xMost.isValid() || !yMost.isValid();
#endif
}

View file

@ -34,8 +34,6 @@ struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin>
Super;
static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
// Constructors
nsRect() : Super() { MOZ_COUNT_CTOR(nsRect); }
nsRect(const nsRect& aRect) : Super(aRect) { MOZ_COUNT_CTOR(nsRect); }
@ -68,9 +66,6 @@ struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
}
[[nodiscard]] nsRect SaturatingUnionEdges(const nsRect& aRect) const {
#ifdef NS_COORD_IS_FLOAT
return UnionEdges(aRect);
#else
nscoord resultX = std::min(aRect.X(), x);
int64_t w =
std::max(int64_t(aRect.X()) + aRect.Width(), int64_t(x) + width) -
@ -99,10 +94,8 @@ struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
}
}
return nsRect(resultX, resultY, nscoord(w), nscoord(h));
#endif
}
#ifndef NS_COORD_IS_FLOAT
// Make all nsRect Union methods be saturating.
[[nodiscard]] nsRect UnionEdges(const nsRect& aRect) const {
return SaturatingUnionEdges(aRect);
@ -117,8 +110,8 @@ struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
*this = aRect1.Union(aRect2);
}
# if defined(_MSC_VER) && !defined(__clang__) && \
(defined(_M_X64) || defined(_M_IX86))
#if defined(_MSC_VER) && !defined(__clang__) && \
(defined(_M_X64) || defined(_M_IX86))
// Only MSVC supports inlining intrinsics for archs you're not compiling for.
[[nodiscard]] nsRect Intersect(const nsRect& aRect) const {
nsRect result;
@ -218,7 +211,6 @@ struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
}
return true;
}
# endif
#endif
// Return whether this rect's right or bottom edge overflow int32.

View file

@ -2663,6 +2663,29 @@ void gfxPlatform::InitWebRenderConfig() {
MOZ_ASSERT(gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT));
useVideoOverlay = true;
}
if (useVideoOverlay &&
!StaticPrefs::
gfx_webrender_dcomp_video_overlay_win_force_enabled_AtStartup()) {
nsCString failureId;
int32_t status;
const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
if (NS_FAILED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_VIDEO_OVERLAY,
failureId, &status))) {
FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_OVERLAY);
feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
"gfxInfo is broken",
"FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
useVideoOverlay = false;
} else {
if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) {
FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_OVERLAY);
feature.DisableByDefault(FeatureStatus::Blocked,
"Blocklisted by gfxInfo", failureId);
useVideoOverlay = false;
}
}
}
}
if (useVideoOverlay) {

View file

@ -1173,7 +1173,7 @@ static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
}
nsCString failureId;
const auto lib = gl::DefaultEglLibrary(&failureId);
const auto lib = gl::GLLibraryEGL::Get(&failureId);
if (!lib) {
aError.Assign(
nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));

View file

@ -1601,7 +1601,7 @@ impl ComplexClipRegion {
}
}
pub const POLYGON_CLIP_VERTEX_MAX: usize = 16;
pub const POLYGON_CLIP_VERTEX_MAX: usize = 32;
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]

View file

@ -562,6 +562,11 @@ bitflags! {
/// to see which frames were driven by the vsync scheduler so
/// we store a bit for it.
const VSYNC = 1 << 16;
const SKIPPED_COMPOSITE = 1 << 17;
/// Gecko does some special things when it starts observing vsync
/// so it can be useful to know what frames are associated with it.
const START_OBSERVING_VSYNC = 1 << 18;
const ASYNC_IMAGE_COMPOSITE_UNTIL = 1 << 19;
}
}

View file

@ -1,11 +1,7 @@
mod asynchronous;
mod synchronous;
use std::{
cell::{Ref, RefCell},
collections::HashSet,
rc::Rc,
};
use std::{collections::HashSet, rc::Rc, sync::Mutex, sync::MutexGuard};
use crate::errors::L10nRegistrySetupError;
use crate::source::{FileSource, ResourceId};
@ -23,13 +19,13 @@ pub type FluentResourceSet = Vec<Rc<FluentResource>>;
#[derive(Default)]
struct Shared<P, B> {
sources: RefCell<Vec<Vec<FileSource>>>,
sources: Mutex<Vec<Vec<FileSource>>>,
provider: P,
bundle_adapter: Option<B>,
}
pub struct L10nRegistryLocked<'a, B> {
lock: Ref<'a, Vec<Vec<FileSource>>>,
lock: MutexGuard<'a, Vec<Vec<FileSource>>>,
bundle_adapter: Option<&'a B>,
}
@ -106,7 +102,11 @@ impl<P, B> L10nRegistry<P, B> {
pub fn lock(&self) -> L10nRegistryLocked<'_, B> {
L10nRegistryLocked {
lock: self.shared.sources.borrow(),
// The lock() method only fails here if another thread has panicked
// while holding the lock. In this case, we'll propagate the panic
// as well. It's not clear what the recovery strategy would be for
// us to deal with a panic in another thread.
lock: self.shared.sources.lock().unwrap(),
bundle_adapter: self.shared.bundle_adapter.as_ref(),
}
}
@ -118,7 +118,7 @@ impl<P, B> L10nRegistry<P, B> {
let mut sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
for new_source in new_sources {
@ -141,7 +141,7 @@ impl<P, B> L10nRegistry<P, B> {
let mut sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
for upd_source in upd_sources {
@ -168,7 +168,7 @@ impl<P, B> L10nRegistry<P, B> {
let mut sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
let del_sources: Vec<String> = del_sources.into_iter().map(|s| s.to_string()).collect();
@ -185,7 +185,7 @@ impl<P, B> L10nRegistry<P, B> {
let mut sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
sources.clear();
Ok(())
@ -195,7 +195,7 @@ impl<P, B> L10nRegistry<P, B> {
let sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
Ok(sources.iter().flatten().map(|s| s.name.clone()).collect())
}
@ -204,7 +204,7 @@ impl<P, B> L10nRegistry<P, B> {
let sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
Ok(sources.iter().flatten().any(|source| source.name == name))
}
@ -213,7 +213,7 @@ impl<P, B> L10nRegistry<P, B> {
let sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
Ok(sources
.iter()
@ -225,7 +225,7 @@ impl<P, B> L10nRegistry<P, B> {
let sources = self
.shared
.sources
.try_borrow_mut()
.try_lock()
.map_err(|_| L10nRegistrySetupError::RegistryLocked)?;
let mut result = HashSet::new();
for source in sources.iter().flatten() {

View file

@ -18,13 +18,19 @@
#include "js/OffThreadScriptCompilation.h"
#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_GetElement
#include "js/SourceText.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/CycleCollectedJSContext.h" // nsAutoMicroTask
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "nsICacheInfoChannel.h" //nsICacheInfoChannel
#include "nsICacheInfoChannel.h" // nsICacheInfoChannel
#include "nsNetUtil.h" // NS_NewURI
#include "nsThreadUtils.h" // GetMainThreadSerialEventTarget
#include "xpcpublic.h"
using JS::SourceText;
using mozilla::GetMainThreadSerialEventTarget;
using mozilla::Preferences;
using mozilla::dom::AutoJSAPI;
namespace JS::loader {
@ -105,6 +111,294 @@ NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase, mFetchingModules, mFetchedModules,
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleLoaderBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleLoaderBase)
// static
void ModuleLoaderBase::EnsureModuleHooksInitialized() {
AutoJSAPI jsapi;
jsapi.Init();
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
if (JS::GetModuleResolveHook(rt)) {
return;
}
JS::SetModuleResolveHook(rt, HostResolveImportedModule);
JS::SetModuleMetadataHook(rt, HostPopulateImportMeta);
JS::SetScriptPrivateReferenceHooks(rt, HostAddRefTopLevelScript,
HostReleaseTopLevelScript);
JS::SetSupportedAssertionsHook(rt, HostGetSupportedImportAssertions);
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
"javascript.options.dynamicImport",
(void*)nullptr);
}
// static
void ModuleLoaderBase::DynamicImportPrefChangedCallback(const char* aPrefName,
void* aClosure) {
bool enabled = Preferences::GetBool(aPrefName);
JS::ModuleDynamicImportHook hook =
enabled ? HostImportModuleDynamically : nullptr;
AutoJSAPI jsapi;
jsapi.Init();
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
JS::SetModuleDynamicImportHook(rt, hook);
}
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, moduleRequest)
/**
* Implement the HostResolveImportedModule abstract operation.
*
* Resolve a module specifier string and look this up in the module
* map, returning the result. This is only called for previously
* loaded modules and always succeeds.
*
* @param aReferencingPrivate A JS::Value which is either undefined
* or contains a LoadedScript private pointer.
* @param aModuleRequest A module request object.
* @returns module This is set to the module found.
*/
// static
JSObject* ModuleLoaderBase::HostResolveImportedModule(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest) {
JS::Rooted<JSObject*> module(aCx);
{
// LoadedScript should only live in this block, otherwise it will be a GC
// hazard
RefPtr<LoadedScript> script(
GetLoadedScriptOrNull(aCx, aReferencingPrivate));
JS::Rooted<JSString*> specifierString(
aCx, JS::GetModuleRequestSpecifier(aCx, aModuleRequest));
if (!specifierString) {
return nullptr;
}
// Let url be the result of resolving a module specifier given referencing
// module script and specifier.
nsAutoJSString string;
if (!string.init(aCx, specifierString)) {
return nullptr;
}
RefPtr<ModuleLoaderBase> loader = GetCurrentModuleLoader(aCx);
if (!loader) {
return nullptr;
}
nsCOMPtr<nsIURI> uri =
ModuleLoaderBase::ResolveModuleSpecifier(loader, script, string);
// This cannot fail because resolving a module specifier must have been
// previously successful with these same two arguments.
MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
// Use sandboxed global when doing a WebExtension content-script load.
nsCOMPtr<nsIGlobalObject> global;
if (mozilla::BasePrincipal::Cast(nsContentUtils::SubjectPrincipal(aCx))
->ContentScriptAddonPolicy()) {
global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
MOZ_ASSERT(
xpc::IsWebExtensionContentScriptSandbox(global->GetGlobalJSObject()));
}
// Let resolved module script be moduleMap[url]. (This entry must exist for
// us to have gotten to this point.)
ModuleScript* ms = loader->GetFetchedModule(uri, global);
MOZ_ASSERT(ms, "Resolved module not found in module map");
MOZ_ASSERT(!ms->HasParseError());
MOZ_ASSERT(ms->ModuleRecord());
module.set(ms->ModuleRecord());
}
return module;
}
// static
bool ModuleLoaderBase::HostPopulateImportMeta(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aMetaObject) {
RefPtr<ModuleScript> script =
static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(script->IsModuleScript());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
aReferencingPrivate);
nsAutoCString url;
MOZ_DIAGNOSTIC_ASSERT(script->BaseURL());
MOZ_ALWAYS_SUCCEEDS(script->BaseURL()->GetAsciiSpec(url));
JS::Rooted<JSString*> urlString(aCx, JS_NewStringCopyZ(aCx, url.get()));
if (!urlString) {
JS_ReportOutOfMemory(aCx);
return false;
}
return JS_DefineProperty(aCx, aMetaObject, "url", urlString,
JSPROP_ENUMERATE);
}
// static
bool ModuleLoaderBase::HostImportModuleDynamically(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest, JS::Handle<JSObject*> aPromise) {
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
JS::Rooted<JSString*> specifierString(
aCx, JS::GetModuleRequestSpecifier(aCx, aModuleRequest));
if (!specifierString) {
return false;
}
// Attempt to resolve the module specifier.
nsAutoJSString specifier;
if (!specifier.init(aCx, specifierString)) {
return false;
}
RefPtr<ModuleLoaderBase> loader = GetCurrentModuleLoader(aCx);
if (!loader) {
return false;
}
nsCOMPtr<nsIURI> uri =
ModuleLoaderBase::ResolveModuleSpecifier(loader, script, specifier);
if (!uri) {
JS::Rooted<JS::Value> error(aCx);
nsresult rv = ModuleLoaderBase::HandleResolveFailure(aCx, script, specifier,
0, 0, &error);
if (NS_FAILED(rv)) {
JS_ReportOutOfMemory(aCx);
return false;
}
JS_SetPendingException(aCx, error);
return false;
}
// Create a new top-level load request.
RefPtr<ModuleLoadRequest> request = loader->CreateDynamicImport(
aCx, uri, script, aReferencingPrivate, specifierString, aPromise);
loader->StartDynamicImport(request);
return true;
}
bool ModuleLoaderBase::HostGetSupportedImportAssertions(
JSContext* aCx, JS::ImportAssertionVector& aValues) {
MOZ_ASSERT(aValues.empty());
if (!aValues.reserve(1)) {
JS_ReportOutOfMemory(aCx);
return false;
}
aValues.infallibleAppend(JS::ImportAssertion::Type);
return true;
}
// static
ModuleLoaderBase* ModuleLoaderBase::GetCurrentModuleLoader(JSContext* aCx) {
auto reportError = mozilla::MakeScopeExit([aCx]() {
JS_ReportErrorASCII(aCx, "No ScriptLoader found for the current context");
});
JS::Rooted<JSObject*> object(aCx, JS::CurrentGlobalOrNull(aCx));
if (!object) {
return nullptr;
}
nsIGlobalObject* global = xpc::NativeGlobal(object);
if (!global) {
return nullptr;
}
ModuleLoaderBase* loader = global->GetModuleLoader(aCx);
if (!loader) {
return nullptr;
}
reportError.release();
return loader;
}
// static
LoadedScript* ModuleLoaderBase::GetLoadedScriptOrNull(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate) {
if (aReferencingPrivate.isUndefined()) {
return nullptr;
}
auto* script = static_cast<LoadedScript*>(aReferencingPrivate.toPrivate());
if (script->IsEventScript()) {
return nullptr;
}
MOZ_ASSERT_IF(
script->IsModuleScript(),
JS::GetModulePrivate(script->AsModuleScript()->ModuleRecord()) ==
aReferencingPrivate);
return script;
}
nsresult ModuleLoaderBase::StartModuleLoad(ModuleLoadRequest* aRequest) {
return StartOrRestartModuleLoad(aRequest, RestartRequest::No);
}
nsresult ModuleLoaderBase::RestartModuleLoad(ModuleLoadRequest* aRequest) {
return StartOrRestartModuleLoad(aRequest, RestartRequest::Yes);
}
nsresult ModuleLoaderBase::StartOrRestartModuleLoad(ModuleLoadRequest* aRequest,
RestartRequest aRestart) {
MOZ_ASSERT(aRequest->IsFetching());
aRequest->SetUnknownDataType();
// If we're restarting the request, the module should already be in the
// "fetching" map.
MOZ_ASSERT_IF(
aRestart == RestartRequest::Yes,
IsModuleFetching(aRequest->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal()));
// Check with the derived class whether we should load this module.
nsresult rv = NS_OK;
if (!CanStartLoad(aRequest, &rv)) {
return rv;
}
// Check whether the module has been fetched or is currently being fetched,
// and if so wait for it rather than starting a new fetch.
ModuleLoadRequest* request = aRequest->AsModuleRequest();
if (aRestart == RestartRequest::No &&
ModuleMapContainsURL(request->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal())) {
LOG(("ScriptLoadRequest (%p): Waiting for module fetch", aRequest));
WaitForModuleFetch(request->mURI,
aRequest->GetLoadContext()->GetWebExtGlobal())
->Then(GetMainThreadSerialEventTarget(), __func__, request,
&ModuleLoadRequest::ModuleLoaded,
&ModuleLoadRequest::LoadFailed);
return NS_OK;
}
rv = StartFetch(aRequest);
NS_ENSURE_SUCCESS(rv, rv);
// We successfully started fetching a module so put its URL in the module
// map and mark it as fetching.
if (aRestart == RestartRequest::No) {
SetModuleFetchStarted(aRequest->AsModuleRequest());
}
return NS_OK;
}
bool ModuleLoaderBase::ModuleMapContainsURL(nsIURI* aURL,
nsIGlobalObject* aGlobal) const {
// Returns whether we have fetched, or are currently fetching, a module script
@ -241,7 +535,7 @@ nsresult ModuleLoaderBase::CreateModuleScript(ModuleLoadRequest* aRequest) {
return NS_ERROR_FAILURE;
}
mozilla::dom::AutoJSAPI jsapi;
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return NS_ERROR_FAILURE;
}
@ -353,7 +647,7 @@ nsresult ModuleLoaderBase::HandleResolveFailure(
}
already_AddRefed<nsIURI> ModuleLoaderBase::ResolveModuleSpecifier(
ScriptLoaderInterface* aLoader, LoadedScript* aScript,
ModuleLoaderBase* aLoader, LoadedScript* aScript,
const nsAString& aSpecifier) {
// The following module specifiers are allowed by the spec:
// - a valid absolute URL
@ -383,7 +677,7 @@ already_AddRefed<nsIURI> ModuleLoaderBase::ResolveModuleSpecifier(
if (aScript) {
baseURL = aScript->BaseURL();
} else {
baseURL = aLoader->GetBaseURI();
baseURL = aLoader->mLoader->GetBaseURI();
}
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, baseURL);
@ -398,7 +692,7 @@ nsresult ModuleLoaderBase::ResolveRequestedModules(
ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOut) {
ModuleScript* ms = aRequest->mModuleScript;
mozilla::dom::AutoJSAPI jsapi;
AutoJSAPI jsapi;
if (!jsapi.Init(ms->ModuleRecord())) {
return NS_ERROR_FAILURE;
}
@ -432,7 +726,7 @@ nsresult ModuleLoaderBase::ResolveRequestedModules(
// and requested.
ModuleLoaderBase* requestModuleLoader = aRequest->mLoader;
nsCOMPtr<nsIURI> uri =
ResolveModuleSpecifier(requestModuleLoader->mLoader, ms, specifier);
ResolveModuleSpecifier(requestModuleLoader, ms, specifier);
if (!uri) {
uint32_t lineNumber = 0;
uint32_t columnNumber = 0;
@ -569,7 +863,7 @@ void ModuleLoaderBase::StartDynamicImport(ModuleLoadRequest* aRequest) {
void ModuleLoaderBase::FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
nsresult aResult) {
mozilla::dom::AutoJSAPI jsapi;
AutoJSAPI jsapi;
MOZ_ASSERT(NS_FAILED(aResult));
MOZ_ALWAYS_TRUE(jsapi.Init(aRequest->mDynamicPromise));
FinishDynamicImport(jsapi.cx(), aRequest, aResult, nullptr);
@ -613,7 +907,9 @@ void ModuleLoaderBase::FinishDynamicImport(
}
ModuleLoaderBase::ModuleLoaderBase(ScriptLoaderInterface* aLoader)
: mLoader(aLoader) {}
: mLoader(aLoader) {
EnsureModuleHooksInitialized();
}
ModuleLoaderBase::~ModuleLoaderBase() {
mDynamicImportRequests.CancelRequestsAndClear();
@ -688,7 +984,7 @@ bool ModuleLoaderBase::InstantiateModuleTree(ModuleLoadRequest* aRequest) {
MOZ_ASSERT(moduleScript->ModuleRecord());
mozilla::dom::AutoJSAPI jsapi;
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
return false;
}

View file

@ -11,6 +11,7 @@
#include "ScriptLoadRequest.h"
#include "js/TypeDecls.h" // JS::MutableHandle, JS::Handle, JS::Root
#include "js/Modules.h"
#include "nsRefPtrHashtable.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
@ -102,6 +103,7 @@ class ModuleLoaderBase : public nsISupports {
NS_DECL_CYCLE_COLLECTION_CLASS(ModuleLoaderBase)
explicit ModuleLoaderBase(ScriptLoaderInterface* aLoader);
using LoadedScript = JS::loader::LoadedScript;
using ScriptFetchOptions = JS::loader::ScriptFetchOptions;
using ScriptLoadRequest = JS::loader::ScriptLoadRequest;
using ModuleLoadRequest = JS::loader::ModuleLoadRequest;
@ -109,25 +111,34 @@ class ModuleLoaderBase : public nsISupports {
using MaybeSourceText =
mozilla::MaybeOneOf<JS::SourceText<char16_t>, JS::SourceText<Utf8Unit>>;
// Methods that must be overwritten by an extending class. These are called
// Methods that must be implemented by an extending class. These are called
// internally by ModuleLoaderBase.
private:
virtual void EnsureModuleHooksInitialized() {
MOZ_ASSERT(false, "You must override EnsureModuleHooksInitialized");
}
virtual nsresult StartModuleLoad(ScriptLoadRequest* aRequest) = 0;
virtual nsresult RestartModuleLoad(ScriptLoadRequest* aRequest) = 0;
// Create a module load request for a static module import.
virtual already_AddRefed<ModuleLoadRequest> CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) = 0;
// Called by HostImportModuleDynamically hook.
virtual already_AddRefed<ModuleLoadRequest> CreateDynamicImport(
JSContext* aCx, nsIURI* aURI, LoadedScript* aMaybeActiveScript,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise) = 0;
// Check whether we can load a module. May return false with |aRvOut| set to
// NS_OK to abort load without returning an error.
virtual bool CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) = 0;
// Start the process of fetching module source or bytecode. This is only
// called if CanStartLoad returned true.
virtual nsresult StartFetch(ModuleLoadRequest* aRequest) = 0;
virtual void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) = 0;
virtual nsresult CompileOrFinishModuleScript(
JSContext* aCx, JS::Handle<JSObject*> aGlobal,
JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest,
JS::MutableHandle<JSObject*> aModuleScript) = 0;
// Create a module load request for a static module import.
virtual already_AddRefed<ModuleLoadRequest> CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) = 0;
// Public API methods.
public:
@ -137,16 +148,10 @@ class ModuleLoaderBase : public nsISupports {
bool HasDynamicImport(ModuleLoadRequest* aRequest) const;
#endif
static already_AddRefed<nsIURI> ResolveModuleSpecifier(
ScriptLoaderInterface* loader, LoadedScript* aScript,
const nsAString& aSpecifier);
static nsresult HandleResolveFailure(JSContext* aCx, LoadedScript* aScript,
const nsAString& aSpecifier,
uint32_t aLineNumber,
uint32_t aColumnNumber,
JS::MutableHandle<JS::Value> errorOut);
ModuleScript* GetFetchedModule(nsIURI* aURL, nsIGlobalObject* aGlobal) const;
// Start a load for a module script URI. Returns immediately if the module is
// already being loaded.
nsresult StartModuleLoad(ModuleLoadRequest* aRequest);
nsresult RestartModuleLoad(ModuleLoadRequest* aRequest);
void SetModuleFetchFinishedAndResumeWaitingRequests(
ModuleLoadRequest* aRequest, nsresult aResult);
@ -162,19 +167,52 @@ class ModuleLoaderBase : public nsISupports {
void ProcessDynamicImport(ModuleLoadRequest* aRequest);
void CancelAndClearDynamicImports();
// Protected methods for used by concrete implementation.
// Internal methods.
private:
friend class JS::loader::ModuleLoadRequest;
static ModuleLoaderBase* GetCurrentModuleLoader(JSContext* aCx);
static LoadedScript* GetLoadedScriptOrNull(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate);
static void EnsureModuleHooksInitialized();
static void DynamicImportPrefChangedCallback(const char* aPrefName,
void* aClosure);
static JSObject* HostResolveImportedModule(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest);
static bool HostPopulateImportMeta(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aMetaObject);
static bool HostImportModuleDynamically(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSObject*> aModuleRequest, JS::Handle<JSObject*> aPromise);
static bool HostGetSupportedImportAssertions(
JSContext* aCx, JS::ImportAssertionVector& aValues);
static already_AddRefed<nsIURI> ResolveModuleSpecifier(
ModuleLoaderBase* aLoader, LoadedScript* aScript,
const nsAString& aSpecifier);
static nsresult HandleResolveFailure(JSContext* aCx, LoadedScript* aScript,
const nsAString& aSpecifier,
uint32_t aLineNumber,
uint32_t aColumnNumber,
JS::MutableHandle<JS::Value> errorOut);
enum class RestartRequest { No, Yes };
nsresult StartOrRestartModuleLoad(ModuleLoadRequest* aRequest,
RestartRequest aRestart);
protected:
bool ModuleMapContainsURL(nsIURI* aURL, nsIGlobalObject* aGlobal) const;
bool IsModuleFetching(nsIURI* aURL, nsIGlobalObject* aGlobal) const;
RefPtr<GenericNonExclusivePromise> WaitForModuleFetch(
nsIURI* aURL, nsIGlobalObject* aGlobal);
void SetModuleFetchStarted(ModuleLoadRequest* aRequest);
// Internal methods.
private:
friend class JS::loader::ModuleLoadRequest;
ModuleScript* GetFetchedModule(nsIURI* aURL, nsIGlobalObject* aGlobal) const;
// Helper function to set up the global correctly for dynamic imports.
nsresult EvaluateModule(ScriptLoadRequest* aRequest);

Some files were not shown because too many files have changed in this diff Show more