Merge autoland to mozilla-central a=merge

This commit is contained in:
Andreea Pavel 2022-04-28 00:33:50 +03:00
Родитель fbda844614 04a3fefa59
Коммит 86c98c486f
191 изменённых файлов: 3995 добавлений и 2218 удалений

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

@ -6318,7 +6318,7 @@ nsBrowserAccess.prototype = {
forceNotRemote,
userContextId,
aOpenWindowInfo,
null,
aOpenWindowInfo?.parent?.top.embedderElement,
aTriggeringPrincipal,
"",
aCsp,

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

@ -914,7 +914,9 @@ DownloadsDataCtor.prototype = {
if (!download.newDownloadNotified) {
download.newDownloadNotified = true;
this._notifyDownloadEvent("start");
this._notifyDownloadEvent("start", {
openDownloadsListOnStart: download.openDownloadsListOnStart,
});
}
},
@ -968,12 +970,15 @@ DownloadsDataCtor.prototype = {
/**
* Displays a new or finished download notification in the most recent browser
* window, if one is currently available with the required privacy type.
*
* @param aType
* @param {string} aType
* Set to "start" for new downloads, "finish" for completed downloads,
* "error" for downloads that failed and need attention
* @param {boolean} [openDownloadsListOnStart]
* (Only relevant when aType = "start")
* true (default) - open the downloads panel.
* false - only show an indicator notification.
*/
_notifyDownloadEvent(aType) {
_notifyDownloadEvent(aType, { openDownloadsListOnStart = true } = {}) {
DownloadsCommon.log(
"Attempting to notify that a new download has started or finished."
);
@ -987,6 +992,7 @@ DownloadsDataCtor.prototype = {
}
let shouldOpenDownloadsPanel =
openDownloadsListOnStart &&
aType == "start" &&
Services.prefs.getBoolPref(
"browser.download.improvements_to_download_panel"

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

@ -77,23 +77,20 @@ add_task(async function test_customizemode_doesnt_wreck_things() {
});
/**
* Make sure the downloads panel _does not_ open automatically if we set the
* pref telling it not to do that.
* Start a download and check that the downloads panel opens correctly according
* to the download parameter, openDownloadsListOnStart
* @param {boolean} [openDownloadsListOnStart]
* true (default) - open downloads panel when download starts
* false - no downloads panel; update indicator attention state
*/
add_task(async function test_downloads_panel_opening_pref() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.download.improvements_to_download_panel", true],
["browser.download.always_ask_before_handling_new_types", false],
["browser.download.alwaysOpenPanel", false],
],
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
async function downloadAndCheckPanel({ openDownloadsListOnStart = true } = {}) {
info("creating a download and setting it to in progress");
await task_addDownloads([{ state: DownloadsCommon.DOWNLOAD_DOWNLOADING }]);
await task_addDownloads([
{
state: DownloadsCommon.DOWNLOAD_DOWNLOADING,
openDownloadsListOnStart,
},
]);
let publicList = await Downloads.getList(Downloads.PUBLIC);
let downloads = await publicList.getAll();
downloads[0].stopped = false;
@ -116,7 +113,9 @@ add_task(async function test_downloads_panel_opening_pref() {
};
});
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
DownloadsCommon.getData(window)._notifyDownloadEvent("start", {
openDownloadsListOnStart,
});
is(
DownloadsPanel.isPanelShowing,
false,
@ -126,12 +125,160 @@ add_task(async function test_downloads_panel_opening_pref() {
info("waiting for download to start");
await promiseDownloadStartedNotification;
DownloadsIndicatorView.showEventNotification = oldShowEventNotification;
is(DownloadsPanel.panel.state, "closed", "Panel should be closed");
}
/**
* Make sure the downloads panel _does not_ open automatically if we set the
* pref telling it not to do that.
*/
add_task(async function test_downloads_panel_opening_pref() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.download.improvements_to_download_panel", true],
["browser.download.always_ask_before_handling_new_types", false],
["browser.download.alwaysOpenPanel", false],
],
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
await downloadAndCheckPanel();
await SpecialPowers.popPrefEnv();
});
/**
* Make sure the downloads panel opens automatically with new download, only if no other downloads are in progress.
* Make sure the downloads panel _does not_ open automatically if we pass the
* parameter telling it not to do that to the download constructor.
*/
add_task(async function test_downloads_openDownloadsListOnStart_param() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.download.improvements_to_download_panel", true],
["browser.download.always_ask_before_handling_new_types", false],
["browser.download.alwaysOpenPanel", true],
],
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
await downloadAndCheckPanel({ openDownloadsListOnStart: false });
await SpecialPowers.popPrefEnv();
});
/**
* Make sure the downloads panel _does not_ open automatically when an
* extension calls the browser.downloads.download API method while it is
* not handling user input, but that we do open it automatically when
* the same WebExtensions API is called while handling user input
* (See Bug 1759231)
*/
add_task(async function test_downloads_panel_on_webext_download_api() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.download.improvements_to_download_panel", true],
["browser.download.always_ask_before_handling_new_types", false],
["browser.download.alwaysOpenPanel", true],
],
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
const extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["downloads"],
},
background() {
async function startDownload(downloadOptions) {
/* globals browser */
const downloadId = await browser.downloads.download(downloadOptions);
const downloadDone = new Promise(resolve => {
browser.downloads.onChanged.addListener(function listener(delta) {
browser.test.log(`downloads.onChanged = ${JSON.stringify(delta)}`);
if (
delta.id == downloadId &&
delta.state?.current !== "in_progress"
) {
browser.downloads.onChanged.removeListener(listener);
resolve();
}
});
});
browser.test.sendMessage("start-download:done");
await downloadDone;
await browser.downloads.removeFile(downloadId);
browser.test.sendMessage("removed-download-file");
}
browser.test.onMessage.addListener(
(msg, { withHandlingUserInput, downloadOptions }) => {
if (msg !== "start-download") {
browser.test.fail(`Got unexpected test message: ${msg}`);
return;
}
if (withHandlingUserInput) {
browser.test.withHandlingUserInput(() =>
startDownload(downloadOptions)
);
} else {
startDownload(downloadOptions);
}
}
);
},
});
await extension.startup();
startServer();
async function testExtensionDownloadCall({ withHandlingUserInput }) {
mustInterruptResponses();
let rnd = Math.random();
let url = httpUrl(`interruptible.txt?q=${rnd}`);
extension.sendMessage("start-download", {
withHandlingUserInput,
downloadOptions: { url },
});
await extension.awaitMessage("start-download:done");
let publicList = await Downloads.getList(Downloads.PUBLIC);
let downloads = await publicList.getAll();
let download = downloads.find(d => d.source.url === url);
is(download.source.url, url, "download has the expected url");
is(
download.openDownloadsListOnStart,
withHandlingUserInput,
`download panel should ${withHandlingUserInput ? "open" : "stay closed"}`
);
continueResponses();
await extension.awaitMessage("removed-download-file");
}
info(
"Test extension downloads.download API method call without handling user input"
);
await testExtensionDownloadCall({ withHandlingUserInput: true });
info(
"Test extension downloads.download API method call while handling user input"
);
await testExtensionDownloadCall({ withHandlingUserInput: false });
await extension.unload();
await SpecialPowers.popPrefEnv();
});
/**
* Make sure the downloads panel opens automatically with new download, only if
* no other downloads are in progress.
*/
add_task(async function test_downloads_panel_remains_closed() {
await SpecialPowers.pushPrefEnv({

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

@ -242,6 +242,7 @@ async function task_addDownloads(aItems) {
: null,
hasPartialData: item.state == DownloadsCommon.DOWNLOAD_PAUSED,
hasBlockedData: item.hasBlockedData || false,
openDownloadsListOnStart: item.openDownloadsListOnStart ?? true,
contentType: item.contentType,
startTime: new Date(startTimeMs++),
};

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

@ -425,6 +425,12 @@ class BasePopup {
if (this.destroyed) {
return;
}
// Only block the parser for the preloaded browser, initBrowser will be
// called again when the browserAction popup is navigated and we should
// not block the parser in that case, otherwise the navigating the popup
// to another extension page will never complete and the popup will
// stay stuck on the previous extension page. See Bug 1747813.
this.blockParser = false;
this.browser.messageManager.sendAsyncMessage("Extension:UnblockParser");
});
}
@ -580,6 +586,11 @@ class ViewPopup extends BasePopup {
this.tempPanel = panel;
this.tempBrowser = this.browser;
// NOTE: this class is added to the preload browser and never removed because
// the preload browser is then switched with a new browser once we are about to
// make the popup visible (this class is not actually used anywhere but it may
// be useful to keep it around to be able to identify the preload buffer while
// investigating issues).
this.browser.classList.add("webextension-preload-browser");
}

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

@ -76,3 +76,72 @@ add_task(async function process_switch_in_sidebars_popups() {
await closeBrowserAction(extension);
await extension.unload();
});
// Test that navigating the browserAction popup between extension pages doesn't keep the
// parser blocked (See Bug 1747813).
add_task(
async function test_navigate_browserActionPopups_shouldnot_block_parser() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
browser_action: {
default_popup: "popup-1.html",
},
},
files: {
"popup-1.html": `<!DOCTYPE html><meta charset=utf-8><script src=popup-1.js></script><h1>Popup 1</h1>`,
"popup-2.html": `<!DOCTYPE html><meta charset=utf-8><script src=popup-2.js></script><h1>Popup 2</h1>`,
"popup-1.js": function() {
browser.test.onMessage.addListener(msg => {
if (msg !== "navigate-popup") {
browser.test.fail(`Unexpected test message "${msg}"`);
return;
}
location.href = "/popup-2.html";
});
window.onload = () => browser.test.sendMessage("popup-page-1");
},
"popup-2.js": function() {
window.onload = () => browser.test.sendMessage("popup-page-2");
},
},
});
// Make sure the mouse isn't hovering over the browserAction widget.
EventUtils.synthesizeMouseAtCenter(
gURLBar.textbox,
{ type: "mouseover" },
window
);
await extension.startup();
// Triggers popup preload (otherwise we wouldn't be blocking the parser for the browserAction popup
// and the issue wouldn't be triggered, a real user on the contrary has a pretty high chance to trigger a
// preload while hovering the browserAction popup before opening the popup with a click).
let widget = getBrowserActionWidget(extension).forWindow(window);
EventUtils.synthesizeMouseAtCenter(
widget.node,
{ type: "mouseover" },
window
);
await clickBrowserAction(extension);
await extension.awaitMessage("popup-page-1");
extension.sendMessage("navigate-popup");
await extension.awaitMessage("popup-page-2");
// If the bug is triggered (e.g. it did regress), the test will get stuck waiting for
// the test message "popup-page-2" (which will never be sent because the extension page
// script isn't executed while the parser is blocked).
ok(
true,
"Extension browserAction popup successfully navigated to popup-page-2.html"
);
await closeBrowserAction(extension);
await extension.unload();
}
);

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

@ -290,7 +290,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
...eventData,
event_context: {
...eventData.event_context,
page: "about:welcome",
},
});
}

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

@ -23,6 +23,141 @@ module.exports = ReactDOM;
/* 3 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "AboutWelcomeUtils": () => (/* binding */ AboutWelcomeUtils),
/* harmony export */ "DEFAULT_RTAMO_CONTENT": () => (/* binding */ DEFAULT_RTAMO_CONTENT)
/* harmony export */ });
/* 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/. */
// If we're in a subdialog, then this is a spotlight modal
const page = document.querySelector(":root[dialogroot=true]") ? "spotlight" : "about:welcome";
const AboutWelcomeUtils = {
handleUserAction(action) {
window.AWSendToParent("SPECIAL_ACTION", action);
},
sendImpressionTelemetry(messageId, context) {
window.AWSendEventTelemetry({
event: "IMPRESSION",
event_context: { ...context,
page
},
message_id: messageId
});
},
sendActionTelemetry(messageId, elementId, eventName = "CLICK_BUTTON") {
const ping = {
event: eventName,
event_context: {
source: elementId,
page
},
message_id: messageId
};
window.AWSendEventTelemetry(ping);
},
async fetchFlowParams(metricsFlowUri) {
let flowParams;
try {
const response = await fetch(metricsFlowUri, {
credentials: "omit"
});
if (response.status === 200) {
const {
deviceId,
flowId,
flowBeginTime
} = await response.json();
flowParams = {
deviceId,
flowId,
flowBeginTime
};
} else {
console.error("Non-200 response", response); // eslint-disable-line no-console
}
} catch (e) {
flowParams = null;
}
return flowParams;
},
sendEvent(type, detail) {
document.dispatchEvent(new CustomEvent(`AWPage:${type}`, {
bubbles: true,
detail
}));
}
};
const DEFAULT_RTAMO_CONTENT = {
template: "return_to_amo",
utm_term: "rtamo",
content: {
position: "corner",
hero_text: {
string_id: "mr1-welcome-screen-hero-text"
},
title: {
string_id: "return-to-amo-subtitle"
},
has_noodles: true,
subtitle: {
string_id: "return-to-amo-addon-title"
},
help_text: {
string_id: "mr1-onboarding-welcome-image-caption"
},
backdrop: "#212121 url(chrome://activity-stream/content/data/content/assets/proton-bkg.avif) center/cover no-repeat fixed",
primary_button: {
label: {
string_id: "return-to-amo-add-extension-label"
},
source_id: "ADD_EXTENSION_BUTTON",
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {
url: null,
telemetrySource: "rtamo"
}
}
},
secondary_button: {
label: {
string_id: "onboarding-not-now-button-label"
},
source_id: "RTAMO_START_BROWSING_BUTTON",
action: {
type: "OPEN_AWESOME_BAR"
}
},
secondary_button_top: {
label: {
string_id: "mr1-onboarding-sign-in-button-label"
},
source_id: "RTAMO_FXA_SIGNIN_BUTTON",
action: {
data: {
entrypoint: "activity-stream-firstrun"
},
type: "SHOW_FIREFOX_ACCOUNTS",
addFlowParams: true
}
}
}
};
/***/ }),
/* 4 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "MultiStageAboutWelcome": () => (/* binding */ MultiStageAboutWelcome),
@ -32,8 +167,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(11);
@ -342,7 +477,7 @@ class WelcomeScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
}
/***/ }),
/* 4 */
/* 5 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
@ -435,137 +570,6 @@ const Localized = ({
textNodes.length ? textNodes : null);
};
/***/ }),
/* 5 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "AboutWelcomeUtils": () => (/* binding */ AboutWelcomeUtils),
/* harmony export */ "DEFAULT_RTAMO_CONTENT": () => (/* binding */ DEFAULT_RTAMO_CONTENT)
/* harmony export */ });
/* 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/. */
const AboutWelcomeUtils = {
handleUserAction(action) {
window.AWSendToParent("SPECIAL_ACTION", action);
},
sendImpressionTelemetry(messageId, context) {
window.AWSendEventTelemetry({
event: "IMPRESSION",
event_context: context,
message_id: messageId
});
},
sendActionTelemetry(messageId, elementId, eventName = "CLICK_BUTTON") {
const ping = {
event: eventName,
event_context: {
source: elementId,
page: "about:welcome"
},
message_id: messageId
};
window.AWSendEventTelemetry(ping);
},
async fetchFlowParams(metricsFlowUri) {
let flowParams;
try {
const response = await fetch(metricsFlowUri, {
credentials: "omit"
});
if (response.status === 200) {
const {
deviceId,
flowId,
flowBeginTime
} = await response.json();
flowParams = {
deviceId,
flowId,
flowBeginTime
};
} else {
console.error("Non-200 response", response); // eslint-disable-line no-console
}
} catch (e) {
flowParams = null;
}
return flowParams;
},
sendEvent(type, detail) {
document.dispatchEvent(new CustomEvent(`AWPage:${type}`, {
bubbles: true,
detail
}));
}
};
const DEFAULT_RTAMO_CONTENT = {
template: "return_to_amo",
utm_term: "rtamo",
content: {
position: "corner",
hero_text: {
string_id: "mr1-welcome-screen-hero-text"
},
title: {
string_id: "return-to-amo-subtitle"
},
has_noodles: true,
subtitle: {
string_id: "return-to-amo-addon-title"
},
help_text: {
string_id: "mr1-onboarding-welcome-image-caption"
},
backdrop: "#212121 url(chrome://activity-stream/content/data/content/assets/proton-bkg.avif) center/cover no-repeat fixed",
primary_button: {
label: {
string_id: "return-to-amo-add-extension-label"
},
source_id: "ADD_EXTENSION_BUTTON",
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {
url: null,
telemetrySource: "rtamo"
}
}
},
secondary_button: {
label: {
string_id: "onboarding-not-now-button-label"
},
source_id: "RTAMO_START_BROWSING_BUTTON",
action: {
type: "OPEN_AWESOME_BAR"
}
},
secondary_button_top: {
label: {
string_id: "mr1-onboarding-sign-in-button-label"
},
source_id: "RTAMO_FXA_SIGNIN_BUTTON",
action: {
data: {
entrypoint: "activity-stream-firstrun"
},
type: "SHOW_FIREFOX_ACCOUNTS",
addFlowParams: true
}
}
}
};
/***/ }),
/* 6 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
@ -577,11 +581,11 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _Colorways__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
/* harmony import */ var _MobileDownloads__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
/* harmony import */ var _Themes__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
/* harmony import */ var _MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3);
/* harmony import */ var _MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4);
/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(10);
/* 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,
@ -820,7 +824,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* 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/. */
@ -1008,7 +1012,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* 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/. */
@ -1067,7 +1071,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* 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/. */
@ -1122,8 +1126,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* 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/. */
@ -1412,7 +1416,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -1607,8 +1611,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -1619,6 +1624,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
@ -1645,17 +1651,12 @@ class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
domComplete,
domInteractive
} = performance.getEntriesByType("navigation").pop();
window.AWSendEventTelemetry({
event: "IMPRESSION",
event_context: {
domComplete,
domInteractive,
mountStart: performance.getEntriesByName("mount").pop().startTime,
domState,
source: this.props.UTMTerm,
page: "about:welcome"
},
message_id: this.props.messageId
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendImpressionTelemetry(this.props.messageId, {
domComplete,
domInteractive,
mountStart: performance.getEntriesByName("mount").pop().startTime,
domState,
source: this.props.UTMTerm
});
};
@ -1681,7 +1682,7 @@ class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
} = this;
if (props.template === "return_to_amo") {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__.ReturnToAMO, {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__.ReturnToAMO, {
message_id: props.messageId,
type: props.type,
name: props.name,
@ -1692,7 +1693,7 @@ class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
});
}
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__.MultiStageAboutWelcome, {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__.MultiStageAboutWelcome, {
message_id: props.messageId,
screens: props.screens,
metricsFlowUri: this.state.metricsFlowUri,

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

@ -4,6 +4,7 @@
import React from "react";
import ReactDOM from "react-dom";
import { AboutWelcomeUtils } from "../lib/aboutwelcome-utils";
import { MultiStageAboutWelcome } from "./components/MultiStageAboutWelcome";
import { ReturnToAMO } from "./components/ReturnToAMO";
@ -27,17 +28,12 @@ class AboutWelcome extends React.PureComponent {
const { domComplete, domInteractive } = performance
.getEntriesByType("navigation")
.pop();
window.AWSendEventTelemetry({
event: "IMPRESSION",
event_context: {
domComplete,
domInteractive,
mountStart: performance.getEntriesByName("mount").pop().startTime,
domState,
source: this.props.UTMTerm,
page: "about:welcome",
},
message_id: this.props.messageId,
AboutWelcomeUtils.sendImpressionTelemetry(this.props.messageId, {
domComplete,
domInteractive,
mountStart: performance.getEntriesByName("mount").pop().startTime,
domState,
source: this.props.UTMTerm,
});
};
if (document.readyState === "complete") {

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

@ -2,6 +2,11 @@
* 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/. */
// If we're in a subdialog, then this is a spotlight modal
const page = document.querySelector(":root[dialogroot=true]")
? "spotlight"
: "about:welcome";
export const AboutWelcomeUtils = {
handleUserAction(action) {
window.AWSendToParent("SPECIAL_ACTION", action);
@ -9,7 +14,10 @@ export const AboutWelcomeUtils = {
sendImpressionTelemetry(messageId, context) {
window.AWSendEventTelemetry({
event: "IMPRESSION",
event_context: context,
event_context: {
...context,
page,
},
message_id: messageId,
});
},
@ -18,7 +26,7 @@ export const AboutWelcomeUtils = {
event: eventName,
event_context: {
source: elementId,
page: "about:welcome",
page,
},
message_id: messageId,
};

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

@ -50,6 +50,7 @@ support-files=
[browser_discovery_card.js]
[browser_getScreenshots.js]
[browser_multistage_spotlight.js]
[browser_multistage_spotlight_telemetry.js]
[browser_newtab_overrides.js]
[browser_newtab_header.js]
[browser_newtab_last_LinkMenu.js]

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

@ -342,6 +342,11 @@ add_task(async function test_AWMultistage_Primary_Action() {
"DEFAULT_ABOUTWELCOME_PROTON_SITES",
"SITES MessageId sent in impression event telemetry"
);
Assert.equal(
impressionCall.args[1].event_context.page,
"about:welcome",
"event context page set to 'about:welcome'"
);
}
// For some builds, we can stub fast enough to catch the performance
@ -677,3 +682,28 @@ test_newtab(
},
"about:welcome"
);
add_task(async function test_send_aboutwelcome_as_page_in_event_telemetry() {
const sandbox = sinon.createSandbox();
let browser = await openAboutWelcome();
let aboutWelcomeActor = await getAboutWelcomeParent(browser);
// Stub AboutWelcomeParent Content Message Handler
let telemetryStub = sandbox.stub(aboutWelcomeActor, "onContentMessage");
await onButtonClick(browser, "button.primary");
Assert.equal(
telemetryStub.lastCall.args[1].event,
"CLICK_BUTTON",
"Event telemetry sent on primary button press"
);
Assert.equal(
telemetryStub.lastCall.args[1].event_context.page,
"about:welcome",
"Event context page set to 'about:welcome' in event telemetry"
);
registerCleanupFunction(() => {
sandbox.restore();
});
});

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

@ -0,0 +1,50 @@
"use strict";
const { Spotlight } = ChromeUtils.import(
"resource://activity-stream/lib/Spotlight.jsm"
);
const { PanelTestProvider } = ChromeUtils.import(
"resource://activity-stream/lib/PanelTestProvider.jsm"
);
const { BrowserWindowTracker } = ChromeUtils.import(
"resource:///modules/BrowserWindowTracker.jsm"
);
async function waitForClick(selector, win) {
await TestUtils.waitForCondition(() => win.document.querySelector(selector));
win.document.querySelector(selector).click();
}
async function showDialog(dialogOptions) {
Spotlight.showSpotlightDialog(
dialogOptions.browser,
dialogOptions.message,
dialogOptions.dispatchStub
);
const [win] = await TestUtils.topicObserved("subdialog-loaded");
return win;
}
add_task(async function send_spotlight_as_page_in_telemetry() {
let message = (await PanelTestProvider.getMessages()).find(
m => m.id === "MULTISTAGE_SPOTLIGHT_MESSAGE"
);
let dispatchStub = sinon.stub();
let browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
let win = await showDialog({ message, browser, dispatchStub });
let sandbox = sinon.createSandbox();
sandbox.stub(win, "AWSendEventTelemetry");
await waitForClick("button.secondary", win);
Assert.equal(
win.AWSendEventTelemetry.lastCall.args[0].event_context.page,
"spotlight",
"The value of event context page should be set to 'spotlight' in event telemetry"
);
win.close();
registerCleanupFunction(() => {
sandbox.restore();
});
});

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

@ -70,8 +70,10 @@ add_task(async function test_click_on_footer() {
PRIVACY_PREF_URL,
true
);
// Wait for dropdown animation finished to continue mouse synthesizing.
await sleep(3000);
// Make sure dropdown is visible before continuing mouse synthesizing.
await BrowserTestUtils.waitForCondition(() =>
BrowserTestUtils.is_visible(optionButton)
);
await EventUtils.synthesizeMouseAtCenter(optionButton, {});
info(`expecting tab: about:preferences#privacy opened`);
const prefTab = await prefTabPromise;

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

@ -475,6 +475,7 @@ class HTTPCustomRequestPanel extends Component {
onClick: () => {
const customRequestDetails = {
...this.state,
cause: this.props.request?.cause,
urlQueryParams: urlQueryParams.map(
({ checked, ...params }) => params
),

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

@ -20,6 +20,7 @@ add_task(async function() {
);
return;
}
const { tab, monitor } = await initNetMonitor(POST_RAW_URL, {
requestCount: 1,
});
@ -79,3 +80,83 @@ add_task(async function() {
await teardown(monitor);
});
/**
* Tests if resending an XHR request while XHR filtering is on, displays
* the correct requests
*/
add_task(async function() {
if (
Services.prefs.getBoolPref(
"devtools.netmonitor.features.newEditAndResend",
true
)
) {
const { tab, monitor } = await initNetMonitor(POST_RAW_URL, {
requestCount: 1,
});
const { document, store, windowRequire } = monitor.panelWin;
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
const Actions = windowRequire(
"devtools/client/netmonitor/src/actions/index"
);
store.dispatch(Actions.batchEnable(false));
// Execute XHR request and filter by XHR
await performRequests(monitor, tab, 1);
document.querySelector(".requests-list-filter-xhr-button").click();
// Confirm XHR request and click it
const xhrRequestItem = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, xhrRequestItem);
const waitForHeaders = waitUntil(() =>
document.querySelector(".headers-overview")
);
await waitForHeaders;
const firstRequest = getSelectedRequest(store.getState());
// Open context menu and execute "Edit & Resend".
EventUtils.sendMouseEvent({ type: "contextmenu" }, xhrRequestItem);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
const menuItem = getContextMenuItem(monitor, "request-list-context-resend");
getContextMenuItem(monitor, "request-list-context-resend").click();
const menuPopup = menuItem.parentNode;
const onHidden = new Promise(resolve => {
menuPopup.addEventListener("popuphidden", resolve, { once: true });
});
menuItem.click();
menuPopup.hidePopup();
await onHidden;
await waitForPanels;
// Click the "Send" button and wait till the new request appears in the list
document.querySelector("#http-custom-request-send-button").click();
await waitForNetworkEvents(monitor, 1);
// Filtering by "other" so the resent request is visible after completion
document.querySelector(".requests-list-filter-other-button").click();
// Select new request
const newRequest = document.querySelectorAll(".request-list-item")[1];
EventUtils.sendMouseEvent({ type: "mousedown" }, newRequest);
const resendRequest = getSelectedRequest(store.getState());
ok(
resendRequest.id !== firstRequest.id,
"The second XHR request was made and is unique"
);
await teardown(monitor);
}
});

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

@ -67,3 +67,63 @@ add_task(async function() {
await teardown(monitor);
});
/**
* Tests if editing and resending a XHR request works and the
* new request retains the same cause type.
*/
add_task(async function() {
if (
Services.prefs.getBoolPref(
"devtools.netmonitor.features.newEditAndResend",
true
)
) {
const { tab, monitor } = await initNetMonitor(POST_RAW_URL, {
requestCount: 1,
});
const { document, store, windowRequire } = monitor.panelWin;
const Actions = windowRequire(
"devtools/client/netmonitor/src/actions/index"
);
store.dispatch(Actions.batchEnable(false));
// Executes 1 XHR request
await performRequests(monitor, tab, 1);
// Selects 1st XHR request
const xhrRequest = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, xhrRequest);
// Stores original request for comparison of values later
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
const original = getSelectedRequest(store.getState());
// Context Menu > "Edit & Resend"
EventUtils.sendMouseEvent({ type: "contextmenu" }, xhrRequest);
getContextMenuItem(monitor, "request-list-context-resend").click();
// 1) Wait for "Edit & Resend" panel to appear
// 2) Click the "Send" button
// 3) Wait till the new request appears in the list
await waitUntil(() => document.querySelector(".http-custom-request-panel"));
document.querySelector("#http-custom-request-send-button").click();
await waitForNetworkEvents(monitor, 1);
// Selects new request
const newRequest = document.querySelectorAll(".request-list-item")[1];
EventUtils.sendMouseEvent({ type: "mousedown" }, newRequest);
const request = getSelectedRequest(store.getState());
ok(
original.cause.type === request.cause.type,
"Both requests retain the same cause type"
);
await teardown(monitor);
}
});

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

@ -69,3 +69,94 @@ add_task(async function() {
await teardown(monitor);
});
/**
* Tests if resending an image request uses the same content type
* and hence is not blocked by the CSP of the page.
*/
add_task(async function() {
if (
Services.prefs.getBoolPref(
"devtools.netmonitor.features.newEditAndResend",
true
)
) {
const { tab, monitor } = await initNetMonitor(CSP_RESEND_URL, {
requestCount: 1,
});
const { document, store, windowRequire } = monitor.panelWin;
const Actions = windowRequire(
"devtools/client/netmonitor/src/actions/index"
);
store.dispatch(Actions.batchEnable(false));
// Executes 1 request
await performRequests(monitor, tab, 1);
// Select the image request
const imgRequest = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, imgRequest);
// Stores original request for comparison of values later
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
const origReq = getSelectedRequest(store.getState());
// Context Menu > "Resend"
EventUtils.sendMouseEvent({ type: "contextmenu" }, imgRequest);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
const menuItem = getContextMenuItem(monitor, "request-list-context-resend");
getContextMenuItem(monitor, "request-list-context-resend").click();
const menuPopup = menuItem.parentNode;
const onHidden = new Promise(resolve => {
menuPopup.addEventListener("popuphidden", resolve, { once: true });
});
menuItem.click();
menuPopup.hidePopup();
await onHidden;
await waitForPanels;
const waitForResentRequest = waitForNetworkEvents(monitor, 1);
const buttonSend = document.querySelector(
"#http-custom-request-send-button"
);
buttonSend.click();
await waitForResentRequest;
// Selects request that was resent
const selReq = getSelectedRequest(store.getState());
// Finally, some sanity checks
ok(selReq.url.endsWith("test-image.png"), "Correct request selected");
ok(origReq.url === selReq.url, "Orig and Sel url match");
ok(selReq.cause.type === "img", "Correct type of selected");
ok(origReq.cause.type === selReq.cause.type, "Orig and Sel type match");
const cspOBJ = await SpecialPowers.spawn(
tab.linkedBrowser,
[],
async () => {
return JSON.parse(content.document.cspJSON);
}
);
const policies = cspOBJ["csp-policies"];
is(policies.length, 1, "CSP: should be one policy");
const policy = policies[0];
is(`${policy["img-src"]}`, "*", "CSP: img-src should be *");
await teardown(monitor);
}
});

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

@ -417,6 +417,19 @@ CanonicalBrowsingContext::GetParentProcessWidgetContaining() {
return widget.forget();
}
already_AddRefed<nsIBrowserDOMWindow>
CanonicalBrowsingContext::GetBrowserDOMWindow() {
RefPtr<CanonicalBrowsingContext> chromeTop = TopCrossChromeBoundary();
if (nsCOMPtr<nsIDOMChromeWindow> chromeWin =
do_QueryInterface(chromeTop->GetDOMWindow())) {
nsCOMPtr<nsIBrowserDOMWindow> bdw;
if (NS_SUCCEEDED(chromeWin->GetBrowserDOMWindow(getter_AddRefs(bdw)))) {
return bdw.forget();
}
}
return nullptr;
}
already_AddRefed<WindowGlobalParent>
CanonicalBrowsingContext::GetEmbedderWindowGlobal() const {
uint64_t windowId = GetEmbedderInnerWindowId();
@ -2162,10 +2175,10 @@ bool CanonicalBrowsingContext::StartDocumentLoad(
return true;
}
void CanonicalBrowsingContext::EndDocumentLoad(bool aForProcessSwitch) {
void CanonicalBrowsingContext::EndDocumentLoad(bool aContinueNavigating) {
mCurrentLoad = nullptr;
if (!aForProcessSwitch) {
if (!aContinueNavigating) {
// Resetting the current load identifier on a discarded context
// has no effect when a document load has finished.
Unused << SetCurrentLoadIdentifier(Nothing());

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

@ -25,6 +25,7 @@
#include "nsHashKeys.h"
#include "nsISecureBrowserUI.h"
class nsIBrowserDOMWindow;
class nsISHistory;
class nsIWidget;
class nsIPrintSettings;
@ -111,6 +112,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
WindowGlobalParent* GetTopWindowContext();
already_AddRefed<nsIWidget> GetParentProcessWidgetContaining();
already_AddRefed<nsIBrowserDOMWindow> GetBrowserDOMWindow();
// Same as `GetParentWindowContext`, but will also cross <browser> and
// content/chrome boundaries.
@ -439,7 +441,10 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// Called once DocumentLoadListener completes handling a load, and it
// is either complete, or handed off to the final channel to deliver
// data to the destination docshell.
void EndDocumentLoad(bool aForProcessSwitch);
// If aContinueNavigating it set, the reference to the DocumentLoadListener
// will be cleared to prevent it being cancelled, however the current load ID
// will be preserved until `EndDocumentLoad` is called again.
void EndDocumentLoad(bool aContinueNavigating);
bool SupportsLoadingInParent(nsDocShellLoadState* aLoadState,
uint64_t* aOuterWindowId);

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

@ -15,7 +15,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
TestUtils: "resource://testing-common/TestUtils.jsm",
});
var dirSvc = Services.dirSvc;
var profileDir = do_get_profile();
const kSearchEngineID = "test_urifixup_search_engine";

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

@ -8,7 +8,7 @@ function run_test() {
notifications++;
},
};
Services.os.addObserver(obs, "last-pb-context-exited");
Services.obs.addObserver(obs, "last-pb-context-exited");
run_test_in_child("../unit/test_pb_notification.js", function() {
Assert.equal(notifications, 1);

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

@ -342,6 +342,11 @@ enum class FlushLayout {
Yes,
};
enum class PerformRetargeting {
No,
Yes,
};
template <typename NodeOrElement>
NodeOrElement* CastTo(nsIContent* aContent);
@ -360,6 +365,7 @@ static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
FrameForPointOptions aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple, ViewportType aViewportType,
PerformRetargeting aPerformRetargeting,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
static_assert(std::is_same<nsINode, NodeOrElement>::value ||
std::is_same<Element, NodeOrElement>::value,
@ -367,6 +373,7 @@ static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
constexpr bool returningElements =
std::is_same<Element, NodeOrElement>::value;
const bool retargeting = aPerformRetargeting == PerformRetargeting::Yes;
nsCOMPtr<Document> doc = aRoot.AsNode().OwnerDoc();
@ -420,7 +427,9 @@ static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
// XXXsmaug There is plenty of unspec'ed behavior here
// https://github.com/w3c/webcomponents/issues/735
// https://github.com/w3c/webcomponents/issues/736
content = aRoot.Retarget(content);
if (retargeting) {
content = aRoot.Retarget(content);
}
if (content && content != aNodes.SafeLastElement(nullptr)) {
aNodes.AppendElement(CastTo<NodeOrElement>(content));
@ -436,6 +445,7 @@ static void QueryNodesFromPoint(DocumentOrShadowRoot& aRoot, float aX, float aY,
FrameForPointOptions aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple, ViewportType aViewportType,
PerformRetargeting aPerformRetargeting,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
// As per the spec, we return null if either coord is negative.
if (!aOptions.mBits.contains(FrameForPointOption::IgnoreRootScrollFrame) &&
@ -447,7 +457,8 @@ static void QueryNodesFromPoint(DocumentOrShadowRoot& aRoot, float aX, float aY,
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
QueryNodesFromRect(aRoot, nsRect(pt, nsSize(1, 1)), aOptions,
aShouldFlushLayout, aMultiple, aViewportType, aNodes);
aShouldFlushLayout, aMultiple, aViewportType,
aPerformRetargeting, aNodes);
}
} // namespace
@ -459,19 +470,20 @@ Element* DocumentOrShadowRoot::ElementFromPoint(float aX, float aY) {
void DocumentOrShadowRoot::ElementsFromPoint(
float aX, float aY, nsTArray<RefPtr<Element>>& aElements) {
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
ViewportType::Layout, aElements);
ViewportType::Layout, PerformRetargeting::Yes,
aElements);
}
void DocumentOrShadowRoot::NodesFromPoint(float aX, float aY,
nsTArray<RefPtr<nsINode>>& aNodes) {
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
ViewportType::Layout, aNodes);
ViewportType::Layout, PerformRetargeting::Yes, aNodes);
}
nsINode* DocumentOrShadowRoot::NodeFromPoint(float aX, float aY) {
AutoTArray<RefPtr<nsINode>, 1> nodes;
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::No,
ViewportType::Layout, nodes);
ViewportType::Layout, PerformRetargeting::Yes, nodes);
return nodes.SafeElementAt(0);
}
@ -487,7 +499,7 @@ Element* DocumentOrShadowRoot::ElementFromPointHelper(
AutoTArray<RefPtr<Element>, 1> elements;
QueryNodesFromPoint(*this, aX, aY, options, flush, Multiple::No,
aViewportType, elements);
aViewportType, PerformRetargeting::Yes, elements);
return elements.SafeElementAt(0);
}
@ -522,7 +534,7 @@ void DocumentOrShadowRoot::NodesFromRect(float aX, float aY, float aTopSize,
auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
QueryNodesFromRect(*this, rect, options, flush, Multiple::Yes,
ViewportType::Layout, aReturn);
ViewportType::Layout, PerformRetargeting::No, aReturn);
}
Element* DocumentOrShadowRoot::AddIDTargetObserver(nsAtom* aID,

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

@ -1807,7 +1807,7 @@ already_AddRefed<PathCacheEntry> PathCache::FindOrInsertEntry(
}
Pattern* pattern = nullptr;
if (aPattern) {
pattern = aPattern->Clone();
pattern = aPattern->CloneWeak();
if (!pattern) {
return nullptr;
}

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

@ -72,6 +72,8 @@ class CacheEntry : public RefCounted<CacheEntry> {
const IntRect& GetBounds() const { return mBounds; }
HashNumber GetHash() const { return mHash; }
virtual bool IsValid() const { return true; }
protected:
virtual void RemoveFromList() = 0;
@ -173,7 +175,9 @@ class TextureHandle : public RefCounted<TextureHandle>,
void SetCacheEntry(const RefPtr<CacheEntry>& aEntry) { mCacheEntry = aEntry; }
// Note as used if there is corresponding surface or cache entry.
bool IsUsed() const { return mSurface || mCacheEntry; }
bool IsUsed() const {
return mSurface || (mCacheEntry && mCacheEntry->IsValid());
}
private:
bool mValid = true;
@ -360,6 +364,9 @@ class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
const Point& GetOrigin() const { return mOrigin; }
// Valid if either a mask (no pattern) or there is valid pattern.
bool IsValid() const override { return !mPattern || mPattern->IsValid(); }
private:
// The actual path geometry supplied
SkPath mPath;

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

@ -252,12 +252,14 @@ OffscreenCanvasDisplayHelper::GetSurfaceSnapshot() {
Maybe<int32_t> childId;
HTMLCanvasElement* canvasElement;
RefPtr<gfx::SourceSurface> surface;
layers::CompositableHandle handle;
{
MutexAutoLock lock(mMutex);
hasAlpha = !mData.mIsOpaque;
isAlphaPremult = mData.mIsAlphaPremult;
originPos = mData.mOriginPos;
handle = mData.mHandle;
managerId = mContextManagerId;
childId = mContextChildId;
canvasElement = mCanvasElement;
@ -311,7 +313,9 @@ OffscreenCanvasDisplayHelper::GetSurfaceSnapshot() {
// We don't have a usable surface, and the context lives in the compositor
// process.
return gfx::CanvasManagerChild::Get()->GetSnapshot(
managerId.value(), childId.value(), hasAlpha);
managerId.value(), childId.value(), handle,
hasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8,
hasAlpha && !isAlphaPremult, originPos == gl::OriginPos::BottomLeft);
}
// If we don't have any protocol IDs, or an existing surface, it is possible

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

@ -155,7 +155,6 @@ tags = imagebitmap
tags = imagebitmap
[test_ImageData_ctor.html]
[test_isPointInStroke.html]
[test_mozGetAsFile.html]
[test_strokeText_throw.html]
[test_toBlob.html]
[test_toBlob_zero_dimension.html]

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

@ -1,61 +0,0 @@
<!DOCTYPE HTML>
<title>Canvas test: mozGetAsFile</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body>
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
function compareAsync(file, canvas, type, callback)
{
var reader = new FileReader();
reader.onload =
function(e) {
is(e.target.result, canvas.toDataURL(type),
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
callback(canvas);
};
reader.readAsDataURL(file);
}
function test1(canvas)
{
var pngfile = canvas.mozGetAsFile("foo.png");
is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
compareAsync(pngfile, canvas, "image/png", test2);
is(pngfile.name, "foo.png", "File name should be what we passed in");
}
function test2(canvas)
{
var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
is(jpegfile.type, "image/jpeg",
"When a valid type is specified that should be returned");
compareAsync(jpegfile, canvas, "image/jpeg", parent.SimpleTest.finish);
is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(async function () {
if (location.search == "?framed") {
is = parent.is;
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
test1(canvas);
} else {
await SpecialPowers.pushPrefEnv({
set: [
["canvas.mozgetasfile.enabled", true],
],
});
let iframe = document.querySelector("iframe");
iframe.src = "test_mozGetAsFile.html?framed";
}
});
</script>
<img src="image_yellow75.png" id="yellow75.png" class="resource">
<iframe></iframe>

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

@ -1018,53 +1018,6 @@ OffscreenCanvas* HTMLCanvasElement::TransferControlToOffscreen(
return mOffscreenCanvas;
}
already_AddRefed<File> HTMLCanvasElement::MozGetAsFile(
const nsAString& aName, const nsAString& aType,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
// do a trust check if this is a write-only canvas
if (mWriteOnly && !aSubjectPrincipal.IsSystemPrincipal()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
RefPtr<File> file;
aRv = MozGetAsFileImpl(aName, aType, aSubjectPrincipal, getter_AddRefs(file));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return file.forget();
}
nsresult HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType,
nsIPrincipal& aSubjectPrincipal,
File** aResult) {
nsCOMPtr<nsIInputStream> stream;
nsAutoString type(aType);
nsresult rv =
ExtractData(nsContentUtils::GetCurrentJSContext(), aSubjectPrincipal,
type, u""_ns, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
uint64_t imgSize;
void* imgData = nullptr;
rv = NS_ReadInputStreamToBuffer(stream, &imgData, -1, &imgSize);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsPIDOMWindowInner> win =
do_QueryInterface(OwnerDoc()->GetScopeObject());
// The File takes ownership of the buffer
RefPtr<File> file = File::CreateMemoryFileWithLastModifiedNow(
win->AsGlobal(), imgData, imgSize, aName, type);
if (NS_WARN_IF(!file)) {
return NS_ERROR_FAILURE;
}
file.forget(aResult);
return NS_OK;
}
nsresult HTMLCanvasElement::GetContext(const nsAString& aContextId,
nsISupports** aContext) {
ErrorResult rv;

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

@ -163,10 +163,6 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
}
already_AddRefed<File> MozGetAsFile(const nsAString& aName,
const nsAString& aType,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv);
already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
ErrorResult& aRv);
PrintCallback* GetMozPrintCallback() const;
@ -325,8 +321,6 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
nsresult ToDataURLImpl(JSContext* aCx, nsIPrincipal& aSubjectPrincipal,
const nsAString& aMimeType,
const JS::Value& aEncoderOptions, nsAString& aDataURL);
nsresult MozGetAsFileImpl(const nsAString& aName, const nsAString& aType,
nsIPrincipal& aSubjectPrincipal, File** aResult);
MOZ_CAN_RUN_SCRIPT void CallPrintCallback();
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,

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

@ -5089,9 +5089,8 @@ bool HTMLInputElement::IsDateTimeTypeSupported(
switch (aDateTimeInputType) {
case FormControlType::InputDate:
case FormControlType::InputTime:
return true;
case FormControlType::InputDatetimeLocal:
return StaticPrefs::dom_forms_datetime_local();
return true;
case FormControlType::InputMonth:
case FormControlType::InputWeek:
return StaticPrefs::dom_forms_datetime_others();

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

@ -1567,8 +1567,7 @@ class HTMLInputElement final : public TextControlElement,
static bool CreatesDateTimeWidget(FormControlType aType) {
return aType == FormControlType::InputDate ||
aType == FormControlType::InputTime ||
(aType == FormControlType::InputDatetimeLocal &&
StaticPrefs::dom_forms_datetime_local_widget());
aType == FormControlType::InputDatetimeLocal;
}
bool CreatesDateTimeWidget() const { return CreatesDateTimeWidget(mType); }

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

@ -244,8 +244,6 @@ bool nsIFormControl::IsSingleLineTextControl(bool aExcludePassword,
case FormControlType::InputMonth:
case FormControlType::InputWeek:
return true;
case FormControlType::InputDatetimeLocal:
return !mozilla::StaticPrefs::dom_forms_datetime_local_widget();
case FormControlType::InputPassword:
return !aExcludePassword;
default:

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

@ -43,18 +43,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=764481
prefs: [["dom.forms.datetime.others", true]],
inputType: "week",
expectedType: "week"
}, {
prefs: [["dom.forms.datetime-local", false]],
inputType: "datetime-local",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime-local", false]],
inputType: "datetime-local",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime-local", true]],
inputType: "datetime-local",
expectedType: "datetime-local"
}
];

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

@ -80,6 +80,7 @@
#include "mozilla/Components.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/StyleSheet.h"
@ -643,6 +644,23 @@ static const char* sObserverTopics[] = {
"network:socket-process-crashed",
};
static const char kFissionEnforceBlockList[] =
"fission.enforceBlocklistedPrefsInSubprocesses";
static const char kFissionOmitBlockListValues[] =
"fission.omitBlocklistedPrefsInSubprocesses";
static void OnFissionBlocklistPrefChange(const char* aPref, void* aData) {
if (strcmp(aPref, kFissionEnforceBlockList) == 0) {
sCrashOnBlocklistedPref =
StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses();
} else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) {
sOmitBlocklistedPrefValues =
StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses();
} else {
MOZ_CRASH("Unknown pref passed to callback");
}
}
// PreallocateProcess is called by the PreallocatedProcessManager.
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
/*static*/ already_AddRefed<ContentParent>
@ -669,6 +687,11 @@ void ContentParent::StartUp() {
BackgroundChild::Startup();
ClientManager::Startup();
Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
kFissionEnforceBlockList);
Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
kFissionOmitBlockListValues);
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
sSandboxBrokerPolicyFactory = MakeUnique<SandboxBrokerPolicyFactory>();
#endif
@ -2511,9 +2534,9 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
// Instantiate the pref serializer. It will be cleaned up in
// `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>(
ShouldSyncPreference);
if (!mPrefSerializer->SerializeToSharedMemory()) {
mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>();
if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_Content,
GetRemoteType())) {
NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
MarkAsDead();
return false;
@ -3639,13 +3662,11 @@ ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
// A pref changed. If it is useful to do so, inform child processes.
if (!ShouldSyncPreference(strData.Data())) {
return NS_OK;
}
Pref pref(strData, /* isLocked */ false,
/* isSanitized */ false, Nothing(), Nothing());
Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
Preferences::GetPreference(&pref);
Preferences::GetPreference(&pref, GeckoProcessType_Content,
GetRemoteType());
if (IsInitialized()) {
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
if (!SendPreferenceUpdate(pref)) {
@ -3792,37 +3813,6 @@ ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
/* static */
bool ContentParent::ShouldSyncPreference(const char* aPref) {
#define PARENT_ONLY_PREF_LIST_ENTRY(s) \
{ s, (sizeof(s) / sizeof(char)) - 1 }
struct ParentOnlyPrefListEntry {
const char* mPrefBranch;
size_t mLen;
};
// These prefs are not useful in child processes.
static const ParentOnlyPrefListEntry sParentOnlyPrefBranchList[] = {
PARENT_ONLY_PREF_LIST_ENTRY("app.update.lastUpdateTime."),
PARENT_ONLY_PREF_LIST_ENTRY("datareporting.policy."),
PARENT_ONLY_PREF_LIST_ENTRY("browser.safebrowsing.provider."),
PARENT_ONLY_PREF_LIST_ENTRY("browser.shell."),
PARENT_ONLY_PREF_LIST_ENTRY("browser.slowStartup."),
PARENT_ONLY_PREF_LIST_ENTRY("browser.startup."),
PARENT_ONLY_PREF_LIST_ENTRY("extensions.getAddons.cache."),
PARENT_ONLY_PREF_LIST_ENTRY("media.gmp-manager."),
PARENT_ONLY_PREF_LIST_ENTRY("media.gmp-gmpopenh264."),
PARENT_ONLY_PREF_LIST_ENTRY("privacy.sanitize."),
};
#undef PARENT_ONLY_PREF_LIST_ENTRY
for (const auto& entry : sParentOnlyPrefBranchList) {
if (strncmp(entry.mPrefBranch, aPref, entry.mLen) == 0) {
return false;
}
}
return true;
}
void ContentParent::UpdateNetworkLinkType() {
nsresult rv;
nsCOMPtr<nsINetworkLinkService> nls =

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

@ -1445,8 +1445,6 @@ class ContentParent final
void UpdateNetworkLinkType();
static bool ShouldSyncPreference(const char* aPref);
already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor,
const nsACString& aName,
ErrorResult& aRv) override;

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

@ -23,6 +23,7 @@ union PrefValue {
struct Pref {
nsCString name;
bool isLocked;
bool isSanitized;
PrefValue? defaultValue;
PrefValue? userValue;
};

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

@ -471,7 +471,8 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
CanonicalBrowsingContext* aTopBC, WindowGlobalParent* aParentWindow,
nsIURI* aChannelCreationURI, nsIChannel* aChannel,
const nsACString& aCurrentRemoteType, bool aHasCOOPMismatch,
uint32_t aLoadStateLoadType, const Maybe<uint64_t>& aChannelId,
bool aForNewTab, uint32_t aLoadStateLoadType,
const Maybe<uint64_t>& aChannelId,
const Maybe<nsCString>& aRemoteTypeOverride) {
// Get the final principal, used to select which process to load into.
nsCOMPtr<nsIPrincipal> resultPrincipal;
@ -660,7 +661,7 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
// Check if we can put the previous document into the BFCache.
if (mozilla::BFCacheInParent() && nsSHistory::GetMaxTotalViewers() > 0 &&
!aParentWindow && !aTopBC->HadOriginalOpener() &&
!aForNewTab && !aParentWindow && !aTopBC->HadOriginalOpener() &&
behavior != IsolationBehavior::Parent &&
(ExtensionPolicyService::GetSingleton().UseRemoteExtensions() ||
behavior != IsolationBehavior::Extension) &&
@ -765,9 +766,9 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
// where we may have multiple documents with the same principal in different
// processes. Those have been handled above, and will not be reaching here.
//
// If we're doing a replace load, we won't be staying in the same
// BrowsingContext, so ignore this step.
if (!options.mReplaceBrowsingContext) {
// If we're doing a replace load or opening a new tab, we won't be staying in
// the same BrowsingContextGroup, so ignore this step.
if (!options.mReplaceBrowsingContext && !aForNewTab) {
// Helper for efficiently determining if a given origin is same-site. This
// will attempt to do a fast equality check, and will only fall back to
// computing the site-origin for content principals.

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

@ -55,7 +55,8 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
CanonicalBrowsingContext* aTopBC, WindowGlobalParent* aParentWindow,
nsIURI* aChannelCreationURI, nsIChannel* aChannel,
const nsACString& aCurrentRemoteType, bool aHasCOOPMismatch,
uint32_t aLoadStateLoadType, const Maybe<uint64_t>& aChannelId,
bool aForNewTab, uint32_t aLoadStateLoadType,
const Maybe<uint64_t>& aChannelId,
const Maybe<nsCString>& aRemoteTypeOverride);
/**

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

@ -46,9 +46,9 @@ bool RDDProcessHost::Launch(StringVector aExtraOpts) {
MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
MOZ_ASSERT(!mRDDChild);
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>(
dom::ContentParent::ShouldSyncPreference);
if (!mPrefSerializer->SerializeToSharedMemory()) {
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_RDD,
/* remoteType */ ""_ns)) {
return false;
}
mPrefSerializer->AddSharedPrefCmdLineArgs(*this, aExtraOpts);

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

@ -96,13 +96,11 @@ void RDDProcessManager::OnPreferenceChange(const char16_t* aData) {
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
// A pref changed. If it is useful to do so, inform child processes.
if (!dom::ContentParent::ShouldSyncPreference(strData.Data())) {
return;
}
mozilla::dom::Pref pref(strData, /* isLocked */ false,
/* isSanitized */ false, Nothing(), Nothing());
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
Preferences::GetPreference(&pref);
Preferences::GetPreference(&pref, GeckoProcessType_RDD,
/* remoteType */ ""_ns);
if (!!mRDDChild) {
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
mRDDChild->SendPreferenceUpdate(pref);

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

@ -340,7 +340,8 @@ void AOMDecoder::OBUIterator::UpdateNext() {
// begin obu_extension_header( ) (5.3.3)
if (temp.mExtensionFlag) {
if (br.BitsLeft() < 8) {
NS_WARNING("Not enough bits left for an OBU extension header");
mResult = MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
"Not enough bits left for an OBU extension header");
return;
}
br.ReadBits(3); // temporal_id
@ -355,14 +356,16 @@ void AOMDecoder::OBUIterator::UpdateNext() {
size_t size;
if (hasSizeField) {
if (br.BitsLeft() < 8) {
NS_WARNING("Not enough bits left for an OBU size field");
mResult = MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
"Not enough bits left for an OBU size field");
return;
}
CheckedUint32 checkedSize = br.ReadULEB128().toChecked<uint32_t>();
// Spec requires that the value ULEB128 reads is (1 << 32) - 1 or below.
// See leb128(): https://aomediacodec.github.io/av1-spec/#leb128
if (!checkedSize.isValid()) {
NS_WARNING("OBU size was too large");
mResult =
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, "OBU size was too large");
return;
}
size = checkedSize.value();
@ -375,10 +378,12 @@ void AOMDecoder::OBUIterator::UpdateNext() {
}
if (br.BitsLeft() / 8 < size) {
NS_WARNING(nsPrintfCString("Size specified by the OBU header (%zu) is more "
"than the actual remaining OBU data (%zu)",
size, br.BitsLeft() / 8)
.get());
mResult = MediaResult(
NS_ERROR_DOM_MEDIA_DECODE_ERR,
nsPrintfCString("Size specified by the OBU header (%zu) is more "
"than the actual remaining OBU data (%zu)",
size, br.BitsLeft() / 8)
.get());
return;
}
@ -391,6 +396,7 @@ void AOMDecoder::OBUIterator::UpdateNext() {
mPosition += bytes + size;
resetExit.release();
mResult = NS_OK;
}
/* static */
@ -413,8 +419,8 @@ already_AddRefed<MediaByteBuffer> AOMDecoder::CreateOBU(
}
/* static */
bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
AV1SequenceInfo& aDestInfo) {
MediaResult AOMDecoder::ReadSequenceHeaderInfo(
const Span<const uint8_t>& aSample, AV1SequenceInfo& aDestInfo) {
// We need to get the last sequence header OBU, the specification does not
// limit a temporal unit to one sequence header.
OBUIterator iter = ReadOBUs(aSample);
@ -422,6 +428,11 @@ bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
while (true) {
if (!iter.HasNext()) {
// Pass along the error from parsing the OBU.
MediaResult result = iter.GetResult();
if (result.Code() != NS_OK) {
return result;
}
break;
}
OBUInfo obu = iter.Next();
@ -431,7 +442,7 @@ bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
}
if (seqOBU.mType != OBUType::SequenceHeader) {
return false;
return NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA;
}
// Sequence header syntax is specified here:
@ -448,9 +459,11 @@ bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
// https://aomediacodec.github.io/av1-spec/#general-sequence-header-obu-syntax
tempInfo.mProfile = br.ReadBits(3);
const bool stillPicture = br.ReadBit();
bool reducedStillPicture = br.ReadBit();
const bool reducedStillPicture = br.ReadBit();
if (!stillPicture && reducedStillPicture) {
NS_WARNING("reduced_still_picture is true while still_picture is false");
return MediaResult(
NS_ERROR_DOM_MEDIA_DECODE_ERR,
"reduced_still_picture is true while still_picture is false");
}
if (reducedStillPicture) {
@ -527,7 +540,7 @@ bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
if (reducedStillPicture) {
aDestInfo = tempInfo;
return true;
return NS_OK;
}
br.ReadBit(); // enable_interintra_compound
@ -647,13 +660,13 @@ bool AOMDecoder::ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
correct &= br.ReadBits(8) == 0;
}
if (!correct) {
NS_WARNING("AV1 sequence header was parsed incorrectly");
return false;
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
"AV1 sequence header was parsed incorrectly");
}
// end trailing_bits( )
aDestInfo = tempInfo;
return true;
return NS_OK;
}
/* static */
@ -769,7 +782,7 @@ already_AddRefed<MediaByteBuffer> AOMDecoder::CreateSequenceHeader(
NS_WARNING("Profile must be 2 for 12-bit");
return nullptr;
}
if (aInfo.mProfile == 2) {
if (aInfo.mProfile == 2 && highBitDepth) {
bw.WriteBit(aInfo.mBitDepth == 12); // twelve_bit
}
@ -873,10 +886,9 @@ already_AddRefed<MediaByteBuffer> AOMDecoder::CreateSequenceHeader(
}
/* static */
void AOMDecoder::ReadAV1CBox(const MediaByteBuffer* aBox,
AV1SequenceInfo& aDestInfo, bool& aHadSeqHdr) {
aHadSeqHdr = false;
void AOMDecoder::TryReadAV1CBox(const MediaByteBuffer* aBox,
AV1SequenceInfo& aDestInfo,
MediaResult& aSeqHdrResult) {
// See av1C specification:
// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-section
BitReader br(aBox);
@ -912,12 +924,13 @@ void AOMDecoder::ReadAV1CBox(const MediaByteBuffer* aBox,
// Minimum possible OBU header size
if (obus.Length() < 1) {
aSeqHdrResult = NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA;
return;
}
// If present, the sequence header will be redundant to some values, but any
// values stored in it should be treated as more accurate than av1C.
aHadSeqHdr = ReadSequenceHeaderInfo(obus, aDestInfo);
aSeqHdrResult = ReadSequenceHeaderInfo(obus, aDestInfo);
}
/* static */

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

@ -82,7 +82,7 @@ class AOMDecoder : public MediaDataDecoder,
struct OBUIterator {
public:
explicit OBUIterator(const Span<const uint8_t>& aData)
: mData(aData), mPosition(0), mGoNext(true) {}
: mData(aData), mPosition(0), mGoNext(true), mResult(NS_OK) {}
bool HasNext() {
UpdateNext();
return !mGoNext;
@ -92,12 +92,14 @@ class AOMDecoder : public MediaDataDecoder,
mGoNext = true;
return mCurrent;
}
MediaResult GetResult() const { return mResult; }
private:
const Span<const uint8_t>& mData;
size_t mPosition;
OBUInfo mCurrent;
bool mGoNext;
MediaResult mResult;
// Used to fill mCurrent with the next OBU in the iterator.
// mGoNext must be set to false if the next OBU is retrieved,
@ -225,17 +227,33 @@ class AOMDecoder : public MediaDataDecoder,
};
// Get a sequence header's info from a sample.
// Returns false if the sample was not a sequence header.
static bool ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
AV1SequenceInfo& aDestInfo);
// Returns a MediaResult with codes:
// NS_OK: Sequence header was successfully found and read.
// NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA: Sequence header was not present.
// Other errors will indicate that the data was corrupt.
static MediaResult ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
AV1SequenceInfo& aDestInfo);
// Writes a sequence header OBU to the buffer.
static already_AddRefed<MediaByteBuffer> CreateSequenceHeader(
const AV1SequenceInfo& aInfo, nsresult& aResult);
// Reads the raw data of an ISOBMFF-compatible av1 configuration box (av1C),
// including any included sequence header.
static void TryReadAV1CBox(const MediaByteBuffer* aBox,
AV1SequenceInfo& aDestInfo,
MediaResult& aSeqHdrResult);
// Reads the raw data of an ISOBMFF-compatible av1 configuration box (av1C),
// including any included sequence header.
// This function should only be called for av1C boxes made by WriteAV1CBox, as
// it will assert that the box and its contained OBUs are not corrupted.
static void ReadAV1CBox(const MediaByteBuffer* aBox,
AV1SequenceInfo& aDestInfo, bool& aHadSeqHdr);
AV1SequenceInfo& aDestInfo, bool& aHadSeqHdr) {
MediaResult seqHdrResult;
TryReadAV1CBox(aBox, aDestInfo, seqHdrResult);
nsresult code = seqHdrResult.Code();
MOZ_ASSERT(code == NS_OK || code == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
aHadSeqHdr = code == NS_OK;
}
// Writes an ISOBMFF-compatible av1 configuration box (av1C) to the buffer.
static void WriteAV1CBox(const AV1SequenceInfo& aInfo,
MediaByteBuffer* aDestBox, bool& aHasSeqHdr);

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

@ -8,6 +8,7 @@
#include "WMFUtils.h"
#include "mozilla/Logging.h"
#include "nsThreadUtils.h"
#include "mozilla/mscom/COMWrappers.h"
#include "mozilla/mscom/Utils.h"
#include "PlatformDecoderModule.h"
@ -30,7 +31,7 @@ MFTDecoder::~MFTDecoder() {
HRESULT MFTDecoder::Create(const GUID& aCLSID) {
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
HRESULT hr = CoCreateInstance(
HRESULT hr = mscom::wrapped::CoCreateInstance(
aCLSID, nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(static_cast<IMFTransform**>(getter_AddRefs(mDecoder))));
NS_WARNING_ASSERTION(SUCCEEDED(hr), "Failed to create MFT by CLSID");

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

@ -170,6 +170,20 @@ int WMFDecoderModule::GetNumDecoderThreads() {
/* static */
HRESULT WMFDecoderModule::CreateMFTDecoder(const WMFStreamType& aType,
RefPtr<MFTDecoder>& aDecoder) {
// Do not expose any video decoder on utility process which is only for audio
// decoding.
if (XRE_IsUtilityProcess()) {
switch (aType) {
case WMFStreamType::H264:
case WMFStreamType::VP8:
case WMFStreamType::VP9:
case WMFStreamType::AV1:
return E_FAIL;
default:
break;
}
}
switch (aType) {
case WMFStreamType::H264:
return aDecoder->Create(CLSID_CMSH264DecoderMFT);
@ -271,6 +285,20 @@ bool WMFDecoderModule::CanCreateMFTDecoder(const WMFStreamType& aType) {
break;
}
// Do not expose any video decoder on utility process which is only for audio
// decoding.
if (XRE_IsUtilityProcess()) {
switch (aType) {
case WMFStreamType::H264:
case WMFStreamType::VP8:
case WMFStreamType::VP9:
case WMFStreamType::AV1:
return false;
default:
break;
}
}
return sSupportedTypes.contains(aType);
}

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

@ -321,11 +321,12 @@ class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
// If we're passed AV1 codec configuration, store it so that we can
// instantiate a decoder in MediaChangeMonitor::Create.
AOMDecoder::AV1SequenceInfo seqInfo;
bool hadSeqHdr;
AOMDecoder::ReadAV1CBox(mCurrentConfig.mExtraData, seqInfo, hadSeqHdr);
MediaResult seqHdrResult;
AOMDecoder::TryReadAV1CBox(mCurrentConfig.mExtraData, seqInfo,
seqHdrResult);
// If the av1C box doesn't include a sequence header specifying image
// size, keep the one provided by VideoInfo.
if (hadSeqHdr) {
if (seqHdrResult.Code() != NS_OK) {
seqInfo.mImage = mCurrentConfig.mImage;
}
@ -365,6 +366,14 @@ class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
mCurrentConfig.mDisplay = newDisplay;
mCurrentConfig.ResetImageRect();
}
bool wroteSequenceHeader = false;
// Our headers should all be around the same size.
mCurrentConfig.mExtraData->ClearAndRetainStorage();
AOMDecoder::WriteAV1CBox(aInfo, mCurrentConfig.mExtraData.get(),
wroteSequenceHeader);
// Header should always be written ReadSequenceHeaderInfo succeeds.
MOZ_ASSERT(wroteSequenceHeader);
}
MediaResult CheckForChange(MediaRawData* aSample) override {
@ -376,10 +385,17 @@ class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
// We don't trust the keyframe flag as set on the MediaRawData.
AOMDecoder::AV1SequenceInfo info;
if (!AOMDecoder::ReadSequenceHeaderInfo(dataSpan, info)) {
MediaResult seqHdrResult =
AOMDecoder::ReadSequenceHeaderInfo(dataSpan, info);
nsresult seqHdrCode = seqHdrResult.Code();
if (seqHdrCode == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
return NS_OK;
}
if (seqHdrCode != NS_OK) {
LOG("AV1ChangeMonitor::CheckForChange read a corrupted sample: %s",
seqHdrResult.Description().get());
return seqHdrResult;
}
nsresult rv = NS_OK;
if (mInfo.isSome() &&
@ -398,12 +414,6 @@ class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
rv = NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
}
bool wroteSequenceHeader = false;
// Our headers should all be around the same size.
mCurrentConfig.mExtraData->ClearAndRetainStorage();
AOMDecoder::WriteAV1CBox(info, mCurrentConfig.mExtraData.get(),
wroteSequenceHeader);
MOZ_ASSERT(wroteSequenceHeader);
UpdateConfig(info);
if (rv == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {

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

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<video src="1765842.webm" type="video/webm" autoplay="true" controls></video>
</body>
</html>

Двоичные данные
dom/media/test/crashtests/1765842.webm Normal file

Двоичный файл не отображается.

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

@ -152,3 +152,4 @@ load 1734008.html
load 1741677.html
load 1748272.html
load 1752917.html
load 1765842.html

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

@ -298,22 +298,28 @@ struct ParamTraits<mozilla::dom::RTCInboundRtpStreamStats> {
static void Write(MessageWriter* aWriter, const paramType& aParam) {
WriteParam(aWriter, aParam.mRemoteId);
WriteParam(aWriter, aParam.mFramesDecoded);
WriteParam(aWriter, aParam.mFrameWidth);
WriteParam(aWriter, aParam.mFrameHeight);
WriteParam(aWriter, aParam.mBytesReceived);
WriteParam(aWriter, aParam.mNackCount);
WriteParam(aWriter, aParam.mFirCount);
WriteParam(aWriter, aParam.mPliCount);
WriteParam(aWriter, aParam.mFramesPerSecond);
WriteParam(aWriter, aParam.mFramesReceived);
WriteRTCReceivedRtpStreamStats(aWriter, aParam);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
return ReadParam(aReader, &(aResult->mRemoteId)) &&
ReadParam(aReader, &(aResult->mFramesDecoded)) &&
ReadParam(aReader, &(aResult->mFrameWidth)) &&
ReadParam(aReader, &(aResult->mFrameHeight)) &&
ReadParam(aReader, &(aResult->mBytesReceived)) &&
ReadParam(aReader, &(aResult->mNackCount)) &&
ReadParam(aReader, &(aResult->mFirCount)) &&
ReadParam(aReader, &(aResult->mPliCount)) &&
ReadParam(aReader, &(aResult->mFramesPerSecond)) &&
ReadParam(aReader, &(aResult->mFramesReceived)) &&
ReadRTCReceivedRtpStreamStats(aReader, aResult);
}
};
@ -343,6 +349,9 @@ struct ParamTraits<mozilla::dom::RTCOutboundRtpStreamStats> {
WriteParam(aWriter, aParam.mNackCount);
WriteParam(aWriter, aParam.mFirCount);
WriteParam(aWriter, aParam.mPliCount);
WriteParam(aWriter, aParam.mFrameWidth);
WriteParam(aWriter, aParam.mFrameHeight);
WriteParam(aWriter, aParam.mFramesSent);
WriteRTCSentRtpStreamStats(aWriter, aParam);
}
@ -353,6 +362,9 @@ struct ParamTraits<mozilla::dom::RTCOutboundRtpStreamStats> {
ReadParam(aReader, &(aResult->mNackCount)) &&
ReadParam(aReader, &(aResult->mFirCount)) &&
ReadParam(aReader, &(aResult->mPliCount)) &&
ReadParam(aReader, &(aResult->mFrameWidth)) &&
ReadParam(aReader, &(aResult->mFrameHeight)) &&
ReadParam(aReader, &(aResult->mFramesSent)) &&
ReadRTCSentRtpStreamStats(aReader, aResult);
}
};

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

@ -431,10 +431,13 @@ nsTArray<RefPtr<RTCStatsPromise>> RTCRtpReceiver::GetStatsInternal() {
local.mFramesDecoded.Construct(videoStats->frames_decoded);
local.mFramesPerSecond.Construct(videoStats->decode_frame_rate);
local.mFrameWidth.Construct(videoStats->width);
local.mFrameHeight.Construct(videoStats->height);
// XXX: key_frames + delta_frames may undercount frames because they were dropped in FrameBuffer::InsertFrame. (bug 1766553)
local.mFramesReceived.Construct(videoStats->frame_counts.key_frames + videoStats->frame_counts.delta_frames);
/*
* Potential new stats that are now available upstream.
local.mFrameWidth.Construct(videoStats->width);
local.mFrameheight.Construct(videoStats->height);
if (videoStats->qp_sum) {
local.mQpSum.Construct(*videoStats->qp_sum.value);
}

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

@ -369,6 +369,9 @@ nsTArray<RefPtr<dom::RTCStatsPromise>> RTCRtpSender::GetStatsInternal() {
streamStats->rtp_stats.retransmitted.packets);
local.mRetransmittedBytesSent.Construct(
streamStats->rtp_stats.retransmitted.payload_bytes);
local.mFramesSent.Construct(streamStats->frames_encoded);
local.mFrameWidth.Construct(streamStats->width);
local.mFrameHeight.Construct(streamStats->height);
/*
* Potential new stats that are now available upstream.
local.mTargetBitrate.Construct(videoStats->target_media_bitrate_bps);

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

@ -24,6 +24,10 @@
namespace mozilla {
// QP scaling thresholds.
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
// Encoder.
WebrtcGmpVideoEncoder::WebrtcGmpVideoEncoder(std::string aPCHandle)
: mGMP(nullptr),
@ -459,6 +463,18 @@ int32_t WebrtcGmpVideoEncoder::SetRates(
return WEBRTC_VIDEO_CODEC_OK;
}
WebrtcVideoEncoder::EncoderInfo WebrtcGmpVideoEncoder::GetEncoderInfo() const {
WebrtcVideoEncoder::EncoderInfo info;
info.supports_native_handle = false;
info.implementation_name = "GMPOpenH264";
info.scaling_settings =
WebrtcVideoEncoder::ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold);
info.is_hardware_accelerated = false;
info.supports_simulcast = false;
return info;
}
/* static */
int32_t WebrtcGmpVideoEncoder::SetRates_g(RefPtr<WebrtcGmpVideoEncoder> aThis,
uint32_t aNewBitRateKbps,

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

@ -145,6 +145,8 @@ class RefCountedWebrtcVideoEncoder {
virtual MediaEventSource<uint64_t>* ReleasePluginEvent() = 0;
virtual WebrtcVideoEncoder::EncoderInfo GetEncoderInfo() const = 0;
protected:
virtual ~RefCountedWebrtcVideoEncoder() = default;
};
@ -171,6 +173,8 @@ class WebrtcGmpVideoEncoder : public GMPVideoEncoderCallbackProxy,
int32_t SetRates(
const webrtc::VideoEncoder::RateControlParameters& aParameters) override;
WebrtcVideoEncoder::EncoderInfo GetEncoderInfo() const override;
MediaEventSource<uint64_t>* InitPluginEvent() override {
return &mInitPluginEvent;
}
@ -341,6 +345,10 @@ class WebrtcVideoEncoderProxy : public WebrtcVideoEncoder {
mEncoderImpl->SetRates(aParameters);
}
EncoderInfo GetEncoderInfo() const override {
return mEncoderImpl->GetEncoderInfo();
}
private:
const RefPtr<RefCountedWebrtcVideoEncoder> mEncoderImpl;
};

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

@ -261,6 +261,15 @@ already_AddRefed<MediaDataEncoder> WebrtcMediaDataEncoder::CreateEncoder(
return mFactory->CreateEncoder(params);
}
WebrtcVideoEncoder::EncoderInfo WebrtcMediaDataEncoder::GetEncoderInfo() const {
WebrtcVideoEncoder::EncoderInfo info;
info.supports_native_handle = false;
info.implementation_name = "MediaDataEncoder";
info.is_hardware_accelerated = false;
info.supports_simulcast = false;
return info;
}
int32_t WebrtcMediaDataEncoder::RegisterEncodeCompleteCallback(
webrtc::EncodedImageCallback* aCallback) {
MutexAutoLock lock(mCallbackMutex);

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

@ -41,6 +41,7 @@ class WebrtcMediaDataEncoder : public RefCountedWebrtcVideoEncoder {
int32_t SetRates(
const webrtc::VideoEncoder::RateControlParameters& aParameters) override;
WebrtcVideoEncoder::EncoderInfo GetEncoderInfo() const override;
MediaEventSource<uint64_t>* InitPluginEvent() override { return nullptr; }
MediaEventSource<uint64_t>* ReleasePluginEvent() override { return nullptr; }

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

@ -27,6 +27,9 @@ const statsExpectedByType = {
"framesDecoded",
"discardedPackets",
"framesPerSecond",
"frameWidth",
"frameHeight",
"framesReceived",
],
unimplemented: [
"mediaTrackId",
@ -62,7 +65,14 @@ const statsExpectedByType = {
"retransmittedBytesSent",
],
optional: ["nackCount", "qpSum"],
localVideoOnly: ["framesEncoded", "firCount", "pliCount"],
localVideoOnly: [
"framesEncoded",
"firCount",
"pliCount",
"frameWidth",
"frameHeight",
"framesSent",
],
unimplemented: ["mediaTrackId", "transportId", "sliCount", "targetBitrate"],
deprecated: ["isRemote"],
},
@ -517,6 +527,27 @@ function pedanticChecks(report) {
`${stat.type}.framesDecoded is a sane number for a short ` +
`${stat.kind} test. value=${stat.framesDecoded}`
);
// frameWidth
ok(
stat.frameWidth > 0 && stat.frameWidth < 100000,
`${stat.type}.frameWidth is a sane number for a short ` +
`${stat.kind} test. value=${stat.framesSent}`
);
// frameHeight
ok(
stat.frameHeight > 0 && stat.frameHeight < 100000,
`${stat.type}.frameHeight is a sane number for a short ` +
`${stat.kind} test. value=${stat.frameHeight}`
);
// framesReceived
ok(
stat.framesReceived >= 0 && stat.framesReceived < 100000,
`${stat.type}.framesReceived is a sane number for a short ` +
`${stat.kind} test. value=${stat.framesReceived}`
);
}
} else if (stat.type == "remote-inbound-rtp") {
// roundTripTime
@ -664,6 +695,27 @@ function pedanticChecks(report) {
`${stat.type}.framesEncoded is a sane number for a short ` +
`${stat.kind} test. value=${stat.framesEncoded}`
);
// frameWidth
ok(
stat.frameWidth >= 0 && stat.frameWidth < 100000,
`${stat.type}.frameWidth is a sane number for a short ` +
`${stat.kind} test. value=${stat.frameWidth}`
);
// frameHeight
ok(
stat.frameHeight >= 0 && stat.frameHeight < 100000,
`${stat.type}.frameHeight is a sane number for a short ` +
`${stat.kind} test. value=${stat.frameHeight}`
);
// framesSent
ok(
stat.framesSent >= 0 && stat.framesSent < 100000,
`${stat.type}.framesSent is a sane number for a short ` +
`${stat.kind} test. value=${stat.framesSent}`
);
}
} else if (stat.type == "remote-outbound-rtp") {
//

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

@ -34,7 +34,8 @@ add_task(async function() {
});
// Top-Level scheme: HTTP
testSet.push(
// NOTE(freddyb): Test case temporarily disabled. See bug 1735565
/*testSet.push(
runTest({
queryString: "test1.1",
topLevelScheme: "http",
@ -43,7 +44,7 @@ add_task(async function() {
expectedSameOrigin: "http",
expectedCrossOrigin: "http",
})
);
);*/
// Top-Level scheme: HTTPS
testSet.push(
runTest({

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

@ -1,14 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>nsIDOMWindowUtils::nodesFromRect test - bug 489127</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
<title>nsIDOMWindowUtils::nodesFromRect test - bug 489127</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script>
var SimpleTest = window.opener.SimpleTest;
function ok() { window.opener.ok.apply(window.opener, arguments); }
function done() { window.opener.done.apply(window.opener, arguments); }
function info() { window.opener.info.apply(window.opener, arguments); }
let e = {};
let dwu = window.windowUtils;
@ -30,9 +29,8 @@
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] != list[i]) {
ok(false, "Unexpected node #" + i + " for rect " +
"[" + x + "," + y + "], " +
"[" + top + "," + right + "," + bottom + "," + left + "]");
ok(false, `Unexpected node #${i} (${nodes[i].id} vs. ${list[i].id}) ` +
`[${x}, ${y}] [${top}, ${right}, ${bottom}, ${left}]`);
return;
}
}
@ -42,14 +40,21 @@
}
function doTest() {
// Set up shortcut access to elements
e.html = document.getElementsByTagName("html")[0];
e.html = document.documentElement;
['h1', 'd1', 'd2', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'span',
'a1', 'a2', 'a3', 'transf', 'iframe1', 'body', 'opacity'].forEach(function(a) {
'a1', 'a2', 'a3', 'transf', 'iframe1', 'body', 'opacity', 'host'].forEach(function(a) {
e[a] = document.getElementById(a);
});
let shadow = e.host.attachShadow({ mode: "open" });
shadow.innerHTML = `
<style>
#host-inner { height: 100px; width: 100px; background-color: blue }
</style>
<div id="host-inner"></div>
`;
window.scrollTo(0, 0);
// Top, Right, Bottom, Left directions:
@ -102,8 +107,8 @@
check(61, 671, 0, 30, 0, 10, false, [e.transf]);
check(61, 671, 0, 30, 90, 10, false, [e.transf.firstChild, e.transf]);
// opacity: with and without aVisibleOnly = true
{
info("opacity: with and without aVisibleOnly = true");
let [x, y] = getCenterFor(e.opacity);
check(x, y, 1, 1, 1, 1, false, [e.opacity]);
check(x, y, 1, 1, 1, 1, true, []);
@ -112,6 +117,7 @@
// Check elements behind opaque backgrounds of other elements don't show up
// in the list when aVisibleOnly = true.
{
info("elements behind opaque backgrounds of other elements with aVisibleOnly=true");
let container = document.getElementById('obscured-test');
let fg = document.getElementById('obscured-test-foreground');
let bg = document.getElementById('obscured-test-background');
@ -124,8 +130,7 @@
check(x, y, 1, 1, 1, 1, true, [fg], kListIsComplete);
check(x, y, 1, 1, 1, 1, true, [fg], kListIsComplete, 0.5);
// Occluded with different opacity thresholds, with background colors and
// opacity.
info("Occluded with different opacity thresholds, with background colors and opacity");
fg.style.backgroundColor = "rgba(0, 255, 0, 0.5)";
check(x, y, 1, 1, 1, 1, true, [fg], kListIsComplete, 0.4);
check(x, y, 1, 1, 1, 1, true, [fg, bg], kListIsComplete, 0.6);
@ -137,6 +142,14 @@
check(x, y, 1, 1, 1, 1, true, [fg, bg], kListIsComplete, 0.6);
}
{
info("Shadow DOM retargeting");
let [x, y] = getCenterFor(e.host);
let inner = shadow.getElementById("host-inner");
check(x, y, 1, 1, 1, 1, false, [inner, e.host]);
}
done();
}
@ -147,8 +160,7 @@
addLoadEvent(doTest);
</script>
<style type="text/css">
<style>
body {
margin: 8px;
padding: 0;
@ -215,7 +227,6 @@ span {
background: green;
}
</style>
</head>
<body id="body">
<h1 id="h1"></h1>
<div id="d1"></div>
@ -248,9 +259,10 @@ span {
<div id="opacity">text</div>
<div id="host"></div>
<div id="obscured-test">
<div id="obscured-test-background"></div>
<div id="obscured-test-foreground"></div>
</div>
</body>
</html>

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

@ -5,9 +5,12 @@
#include "mozilla/dom/WebGPUBinding.h"
#include "CanvasContext.h"
#include "nsDisplayList.h"
#include "gfxUtils.h"
#include "LayerUserData.h"
#include "nsDisplayList.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/layers/CanvasRenderer.h"
#include "mozilla/layers/CompositableInProcessManager.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/LayersSurfaces.h"
@ -78,6 +81,7 @@ void CanvasContext::Configure(const dom::GPUCanvasConfiguration& aDesc) {
} else if (mOffscreenCanvas) {
dom::OffscreenCanvasDisplayData data;
data.mSize = {mWidth, mHeight};
data.mIsOpaque = false;
data.mHandle = mHandle;
mOffscreenCanvas->UpdateDisplayData(data);
}
@ -123,5 +127,69 @@ void CanvasContext::SwapChainPresent() {
}
}
bool CanvasContext::InitializeCanvasRenderer(
nsDisplayListBuilder* aBuilder, layers::CanvasRenderer* aRenderer) {
// This path is only used for rendering when we use the fallback Paint path,
// used by reftest-snapshot, printing and Firefox Screenshot.
if (!mHandle) {
return false;
}
layers::CanvasRendererData data;
data.mContext = this;
data.mSize = mGfxSize;
data.mIsOpaque = false;
aRenderer->Initialize(data);
aRenderer->SetDirty();
return true;
}
mozilla::UniquePtr<uint8_t[]> CanvasContext::GetImageBuffer(int32_t* aFormat) {
gfxAlphaType any;
RefPtr<gfx::SourceSurface> snapshot = GetSurfaceSnapshot(&any);
if (!snapshot) {
*aFormat = 0;
return nullptr;
}
RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
return gfxUtils::GetImageBuffer(dataSurface, /* aIsAlphaPremultiplied */ true,
aFormat);
}
NS_IMETHODIMP CanvasContext::GetInputStream(const char* aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream** aStream) {
gfxAlphaType any;
RefPtr<gfx::SourceSurface> snapshot = GetSurfaceSnapshot(&any);
if (!snapshot) {
return NS_ERROR_FAILURE;
}
RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
return gfxUtils::GetInputStream(dataSurface, /* aIsAlphaPremultiplied */ true,
aMimeType, aEncoderOptions, aStream);
}
already_AddRefed<mozilla::gfx::SourceSurface> CanvasContext::GetSurfaceSnapshot(
gfxAlphaType* aOutAlphaType) {
if (aOutAlphaType) {
*aOutAlphaType = gfxAlphaType::Premult;
}
auto* const cm = gfx::CanvasManagerChild::Get();
if (!cm) {
return nullptr;
}
if (!mBridge || !mBridge->IsOpen() || !mHandle) {
return nullptr;
}
return cm->GetSnapshot(cm->Id(), mBridge->Id(), mHandle, mGfxFormat,
/* aPremultiply */ false, /* aYFlip */ false);
}
} // namespace webgpu
} // namespace mozilla

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

@ -54,20 +54,14 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
return NS_OK;
}
mozilla::UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override {
MOZ_CRASH("todo");
}
bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
layers::CanvasRenderer* aRenderer) override;
mozilla::UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
NS_IMETHOD GetInputStream(const char* aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream** aStream) override {
*aStream = nullptr;
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIInputStream** aStream) override;
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* aOutAlphaType) override {
return nullptr;
}
gfxAlphaType* aOutAlphaType) override;
void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override {}
bool GetIsOpaque() override { return true; }

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

@ -640,6 +640,36 @@ static void PresentCallback(ffi::WGPUBufferMapAsyncStatus status,
delete req;
}
ipc::IPCResult WebGPUParent::GetFrontBufferSnapshot(
IProtocol* aProtocol, const CompositableHandle& aHandle,
Maybe<Shmem>& aShmem, gfx::IntSize& aSize) {
const auto& lookup = mCanvasMap.find(aHandle.Value());
if (lookup == mCanvasMap.end()) {
return IPC_OK();
}
RefPtr<PresentationData> data = lookup->second.get();
aSize = data->mTextureHost->GetSize();
uint32_t stride =
aSize.width * BytesPerPixel(data->mTextureHost->GetFormat());
uint32_t len = data->mRowCount * stride;
Shmem shmem;
if (!AllocShmem(len, ipc::Shmem::SharedMemory::TYPE_BASIC, &shmem)) {
return IPC_OK();
}
uint8_t* dst = shmem.get<uint8_t>();
uint8_t* src = data->mTextureHost->GetBuffer();
for (uint32_t row = 0; row < data->mRowCount; ++row) {
memcpy(dst, src, stride);
src += data->mTargetPitch;
dst += stride;
}
aShmem.emplace(std::move(shmem));
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvSwapChainPresent(
const CompositableHandle& aHandle, RawId aTextureId,
RawId aCommandEncoderId) {

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

@ -11,8 +11,7 @@
#include "WebGPUTypes.h"
#include "base/timer.h"
namespace mozilla {
namespace webgpu {
namespace mozilla::webgpu {
class ErrorBuffer;
class PresentationData;
@ -90,6 +89,11 @@ class WebGPUParent final : public PWebGPUParent {
ipc::IPCResult RecvDevicePopErrorScope(
RawId aSelfId, DevicePopErrorScopeResolver&& aResolver);
ipc::IPCResult GetFrontBufferSnapshot(IProtocol* aProtocol,
const CompositableHandle& aHandle,
Maybe<Shmem>& aShmem,
gfx::IntSize& aSize);
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
@ -109,7 +113,6 @@ class WebGPUParent final : public PWebGPUParent {
std::unordered_map<uint64_t, ErrorScopeStack> mErrorScopeMap;
};
} // namespace webgpu
} // namespace mozilla
} // namespace mozilla::webgpu
#endif // WEBGPU_PARENT_H_

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

@ -39,8 +39,6 @@ interface HTMLCanvasElement : HTMLElement {
partial interface HTMLCanvasElement {
[Pure, SetterThrows]
attribute boolean mozOpaque;
[Throws, NeedsSubjectPrincipal, Pref="canvas.mozgetasfile.enabled"]
File mozGetAsFile(DOMString name, optional DOMString? type = null);
// A Mozilla-only extension to get a canvas context backed by double-buffered
// shared memory. Only privileged callers can call this.
[ChromeOnly, Throws]

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

@ -64,11 +64,14 @@ dictionary RTCReceivedRtpStreamStats: RTCRtpStreamStats {
dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
DOMString remoteId;
unsigned long framesDecoded;
unsigned long frameWidth;
unsigned long frameHeight;
unsigned long long bytesReceived;
unsigned long nackCount;
unsigned long firCount;
unsigned long pliCount;
double framesPerSecond;
unsigned long framesReceived;
};
dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
@ -91,6 +94,9 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
unsigned long long headerBytesSent;
unsigned long long retransmittedPacketsSent;
unsigned long long retransmittedBytesSent;
unsigned long frameWidth;
unsigned long frameHeight;
unsigned long framesSent;
};
dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {

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

@ -66,7 +66,22 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(window);
auto storageAllowed = StorageAllowedForWindow(window);
// Our current idiom is that storage-related APIs specialize for the system
// principal themselves, which is consistent with StorageAllowedForwindow not
// specializing for the system principal. Without this specialization we
// would end up with ePrivateBrowsing for system principaled private browsing
// windows which is explicitly not what we want. System Principal code always
// should have access to storage. It may make sense to enhance
// StorageAllowedForWindow in the future to handle this after comprehensive
// auditing.
nsCOMPtr<nsIPrincipal> principal = aGlobal.GetSubjectPrincipal();
StorageAccess storageAllowed;
if (principal && principal->IsSystemPrincipal()) {
storageAllowed = StorageAccess::eAllow;
} else {
storageAllowed = StorageAllowedForWindow(window);
}
if (storageAllowed == StorageAccess::eDeny) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
@ -83,8 +98,6 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
// StorageAccess value.
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (storageAllowed == StorageAccess::ePrivateBrowsing) {
nsCOMPtr<Document> doc = window->GetExtantDoc();
nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
uint32_t privateBrowsingId = 0;
if (principal) {
MOZ_ALWAYS_SUCCEEDS(principal->GetPrivateBrowsingId(&privateBrowsingId));

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

@ -61,9 +61,21 @@ function doTests() {
});
}
function doSystemSharedWorkerTest() {
try {
let chromeShared =
new wP.SharedWorker("chrome://mochitests/content/dom/workers/test/sharedWorker_privateBrowsing.js");
ok(true, "system SharedWorker created without throwing or crashing!");
} catch (_ex) {
ok(false, "system SharedWorker should not throw or crash");
}
runTest();
}
var steps = [
setupWindow,
doTests
doTests,
doSystemSharedWorkerTest,
];
function runTest() {

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

@ -251,7 +251,7 @@ struct ShadowOptions {
* matching DrawTarget. Not adhering to this condition will make a draw call
* fail.
*/
class GradientStops : public external::AtomicRefCounted<GradientStops> {
class GradientStops : public SupportsThreadSafeWeakPtr<GradientStops> {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
virtual ~GradientStops() = default;
@ -275,8 +275,15 @@ class Pattern {
virtual PatternType GetType() const = 0;
/** Instantiate a new clone with the same pattern type and values. */
virtual Pattern* Clone() const { return nullptr; }
/** Instantiate a new clone with the same pattern type and values. Any
* internal strong references will be converted to weak references. */
virtual Pattern* CloneWeak() const { return nullptr; }
/** Whether the pattern holds an internal weak reference. */
virtual bool IsWeak() const { return false; }
/** Whether any internal weak references still point to a target. */
virtual bool IsValid() const { return true; }
/** Determine if the pattern type and values exactly match. */
virtual bool operator==(const Pattern& aOther) const = 0;
@ -285,6 +292,19 @@ class Pattern {
protected:
Pattern() = default;
// Utility functions to check if a weak reference is still valid.
template <typename T>
static inline bool IsRefValid(const RefPtr<T>& aPtr) {
// RefPtrs are always valid.
return true;
}
template <typename T>
static inline bool IsRefValid(const ThreadSafeWeakPtr<T>& aPtr) {
// Weak refs are only valid if they aren't dead.
return !aPtr.IsDead();
}
};
class ColorPattern : public Pattern {
@ -295,7 +315,7 @@ class ColorPattern : public Pattern {
PatternType GetType() const override { return PatternType::COLOR; }
Pattern* Clone() const override { return new ColorPattern(mColor); }
Pattern* CloneWeak() const override { return new ColorPattern(mColor); }
bool operator==(const Pattern& aOther) const override {
if (aOther.GetType() != PatternType::COLOR) {
@ -313,150 +333,201 @@ class ColorPattern : public Pattern {
* stored in a separate object and are backend dependent. This class itself
* may be used on the stack.
*/
class LinearGradientPattern : public Pattern {
template <template <typename> typename REF = RefPtr>
class LinearGradientPatternT : public Pattern {
typedef LinearGradientPatternT<ThreadSafeWeakPtr> Weak;
public:
/// For constructor parameter description, see member data documentation.
LinearGradientPattern(const Point& aBegin, const Point& aEnd,
already_AddRefed<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
: mBegin(aBegin), mEnd(aEnd), mStops(aStops), mMatrix(aMatrix) {}
LinearGradientPatternT(const Point& aBegin, const Point& aEnd,
RefPtr<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
: mBegin(aBegin),
mEnd(aEnd),
mStops(std::move(aStops)),
mMatrix(aMatrix) {}
PatternType GetType() const override { return PatternType::LINEAR_GRADIENT; }
Pattern* Clone() const override {
return new LinearGradientPattern(mBegin, mEnd, do_AddRef(mStops), mMatrix);
Pattern* CloneWeak() const override {
return new Weak(mBegin, mEnd, do_AddRef(mStops), mMatrix);
}
bool IsWeak() const override {
return std::is_same<decltype(*this), Weak>::value;
}
bool IsValid() const override { return IsRefValid(mStops); }
template <template <typename> typename T>
bool operator==(const LinearGradientPatternT<T>& aOther) const {
return mBegin == aOther.mBegin && mEnd == aOther.mEnd &&
mStops == aOther.mStops && mMatrix.ExactlyEquals(aOther.mMatrix);
}
bool operator==(const Pattern& aOther) const override {
if (aOther.GetType() != PatternType::LINEAR_GRADIENT) {
return false;
}
const LinearGradientPattern& other =
static_cast<const LinearGradientPattern&>(aOther);
return mBegin == other.mBegin && mEnd == other.mEnd &&
mStops == other.mStops && mMatrix.ExactlyEquals(other.mMatrix);
return aOther.IsWeak()
? *this == static_cast<const Weak&>(aOther)
: *this == static_cast<const LinearGradientPatternT<>&>(aOther);
}
Point mBegin; //!< Start of the linear gradient
Point mEnd; /**< End of the linear gradient - NOTE: In the case
of a zero length gradient it will act as the
color of the last stop. */
RefPtr<GradientStops>
mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw
target this pattern will be used with. */
Matrix mMatrix; /**< A matrix that transforms the pattern into
user space */
Point mBegin; //!< Start of the linear gradient
Point mEnd; /**< End of the linear gradient - NOTE: In the case
of a zero length gradient it will act as the
color of the last stop. */
REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw
target this pattern will be used with. */
Matrix mMatrix; /**< A matrix that transforms the pattern into
user space */
};
typedef LinearGradientPatternT<> LinearGradientPattern;
/**
* This class is used for Radial Gradient Patterns, the gradient stops are
* stored in a separate object and are backend dependent. This class itself
* may be used on the stack.
*/
class RadialGradientPattern : public Pattern {
template <template <typename> typename REF = RefPtr>
class RadialGradientPatternT : public Pattern {
typedef RadialGradientPatternT<ThreadSafeWeakPtr> Weak;
public:
/// For constructor parameter description, see member data documentation.
RadialGradientPattern(const Point& aCenter1, const Point& aCenter2,
Float aRadius1, Float aRadius2,
already_AddRefed<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
RadialGradientPatternT(const Point& aCenter1, const Point& aCenter2,
Float aRadius1, Float aRadius2,
RefPtr<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
: mCenter1(aCenter1),
mCenter2(aCenter2),
mRadius1(aRadius1),
mRadius2(aRadius2),
mStops(aStops),
mStops(std::move(aStops)),
mMatrix(aMatrix) {}
PatternType GetType() const override { return PatternType::RADIAL_GRADIENT; }
Pattern* Clone() const override {
return new RadialGradientPattern(mCenter1, mCenter2, mRadius1, mRadius2,
do_AddRef(mStops), mMatrix);
Pattern* CloneWeak() const override {
return new Weak(mCenter1, mCenter2, mRadius1, mRadius2, do_AddRef(mStops),
mMatrix);
}
bool IsWeak() const override {
return std::is_same<decltype(*this), Weak>::value;
}
bool IsValid() const override { return IsRefValid(mStops); }
template <template <typename> typename T>
bool operator==(const RadialGradientPatternT<T>& aOther) const {
return mCenter1 == aOther.mCenter1 && mCenter2 == aOther.mCenter2 &&
mRadius1 == aOther.mRadius1 && mRadius2 == aOther.mRadius2 &&
mStops == aOther.mStops && mMatrix.ExactlyEquals(aOther.mMatrix);
}
bool operator==(const Pattern& aOther) const override {
if (aOther.GetType() != PatternType::RADIAL_GRADIENT) {
return false;
}
const RadialGradientPattern& other =
static_cast<const RadialGradientPattern&>(aOther);
return mCenter1 == other.mCenter1 && mCenter2 == other.mCenter2 &&
mRadius1 == other.mRadius1 && mRadius2 == other.mRadius2 &&
mStops == other.mStops && mMatrix.ExactlyEquals(other.mMatrix);
return aOther.IsWeak()
? *this == static_cast<const Weak&>(aOther)
: *this == static_cast<const RadialGradientPatternT<>&>(aOther);
}
Point mCenter1; //!< Center of the inner (focal) circle.
Point mCenter2; //!< Center of the outer circle.
Float mRadius1; //!< Radius of the inner (focal) circle.
Float mRadius2; //!< Radius of the outer circle.
RefPtr<GradientStops>
mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw target
this pattern will be used with. */
Point mCenter1; //!< Center of the inner (focal) circle.
Point mCenter2; //!< Center of the outer circle.
Float mRadius1; //!< Radius of the inner (focal) circle.
Float mRadius2; //!< Radius of the outer circle.
REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw
target this pattern will be used with. */
Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};
typedef RadialGradientPatternT<> RadialGradientPattern;
/**
* This class is used for Conic Gradient Patterns, the gradient stops are
* stored in a separate object and are backend dependent. This class itself
* may be used on the stack.
*/
class ConicGradientPattern : public Pattern {
template <template <typename> typename REF = RefPtr>
class ConicGradientPatternT : public Pattern {
typedef ConicGradientPatternT<ThreadSafeWeakPtr> Weak;
public:
/// For constructor parameter description, see member data documentation.
ConicGradientPattern(const Point& aCenter, Float aAngle, Float aStartOffset,
Float aEndOffset, already_AddRefed<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
ConicGradientPatternT(const Point& aCenter, Float aAngle, Float aStartOffset,
Float aEndOffset, RefPtr<GradientStops> aStops,
const Matrix& aMatrix = Matrix())
: mCenter(aCenter),
mAngle(aAngle),
mStartOffset(aStartOffset),
mEndOffset(aEndOffset),
mStops(aStops),
mStops(std::move(aStops)),
mMatrix(aMatrix) {}
PatternType GetType() const override { return PatternType::CONIC_GRADIENT; }
Pattern* Clone() const override {
return new ConicGradientPattern(mCenter, mAngle, mStartOffset, mEndOffset,
do_AddRef(mStops), mMatrix);
Pattern* CloneWeak() const override {
return new Weak(mCenter, mAngle, mStartOffset, mEndOffset,
do_AddRef(mStops), mMatrix);
}
bool IsWeak() const override {
return std::is_same<decltype(*this), Weak>::value;
}
bool IsValid() const override { return IsRefValid(mStops); }
template <template <typename> typename T>
bool operator==(const ConicGradientPatternT<T>& aOther) const {
return mCenter == aOther.mCenter && mAngle == aOther.mAngle &&
mStartOffset == aOther.mStartOffset &&
mEndOffset == aOther.mEndOffset && mStops == aOther.mStops &&
mMatrix.ExactlyEquals(aOther.mMatrix);
}
bool operator==(const Pattern& aOther) const override {
if (aOther.GetType() != PatternType::CONIC_GRADIENT) {
return false;
}
const ConicGradientPattern& other =
static_cast<const ConicGradientPattern&>(aOther);
return mCenter == other.mCenter && mAngle == other.mAngle &&
mStartOffset == other.mStartOffset &&
mEndOffset == other.mEndOffset && mStops == other.mStops &&
mMatrix.ExactlyEquals(other.mMatrix);
return aOther.IsWeak()
? *this == static_cast<const Weak&>(aOther)
: *this == static_cast<const ConicGradientPatternT<>&>(aOther);
}
Point mCenter; //!< Center of the gradient
Float mAngle; //!< Start angle of gradient
Float mStartOffset; // Offset of first stop
Float mEndOffset; // Offset of last stop
RefPtr<GradientStops>
mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw target
this pattern will be used with. */
Point mCenter; //!< Center of the gradient
Float mAngle; //!< Start angle of gradient
Float mStartOffset; // Offset of first stop
Float mEndOffset; // Offset of last stop
REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw
target this pattern will be used with. */
Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};
typedef ConicGradientPatternT<> ConicGradientPattern;
/**
* This class is used for Surface Patterns, they wrap a surface and a
* repetition mode for the surface. This may be used on the stack.
*/
class SurfacePattern : public Pattern {
template <template <typename> typename REF = RefPtr>
class SurfacePatternT : public Pattern {
typedef SurfacePatternT<ThreadSafeWeakPtr> Weak;
public:
/// For constructor parameter description, see member data documentation.
SurfacePattern(SourceSurface* aSourceSurface, ExtendMode aExtendMode,
const Matrix& aMatrix = Matrix(),
SamplingFilter aSamplingFilter = SamplingFilter::GOOD,
const IntRect& aSamplingRect = IntRect())
: mSurface(aSourceSurface),
SurfacePatternT(RefPtr<SourceSurface> aSourceSurface, ExtendMode aExtendMode,
const Matrix& aMatrix = Matrix(),
SamplingFilter aSamplingFilter = SamplingFilter::GOOD,
const IntRect& aSamplingRect = IntRect())
: mSurface(std::move(aSourceSurface)),
mExtendMode(aExtendMode),
mSamplingFilter(aSamplingFilter),
mMatrix(aMatrix),
@ -464,25 +535,37 @@ class SurfacePattern : public Pattern {
PatternType GetType() const override { return PatternType::SURFACE; }
Pattern* Clone() const override {
return new SurfacePattern(mSurface, mExtendMode, mMatrix, mSamplingFilter,
mSamplingRect);
Pattern* CloneWeak() const override {
return new Weak(do_AddRef(mSurface), mExtendMode, mMatrix, mSamplingFilter,
mSamplingRect);
}
bool IsWeak() const override {
return std::is_same<decltype(*this), Weak>::value;
}
bool IsValid() const override { return IsRefValid(mSurface); }
template <template <typename> typename T>
bool operator==(const SurfacePatternT<T>& aOther) const {
return mSurface == aOther.mSurface && mExtendMode == aOther.mExtendMode &&
mSamplingFilter == aOther.mSamplingFilter &&
mMatrix.ExactlyEquals(aOther.mMatrix) &&
mSamplingRect.IsEqualEdges(aOther.mSamplingRect);
}
bool operator==(const Pattern& aOther) const override {
if (aOther.GetType() != PatternType::SURFACE) {
return false;
}
const SurfacePattern& other = static_cast<const SurfacePattern&>(aOther);
return mSurface == other.mSurface && mExtendMode == other.mExtendMode &&
mSamplingFilter == other.mSamplingFilter &&
mMatrix.ExactlyEquals(other.mMatrix) &&
mSamplingRect.IsEqualEdges(other.mSamplingRect);
return aOther.IsWeak()
? *this == static_cast<const Weak&>(aOther)
: *this == static_cast<const SurfacePatternT<>&>(aOther);
}
RefPtr<SourceSurface> mSurface; //!< Surface to use for drawing
ExtendMode mExtendMode; /**< This determines how the image is extended
outside the bounds of the image */
REF<SourceSurface> mSurface; //!< Surface to use for drawing
ExtendMode mExtendMode; /**< This determines how the image is extended
outside the bounds of the image */
SamplingFilter
mSamplingFilter; //!< Resampling filter for resampling the image.
Matrix mMatrix; //!< Transforms the pattern into user space
@ -492,6 +575,8 @@ class SurfacePattern : public Pattern {
specified. */
};
typedef SurfacePatternT<> SurfacePattern;
class StoredPattern;
static const int32_t kReasonableSurfaceSize = 8192;
@ -506,7 +591,7 @@ static const int32_t kReasonableSurfaceSize = 8192;
* used on random threads now. This will be fixed in the future. Eventually
* all SourceSurface should be thread-safe.
*/
class SourceSurface : public external::AtomicRefCounted<SourceSurface> {
class SourceSurface : public SupportsThreadSafeWeakPtr<SourceSurface> {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
virtual ~SourceSurface() = default;

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

@ -144,13 +144,15 @@ RefPtr<webgpu::WebGPUChild> CanvasManagerChild::GetWebGPUChild() {
}
already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
uint32_t aManagerId, int32_t aProtocolId, bool aHasAlpha) {
uint32_t aManagerId, int32_t aProtocolId,
const layers::CompositableHandle& aHandle, SurfaceFormat aFormat,
bool aPremultiply, bool aYFlip) {
if (!CanSend()) {
return nullptr;
}
webgl::FrontBufferSnapshotIpc res;
if (!SendGetSnapshot(aManagerId, aProtocolId, &res)) {
if (!SendGetSnapshot(aManagerId, aProtocolId, aHandle, &res)) {
return nullptr;
}
@ -178,7 +180,7 @@ already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
}
SurfaceFormat format =
aHasAlpha ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
IsOpaque(aFormat) ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
RefPtr<DataSourceSurface> surface =
Factory::CreateDataSourceSurfaceWithStride(size, format, stride.value(),
/* aZero */ false);
@ -192,21 +194,32 @@ already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
return nullptr;
}
// The buffer we read back from WebGL is R8G8B8A8, not premultiplied and has
// its rows inverted. For the general case, we want surfaces represented as
// premultiplied B8G8R8A8, with its rows ordered top to bottom. Given this
// path is used for screenshots/SurfaceFromElement, that's the representation
// we need.
if (aHasAlpha) {
if (!PremultiplyYFlipData(res.shmem->get<uint8_t>(), stride.value(),
SurfaceFormat::R8G8B8A8, map.GetData(),
map.GetStride(), format, size)) {
// The buffer we may readback from the canvas could be R8G8B8A8, not
// premultiplied, and/or has its rows iverted. For the general case, we want
// surfaces represented as premultiplied B8G8R8A8, with its rows ordered top
// to bottom. Given this path is used for screenshots/SurfaceFromElement,
// that's the representation we need.
if (aYFlip) {
if (aPremultiply) {
if (!PremultiplyYFlipData(res.shmem->get<uint8_t>(), stride.value(),
aFormat, map.GetData(), map.GetStride(), format,
size)) {
return nullptr;
}
} else {
if (!SwizzleYFlipData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
map.GetData(), map.GetStride(), format, size)) {
return nullptr;
}
}
} else if (aPremultiply) {
if (!PremultiplyData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
map.GetData(), map.GetStride(), format, size)) {
return nullptr;
}
} else {
if (!SwizzleYFlipData(res.shmem->get<uint8_t>(), stride.value(),
SurfaceFormat::R8G8B8X8, map.GetData(),
map.GetStride(), format, size)) {
if (!SwizzleData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
map.GetData(), map.GetStride(), format, size)) {
return nullptr;
}
}

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

@ -8,6 +8,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/gfx/PCanvasManagerChild.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ThreadLocal.h"
namespace mozilla {
@ -29,9 +30,10 @@ class CanvasManagerChild final : public PCanvasManagerChild {
explicit CanvasManagerChild(uint32_t aId);
uint32_t Id() const { return mId; }
already_AddRefed<DataSourceSurface> GetSnapshot(uint32_t aManagerId,
int32_t aProtocolId,
bool aHasAlpha);
already_AddRefed<DataSourceSurface> GetSnapshot(
uint32_t aManagerId, int32_t aProtocolId,
const layers::CompositableHandle& aHandle, SurfaceFormat aFormat,
bool aPremultiply, bool aYFlip);
void ActorDestroy(ActorDestroyReason aReason) override;
static CanvasManagerChild* Get();

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

@ -111,7 +111,7 @@ mozilla::ipc::IPCResult CanvasManagerParent::RecvInitialize(
mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
const uint32_t& aManagerId, const int32_t& aProtocolId,
webgl::FrontBufferSnapshotIpc* aResult) {
const CompositableHandle& aHandle, webgl::FrontBufferSnapshotIpc* aResult) {
if (!aManagerId) {
return IPC_FAIL(this, "invalid id");
}
@ -129,16 +129,33 @@ mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
return IPC_FAIL(this, "invalid actor");
}
if (actor->GetProtocolId() != ProtocolId::PWebGLMsgStart ||
actor->GetSide() != mozilla::ipc::Side::ParentSide) {
if (actor->GetSide() != mozilla::ipc::Side::ParentSide) {
return IPC_FAIL(this, "unsupported actor");
}
RefPtr<dom::WebGLParent> webgl = static_cast<dom::WebGLParent*>(actor);
webgl::FrontBufferSnapshotIpc buffer;
mozilla::ipc::IPCResult rv = webgl->GetFrontBufferSnapshot(&buffer, this);
if (!rv) {
return rv;
switch (actor->GetProtocolId()) {
case ProtocolId::PWebGLMsgStart: {
RefPtr<dom::WebGLParent> webgl = static_cast<dom::WebGLParent*>(actor);
mozilla::ipc::IPCResult rv = webgl->GetFrontBufferSnapshot(&buffer, this);
if (!rv) {
return rv;
}
} break;
case ProtocolId::PWebGPUMsgStart: {
RefPtr<webgpu::WebGPUParent> webgpu =
static_cast<webgpu::WebGPUParent*>(actor);
IntSize size;
mozilla::ipc::IPCResult rv =
webgpu->GetFrontBufferSnapshot(this, aHandle, buffer.shmem, size);
if (!rv) {
return rv;
}
buffer.surfSize.x = static_cast<uint32_t>(size.width);
buffer.surfSize.y = static_cast<uint32_t>(size.height);
} break;
default:
return IPC_FAIL(this, "unsupported protocol");
}
*aResult = std::move(buffer);

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

@ -30,6 +30,7 @@ class CanvasManagerParent final : public PCanvasManagerParent {
mozilla::ipc::IPCResult RecvInitialize(const uint32_t& aId);
mozilla::ipc::IPCResult RecvGetSnapshot(
const uint32_t& aManagerId, const int32_t& aProtocolId,
const CompositableHandle& aHandle,
webgl::FrontBufferSnapshotIpc* aResult);
private:

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

@ -42,9 +42,9 @@ bool GPUProcessHost::Launch(StringVector aExtraOpts) {
MOZ_ASSERT(!mGPUChild);
MOZ_ASSERT(!gfxPlatform::IsHeadless());
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>(
dom::ContentParent::ShouldSyncPreference);
if (!mPrefSerializer->SerializeToSharedMemory()) {
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_GPU,
/* remoteType */ ""_ns)) {
return false;
}
mPrefSerializer->AddSharedPrefCmdLineArgs(*this, aExtraOpts);

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

@ -163,13 +163,11 @@ void GPUProcessManager::OnPreferenceChange(const char16_t* aData) {
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
// A pref changed. If it is useful to do so, inform child processes.
if (!dom::ContentParent::ShouldSyncPreference(strData.Data())) {
return;
}
mozilla::dom::Pref pref(strData, /* isLocked */ false,
/* isSanitized */ false, Nothing(), Nothing());
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
Preferences::GetPreference(&pref);
Preferences::GetPreference(&pref, GeckoProcessType_GPU,
/* remoteType */ ""_ns);
if (!!mGPUChild) {
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
mGPUChild->SendPreferenceUpdate(pref);

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

@ -5,9 +5,11 @@
* 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 "mozilla/layers/LayersMessageUtils.h";
include protocol PWebGL;
include protocol PWebGPU;
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::webgl::FrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
namespace mozilla {
@ -39,7 +41,7 @@ parent:
// intended to be used by the main thread in the content process to block
// reading without having to block on the worker thread that owns the context
// instance.
sync GetSnapshot(uint32_t aManagerId, int32_t aProtocolId) returns (FrontBufferSnapshotIpc ret);
sync GetSnapshot(uint32_t aManagerId, int32_t aProtocolId, CompositableHandle aHandle) returns (FrontBufferSnapshotIpc ret);
};
} // gfx

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

@ -1728,6 +1728,8 @@ bool gfxPlatformFontList::InitializeFamily(fontlist::Family* aFamily,
gfxFontEntry* gfxPlatformFontList::FindFontForFamily(
nsPresContext* aPresContext, const nsACString& aFamily,
const gfxFontStyle* aStyle) {
AutoLock lock(mLock);
nsAutoCString key;
GenerateFontListKey(aFamily, key);

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

@ -331,7 +331,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
gfxFontEntry* FindFontForFamily(nsPresContext* aPresContext,
const nsACString& aFamily,
const gfxFontStyle* aStyle) REQUIRES(mLock);
const gfxFontStyle* aStyle);
mozilla::fontlist::FontList* SharedFontList() const {
return mSharedFontList.get();

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

@ -216,13 +216,11 @@ void VRProcessManager::OnPreferenceChange(const char16_t* aData) {
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
// A pref changed. If it is useful to do so, inform child processes.
if (!dom::ContentParent::ShouldSyncPreference(strData.Data())) {
return;
}
mozilla::dom::Pref pref(strData, /* isLocked */ false,
/* isSanitized */ false, Nothing(), Nothing());
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
Preferences::GetPreference(&pref);
Preferences::GetPreference(&pref, GeckoProcessType_VR,
/* remoteType */ ""_ns);
if (!!mVRChild) {
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
mVRChild->SendPreferenceUpdate(pref);

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

@ -16,6 +16,7 @@
#include "mozilla/ipc/ProcessUtils.h"
#include "mozilla/ipc/ProtocolTypes.h"
#include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/Unused.h"
@ -54,9 +55,9 @@ bool VRProcessParent::Launch() {
std::vector<std::string> extraArgs;
ProcessChild::AddPlatformBuildID(extraArgs);
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>(
dom::ContentParent::ShouldSyncPreference);
if (!mPrefSerializer->SerializeToSharedMemory()) {
mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_VR,
/* remoteType */ ""_ns)) {
return false;
}
mPrefSerializer->AddSharedPrefCmdLineArgs(*this, extraArgs);

843
gfx/wr/Cargo.lock сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -21,13 +21,7 @@ opt-level = 2
[profile.release.package.glsl]
opt-level = 2
# Running wrench on android built with master cargo-apk results in a crash
# due to a mismatched version of android_glue (a dependency of winit).
# Override it to use a suitable version of android_glue.
# See https://github.com/rust-windowing/android-rs-glue/issues/239.
# This can be removed once a new version of android_glue is published to crates.io.
[patch.crates-io]
android_glue = { git = "https://github.com/rust-windowing/android-rs-glue.git", rev = "e3ac6edea5814e1faca0c31ea8fac6877cb929ea" }
# this is a version that fixes some incompatibilites with newer rust/aarch64
winit = { version = "0.19", git = "https://github.com/jrmuizel/winit", branch="wr" }
fog = { path = "fog" }
# use a patched version of glutin that works on android
glutin = { version = "0.28", git = "https://github.com/jamienicol/glutin", branch="wr" }

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

@ -58,10 +58,10 @@ app_units = "0.7"
env_logger = "0.5"
euclid = "0.22"
gleam = "0.13"
glutin = "0.21"
glutin = "0.28"
rayon = "1"
webrender = { path = "../webrender" }
winit = "0.19"
winit = "0.26"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.7"

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

@ -54,25 +54,26 @@ impl Example for App {
fn on_event(
&mut self,
event: winit::WindowEvent,
event: winit::event::WindowEvent,
_window: &winit::window::Window,
_api: &mut RenderApi,
_document_id: DocumentId
_document_id: DocumentId,
) -> bool {
match event {
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
} => {
match key {
winit::VirtualKeyCode::Right => {
winit::event::VirtualKeyCode::Right => {
self.rect_count += 1;
println!("rects = {}", self.rect_count);
}
winit::VirtualKeyCode::Left => {
winit::event::VirtualKeyCode::Left => {
self.rect_count = cmp::max(self.rect_count, 1) - 1;
println!("rects = {}", self.rect_count);
}

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

@ -141,24 +141,30 @@ impl Example for App {
self.add_rounded_rect(bounds, ColorF::new(0.0, 0.0, 1.0, 0.5), builder, pipeline_id, key2, None);
}
fn on_event(&mut self, win_event: winit::WindowEvent, api: &mut RenderApi, document_id: DocumentId) -> bool {
fn on_event(
&mut self,
win_event: winit::event::WindowEvent,
_window: &winit::window::Window,
api: &mut RenderApi,
document_id: DocumentId
) -> bool {
let mut rebuild_display_list = false;
match win_event {
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
} => {
let (delta_angle, delta_opacity) = match key {
winit::VirtualKeyCode::Down => (0.0, -0.1),
winit::VirtualKeyCode::Up => (0.0, 0.1),
winit::VirtualKeyCode::Right => (1.0, 0.0),
winit::VirtualKeyCode::Left => (-1.0, 0.0),
winit::VirtualKeyCode::R => {
winit::event::VirtualKeyCode::Down => (0.0, -0.1),
winit::event::VirtualKeyCode::Up => (0.0, 0.1),
winit::event::VirtualKeyCode::Right => (1.0, 0.0),
winit::event::VirtualKeyCode::Left => (-1.0, 0.0),
winit::event::VirtualKeyCode::R => {
rebuild_display_list = true;
(0.0, 0.0)
}

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

@ -8,17 +8,18 @@ use std::env;
use std::path::PathBuf;
use webrender;
use winit;
use winit::platform::run_return::EventLoopExtRunReturn;
use webrender::{DebugFlags, ShaderPrecacheFlags};
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
struct Notifier {
events_proxy: winit::EventsLoopProxy,
events_proxy: winit::event_loop::EventLoopProxy<()>,
}
impl Notifier {
fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
fn new(events_proxy: winit::event_loop::EventLoopProxy<()>) -> Notifier {
Notifier { events_proxy }
}
}
@ -32,7 +33,7 @@ impl RenderNotifier for Notifier {
fn wake_up(&self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
let _ = self.events_proxy.wakeup();
let _ = self.events_proxy.send_event(());
}
fn new_frame_ready(&self,
@ -83,7 +84,8 @@ pub trait Example {
);
fn on_event(
&mut self,
_: winit::WindowEvent,
_: winit::event::WindowEvent,
_: &winit::window::Window,
_: &mut RenderApi,
_: DocumentId,
) -> bool {
@ -123,11 +125,10 @@ pub fn main_wrapper<E: Example>(
None
};
let mut events_loop = winit::EventsLoop::new();
let window_builder = winit::WindowBuilder::new()
let mut events_loop = winit::event_loop::EventLoop::new();
let window_builder = winit::window::WindowBuilder::new()
.with_title(E::TITLE)
.with_multitouch()
.with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
.with_inner_size(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
let windowed_context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
@ -154,7 +155,7 @@ pub fn main_wrapper<E: Example>(
println!("OpenGL version {}", gl.get_string(gl::VERSION));
println!("Shader resource path: {:?}", res_path);
let device_pixel_ratio = windowed_context.window().get_hidpi_factor() as f32;
let device_pixel_ratio = windowed_context.window().scale_factor() as f32;
println!("Device pixel ratio: {}", device_pixel_ratio);
println!("Loading shaders...");
@ -171,9 +172,7 @@ pub fn main_wrapper<E: Example>(
let device_size = {
let size = windowed_context
.window()
.get_inner_size()
.unwrap()
.to_physical(device_pixel_ratio as f64);
.inner_size();
DeviceIntSize::new(size.width as i32, size.height as i32)
};
let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
@ -218,48 +217,55 @@ pub fn main_wrapper<E: Example>(
api.send_transaction(document_id, txn);
println!("Entering event loop");
events_loop.run_forever(|global_event| {
events_loop.run_return(|global_event, _elwt, control_flow| {
let mut txn = Transaction::new();
let mut custom_event = true;
let old_flags = debug_flags;
let win_event = match global_event {
winit::Event::WindowEvent { event, .. } => event,
_ => return winit::ControlFlow::Continue,
winit::event::Event::WindowEvent { event, .. } => event,
_ => return,
};
match win_event {
winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break,
winit::WindowEvent::AxisMotion { .. } |
winit::WindowEvent::CursorMoved { .. } => {
winit::event::WindowEvent::CloseRequested => {
*control_flow = winit::event_loop::ControlFlow::Exit;
return;
}
winit::event::WindowEvent::AxisMotion { .. } |
winit::event::WindowEvent::CursorMoved { .. } => {
custom_event = example.on_event(
win_event,
&mut api,
document_id,
);
win_event,
windowed_context.window(),
&mut api,
document_id,
);
// skip high-frequency events from triggering a frame draw.
if !custom_event {
return winit::ControlFlow::Continue;
return;
}
},
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
} => match key {
winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
winit::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
winit::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
winit::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
winit::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
winit::VirtualKeyCode::Q => debug_flags.toggle(
winit::event::VirtualKeyCode::Escape => {
*control_flow = winit::event_loop::ControlFlow::Exit;
return;
}
winit::event::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
winit::event::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
winit::event::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
winit::event::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
winit::event::VirtualKeyCode::Q => debug_flags.toggle(
DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
),
winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
winit::VirtualKeyCode::M => api.notify_memory_pressure(),
winit::VirtualKeyCode::C => {
winit::event::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
winit::event::VirtualKeyCode::M => api.notify_memory_pressure(),
winit::event::VirtualKeyCode::C => {
let path: PathBuf = "../captures/example".into();
//TODO: switch between SCENE/FRAME capture types
// based on "shift" modifier, when `glutin` is updated.
@ -269,6 +275,7 @@ pub fn main_wrapper<E: Example>(
_ => {
custom_event = example.on_event(
win_event,
windowed_context.window(),
&mut api,
document_id,
)
@ -276,6 +283,7 @@ pub fn main_wrapper<E: Example>(
},
other => custom_event = example.on_event(
other,
windowed_context.window(),
&mut api,
document_id,
),
@ -313,7 +321,7 @@ pub fn main_wrapper<E: Example>(
example.draw_custom(&*gl);
windowed_context.swap_buffers().ok();
winit::ControlFlow::Continue
*control_flow = winit::event_loop::ControlFlow::Wait;
});
renderer.deinit();

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

@ -77,12 +77,18 @@ impl Example for App {
builder.pop_stacking_context();
}
fn on_event(&mut self, event: winit::WindowEvent, api: &mut RenderApi, document_id: DocumentId) -> bool {
fn on_event(
&mut self,
event: winit::event::WindowEvent,
_window: &winit::window::Window,
api: &mut RenderApi,
document_id: DocumentId,
) -> bool {
match event {
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
virtual_keycode: Some(winit::VirtualKeyCode::Space),
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(winit::event::VirtualKeyCode::Space),
..
},
..

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

@ -17,13 +17,14 @@ use webrender::api::units::*;
use webrender::render_api::*;
use webrender::DebugFlags;
use winit::dpi::LogicalSize;
use winit::platform::run_return::EventLoopExtRunReturn;
struct Notifier {
events_proxy: winit::EventsLoopProxy,
events_proxy: winit::event_loop::EventLoopProxy<()>,
}
impl Notifier {
fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
fn new(events_proxy: winit::event_loop::EventLoopProxy<()>) -> Notifier {
Notifier { events_proxy }
}
}
@ -37,7 +38,7 @@ impl RenderNotifier for Notifier {
fn wake_up(&self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
let _ = self.events_proxy.wakeup();
let _ = self.events_proxy.send_event(());
}
fn new_frame_ready(&self,
@ -50,7 +51,7 @@ impl RenderNotifier for Notifier {
}
struct Window {
events_loop: winit::EventsLoop, //TODO: share events loop?
events_loop: winit::event_loop::EventLoop<()>, //TODO: share events loop?
context: Option<glutin::WindowedContext<NotCurrent>>,
renderer: webrender::Renderer,
name: &'static str,
@ -63,11 +64,10 @@ struct Window {
impl Window {
fn new(name: &'static str, clear_color: ColorF) -> Self {
let events_loop = winit::EventsLoop::new();
let window_builder = winit::WindowBuilder::new()
let events_loop = winit::event_loop::EventLoop::new();
let window_builder = winit::window::WindowBuilder::new()
.with_title(name)
.with_multitouch()
.with_dimensions(LogicalSize::new(800., 600.));
.with_inner_size(LogicalSize::new(800. as f64, 600. as f64));
let context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
@ -88,8 +88,6 @@ impl Window {
glutin::Api::WebGl => unimplemented!(),
};
let device_pixel_ratio = context.window().get_hidpi_factor() as f32;
let opts = webrender::RendererOptions {
clear_color,
..webrender::RendererOptions::default()
@ -98,9 +96,7 @@ impl Window {
let device_size = {
let size = context
.window()
.get_inner_size()
.unwrap()
.to_physical(device_pixel_ratio as f64);
.inner_size();
DeviceIntSize::new(size.width as i32, size.height as i32)
};
let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
@ -140,45 +136,46 @@ impl Window {
let renderer = &mut self.renderer;
let api = &mut self.api;
self.events_loop.poll_events(|global_event| match global_event {
winit::Event::WindowEvent { event, .. } => match event {
winit::WindowEvent::CloseRequested |
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
virtual_keycode: Some(winit::VirtualKeyCode::Escape),
self.events_loop.run_return(|global_event, _elwt, control_flow| {
*control_flow = winit::event_loop::ControlFlow::Exit;
match global_event {
winit::event::Event::WindowEvent { event, .. } => match event {
winit::event::WindowEvent::CloseRequested |
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
virtual_keycode: Some(winit::event::VirtualKeyCode::Escape),
..
},
..
},
..
} => {
do_exit = true
}
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
virtual_keycode: Some(winit::VirtualKeyCode::P),
} => {
do_exit = true
}
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(winit::event::VirtualKeyCode::P),
..
},
..
},
..
} => {
println!("set flags {}", my_name);
api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG))
} => {
println!("set flags {}", my_name);
api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG))
}
_ => {}
}
_ => {}
}
_ => {}
});
if do_exit {
return true
}
let context = unsafe { self.context.take().unwrap().make_current().unwrap() };
let device_pixel_ratio = context.window().get_hidpi_factor() as f32;
let device_pixel_ratio = context.window().scale_factor() as f32;
let device_size = {
let size = context
.window()
.get_inner_size()
.unwrap()
.to_physical(device_pixel_ratio as f64);
.inner_size();
DeviceIntSize::new(size.width as i32, size.height as i32)
};
let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);

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

@ -165,22 +165,28 @@ impl Example for App {
builder.pop_stacking_context();
}
fn on_event(&mut self, event: winit::WindowEvent, api: &mut RenderApi, document_id: DocumentId) -> bool {
fn on_event(
&mut self,
event: winit::event::WindowEvent,
window: &winit::window::Window,
api: &mut RenderApi,
document_id: DocumentId,
) -> bool {
let mut txn = Transaction::new();
match event {
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
} => {
let offset = match key {
winit::VirtualKeyCode::Down => Some(LayoutVector2D::new(0.0, -10.0)),
winit::VirtualKeyCode::Up => Some(LayoutVector2D::new(0.0, 10.0)),
winit::VirtualKeyCode::Right => Some(LayoutVector2D::new(-10.0, 0.0)),
winit::VirtualKeyCode::Left => Some(LayoutVector2D::new(10.0, 0.0)),
winit::event::VirtualKeyCode::Down => Some(LayoutVector2D::new(0.0, -10.0)),
winit::event::VirtualKeyCode::Up => Some(LayoutVector2D::new(0.0, 10.0)),
winit::event::VirtualKeyCode::Right => Some(LayoutVector2D::new(-10.0, 0.0)),
winit::event::VirtualKeyCode::Left => Some(LayoutVector2D::new(10.0, 0.0)),
_ => None,
};
@ -197,14 +203,15 @@ impl Example for App {
txn.generate_frame(0, RenderReasons::empty());
}
}
winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
self.cursor_position = WorldPoint::new(x as f32, y as f32);
winit::event::WindowEvent::CursorMoved { position, .. } => {
let pos: LogicalPosition<f32> = position.to_logical(window.scale_factor());
self.cursor_position = WorldPoint::new(pos.x, pos.y);
}
winit::WindowEvent::MouseWheel { delta, .. } => {
winit::event::WindowEvent::MouseWheel { delta, .. } => {
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
winit::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
winit::MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
winit::event::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
winit::event::MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
};
self.scroll_offset += LayoutVector2D::new(dx, dy);
@ -219,7 +226,7 @@ impl Example for App {
txn.generate_frame(0, RenderReasons::empty());
}
winit::WindowEvent::MouseInput { .. } => {
winit::event::WindowEvent::MouseInput { .. } => {
let results = api.hit_test(
document_id,
self.cursor_position,

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

@ -192,14 +192,15 @@ impl Example for App {
fn on_event(
&mut self,
event: winit::WindowEvent,
event: winit::event::WindowEvent,
_window: &winit::window::Window,
api: &mut RenderApi,
document_id: DocumentId,
) -> bool {
match event {
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(key),
..
},
@ -208,7 +209,7 @@ impl Example for App {
let mut txn = Transaction::new();
match key {
winit::VirtualKeyCode::S => {
winit::event::VirtualKeyCode::S => {
self.stress_keys.clear();
for _ in 0 .. 16 {
@ -235,10 +236,10 @@ impl Example for App {
}
}
}
winit::VirtualKeyCode::D => if let Some(image_key) = self.image_key.take() {
winit::event::VirtualKeyCode::D => if let Some(image_key) = self.image_key.take() {
txn.delete_image(image_key);
},
winit::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
winit::event::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
let size = 128;
self.image_generator.generate_image(size);
@ -249,7 +250,7 @@ impl Example for App {
&DirtyRect::All,
);
},
winit::VirtualKeyCode::E => {
winit::event::VirtualKeyCode::E => {
if let Some(image_key) = self.image_key.take() {
txn.delete_image(image_key);
}
@ -272,7 +273,7 @@ impl Example for App {
self.image_key = Some(image_key);
}
winit::VirtualKeyCode::R => {
winit::event::VirtualKeyCode::R => {
if let Some(image_key) = self.image_key.take() {
txn.delete_image(image_key);
}

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

@ -189,7 +189,8 @@ impl Example for App {
fn on_event(
&mut self,
_event: winit::WindowEvent,
_event: winit::event::WindowEvent,
_window: &winit::window::Window,
_api: &mut RenderApi,
_document_id: DocumentId,
) -> bool {

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

@ -11,17 +11,15 @@ packages = [
"core-foundation-sys",
"core-graphics",
"gl_generator",
"gleam",
# glsl requires 5.1, and xcursor (required by winit) requires 7.1.
# when a version of glsl depending on 7.1 is published we can update.
"nom",
"rand_core",
# https://github.com/trimental/andrew/issues/5
"rusttype",
# https://bugzilla.mozilla.org/show_bug.cgi?id=1615148
"smallvec",
# Can be fixed by updating clap dependency - see bug 1765326
"strsim",
"yaml-rust",
# These are tracked in bug 1587468, see there for pending work.
"proc-macro2",
"quote",
"unicode-xid",
# Can be fixed by removing time dependency - see bug 1765324
"wasi",
]
# Files that are ignored for all tidy and lint checks.

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

@ -6,11 +6,16 @@ build = "build.rs"
license = "MPL-2.0"
edition = "2018"
# Required by cargo-apk to build for Android
[lib]
crate-type = ["lib", "cdylib"]
path = "src/main.rs"
[dependencies]
base64 = "0.13"
env_logger = { version = "0.5", optional = true }
gleam = "0.13"
glutin = "0.21"
glutin = "0.28"
clap = { version = "2", features = ["yaml"] }
glsl = "4.0"
log = "0.4"
@ -22,7 +27,7 @@ crossbeam = "0.2"
osmesa-sys = { version = "0.1.2", optional = true }
osmesa-src = { version = "0.2", git = "https://github.com/servo/osmesa-src", optional = true }
webrender = { path = "../webrender", features = ["capture", "replay", "png", "profiler", "no_static_freetype", "leak_checks"] }
winit = "0.19"
winit = "0.26"
serde = { version = "1.0", features = ["derive"] }
semver = "0.9.0"
swgl = { path = "../swgl", optional = true }
@ -46,25 +51,23 @@ software = [ "swgl" ]
dwrote = "0.11"
mozangle = { version = "0.3.2", features = ["egl"] }
[target.'cfg(target_os = "android")'.dependencies]
ndk-glue = "0.5"
[target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
font-loader = "0.11"
# Configuration information used when building wrench as an APK.
[package.metadata.android]
package_name = "org.mozilla.wrench"
label = "Wrench"
# keep it in sync with android-sdk-version in android-sdk.configure
android_version = 31
target_sdk_version = 18
min_sdk_version = 18
fullscreen = true
package = "org.mozilla.wrench"
build_targets = [ "armv7-linux-androideabi", "i686-linux-android" ]
opengles_version_major = 3
opengles_version_minor = 0
[package.metadata.android.application_attributes]
"android:hardwareAccelerated" = "true"
[package.metadata.android.activity_attributes]
"android:screenOrientation" = "unspecified"
"android:uiOptions" = "none"
[[package.metadata.android.permission]]
name = "android.permission.READ_EXTERNAL_STORAGE"
[package.metadata.android.sdk]
# keep it in sync with android-sdk-version in android-sdk.configure
target_sdk_version = 31
min_sdk_version = 18
[package.metadata.android.application]
label = "Wrench"

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

@ -10,10 +10,11 @@ Follow the steps at https://github.com/rust-windowing/android-rs-glue#setting-up
- Install both the i686-linux-android and armv7-linux-androideabi rust
targets, as the APK will include native libraries with both architectures.
- Don't install currently published version of cargo-apk as it doesn't work with the
version of winit and glutin we are using.
Instead, install the git master version of our fork like so:
cargo install --git https://github.com/jamienicol/android-rs-glue cargo-apk
- Don't install currently published version of cargo-apk, as it is missing the following
required patch: https://github.com/rust-windowing/android-ndk-rs/pull/236
Instead, install the git master version like so:
cargo install --git https://github.com/rust-windowing/android-ndk-rs cargo-apk
- Consider adding ~/.mozbuild/android-sdk-linux/platform-tools to your path, for the adb commands below.
@ -22,23 +23,23 @@ Compiling and running:
Compile wrench:
cd wrench
export ANDROID_HOME=$HOME/.mozbuild/android-sdk-linux # exact path may vary
export NDK_HOME=$HOME/.mozbuild/android-ndk-r17b # exact path may vary
export ANDROID_SDK_ROOT=$HOME/.mozbuild/android-sdk-linux # exact path may vary
export ANDROID_NDK_ROOT=$HOME/.mozbuild/android-ndk-r21d # exact path may vary
cargo apk build
Install the APK:
adb install -r ../target/android-artifacts/debug/apk/wrench.apk
adb install -r ../target/debug/apk/wrench.apk
Set command line arguments and env vars for wrench:
adb shell
mkdir /sdcard/wrench
echo "load reftests/aa/rounded-rects.yaml" >/sdcard/wrench/args
echo "env: WRENCH_REFTEST_CONDITION_EMULATOR=1" >>/sdcard/wrench/args # If you're using the emulator
echo "env: WRENCH_REFTEST_CONDITION_DEVICE=1" >>/sdcard/wrench/args # If you're using a device
mkdir /storage/emulated/0/Android/data/org.mozilla.wrench/files/wrench
echo "load reftests/aa/rounded-rects.yaml" >/storage/emulated/0/Android/data/org.mozilla.wrench/files/wrench/args
echo "env: WRENCH_REFTEST_CONDITION_EMULATOR=1" >>/storage/emulated/0/Android/data/org.mozilla.wrench/files/wrench/args # If you're using the emulator
echo "env: WRENCH_REFTEST_CONDITION_DEVICE=1" >>/storage/emulated/0/Android/data/org.mozilla.wrench/files/wrench/args # If you're using a device
exit
Push reftests (if you need these files for what you're doing):
adb push reftests /sdcard/wrench/
adb push reftests /storage/emulated/0/Android/data/org.mozilla.wrench/files/wrench/
Run the application:
adb shell am start -n org.mozilla.wrench/android.app.NativeActivity
@ -49,11 +50,11 @@ Release mode:
Building in release does work as well. Use the following steps to compile wrench:
cd wrench
export ANDROID_HOME=$HOME/.mozbuild/android-sdk-linux # exact path may vary
export NDK_HOME=$HOME/.mozbuild/android-ndk # exact path may vary
export ANDROID_SDK_ROOT=$HOME/.mozbuild/android-sdk-linux # exact path may vary
export ANDROID_NDK_ROOT=$HOME/.mozbuild/android-ndk-r21d # exact path may vary
cargo apk build --release
Now the APK at ../target/android-artifacts/release/apk/wrench.apk
Now the APK at ../target/release/apk/wrench.apk
should be signed and installable (you may need to uninstall the debug APK first if you
have that installed).
@ -66,7 +67,7 @@ Running reftests like a boss (on a local emulator):
This will automatically do the following:
- Download the blessed android AVDs from taskcluster
- Start the emulator (using your ~/.mozbuild/android-sdk-linux emulator binaries)
- Install the debug APK (from gfx/wr/wrench/target/android-artifacts/debug/apk/wrench.apk)
- Install the debug APK (from gfx/wr/wrench/target/debug/apk/wrench.apk)
- Copy the reftests to the sdcard
- Write an args file to the sdcard
- Run wrench
@ -80,7 +81,7 @@ Running reftests like a boss (on a local emulator):
If you want to use a release APK (runs much faster), build it as per the "Release mode"
instructions above and set the WRENCH_APK env var to point to the APK:
to point to it:
export WRENCH_APK=gfx/wr/target/android-artifacts/release/apk/wrench.apk
export WRENCH_APK=gfx/wr/target/release/apk/wrench.apk
./mach python testing/mozharness/scripts/android_wrench.py --config testing/mozharness/configs/android/wrench.py
Running reftests like a boss (on a local device):

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use glutin::{self, ContextBuilder, ContextCurrentState, CreationError};
use winit::{EventsLoop, Window, WindowBuilder};
use winit::{event_loop::EventLoop, window::Window, window::WindowBuilder};
#[cfg(not(windows))]
pub enum Context {}
@ -16,7 +16,7 @@ impl Context {
pub fn with_window<T: ContextCurrentState>(
_: WindowBuilder,
_: ContextBuilder<'_, T>,
_: &EventsLoop,
_: &EventLoop<()>,
) -> Result<(Window, Self), CreationError> {
Err(CreationError::PlatformSpecific(
"ANGLE rendering is only supported on Windows".into(),
@ -27,16 +27,16 @@ impl Context {
pub fn with_window<T: ContextCurrentState>(
window_builder: WindowBuilder,
context_builder: ContextBuilder<'_, T>,
events_loop: &EventsLoop,
events_loop: &EventLoop<()>,
) -> Result<(Window, Self), CreationError> {
use winit::os::windows::WindowExt;
use winit::platform::windows::WindowExtWindows;
// FIXME: &context_builder.pf_reqs https://github.com/tomaka/glutin/pull/1002
let pf_reqs = &glutin::PixelFormatRequirements::default();
let gl_attr = &context_builder.gl_attr.map_sharing(|_| unimplemented!());
let window = window_builder.build(events_loop)?;
Self::new(pf_reqs, gl_attr)
.and_then(|p| p.finish(window.get_hwnd() as _))
.and_then(|p| p.finish(window.hwnd() as _))
.map(|context| (window, context))
}

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

@ -30,10 +30,8 @@ use gleam::gl;
#[cfg(feature = "software")]
use gleam::gl::Gl;
use crate::perf::PerfHarness;
use crate::png::save_flipped;
use crate::rawtest::RawtestHarness;
use crate::reftest::{ReftestHarness, ReftestOptions};
use std::fs;
#[cfg(feature = "headless")]
use std::ffi::CString;
#[cfg(feature = "headless")]
@ -51,7 +49,8 @@ use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
use winit::dpi::{LogicalPosition, LogicalSize};
use winit::VirtualKeyCode;
use winit::event::VirtualKeyCode;
use winit::platform::run_return::EventLoopExtRunReturn;
use crate::wrench::{CapturedSequence, Wrench, WrenchThing};
use crate::yaml_frame_reader::YamlFrameReader;
@ -138,7 +137,7 @@ mod swgl {
pub enum WindowWrapper {
WindowedContext(glutin::WindowedContext<glutin::PossiblyCurrent>, Rc<dyn gl::Gl>, Option<swgl::Context>),
Angle(winit::Window, angle::Context, Rc<dyn gl::Gl>, Option<swgl::Context>),
Angle(winit::window::Window, angle::Context, Rc<dyn gl::Gl>, Option<swgl::Context>),
Headless(HeadlessContext, Rc<dyn gl::Gl>, Option<swgl::Context>),
}
@ -184,11 +183,8 @@ impl WindowWrapper {
}
fn get_inner_size(&self) -> DeviceIntSize {
fn inner_size(window: &winit::Window) -> DeviceIntSize {
let size = window
.get_inner_size()
.unwrap()
.to_physical(window.get_hidpi_factor());
fn inner_size(window: &winit::window::Window) -> DeviceIntSize {
let size = window.inner_size();
DeviceIntSize::new(size.width as i32, size.height as i32)
}
match *self {
@ -203,9 +199,9 @@ impl WindowWrapper {
fn hidpi_factor(&self) -> f32 {
match *self {
WindowWrapper::WindowedContext(ref windowed_context, ..) => {
windowed_context.window().get_hidpi_factor() as f32
windowed_context.window().scale_factor() as f32
}
WindowWrapper::Angle(ref window, ..) => window.get_hidpi_factor() as f32,
WindowWrapper::Angle(ref window, ..) => window.scale_factor() as f32,
WindowWrapper::Headless(..) => 1.0,
}
}
@ -317,7 +313,7 @@ fn make_software_context() -> swgl::Context {
fn make_window(
size: DeviceIntSize,
vsync: bool,
events_loop: &Option<winit::EventsLoop>,
events_loop: &Option<winit::event_loop::EventLoop<()>>,
angle: bool,
gl_request: glutin::GlRequest,
software: bool,
@ -331,11 +327,12 @@ fn make_window(
let wrapper = if let Some(events_loop) = events_loop {
let context_builder = glutin::ContextBuilder::new()
.with_gl(gl_request)
.with_vsync(vsync);
let window_builder = winit::WindowBuilder::new()
// Glutin can fail to create a context on Android if vsync is not set
.with_vsync(vsync || cfg!(target_os = "android"));
let window_builder = winit::window::WindowBuilder::new()
.with_title("WRench")
.with_multitouch()
.with_dimensions(LogicalSize::new(size.width as f64, size.height as f64));
.with_inner_size(LogicalSize::new(size.width as f64, size.height as f64));
if angle {
angle::Context::with_window(
@ -492,11 +489,18 @@ fn reftest<'a>(
rx: Receiver<NotifierEvent>
) -> usize {
let dim = window.get_inner_size();
let base_manifest = if cfg!(target_os = "android") {
Path::new("/sdcard/wrench/reftests/reftest.list")
} else {
Path::new("reftests/reftest.list")
#[cfg(target_os = "android")]
let base_manifest = {
let mut list_path = PathBuf::new();
list_path.push(ndk_glue::native_activity().external_data_path().to_str().unwrap());
list_path.push("wrench");
list_path.push("reftests");
list_path.push("reftest.list");
list_path
};
#[cfg(not(target_os = "android"))]
let base_manifest = Path::new("reftests/reftest.list").to_owned();
let specific_reftest = subargs.value_of("REFTEST").map(Path::new);
let mut reftest_options = ReftestOptions::default();
if let Some(allow_max_diff) = subargs.value_of("fuzz_tolerance") {
@ -504,12 +508,13 @@ fn reftest<'a>(
reftest_options.allow_num_differences = dim.width as usize * dim.height as usize;
}
let num_failures = ReftestHarness::new(&mut wrench, window, &rx)
.run(base_manifest, specific_reftest, &reftest_options);
.run(&base_manifest, specific_reftest, &reftest_options);
wrench.shut_down(rx);
num_failures
}
fn main() {
#[cfg_attr(target_os = "android", ndk_glue::main)]
pub fn main() {
#[cfg(feature = "env_logger")]
env_logger::init();
@ -528,16 +533,22 @@ fn main() {
let clap = clap::App::from_yaml(args_yaml)
.setting(clap::AppSettings::ArgRequiredElseHelp);
// On android devices, attempt to read command line arguments
// from a text file located at /sdcard/wrench/args.
let args = if cfg!(target_os = "android") {
// On android devices, attempt to read command line arguments from a text
// file located at <external_data_dir>/wrench/args.
#[cfg(target_os = "android")]
let args = {
// get full backtraces by default because it's hard to request
// externally on android
std::env::set_var("RUST_BACKTRACE", "full");
let mut args = vec!["wrench".to_string()];
if let Ok(wrench_args) = fs::read_to_string("/sdcard/wrench/args") {
let mut args_path = PathBuf::new();
args_path.push(ndk_glue::native_activity().external_data_path().to_str().unwrap());
args_path.push("wrench");
args_path.push("args");
if let Ok(wrench_args) = std::fs::read_to_string(&args_path) {
for line in wrench_args.lines() {
if let Some(envvar) = line.strip_prefix("env: ") {
if let Some((lhs, rhs)) = envvar.split_once('=') {
@ -555,10 +566,11 @@ fn main() {
}
clap.get_matches_from(&args)
} else {
clap.get_matches()
};
#[cfg(not(target_os = "android"))]
let args = clap.get_matches();
// handle some global arguments
let res_path = args.value_of("shaders").map(PathBuf::from);
let size = args.value_of("size")
@ -602,7 +614,7 @@ fn main() {
let mut events_loop = if args.is_present("headless") {
None
} else {
Some(winit::EventsLoop::new())
Some(winit::event_loop::EventLoop::new())
};
let gl_request = match args.value_of("renderer") {
@ -625,6 +637,21 @@ fn main() {
let software = args.is_present("software");
// On Android we can only create an OpenGL context when we have a
// native_window handle, so wait here until we are resumed and have a
// handle. If the app gets minimized this will no longer be valid, but
// that's okay for wrench's usage.
#[cfg(target_os = "android")]
{
events_loop.as_mut().unwrap().run_return(|event, _elwt, control_flow| {
if let winit::event::Event::Resumed = event {
if ndk_glue::native_window().is_some() {
*control_flow = winit::event_loop::ControlFlow::Exit;
}
}
});
}
let mut window = make_window(
size,
args.is_present("vsync"),
@ -681,8 +708,7 @@ fn main() {
render(
&mut wrench,
&mut window,
size,
&mut events_loop,
events_loop.as_mut().expect("`wrench show` is not supported in headless mode"),
subargs,
no_block,
no_batch,
@ -766,8 +792,7 @@ fn main() {
fn render<'a>(
wrench: &mut Wrench,
window: &mut WindowWrapper,
size: DeviceIntSize,
events_loop: &mut Option<winit::EventsLoop>,
events_loop: &mut winit::event_loop::EventLoop<()>,
subargs: &clap::ArgMatches<'a>,
no_block: bool,
no_batch: bool,
@ -798,10 +823,6 @@ fn render<'a>(
}
};
let mut show_help = false;
let mut do_loop = false;
let mut cursor_position = WorldPoint::zero();
window.update(wrench);
thing.do_frame(wrench);
@ -818,197 +839,178 @@ fn render<'a>(
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
let mut body = |wrench: &mut Wrench, events: Vec<winit::Event>| {
let mut do_frame = false;
let mut do_render = !events.is_empty();
let mut show_help = false;
let mut do_loop = false;
let mut cursor_position = WorldPoint::zero();
let mut do_render = false;
let mut do_frame = false;
for event in events {
match event {
winit::Event::Awakened => {}
winit::Event::WindowEvent { event, .. } => match event {
winit::WindowEvent::CloseRequested => {
return winit::ControlFlow::Break;
}
winit::WindowEvent::Refresh |
winit::WindowEvent::Focused(..) => {}
winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
cursor_position = WorldPoint::new(x as f32, y as f32);
wrench.renderer.set_cursor_position(
DeviceIntPoint::new(
cursor_position.x.round() as i32,
cursor_position.y.round() as i32,
),
);
}
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Pressed,
virtual_keycode: Some(vk),
..
},
events_loop.run_return(|event, _elwt, control_flow| {
// By default after each iteration of the event loop we block the thread until the next
// events arrive. --no-block can be used to run the event loop as quickly as possible.
// On Android, we are generally profiling when running wrench, and don't want to block
// on UI events.
if !no_block && cfg!(not(target_os = "android")) {
*control_flow = winit::event_loop::ControlFlow::Wait;
} else {
*control_flow = winit::event_loop::ControlFlow::Poll;
}
match event {
winit::event::Event::UserEvent(_) => {
do_render = true;
}
winit::event::Event::WindowEvent { event, .. } => match event {
winit::event::WindowEvent::CloseRequested => {
*control_flow = winit::event_loop::ControlFlow::Exit;
}
winit::event::WindowEvent::Focused(..) => do_render = true,
winit::event::WindowEvent::CursorMoved { position, .. } => {
let pos: LogicalPosition<f32> = position.to_logical(window.hidpi_factor() as f64);
cursor_position = WorldPoint::new(pos.x, pos.y);
wrench.renderer.set_cursor_position(
DeviceIntPoint::new(
cursor_position.x.round() as i32,
cursor_position.y.round() as i32,
),
);
do_render = true;
}
winit::event::WindowEvent::KeyboardInput {
input: winit::event::KeyboardInput {
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(vk),
..
} => match vk {
VirtualKeyCode::Escape => {
return winit::ControlFlow::Break;
}
VirtualKeyCode::B => {
debug_flags.toggle(DebugFlags::INVALIDATION_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::P => {
debug_flags.toggle(DebugFlags::PROFILER_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::O => {
debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::I => {
debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::D => {
debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::Q => {
debug_flags.toggle(DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::V => {
debug_flags.toggle(DebugFlags::SHOW_OVERDRAW);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::G => {
debug_flags.toggle(DebugFlags::GPU_CACHE_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
// force scene rebuild to see the full set of used GPU cache entries
let mut txn = Transaction::new();
txn.set_root_pipeline(wrench.root_pipeline_id);
wrench.api.send_transaction(wrench.document_id, txn);
do_render = false;
do_frame = true;
}
VirtualKeyCode::M => {
wrench.api.notify_memory_pressure();
}
VirtualKeyCode::L => {
do_loop = !do_loop;
}
VirtualKeyCode::Left => {
thing.prev_frame();
do_render = false;
do_frame = true;
}
VirtualKeyCode::Right => {
thing.next_frame();
do_render = false;
do_frame = true;
}
VirtualKeyCode::H => {
show_help = !show_help;
}
VirtualKeyCode::C => {
let path = PathBuf::from("../captures/wrench");
wrench.api.save_capture(path, CaptureBits::all());
do_render = false;
}
VirtualKeyCode::X => {
let results = wrench.api.hit_test(
wrench.document_id,
cursor_position,
);
println!("Hit test results:");
for item in &results.items {
println!("{:?}", item);
}
println!();
do_render = false;
}
VirtualKeyCode::Z => {
debug_flags.toggle(DebugFlags::ZOOM_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
VirtualKeyCode::Y => {
println!("Clearing all caches...");
wrench.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
do_frame = true;
}
_other_virtual_keycode => { do_render = false; }
},
..
} => match vk {
VirtualKeyCode::Escape => {
*control_flow = winit::event_loop::ControlFlow::Exit;
}
_other_window_event => { do_render = false; }
},
_other_event => { do_render = false; }
VirtualKeyCode::B => {
debug_flags.toggle(DebugFlags::INVALIDATION_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::P => {
debug_flags.toggle(DebugFlags::PROFILER_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::O => {
debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::I => {
debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::D => {
debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::Q => {
debug_flags.toggle(DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::V => {
debug_flags.toggle(DebugFlags::SHOW_OVERDRAW);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::G => {
debug_flags.toggle(DebugFlags::GPU_CACHE_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
// force scene rebuild to see the full set of used GPU cache entries
let mut txn = Transaction::new();
txn.set_root_pipeline(wrench.root_pipeline_id);
wrench.api.send_transaction(wrench.document_id, txn);
do_frame = true;
}
VirtualKeyCode::M => {
wrench.api.notify_memory_pressure();
do_render = true;
}
VirtualKeyCode::L => {
do_loop = !do_loop;
do_render = true;
}
VirtualKeyCode::Left => {
thing.prev_frame();
do_frame = true;
}
VirtualKeyCode::Right => {
thing.next_frame();
do_frame = true;
}
VirtualKeyCode::H => {
show_help = !show_help;
do_render = true;
}
VirtualKeyCode::C => {
let path = PathBuf::from("../captures/wrench");
wrench.api.save_capture(path, CaptureBits::all());
}
VirtualKeyCode::X => {
let results = wrench.api.hit_test(
wrench.document_id,
cursor_position,
);
println!("Hit test results:");
for item in &results.items {
println!("{:?}", item);
}
println!();
}
VirtualKeyCode::Z => {
debug_flags.toggle(DebugFlags::ZOOM_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::Y => {
println!("Clearing all caches...");
wrench.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
do_frame = true;
}
_ => {}
}
_ => {}
},
winit::event::Event::MainEventsCleared => {
window.update(wrench);
if do_frame {
do_frame = false;
let frame_num = thing.do_frame(wrench);
unsafe {
CURRENT_FRAME_NUMBER = frame_num;
}
}
if do_render {
do_render = false;
if show_help {
wrench.show_onscreen_help();
}
wrench.render();
window.upload_software_to_native();
window.swap_buffers();
if do_loop {
thing.next_frame();
}
}
}
_ => {}
}
window.update(wrench);
if do_frame {
let frame_num = thing.do_frame(wrench);
unsafe {
CURRENT_FRAME_NUMBER = frame_num;
}
}
if do_render {
if show_help {
wrench.show_onscreen_help();
}
wrench.render();
window.upload_software_to_native();
window.swap_buffers();
if do_loop {
thing.next_frame();
}
}
winit::ControlFlow::Continue
};
if let Some(events_loop) = events_loop.as_mut() {
// We want to ensure that we:
//
// (a) Block the thread when no events are present (for CPU/battery purposes)
// (b) Don't lag the input events by having the event queue back up.
loop {
let mut pending_events = Vec::new();
// Block the thread until at least one event arrives
// On Android, we are generally profiling when running
// wrench, and don't want to block on UI events.
if !no_block && cfg!(not(target_os = "android")) {
events_loop.run_forever(|event| {
pending_events.push(event);
winit::ControlFlow::Break
});
}
// Collect any other pending events that are also available
events_loop.poll_events(|event| {
pending_events.push(event);
});
// Ensure there is at least one event present so that the
// frame gets rendered.
if pending_events.is_empty() {
pending_events.push(winit::Event::Awakened);
}
// Process all of those pending events in the next vsync period
if body(wrench, pending_events) == winit::ControlFlow::Break {
break;
}
}
} else {
while body(wrench, vec![winit::Event::Awakened]) == winit::ControlFlow::Continue {}
let fb_rect = FramebufferIntSize::new(size.width, size.height).into();
let pixels = wrench.renderer.read_pixels_rgba8(fb_rect);
save_flipped("screenshot.png", pixels, size);
}
});
}

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

@ -9,7 +9,7 @@ use crossbeam::sync::chase_lev;
use dwrote;
#[cfg(all(unix, not(target_os = "android")))]
use font_loader::system_fonts;
use winit::EventsLoopProxy;
use winit::event_loop::EventLoopProxy;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
@ -36,7 +36,7 @@ pub enum FontDescriptor {
}
struct NotifierData {
events_loop_proxy: Option<EventsLoopProxy>,
events_loop_proxy: Option<EventLoopProxy<()>>,
frames_notified: u32,
timing_receiver: chase_lev::Stealer<time::SteadyTime>,
verbose: bool,
@ -44,7 +44,7 @@ struct NotifierData {
impl NotifierData {
fn new(
events_loop_proxy: Option<EventsLoopProxy>,
events_loop_proxy: Option<EventLoopProxy<()>>,
timing_receiver: chase_lev::Stealer<time::SteadyTime>,
verbose: bool,
) -> Self {
@ -84,7 +84,7 @@ impl Notifier {
if let Some(ref _elp) = data.events_loop_proxy {
#[cfg(not(target_os = "android"))]
let _ = _elp.wakeup();
let _ = _elp.send_event(());
}
}
}
@ -217,7 +217,7 @@ impl Wrench {
#[allow(clippy::too_many_arguments)]
pub fn new(
window: &mut WindowWrapper,
proxy: Option<EventsLoopProxy>,
proxy: Option<EventLoopProxy<()>>,
shader_override_path: Option<PathBuf>,
use_optimized_shaders: bool,
size: DeviceIntSize,
@ -268,7 +268,7 @@ impl Wrench {
// put an Awakened event into the queue to kick off the first frame
if let Some(ref _elp) = proxy {
#[cfg(not(target_os = "android"))]
let _ = _elp.wakeup();
let _ = _elp.send_event(());
}
let (timing_sender, timing_receiver) = chase_lev::deque();

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

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<canvas id="crashtest" width="50000" height="50000" />
<script>
document.getElementById("crashtest").mozGetAsFile("foo.png", "image/png");
document.getElementById("crashtest").mozGetAsFile("foo.jpeg", "image/jpeg");
</script>
</body>
</html>

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

@ -9,7 +9,6 @@ load 570451.png
# Bug 1390704 - Skip on debug because it triggers a quadratic behavior that makes it take
# so much time that it can trip on the reftest timeout of 5 minutes.
skip-if(Android||isDebugBuild||ThreadSanitizer) load 694165-1.xhtml
pref(canvas.mozgetasfile.enabled,true) load 681190.html
load 732319-1.html
load 844403-1.html
load 856616.gif

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

@ -13,6 +13,8 @@
#include "mozilla/ipc/FileDescriptor.h"
#include "base/shared_memory.h"
#include "mozilla/Maybe.h"
#include "mozilla/Preferences.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace ipc {
@ -25,12 +27,12 @@ void SetThisProcessName(const char* aName);
class SharedPreferenceSerializer final {
public:
explicit SharedPreferenceSerializer(
std::function<bool(const char*)>&& aShouldSerializeFn);
explicit SharedPreferenceSerializer();
SharedPreferenceSerializer(SharedPreferenceSerializer&& aOther);
~SharedPreferenceSerializer();
bool SerializeToSharedMemory();
bool SerializeToSharedMemory(const GeckoProcessType aDestinationProcessType,
const nsACString& aDestinationRemoteType);
size_t GetPrefMapSize() const { return mPrefMapSize; }
size_t GetPrefsLength() const { return mPrefsLength; }
@ -48,7 +50,6 @@ class SharedPreferenceSerializer final {
size_t mPrefsLength;
UniqueFileHandle mPrefMapHandle;
UniqueFileHandle mPrefsHandle;
std::function<bool(const char*)> mShouldSerializeFn;
};
class SharedPreferenceDeserializer final {

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

@ -8,6 +8,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/GeckoArgs.h"
#include "mozilla/dom/RemoteType.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsPrintfCString.h"
@ -17,9 +18,8 @@
namespace mozilla {
namespace ipc {
SharedPreferenceSerializer::SharedPreferenceSerializer(
std::function<bool(const char*)>&& aShouldSerializeFn)
: mPrefMapSize(0), mPrefsLength(0), mShouldSerializeFn(aShouldSerializeFn) {
SharedPreferenceSerializer::SharedPreferenceSerializer()
: mPrefMapSize(0), mPrefsLength(0) {
MOZ_COUNT_CTOR(SharedPreferenceSerializer);
}
@ -36,13 +36,20 @@ SharedPreferenceSerializer::SharedPreferenceSerializer(
MOZ_COUNT_CTOR(SharedPreferenceSerializer);
}
bool SharedPreferenceSerializer::SerializeToSharedMemory() {
bool SharedPreferenceSerializer::SerializeToSharedMemory(
const GeckoProcessType aDestinationProcessType,
const nsACString& aDestinationRemoteType) {
mPrefMapHandle =
Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
bool destIsWebContent =
aDestinationProcessType == GeckoProcessType_Content &&
(StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE) ||
StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE));
// Serialize the early prefs.
nsAutoCStringN<1024> prefs;
Preferences::SerializePreferences(prefs, mShouldSerializeFn);
Preferences::SerializePreferences(prefs, destIsWebContent);
mPrefsLength = prefs.Length();
base::SharedMemory shm;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше