Update On Tue Mar 29 20:30:19 CEST 2022
This commit is contained in:
parent
b04421f0b7
commit
3360d722f7
204 changed files with 15043 additions and 22058 deletions
|
@ -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 |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 62 KiB |
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
4479
browser/components/newtab/package-lock.json
generated
4479
browser/components/newtab/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -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:*",
|
||||
|
|
|
@ -60,6 +60,9 @@ module.exports = (env = {}) => ({
|
|||
resolve: {
|
||||
extensions: [".js", ".jsx"],
|
||||
modules: ["node_modules", "."],
|
||||
fallback: {
|
||||
stream: require.resolve("stream-browserify"),
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
"prop-types": "PropTypes",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
®isteredApp);
|
||||
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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
})();
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
@ -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",
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
55
caps/tests/gtest/TestNullPrincipalPrecursor.cpp
Normal file
55
caps/tests/gtest/TestNullPrincipalPrecursor.cpp
Normal 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
|
|
@ -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",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 observer’s internal [[ObservationTargets]] slot,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -675,7 +675,7 @@ bool nsHTMLDocument::WillIgnoreCharsetOverride() {
|
|||
case kCharsetFromDocTypeDefault:
|
||||
case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
|
||||
case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
|
||||
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8:
|
||||
case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
|
||||
case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
|
||||
case kCharsetFromParentFrame:
|
||||
case kCharsetFromXmlDeclaration:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 }),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue