Update On Fri Apr 22 20:36:49 CEST 2022

This commit is contained in:
github-action[bot] 2022-04-22 20:36:50 +02:00
parent c26e94f90b
commit d993c2304a
568 changed files with 7519 additions and 2953 deletions

2
Cargo.lock generated
View file

@ -5793,9 +5793,11 @@ dependencies = [
"dwrote",
"etagere",
"euclid",
"fog",
"freetype",
"fxhash",
"gleam",
"glean",
"glslopt",
"lazy_static",
"libc",

View file

@ -108,6 +108,7 @@ async-task = { git = "https://github.com/smol-rs/async-task", rev="f6488e35beccb
chardetng = { git = "https://github.com/hsivonen/chardetng", rev="3484d3e3ebdc8931493aa5df4d7ee9360a90e76b" }
chardetng_c = { git = "https://github.com/hsivonen/chardetng_c", rev="ed8a4c6f900a90d4dbc1d64b856e61490a1c3570" }
coremidi = { git = "https://github.com/chris-zen/coremidi.git", rev="fc68464b5445caf111e41f643a2e69ccce0b4f83" }
fog = { path = "toolkit/components/glean/api" }
libudev-sys = { path = "dom/webauthn/libudev-sys" }
packed_simd = { package = "packed_simd_2", git = "https://github.com/hsivonen/packed_simd", rev="c149d0a519bf878567c7630096737669ec2ff15f" }
midir = { git = "https://github.com/mozilla/midir.git", rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f" }

View file

@ -159,7 +159,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DocAccessible)
NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
NS_INTERFACE_MAP_END_INHERITING(HyperTextAccessible)
@ -551,17 +550,6 @@ nsRect DocAccessible::RelativeBounds(nsIFrame** aRelativeFrame) const {
// DocAccessible protected member
nsresult DocAccessible::AddEventListeners() {
nsCOMPtr<nsIDocShell> docShell(mDocumentNode->GetDocShell());
// We want to add a command observer only if the document is content and has
// an editor.
if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
if (commandManager) {
commandManager->AddCommandObserver(this, "obs_documentCreated");
}
}
SelectionMgr()->AddDocSelectionListener(mPresShell);
// Add document observer.
@ -576,18 +564,6 @@ nsresult DocAccessible::RemoveEventListeners() {
if (mDocumentNode) {
mDocumentNode->RemoveObserver(this);
nsCOMPtr<nsIDocShell> docShell(mDocumentNode->GetDocShell());
NS_ASSERTION(docShell, "doc should support nsIDocShellTreeItem.");
if (docShell) {
if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
if (commandManager) {
commandManager->RemoveCommandObserver(this, "obs_documentCreated");
}
}
}
}
if (mScrollWatchTimer) {
@ -684,25 +660,6 @@ std::pair<nsPoint, nsRect> DocAccessible::ComputeScrollData(
return {scrollPoint, scrollRange};
}
////////////////////////////////////////////////////////////////////////////////
// nsIObserver
NS_IMETHODIMP
DocAccessible::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (!nsCRT::strcmp(aTopic, "obs_documentCreated")) {
// State editable will now be set, readonly is now clear
// Normally we only fire delayed events created from the node, not an
// accessible object. See the AccStateChangeEvent constructor for details
// about this exceptional case.
RefPtr<AccEvent> event =
new AccStateChangeEvent(this, states::EDITABLE, true);
FireDelayedEvent(event);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessiblePivotObserver
@ -904,6 +861,20 @@ void DocAccessible::ContentAppended(nsIContent* aFirstNewContent) {}
void DocAccessible::ContentStateChanged(dom::Document* aDocument,
nsIContent* aContent,
EventStates aStateMask) {
if (aStateMask.HasState(NS_EVENT_STATE_READWRITE) &&
aContent == mDocumentNode->GetRootElement()) {
// This handles changes to designMode. contentEditable is handled by
// LocalAccessible::AttributeChangesState and
// LocalAccessible::DOMAttributeChanged.
const bool isEditable =
aContent->AsElement()->State().HasState(NS_EVENT_STATE_READWRITE);
RefPtr<AccEvent> event =
new AccStateChangeEvent(this, states::EDITABLE, isEditable);
FireDelayedEvent(event);
event = new AccStateChangeEvent(this, states::READONLY, !isEditable);
FireDelayedEvent(event);
}
LocalAccessible* accessible = GetAccessible(aContent);
if (!accessible) return;

View file

@ -15,7 +15,6 @@
#include "nsTHashMap.h"
#include "mozilla/UniquePtr.h"
#include "nsIDocumentObserver.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsTHashSet.h"
#include "nsWeakReference.h"
@ -44,13 +43,11 @@ class TNotification;
class DocAccessible : public HyperTextAccessibleWrap,
public nsIDocumentObserver,
public nsIObserver,
public nsSupportsWeakReference,
public nsIAccessiblePivotObserver {
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, LocalAccessible)
NS_DECL_NSIOBSERVER
NS_DECL_NSIACCESSIBLEPIVOTOBSERVER
protected:

View file

@ -249,3 +249,78 @@ addAccessibleTask(
},
{ iframe: true, remoteIframe: true, chrome: true }
);
/**
* Test caching of the editable state.
*/
addAccessibleTask(
`<div id="div" contenteditable></div>`,
async function(browser, docAcc) {
const div = findAccessibleChildByID(docAcc, "div");
testStates(div, 0, EXT_STATE_EDITABLE, 0, 0);
// Ensure that a contentEditable descendant doesn't cause editable to be
// exposed on the document.
testStates(docAcc, STATE_READONLY, 0, 0, EXT_STATE_EDITABLE);
info("Setting contentEditable on the body");
let stateChanged = Promise.all([
waitForStateChange(docAcc, EXT_STATE_EDITABLE, true, true),
waitForStateChange(docAcc, STATE_READONLY, false, false),
]);
await invokeContentTask(browser, [], () => {
content.document.body.contentEditable = true;
});
await stateChanged;
testStates(docAcc, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0);
info("Clearing contentEditable on the body");
stateChanged = Promise.all([
waitForStateChange(docAcc, EXT_STATE_EDITABLE, false, true),
waitForStateChange(docAcc, STATE_READONLY, true, false),
]);
await invokeContentTask(browser, [], () => {
content.document.body.contentEditable = false;
});
await stateChanged;
testStates(docAcc, STATE_READONLY, 0, 0, EXT_STATE_EDITABLE);
info("Clearing contentEditable on div");
stateChanged = waitForStateChange(div, EXT_STATE_EDITABLE, false, true);
await invokeContentTask(browser, [], () => {
content.document.getElementById("div").contentEditable = false;
});
await stateChanged;
testStates(div, 0, 0, 0, EXT_STATE_EDITABLE);
info("Setting contentEditable on div");
stateChanged = waitForStateChange(div, EXT_STATE_EDITABLE, true, true);
await invokeContentTask(browser, [], () => {
content.document.getElementById("div").contentEditable = true;
});
await stateChanged;
testStates(div, 0, EXT_STATE_EDITABLE, 0, 0);
info("Setting designMode on document");
stateChanged = Promise.all([
waitForStateChange(docAcc, EXT_STATE_EDITABLE, true, true),
waitForStateChange(docAcc, STATE_READONLY, false, false),
]);
await invokeContentTask(browser, [], () => {
content.document.designMode = "on";
});
await stateChanged;
testStates(docAcc, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0);
info("Clearing designMode on document");
stateChanged = Promise.all([
waitForStateChange(docAcc, EXT_STATE_EDITABLE, false, true),
waitForStateChange(docAcc, STATE_READONLY, true, false),
]);
await invokeContentTask(browser, [], () => {
content.document.designMode = "off";
});
await stateChanged;
testStates(docAcc, STATE_READONLY, 0, 0, EXT_STATE_EDITABLE);
},
{ topLevel: true, iframe: true, remoteIframe: true, chrome: true }
);

View file

@ -92,7 +92,7 @@ const PluginManager = {
}
let { pluginDumpID } = report;
CrashSubmit.submit(pluginDumpID, {
CrashSubmit.submit(pluginDumpID, CrashSubmit.SUBMITTED_FROM_CRASH_TAB, {
recordSubmission: true,
extraExtraKeyVals: keyVals,
});

View file

@ -89,6 +89,7 @@ add_task(async function test_default() {
await crashTabTestHelper(
{},
{
SubmittedFrom: "CrashedTab",
Comments: null,
URL: "",
}
@ -101,6 +102,7 @@ add_task(async function test_default() {
add_task(async function test_just_a_comment() {
await crashTabTestHelper(
{
SubmittedFrom: "CrashedTab",
comments: COMMENTS,
},
{
@ -116,6 +118,7 @@ add_task(async function test_just_a_comment() {
add_task(async function test_send_URL() {
await crashTabTestHelper(
{
SubmittedFrom: "CrashedTab",
includeURL: true,
},
{
@ -131,6 +134,7 @@ add_task(async function test_send_URL() {
add_task(async function test_send_all() {
await crashTabTestHelper(
{
SubmittedFrom: "CrashedTab",
includeURL: true,
comments: COMMENTS,
},

View file

@ -385,6 +385,19 @@ nsBrowserContentHandler.prototype = {
if (cmdLine.handleFlag("kiosk", false)) {
gKiosk = true;
}
if (cmdLine.handleFlag("disable-pinch", false)) {
let defaults = Services.prefs.getDefaultBranch(null);
defaults.setBoolPref("apz.allow_zooming", false);
Services.prefs.lockPref("apz.allow_zooming");
defaults.setCharPref("browser.gesture.pinch.in", "");
Services.prefs.lockPref("browser.gesture.pinch.in");
defaults.setCharPref("browser.gesture.pinch.in.shift", "");
Services.prefs.lockPref("browser.gesture.pinch.in.shift");
defaults.setCharPref("browser.gesture.pinch.out", "");
Services.prefs.lockPref("browser.gesture.pinch.out");
defaults.setCharPref("browser.gesture.pinch.out.shift", "");
Services.prefs.lockPref("browser.gesture.pinch.out.shift");
}
if (cmdLine.handleFlag("browser", false)) {
openBrowserWindow(cmdLine, gSystemPrincipal);
cmdLine.preventDefault = true;
@ -598,7 +611,9 @@ nsBrowserContentHandler.prototype = {
info += " --setDefaultBrowser Set this app as the default browser.\n";
info +=
" --first-startup Run post-install actions before opening a new window.\n";
info += " --kiosk Start the browser in kiosk mode.\n";
info += " --kiosk Start the browser in kiosk mode.\n";
info +=
" --disable-pinch Disable touch-screen and touch-pad pinch gestures.\n";
return info;
},

View file

@ -280,6 +280,7 @@ var DownloadsPanel = {
case "mousemove":
if (
!DownloadsView.contextMenuOpen &&
!DownloadsView.subViewOpen &&
this.panel.contains(document.activeElement)
) {
// Let mouse movement remove focus rings and reset focus in the panel.

View file

@ -34,7 +34,6 @@ support-files = test_spammy_page.html
[browser_download_is_clickable.js]
[browser_downloads_keynav.js]
[browser_downloads_panel_block.js]
skip-if = true # Bug 1352792
[browser_downloads_panel_context_menu.js]
skip-if =
os == "win" && os_version == "10.0" && bits == 64 && !debug # Bug 1719949

View file

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable mozilla/no-arbitrary-setTimeout */
"use strict";
@ -16,13 +19,13 @@ add_task(async function mainTest() {
for (let i = 0; i < verdicts.length; i++) {
await openPanel();
// The current item is always the first one in the listbox since each
// iteration of this loop removes the item at the end.
let item = DownloadsView.richListBox.firstElementChild;
// Handle items backwards, using lastElementChild, to ensure there's no
// code wrongly resetting the selection to the first item during the process.
let item = DownloadsView.richListBox.lastElementChild;
// Open the panel and click the item to show the subview.
info("Open the panel and click the item to show the subview.");
let viewPromise = promiseViewShown(DownloadsBlockedSubview.subview);
EventUtils.sendMouseEvent({ type: "click" }, item);
EventUtils.synthesizeMouseAtCenter(item, {});
await viewPromise;
// Items are listed in newest-to-oldest order, so e.g. the first item's
@ -32,53 +35,57 @@ add_task(async function mainTest() {
verdicts[verdicts.count - i - 1]
);
// Go back to the main view.
info("Go back to the main view.");
viewPromise = promiseViewShown(DownloadsBlockedSubview.mainView);
DownloadsBlockedSubview.panelMultiView.goBack();
await viewPromise;
// Show the subview again.
info("Show the subview again.");
viewPromise = promiseViewShown(DownloadsBlockedSubview.subview);
EventUtils.sendMouseEvent({ type: "click" }, item);
EventUtils.synthesizeMouseAtCenter(item, {});
await viewPromise;
// Click the Open button. The download should be unblocked and then opened,
info("Click the Open button.");
// The download should be unblocked and then opened,
// i.e., unblockAndOpenDownload() should be called on the item. The panel
// should also be closed as a result, so wait for that too.
let unblockOpenPromise = promiseUnblockAndOpenDownloadCalled(item);
let unblockPromise = promiseUnblockAndSaveCalled(item);
let hidePromise = promisePanelHidden();
EventUtils.synthesizeMouse(
// Simulate a mousemove to ensure it's not wrongly being handled by the
// panel as the user changing download selection.
EventUtils.synthesizeMouseAtCenter(
DownloadsBlockedSubview.elements.unblockButton,
10,
10,
{},
window
{ type: "mousemove" }
);
await unblockOpenPromise;
EventUtils.synthesizeMouseAtCenter(
DownloadsBlockedSubview.elements.unblockButton,
{}
);
info("waiting for unblockOpen");
await unblockPromise;
info("waiting for hide panel");
await hidePromise;
window.focus();
await SimpleTest.promiseFocus(window);
// Reopen the panel and show the subview again.
info("Reopen the panel and show the subview again.");
await openPanel();
viewPromise = promiseViewShown(DownloadsBlockedSubview.subview);
EventUtils.sendMouseEvent({ type: "click" }, item);
EventUtils.synthesizeMouseAtCenter(item, {});
await viewPromise;
// Click the Remove button. The panel should close and the item should be
// removed from it.
info("Click the Remove button.");
// The panel should close and the item should be removed from it.
hidePromise = promisePanelHidden();
EventUtils.synthesizeMouse(
EventUtils.synthesizeMouseAtCenter(
DownloadsBlockedSubview.elements.deleteButton,
10,
10,
{},
window
{}
);
info("Waiting for hide panel");
await hidePromise;
info("Open the panel again and check the item is gone.");
await openPanel();
Assert.ok(!item.parentNode);
@ -167,15 +174,12 @@ function promiseViewShown(view) {
return BrowserTestUtils.waitForEvent(view, "ViewShown");
}
function promiseUnblockAndOpenDownloadCalled(item) {
function promiseUnblockAndSaveCalled(item) {
return new Promise(resolve => {
let realFn = item._shell.unblockAndOpenDownload;
item._shell.unblockAndOpenDownload = () => {
item._shell.unblockAndOpenDownload = realFn;
let realFn = item._shell.unblockAndSave;
item._shell.unblockAndSave = async () => {
item._shell.unblockAndSave = realFn;
resolve();
// unblockAndOpenDownload returns a promise (that's resolved when the file
// is opened).
return Promise.resolve();
};
});
}

View file

@ -49,15 +49,10 @@ body[lwt-newtab-brighttext] {
:root[dialogroot] {
background-color: transparent;
min-width: 504px;
overflow: hidden;
}
:root[dialogroot] body {
padding: 0;
}
:root[dialogroot] .onboardingContainer {
overflow: visible;
}
:root[dialogroot] .onboardingContainer:dir(rtl) {
transform: unset;
}
@ -67,14 +62,9 @@ body[lwt-newtab-brighttext] {
:root[dialogroot] .onboardingContainer .screen:dir(rtl) {
transform: unset;
}
:root[dialogroot] .onboardingContainer .screen.with-noodles {
min-width: 610px;
min-height: 610px;
}
.onboardingContainer {
text-align: center;
overflow-x: auto;
height: 100vh;
--transition: 0.6s opacity, 0.6s scale, 0.6s rotate, 0.6s translate;
}
@ -186,6 +176,16 @@ body[lwt-newtab-brighttext] {
.onboardingContainer .screen:dir(rtl) {
transform: rotateY(180deg);
}
.onboardingContainer .screen[pos=center] {
min-width: 504px;
}
.onboardingContainer .screen[pos=center].with-noodles {
min-width: 610px;
min-height: 610px;
}
.onboardingContainer .screen[pos=center].with-noodles .section-main {
height: 504px;
}
.onboardingContainer .brand-logo {
margin-block: 60px 10px;
transition: var(--transition);
@ -1127,6 +1127,3 @@ body[lwt-newtab-brighttext] {
translate: 0 calc(2 * var(--translate));
transition-delay: 0.4s;
}
.onboardingContainer .screen.with-noodles:not(.corner) .section-main {
height: 504px;
}

View file

@ -10,6 +10,7 @@ $break-point-medium: 610px;
$break-point-large: 866px;
$logo-size: 80px;
$main-section-width: 504px;
$noodle-buffer: 106px;
html {
height: 100%;
@ -35,16 +36,12 @@ body {
:root {
&[dialogroot] {
background-color: transparent;
min-width: $main-section-width;
overflow: hidden;
body {
padding: 0;
}
.onboardingContainer {
overflow: visible;
&:dir(rtl) {
transform: unset;
}
@ -55,14 +52,6 @@ body {
&:dir(rtl) {
transform: unset;
}
&.with-noodles {
// Adjust for noodles partially extending out from the square modal
$noodle-buffer: 106px;
min-width: $main-section-width + $noodle-buffer;
min-height: $main-section-width + $noodle-buffer;
}
}
}
}
@ -70,7 +59,6 @@ body {
.onboardingContainer {
text-align: center;
overflow-x: auto;
height: 100vh;
@media (prefers-contrast: more) {
@ -197,6 +185,20 @@ body {
&:dir(rtl) {
transform: rotateY(180deg);
}
&[pos='center'] {
min-width: $main-section-width;
&.with-noodles {
// Adjust for noodles partially extending out from the square modal
min-width: $main-section-width + $noodle-buffer;
min-height: $main-section-width + $noodle-buffer;
.section-main {
height: $main-section-width;
}
}
}
}
.brand-logo {
@ -1407,8 +1409,4 @@ body {
}
}
}
.screen.with-noodles:not(.corner) .section-main {
height: $main-section-width;
}
}

View file

@ -364,6 +364,8 @@ var pktApi = (function() {
setSetting("usedTags", undefined);
setSetting("fsv1", undefined);
_clearRecentSavesCache();
}
/**
@ -766,6 +768,11 @@ var pktApi = (function() {
lastUpdated: 0,
});
}
// Clears the cache, for when a new user logs in.
async function _clearRecentSavesCache() {
const db = await getDatabase();
db.objectStore(STORE_NAME, "readwrite").delete("recentSaves");
}
async function getRecentSavesCache() {
// Get cache

View file

@ -375,7 +375,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "d5546b9cd13f90687b618a7ff10b1569f537a931"
"revision": "a5acb80029e8755e444932beecee0a1093f2906e"
},
"dsb": {
"pin": false,
@ -411,7 +411,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "061a0dd45efc83c59949ab3efc4d34cc80b1b8dd"
"revision": "401329141fec103af75aa0277ba860b1f48e0258"
},
"en-CA": {
"pin": false,
@ -483,7 +483,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "ace0a68a8d7c8ddb98c55069dd289f5afde726a5"
"revision": "14e4e1211725b28e1435b122ed337df8264b659e"
},
"es-CL": {
"pin": false,
@ -627,7 +627,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "667d16e9e25cb41cbefb9c3d29ee10c10a540939"
"revision": "86831f56f8a14c66b562ab118fdd911f9cf8d7a0"
},
"fr": {
"pin": false,
@ -879,7 +879,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "a816442a4351da86a943a4d474542626bde26a5a"
"revision": "6fb2b93bb8aa19d3a484d206e5cbc2daccc7506c"
},
"ia": {
"pin": false,
@ -951,7 +951,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "b563fa32bb2f27fa2585e3e50f3baba18e477028"
"revision": "9e7cc05fb0a2fb868c1995219155e4ebc4eabe79"
},
"ja": {
"pin": false,
@ -1677,7 +1677,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "87127f406c9490fd5215bc3d2c434dcf863e1da9"
"revision": "7f862588705770e79f210a97dac34832e65750f7"
},
"szl": {
"pin": false,
@ -1749,7 +1749,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "9b3244e7bb94b504f6b9449de8d262f7ada681fb"
"revision": "7d4909b99ef5abd91f247aa4ddbbd9ae2650fdba"
},
"th": {
"pin": false,
@ -1947,7 +1947,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "3b68b5389c967aca9ed2ab599620d8fccdfd1696"
"revision": "188ed36a5733b1b0f7ad9645667c23823c621930"
},
"zh-TW": {
"pin": false,

View file

@ -412,7 +412,10 @@ var TabCrashHandler = {
popup: null,
callback: async () => {
if (dumpID) {
UnsubmittedCrashHandler.submitReports([dumpID]);
UnsubmittedCrashHandler.submitReports(
[dumpID],
CrashSubmit.SUBMITTED_FROM_CRASH_TAB
);
}
closeAllNotifications();
},
@ -487,7 +490,10 @@ var TabCrashHandler = {
if (UnsubmittedCrashHandler.autoSubmit) {
let dumpID = this.childMap.get(childID);
if (dumpID) {
UnsubmittedCrashHandler.submitReports([dumpID]);
UnsubmittedCrashHandler.submitReports(
[dumpID],
CrashSubmit.SUBMITTED_FROM_AUTO
);
}
} else {
this.sendToTabCrashedPage(browser);
@ -624,7 +630,7 @@ var TabCrashHandler = {
extraExtraKeyVals.URL = "";
}
CrashSubmit.submit(dumpID, {
CrashSubmit.submit(dumpID, CrashSubmit.SUBMITTED_FROM_CRASH_TAB, {
recordSubmission: true,
extraExtraKeyVals,
}).catch(Cu.reportError);
@ -890,7 +896,7 @@ var UnsubmittedCrashHandler = {
if (reportIDs.length) {
if (this.autoSubmit) {
this.submitReports(reportIDs);
this.submitReports(reportIDs, CrashSubmit.SUBMITTED_FROM_AUTO);
} else if (this.shouldShowPendingSubmissionsNotification()) {
return this.showPendingSubmissionsNotification(reportIDs);
}
@ -1050,7 +1056,7 @@ var UnsubmittedCrashHandler = {
{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.send"),
callback: () => {
this.submitReports(reportIDs);
this.submitReports(reportIDs, CrashSubmit.SUBMITTED_FROM_INFOBAR);
if (onAction) {
onAction();
}
@ -1062,7 +1068,7 @@ var UnsubmittedCrashHandler = {
),
callback: () => {
this.autoSubmit = true;
this.submitReports(reportIDs);
this.submitReports(reportIDs, CrashSubmit.SUBMITTED_FROM_INFOBAR);
if (onAction) {
onAction();
}
@ -1120,20 +1126,17 @@ var UnsubmittedCrashHandler = {
},
/**
* Attempt to submit reports to the crash report server. Each
* report will have the "SubmittedFromInfobar" annotation set
* to "1".
* Attempt to submit reports to the crash report server.
*
* @param reportIDs (Array<string>)
* The array of reportIDs to submit.
* @param submittedFrom (string)
* One of the CrashSubmit.SUBMITTED_FROM_* constants representing
* how this crash was submitted.
*/
submitReports(reportIDs) {
submitReports(reportIDs, submittedFrom) {
for (let reportID of reportIDs) {
CrashSubmit.submit(reportID, {
extraExtraKeyVals: {
SubmittedFromInfobar: "1",
},
}).catch(Cu.reportError);
CrashSubmit.submit(reportID, submittedFrom).catch(Cu.reportError);
}
},
};

View file

@ -137,9 +137,12 @@ function createPendingCrashReports(howMany, accessDate) {
*
* @param reportIDs (Array<string>)
* The IDs for the reports that we expect CrashSubmit to have sent.
* @param extraCheck (Function, optional)
* A function that receives the annotations of the crash report and can
* be used for checking them
* @returns Promise
*/
function waitForSubmittedReports(reportIDs) {
function waitForSubmittedReports(reportIDs, extraCheck) {
let promises = [];
for (let reportID of reportIDs) {
let promise = TestUtils.topicObserved(
@ -149,24 +152,17 @@ function waitForSubmittedReports(reportIDs) {
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
let dumpID = propBag.getPropertyAsAString("minidumpID");
if (dumpID == reportID) {
if (extraCheck) {
let extra = propBag.getPropertyAsInterface(
"extra",
Ci.nsIPropertyBag2
);
extraCheck(extra);
}
return true;
}
let extra = propBag.getPropertyAsInterface(
"extra",
Ci.nsIPropertyBag2
);
const blockedAnnotations = [
"ServerURL",
"TelemetryClientId",
"TelemetryServerURL",
"TelemetrySessionId",
];
for (const key of blockedAnnotations) {
Assert.ok(
!extra.hasKey(key),
"The " + key + " annotation should have been stripped away"
);
}
}
return false;
}
@ -192,7 +188,7 @@ function waitForIgnoredReports(reportIDs) {
for (let reportID of reportIDs) {
let file = dir.clone();
file.append(reportID + ".dmp.ignore");
promises.push(OS.File.exists(file.path));
promises.push(IOUtils.exists(file.path));
}
return Promise.all(promises);
}
@ -361,6 +357,23 @@ add_task(async function test_several_pending() {
* Tests that the notification can submit a report.
*/
add_task(async function test_can_submit() {
function extraCheck(extra) {
const blockedAnnotations = [
"ServerURL",
"TelemetryClientId",
"TelemetryServerURL",
"TelemetrySessionId",
];
for (const key of blockedAnnotations) {
Assert.ok(
!extra.hasKey(key),
"The " + key + " annotation should have been stripped away"
);
}
Assert.equal(extra.get("SubmittedFrom"), "Infobar");
}
let reportIDs = await createPendingCrashReports(1);
let notification = await UnsubmittedCrashHandler.checkForUnsubmittedCrashReports();
Assert.ok(notification, "There should be a notification");
@ -372,8 +385,7 @@ add_task(async function test_can_submit() {
);
// ...which should be the first button.
let submit = buttons[0];
let promiseReports = waitForSubmittedReports(reportIDs);
let promiseReports = waitForSubmittedReports(reportIDs, extraCheck);
info("Sending crash report");
submit.click();
info("Sent!");
@ -460,6 +472,16 @@ add_task(async function test_can_submit_always() {
"The autoSubmit pref should have been set"
);
// Create another report
reportIDs = await createPendingCrashReports(1);
let result = await UnsubmittedCrashHandler.checkForUnsubmittedCrashReports();
// Check that the crash was auto-submitted
Assert.equal(result, null, "The notification should not be shown");
promiseReports = await waitForSubmittedReports(reportIDs, extra => {
Assert.equal(extra.get("SubmittedFrom"), "Auto");
});
// And revert back to default now.
Services.prefs.clearUserPref(pref);

View file

@ -21,14 +21,19 @@
}
#customization-container {
background-color: var(--toolbar-bgcolor);
background-image: var(--toolbar-bgimage);
background-color: var(--toolbar-non-lwt-bgcolor);
background-image: var(--toolbar-non-lwt-bgimage);
color: var(--toolbar-color);
}
#customization-container:-moz-lwtheme {
/* Ensure this displays on top of the non-lwt bgcolor, to make sure it's not
* semi-transparent */
background-image: var(--toolbar-bgimage), linear-gradient(var(--toolbar-bgcolor), var(--toolbar-bgcolor));
}
:root[lwtheme-image] #customization-container {
background-color: transparent;
background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-non-lwt-bgcolor) 45px);
background-image: none;
color: var(--toolbar-non-lwt-textcolor);
text-shadow: none;
}
@ -47,12 +52,6 @@
margin: 20px 20px 15px;
}
:root[lwtheme-image] #customization-header {
text-shadow: 0 0 1em var(--toolbar-non-lwt-bgcolor),
0 0 1em var(--toolbar-non-lwt-bgcolor),
0 0 .5em var(--toolbar-non-lwt-bgcolor);
}
#customization-panel-container {
--customization-panel-padding: 20px;
padding: 0 var(--customization-panel-padding) 25px;

View file

@ -22,7 +22,7 @@ option(env="CBINDGEN", nargs=1, when=cbindgen_is_needed, help="Path to cbindgen"
def check_cbindgen_version(cbindgen, fatal=False):
log.debug("trying cbindgen: %s" % cbindgen)
cbindgen_min_version = Version("0.22.0")
cbindgen_min_version = Version("0.23.0")
# cbindgen x.y.z
version = Version(check_cmd_output(cbindgen, "--version").strip().split(" ")[1])

View file

@ -94,12 +94,14 @@ def get_sdk_dirs(sdk, subdir):
del include_dirs["include"]
valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True)
if valid_versions:
return namespace(
return [
namespace(
path=sdk,
lib=lib_dirs[valid_versions[0]],
include=include_dirs[valid_versions[0]],
lib=lib_dirs[vv],
include=include_dirs[vv],
)
for vv in valid_versions
]
@imports(_from="mozbuild.shellutil", _import="quote")
@ -125,8 +127,8 @@ def valid_windows_sdk_dir(
windows_sdk_dir_env = windows_sdk_dir_env[0]
sdks = {}
for d in windows_sdk_dir:
sdk = get_sdk_dirs(d, "um")
if sdk:
sdklist = get_sdk_dirs(d, "um")
for sdk in sdklist:
check = dedent(
"""\
#include <winsdkver.h>
@ -152,8 +154,9 @@ def valid_windows_sdk_dir(
pass
else:
sdks[d] = maxver, sdk
continue
if d == windows_sdk_dir_env:
break
if d == windows_sdk_dir_env and d not in sdks:
raise FatalCheckError(
"Error while checking the version of the SDK in "
"WINDOWSSDKDIR (%s). Please verify it contains a valid and "
@ -206,8 +209,8 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, compiler, host_comp
windows_sdk_dir_env = windows_sdk_dir_env[0]
sdks = {}
for d in windows_sdk_dir:
sdk = get_sdk_dirs(d, "ucrt")
if sdk:
sdklist = get_sdk_dirs(d, "ucrt")
for sdk in sdklist:
version = os.path.basename(sdk.include)
# We're supposed to always find a version in the directory, because
# the 8.1 SDK, which doesn't have a version in the directory, doesn't
@ -216,8 +219,9 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, compiler, host_comp
# with the UCRT.
if version != "include":
sdks[d] = Version(version), sdk
continue
if d == windows_sdk_dir_env:
break
if d == windows_sdk_dir_env and d not in sdks:
# When WINDOWSSDKDIR is set in the environment and we can't find the
# Universal CRT SDK, chances are this is a start-shell-msvc*.bat
# setup, where INCLUDE and LIB already contain the UCRT paths.

View file

@ -65,9 +65,12 @@ add_task(async function() {
function initChromeDebugger() {
info("Initializing a chrome debugger process.");
return new Promise(resolve => {
BrowserToolboxLauncher.init(onClose, _process => {
info("Browser toolbox process started successfully.");
resolve(_process);
BrowserToolboxLauncher.init({
onClose,
onRun: _process => {
info("Browser toolbox process started successfully.");
resolve(_process);
},
});
});
}

View file

@ -44,10 +44,13 @@ XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
});
const Services = require("Services");
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
const EXPORTED_SYMBOLS = ["BrowserToolboxLauncher"];
var processes = new Set();
const processes = new Set();
/**
* Constructor for creating a process that will hold a chrome toolbox.
@ -60,12 +63,7 @@ var processes = new Set();
* Set to force overwriting the toolbox profile's preferences with the
* current set of preferences.
*/
function BrowserToolboxLauncher(
onClose,
onRun,
overwritePreferences,
binaryPath
) {
function BrowserToolboxLauncher(onClose, onRun, overwritePreferences) {
const emitter = new EventEmitter();
this.on = emitter.on.bind(emitter);
this.off = emitter.off.bind(emitter);
@ -89,7 +87,7 @@ function BrowserToolboxLauncher(
Services.obs.addObserver(this.close, "quit-application");
this._initServer();
this._initProfile(overwritePreferences);
this._create(binaryPath);
this._create();
processes.add(this);
}
@ -98,14 +96,14 @@ EventEmitter.decorate(BrowserToolboxLauncher);
/**
* Initializes and starts a chrome toolbox process.
* @return object
*
* See BrowserToolboxLauncher jsdoc for the arguments.
*/
BrowserToolboxLauncher.init = function(
BrowserToolboxLauncher.init = function({
onClose,
onRun,
overwritePreferences,
binaryPath
) {
} = {}) {
if (
!Services.prefs.getBoolPref("devtools.chrome.enabled") ||
!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")
@ -113,12 +111,7 @@ BrowserToolboxLauncher.init = function(
console.error("Could not start Browser Toolbox, you need to enable it.");
return null;
}
return new BrowserToolboxLauncher(
onClose,
onRun,
overwritePreferences,
binaryPath
);
return new BrowserToolboxLauncher(onClose, onRun, overwritePreferences);
};
/**
@ -275,14 +268,20 @@ BrowserToolboxLauncher.prototype = {
/**
* Creates and initializes the profile & process for the remote debugger.
*/
_create: function(binaryPath) {
_create: function() {
dumpn("Initializing chrome debugging process.");
let command = Services.dirsvc.get("XREExeF", Ci.nsIFile).path;
let profilePath = this._dbgProfilePath;
if (binaryPath) {
command = binaryPath;
// MOZ_BROWSER_TOOLBOX_BINARY is an absolute file path to a custom firefox binary.
// This is especially useful when debugging debug builds which are really slow
// so that you could pass an optimized build for the browser toolbox.
// This is also useful when debugging a patch that break devtools,
// so that you could use a build that works for the browser toolbox.
const customBinaryPath = env.get("MOZ_BROWSER_TOOLBOX_BINARY");
if (customBinaryPath) {
command = customBinaryPath;
profilePath = FileUtils.getDir("TmpD", ["browserToolboxProfile"], true)
.path;
}
@ -305,9 +304,6 @@ BrowserToolboxLauncher.prototype = {
"devtools.webconsole.input.context",
false
);
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
const environment = {
// Allow recording the startup of the browser toolbox when setting
// MOZ_BROWSER_TOOLBOX_PROFILER_STARTUP=1 when running firefox.

View file

@ -69,7 +69,7 @@ async function initBrowserToolboxTask({
let process;
if (!existingProcessClose) {
process = await new Promise(onRun => {
BrowserToolboxLauncher.init(null, onRun, /* overwritePreferences */ true);
BrowserToolboxLauncher.init({ onRun, overwritePreferences: true });
});
ok(true, "Browser toolbox started");
is(

View file

@ -20,7 +20,10 @@ add_task(async function() {
await selectNode("#testid", inspector);
info("Test creating a new property and escaping");
await addProperty(view, 1, "color", "red", "VK_ESCAPE", false);
await addProperty(view, 1, "color", "red", {
commitValueWith: "VK_ESCAPE",
blurNewProperty: false,
});
is(
view.styleDocument.activeElement,

View file

@ -94,7 +94,7 @@ async function testEditProperty(inspector, ruleView) {
is(newValue, "red", "border-color should have been set.");
ruleView.styleDocument.activeElement.blur();
await addProperty(ruleView, 1, "color", "red", ";");
await addProperty(ruleView, 1, "color", "red", { commitValueWith: ";" });
const props = ruleView.element.querySelectorAll(".ruleview-property");
for (let i = 0; i < props.length; i++) {

View file

@ -240,11 +240,12 @@ var openCubicBezierAndChangeCoords = async function(
* The name for the new property
* @param {String} value
* The value for the new property
* @param {String} commitValueWith
* @param {Object=} options
* @param {String=} options.commitValueWith
* Which key should be used to commit the new value. VK_RETURN is used by
* default, but tests might want to use another key to test cancelling
* for exemple.
* @param {Boolean} blurNewProperty
* @param {Boolean=} options.blurNewProperty
* After the new value has been added, a new property would have been
* focused. This parameter is true by default, and that causes the new
* property to be blurred. Set to false if you don't want this.
@ -255,8 +256,7 @@ var addProperty = async function(
ruleIndex,
name,
value,
commitValueWith = "VK_RETURN",
blurNewProperty = true
{ commitValueWith = "VK_RETURN", blurNewProperty = true } = {}
) {
info("Adding new property " + name + ":" + value + " to rule " + ruleIndex);
@ -265,21 +265,32 @@ var addProperty = async function(
const numOfProps = ruleEditor.rule.textProps.length;
const onMutations = new Promise(r => {
// If we're adding the property to a non-element style rule, we don't need to wait
// for mutations.
// If the rule index is 0, then we are updating the rule for the "element"
// selector in the rule view.
// This rule is actually updating the style attribute of the element, and
// therefore we can expect mutations.
// For any other rule index, no mutation should be created, we can resolve
// immediately.
if (ruleIndex !== 0) {
r();
}
// Otherwise, adding the property to the element style rule causes 2 mutations to the
// style attribute on the element: first when the name is added with an empty value,
// and then when the value is added.
let receivedMutations = 0;
// Use CSS.escape for the name in order to match the logic at
// devtools/client/fronts/inspector/rule-rewriter.js
// This leads to odd values in the style attribute and might change in the
// future. See https://bugzilla.mozilla.org/show_bug.cgi?id=1765943
const expectedAttributeValue = `${CSS.escape(name)}: ${value}`;
view.inspector.walker.on("mutations", function onWalkerMutations(
mutations
) {
receivedMutations += mutations.length;
if (receivedMutations >= 2) {
// Wait until we receive a mutation which updates the style attribute
// with the expected value.
const receivedLastMutation = mutations.some(
mut =>
mut.attributeName === "style" &&
mut.newValue.includes(expectedAttributeValue)
);
if (receivedLastMutation) {
view.inspector.walker.off("mutations", onWalkerMutations);
r();
}

View file

@ -63,7 +63,9 @@ add_task(async function() {
.replace(SEPARATOR_GUID, "-")
.substr(0, 16);
ok(
menuDeleteItem.getAttribute("label").includes(truncatedRowName),
JSON.parse(
menuDeleteItem.getAttribute("data-l10n-args")
).itemName.includes(truncatedRowName),
`Context menu item label contains '${rowName}' (maybe truncated)`
);
});

View file

@ -216,7 +216,9 @@ add_task(async function() {
.replace(SEPARATOR_GUID, "-")
.substr(0, 16);
ok(
menuDeleteItem.getAttribute("label").includes(truncatedRowName),
JSON.parse(
menuDeleteItem.getAttribute("data-l10n-args")
).itemName.includes(truncatedRowName),
`Context menu item label contains '${rowName}' (maybe truncated)`
);
});

View file

@ -359,18 +359,17 @@ const proto = {
* @param array ownProperties
* The array that holds the list of known ownProperties names for
* |this.obj|.
* @param number [limit=0]
* @param number [limit=Infinity]
* Optional limit of getter values to find.
* @return object
* An object that maps property names to safe getter descriptors as
* defined by the remote debugging protocol.
*/
// eslint-disable-next-line complexity
_findSafeGetterValues: function(ownProperties, limit = 0) {
_findSafeGetterValues: function(ownProperties, limit = Infinity) {
const safeGetterValues = Object.create(null);
let obj = this.obj;
let level = 0,
i = 0;
currentGetterValuesCount = 0;
// Do not search safe getters in unsafe objects.
if (!DevToolsUtils.isSafeDebuggerObject(obj)) {
@ -387,8 +386,7 @@ const proto = {
}
while (obj && DevToolsUtils.isSafeDebuggerObject(obj)) {
const getters = this._findSafeGetters(obj);
for (const name of getters) {
for (const name of this._findSafeGetters(obj)) {
// Avoid overwriting properties from prototypes closer to this.obj. Also
// avoid providing safeGetterValues from prototypes if property |name|
// is already defined as an own property.
@ -404,38 +402,21 @@ const proto = {
continue;
}
let desc = null,
getter = null;
try {
desc = obj.getOwnPropertyDescriptor(name);
getter = desc.get;
} catch (ex) {
// The above can throw if the cache becomes stale.
}
if (!getter) {
const desc = safeGetOwnPropertyDescriptor(obj, name);
if (!desc?.get) {
// If no getter matches the name, the cache is stale and should be cleaned up.
obj._safeGetters = null;
continue;
}
const result = getter.call(this.obj);
if (!result || "throw" in result) {
const getterValue = this._evaluateGetter(desc.get);
if (getterValue === undefined) {
continue;
}
let getterValue = undefined;
if ("return" in result) {
getterValue = result.return;
} else if ("yield" in result) {
getterValue = result.yield;
}
// Treat an already-rejected Promise as we would a thrown exception
// by not including it as a safe getter value (see Bug 1477765).
if (
getterValue &&
getterValue.class == "Promise" &&
getterValue.promiseState == "rejected"
) {
if (isRejectedPromise(getterValue)) {
// Until we have a good way to handle Promise rejections through the
// debugger API (Bug 1478076), call `catch` when it's safe to do so.
const raw = getterValue.unsafeDereference();
@ -447,21 +428,18 @@ const proto = {
// WebIDL attributes specified with the LenientThis extended attribute
// return undefined and should be ignored.
if (getterValue !== undefined) {
safeGetterValues[name] = {
getterValue: this.hooks.createValueGrip(getterValue),
getterPrototypeLevel: level,
enumerable: desc.enumerable,
writable: level == 0 ? desc.writable : true,
};
if (limit && ++i == limit) {
break;
}
safeGetterValues[name] = {
getterValue: this.hooks.createValueGrip(getterValue),
getterPrototypeLevel: level,
enumerable: desc.enumerable,
writable: level == 0 ? desc.writable : true,
};
++currentGetterValuesCount;
if (currentGetterValuesCount == limit) {
return safeGetterValues;
}
}
if (limit && i == limit) {
break;
}
obj = obj.proto;
level++;
@ -470,6 +448,26 @@ const proto = {
return safeGetterValues;
},
/**
* Evaluate the getter function |desc.get|.
* @param {Object} getter
*/
_evaluateGetter(getter) {
const result = getter.call(this.obj);
if (!result || "throw" in result) {
return undefined;
}
let getterValue = undefined;
if ("return" in result) {
getterValue = result.return;
} else if ("yield" in result) {
getterValue = result.yield;
}
return getterValue;
},
/**
* Find the safe getters for a given Debugger.Object. Safe getters are native
* getters which are safe to execute.
@ -764,3 +762,27 @@ const proto = {
exports.ObjectActor = protocol.ActorClassWithSpec(objectSpec, proto);
exports.ObjectActorProto = proto;
function safeGetOwnPropertyDescriptor(obj, name) {
let desc = null;
try {
desc = obj.getOwnPropertyDescriptor(name);
} catch (ex) {
// The above can throw if the cache becomes stale.
}
return desc;
}
/**
* Check if the value is rejected promise
*
* @param {Object} getterValue
* @returns {boolean} true if the value is rejected promise, false otherwise.
*/
function isRejectedPromise(getterValue) {
return (
getterValue &&
getterValue.class == "Promise" &&
getterValue.promiseState == "rejected"
);
}

View file

@ -197,7 +197,7 @@ function enumObjectProperties(objectActor, options) {
}
}
const safeGetterValues = objectActor._findSafeGetterValues(names, 0);
const safeGetterValues = objectActor._findSafeGetterValues(names);
const safeGetterNames = Object.keys(safeGetterValues);
// Merge the safe getter values into the existing properties list.
for (const name of safeGetterNames) {

View file

@ -55,6 +55,7 @@ exports.CSS_PROPERTIES = {
"revert",
"revert-layer",
"running",
"scroll",
"step-end",
"step-start",
"steps",
@ -1327,6 +1328,7 @@ exports.CSS_PROPERTIES = {
"revert",
"revert-layer",
"running",
"scroll",
"step-end",
"step-start",
"steps",
@ -3277,6 +3279,7 @@ exports.CSS_PROPERTIES = {
"revert",
"revert-layer",
"running",
"scroll",
"step-end",
"step-start",
"steps",

View file

@ -918,7 +918,14 @@ DevToolsStartup.prototype = {
const { BrowserToolboxLauncher } = ChromeUtils.import(
"resource://devtools/client/framework/browser-toolbox/Launcher.jsm"
);
BrowserToolboxLauncher.init(null, null, null, binaryPath);
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
// --jsdebugger $binaryPath is an helper alias to set MOZ_BROWSER_TOOLBOX_BINARY=$binaryPath
// See comment within BrowserToolboxLauncher.
// Setting it as an environment variable helps it being reused if we restart the browser via CmdOrCtrl+R
env.set("MOZ_BROWSER_TOOLBOX_BINARY", binaryPath);
BrowserToolboxLauncher.init();
if (pauseOnStartup) {
// Spin the event loop until the debugger connects.

View file

@ -5,6 +5,8 @@ Some parts of this process, including cloning and compiling, can take a long tim
If at any point you get stuck, please don't hesitate to ask at `https://chat.mozilla.org <https://chat.mozilla.org>`__
in the `#introduction <https://chat.mozilla.org/#/room/#introduction:mozilla.org>`__ channel.
Dont hesitate to look at the :ref:`Getting Set Up To Work On The Firefox Codebase<Getting Set Up To Work On The Firefox Codebase>` for a more detailed tutorial.
Before you start
----------------
Please register and create your account for

View file

@ -21,7 +21,7 @@ namespace dom {
class AbortSignal;
class AbortController final : public nsISupports, public nsWrapperCache {
class AbortController : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbortController)
@ -40,8 +40,8 @@ class AbortController final : public nsISupports, public nsWrapperCache {
void Abort(JSContext* aCx, JS::Handle<JS::Value> aReason);
private:
~AbortController();
protected:
virtual ~AbortController();
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<AbortSignal> mSignal;

View file

@ -25,9 +25,9 @@ namespace dom {
// it appears only to be used internally in the Fetch API. It might be a good
// idea to split AbortSignal into an implementation that can follow, and an
// implementation that can't, to provide this complexity only when it's needed.
class AbortSignal final : public DOMEventTargetHelper,
public AbortSignalImpl,
public AbortFollower {
class AbortSignal : public DOMEventTargetHelper,
public AbortSignalImpl,
public AbortFollower {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(AbortSignal,
@ -57,7 +57,9 @@ class AbortSignal final : public DOMEventTargetHelper,
// AbortFollower
void RunAbortAlgorithm() override;
private:
virtual bool IsTaskSignal() const { return false; }
protected:
~AbortSignal();
};

View file

@ -7,6 +7,7 @@
#include "ScrollTimeline.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/DisplayPortUtils.h"
#include "mozilla/PresShell.h"
@ -45,14 +46,11 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ScrollTimeline,
TimingParams ScrollTimeline::sTiming;
ScrollTimeline::ScrollTimeline(Document* aDocument, const Scroller& aScroller,
StyleScrollDirection aDirection)
StyleScrollAxis aAxis)
: AnimationTimeline(aDocument->GetParentObject()),
mDocument(aDocument),
// FIXME: Bug 1737918: We may have to udpate the constructor arguments
// because this can be nearest, root, or a specific container. For now,
// the input is a source element directly and it is the root element.
mSource(aScroller),
mDirection(aDirection) {
mAxis(aAxis) {
MOZ_ASSERT(aDocument);
// Use default values except for |mDuration| and |mFill|.
@ -63,6 +61,28 @@ ScrollTimeline::ScrollTimeline(Document* aDocument, const Scroller& aScroller,
PlaybackDirection::Alternate, FillMode::Both);
}
static StyleScrollAxis ToStyleScrollAxis(
const StyleScrollDirection aDirection) {
switch (aDirection) {
// The spec defines auto, but there is a spec issue:
// "ISSUE 5 Define these values." in this section. The DOM interface removed
// auto and use block as default value, so we treat auto as block now.
// https://drafts.csswg.org/scroll-animations-1/#descdef-scroll-timeline-orientation
case StyleScrollDirection::Auto:
case StyleScrollDirection::Block:
return StyleScrollAxis::Block;
case StyleScrollDirection::Inline:
return StyleScrollAxis::Inline;
case StyleScrollDirection::Horizontal:
return StyleScrollAxis::Horizontal;
case StyleScrollDirection::Vertical:
return StyleScrollAxis::Vertical;
}
MOZ_ASSERT_UNREACHABLE("Unsupported StyleScrollDirection");
return StyleScrollAxis::Block;
}
already_AddRefed<ScrollTimeline> ScrollTimeline::FromRule(
const RawServoScrollTimelineRule& aRule, Document* aDocument,
const NonOwningAnimationTarget& aTarget) {
@ -73,19 +93,56 @@ already_AddRefed<ScrollTimeline> ScrollTimeline::FromRule(
// dropped automatically becuase no animation owns it and its ref-count
// becomes zero.
StyleScrollDirection direction =
Servo_ScrollTimelineRule_GetOrientation(&aRule);
StyleScrollAxis axis =
ToStyleScrollAxis(Servo_ScrollTimelineRule_GetOrientation(&aRule));
// FIXME: Bug 1737918: applying new spec update, e.g. other scrollers and
// other style values.
RefPtr<ScrollTimeline> timeline;
auto autoScroller = Scroller::Auto(aTarget.mElement->OwnerDoc());
auto autoScroller = Scroller::Root(aTarget.mElement->OwnerDoc());
auto* set =
ScrollTimelineSet::GetOrCreateScrollTimelineSet(autoScroller.mElement);
auto p = set->LookupForAdd(direction);
auto p = set->LookupForAdd(axis);
if (!p) {
timeline = new ScrollTimeline(aDocument, autoScroller, direction);
set->Add(p, direction, timeline);
timeline = new ScrollTimeline(aDocument, autoScroller, axis);
set->Add(p, axis, timeline);
} else {
timeline = p->value();
}
return timeline.forget();
}
/* static */
already_AddRefed<ScrollTimeline> ScrollTimeline::FromAnonymousScroll(
Document* aDocument, const NonOwningAnimationTarget& aTarget,
StyleScrollAxis aAxis, StyleScroller aScroller) {
MOZ_ASSERT(aTarget);
Scroller scroller;
switch (aScroller) {
case StyleScroller::Root:
scroller = Scroller::Root(aTarget.mElement->OwnerDoc());
break;
case StyleScroller::Nearest: {
Element* curr = aTarget.mElement->GetFlattenedTreeParentElement();
Element* root = aTarget.mElement->OwnerDoc()->GetDocumentElement();
while (curr && curr != root) {
const ComputedStyle* style = Servo_Element_GetMaybeOutOfDateStyle(curr);
MOZ_ASSERT(style, "The ancestor should be styled.");
if (style->StyleDisplay()->IsScrollableOverflow()) {
break;
}
curr = curr->GetFlattenedTreeParentElement();
}
// If there is no scroll container, we use root.
scroller = Scroller::Nearest(curr ? curr : root);
}
}
RefPtr<ScrollTimeline> timeline;
auto* set =
ScrollTimelineSet::GetOrCreateScrollTimelineSet(scroller.mElement);
auto p = set->LookupForAdd(aAxis);
if (!p) {
timeline = new ScrollTimeline(aDocument, scroller, aAxis);
set->Add(p, aAxis, timeline);
} else {
timeline = p->value();
}
@ -134,12 +191,9 @@ layers::ScrollDirection ScrollTimeline::Axis() const {
MOZ_ASSERT(mSource && mSource.mElement->GetPrimaryFrame());
const WritingMode wm = mSource.mElement->GetPrimaryFrame()->GetWritingMode();
return mDirection == StyleScrollDirection::Horizontal ||
(!wm.IsVertical() &&
mDirection == StyleScrollDirection::Inline) ||
(wm.IsVertical() &&
(mDirection == StyleScrollDirection::Block ||
mDirection == StyleScrollDirection::Auto))
return mAxis == StyleScrollAxis::Horizontal ||
(!wm.IsVertical() && mAxis == StyleScrollAxis::Inline) ||
(wm.IsVertical() && mAxis == StyleScrollAxis::Block)
? layers::ScrollDirection::eHorizontal
: layers::ScrollDirection::eVertical;
}
@ -177,7 +231,7 @@ void ScrollTimeline::UnregisterFromScrollSource() {
if (ScrollTimelineSet* scrollTimelineSet =
ScrollTimelineSet::GetScrollTimelineSet(mSource.mElement)) {
scrollTimelineSet->Remove(mDirection);
scrollTimelineSet->Remove(mAxis);
if (scrollTimelineSet->IsEmpty()) {
ScrollTimelineSet::DestroyScrollTimelineSet(mSource.mElement);
}
@ -190,16 +244,17 @@ const nsIScrollableFrame* ScrollTimeline::GetScrollFrame() const {
}
switch (mSource.mType) {
case Scroller::Type::Auto:
case StyleScroller::Root:
if (const PresShell* presShell =
mSource.mElement->OwnerDoc()->GetPresShell()) {
return presShell->GetRootScrollFrameAsScrollable();
}
break;
case Scroller::Type::Other:
default:
return nullptr;
case StyleScroller::Nearest:
return nsLayoutUtils::FindScrollableFrameFor(mSource.mElement);
}
MOZ_ASSERT_UNREACHABLE("Unsupported scroller type");
return nullptr;
}

View file

@ -65,25 +65,22 @@ class Element;
class ScrollTimeline final : public AnimationTimeline {
public:
struct Scroller {
// FIXME: Support nearest and replace auto with root in Bug 1737918.
enum class Type : uint8_t {
// For auto. Should be scrolling element of the owner doc.
Auto,
// For any other specific elements.
Other,
};
Type mType = Type::Auto;
StyleScroller mType = StyleScroller::Root;
RefPtr<Element> mElement;
// We use the owner doc of the animation target. This may be different from
// |mDocument| after we implement ScrollTimeline interface for script.
static Scroller Auto(const Document* aOwnerDoc) {
static Scroller Root(const Document* aOwnerDoc) {
// For auto, we use scrolling element as the default scroller.
// However, it's mutable, and we would like to keep things simple, so
// we always register the ScrollTimeline to the document element (i.e.
// root element) because the content of the root scroll frame is the root
// element.
return {Type::Auto, aOwnerDoc->GetDocumentElement()};
return {StyleScroller::Root, aOwnerDoc->GetDocumentElement()};
}
static Scroller Nearest(Element* aElement) {
return {StyleScroller::Nearest, aElement};
}
explicit operator bool() const { return mElement; }
@ -92,14 +89,17 @@ class ScrollTimeline final : public AnimationTimeline {
}
};
// FIXME: Bug 1737918: Rewrite this because @scroll-timeline will be obsolete.
static already_AddRefed<ScrollTimeline> FromRule(
const RawServoScrollTimelineRule& aRule, Document* aDocument,
const NonOwningAnimationTarget& aTarget);
static already_AddRefed<ScrollTimeline> FromAnonymousScroll(
Document* aDocument, const NonOwningAnimationTarget& aTarget,
StyleScrollAxis aAxis, StyleScroller aScroller);
bool operator==(const ScrollTimeline& aOther) const {
return mDocument == aOther.mDocument && mSource == aOther.mSource &&
mDirection == aOther.mDirection;
mAxis == aOther.mAxis;
}
NS_DECL_ISUPPORTS_INHERITED
@ -154,11 +154,6 @@ class ScrollTimeline final : public AnimationTimeline {
}
// A helper to get the physical orientation of this scroll-timeline.
//
// The spec defines auto, but there is a spec issue:
// "ISSUE 5 Define these values." in this section. The DOM interface removed
// auto and use block as default value, so we treat auto as block now.
// https://drafts.csswg.org/scroll-animations-1/#descdef-scroll-timeline-orientation
layers::ScrollDirection Axis() const;
StyleOverflow SourceScrollStyle() const;
@ -175,7 +170,7 @@ class ScrollTimeline final : public AnimationTimeline {
private:
ScrollTimeline() = delete;
ScrollTimeline(Document* aDocument, const Scroller& aScroller,
StyleScrollDirection aDirection);
StyleScrollAxis aAxis);
// Note: This function is required to be idempotent, as it can be called from
// both cycleCollection::Unlink() and ~ScrollTimeline(). When modifying this
@ -189,14 +184,11 @@ class ScrollTimeline final : public AnimationTimeline {
RefPtr<Document> mDocument;
// FIXME: Bug 1733260: new spec proposal uses a new way to define scroller,
// and move the element-based offset into view-timeline, so here we only
// implement the default behavior of scroll timeline:
// 1. "source" is auto (use scrolling element), and
// 2. "scroll-offsets" is none (i.e. always 0% ~ 100%).
// So now we will only use the scroll direction from @scroll-timeline rule.
// FIXME: Bug 1765211: We may have to update the source element once the
// overflow property of the scroll-container is updated when we are using
// nearest scroller.
Scroller mSource;
StyleScrollDirection mDirection;
StyleScrollAxis mAxis;
// Note: it's unfortunate TimingParams cannot be a const variable because
// we have to use StickyTimingDuration::FromMilliseconds() in its
@ -220,16 +212,15 @@ class ScrollTimeline final : public AnimationTimeline {
*/
class ScrollTimelineSet {
public:
// Use StyleScrollDirection as the key, so we reuse the ScrollTimeline with
// the same source and the same direction.
// Use StyleScrollAxis as the key, so we reuse the ScrollTimeline with the
// same source and the same direction.
// Note: the drawback of using the direction as the key is that we have to
// update this once we support more descriptors. This implementation assumes
// scroll-offsets will be obsolute. However, I'm pretty sure @scroll-timeline
// will be obsolute, based on the spec issue. We may have to do a lot of
// updates after the spec updates, so this tentative implmentation should be
// enough for now.
using NonOwningScrollTimelineMap =
HashMap<StyleScrollDirection, ScrollTimeline*>;
using NonOwningScrollTimelineMap = HashMap<StyleScrollAxis, ScrollTimeline*>;
~ScrollTimelineSet() = default;
@ -237,14 +228,14 @@ class ScrollTimelineSet {
static ScrollTimelineSet* GetOrCreateScrollTimelineSet(Element* aElement);
static void DestroyScrollTimelineSet(Element* aElement);
NonOwningScrollTimelineMap::AddPtr LookupForAdd(StyleScrollDirection aKey) {
NonOwningScrollTimelineMap::AddPtr LookupForAdd(StyleScrollAxis aKey) {
return mScrollTimelines.lookupForAdd(aKey);
}
void Add(NonOwningScrollTimelineMap::AddPtr& aPtr, StyleScrollDirection aKey,
void Add(NonOwningScrollTimelineMap::AddPtr& aPtr, StyleScrollAxis aKey,
ScrollTimeline* aScrollTimeline) {
Unused << mScrollTimelines.add(aPtr, aKey, aScrollTimeline);
}
void Remove(StyleScrollDirection aKey) { mScrollTimelines.remove(aKey); }
void Remove(StyleScrollAxis aKey) { mScrollTimelines.remove(aKey); }
bool IsEmpty() const { return mScrollTimelines.empty(); }

View file

@ -35,6 +35,7 @@ class Timeout final : protected LinkedListElement<RefPtr<Timeout>> {
eTimeoutOrInterval,
eIdleCallbackTimeout,
eAbortSignalTimeout,
eDelayedWebTaskTimeout,
};
struct TimeoutIdAndReason {

View file

@ -451,6 +451,7 @@ uint32_t TimeoutManager::GetTimeoutId(Timeout::Reason aReason) {
return ++mIdleCallbackTimeoutCounter;
case Timeout::Reason::eTimeoutOrInterval:
return ++mTimeoutIdCounter;
case Timeout::Reason::eDelayedWebTaskTimeout:
default:
return std::numeric_limits<uint32_t>::max(); // no cancellation support
}

View file

@ -153,6 +153,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ProxyHandlerUtils.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/WebTaskSchedulerMainThread.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ServiceWorker.h"
@ -1291,6 +1292,11 @@ void nsGlobalWindowInner::FreeInnerObjects() {
mContentMediaController = nullptr;
if (mWebTaskScheduler) {
mWebTaskScheduler->Disconnect();
mWebTaskScheduler = nullptr;
}
mSharedWorkers.Clear();
#ifdef MOZ_WEBSPEECH
@ -1386,6 +1392,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
#endif
@ -1484,6 +1492,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
if (tmp->mWebTaskScheduler) {
tmp->mWebTaskScheduler->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
}
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
#endif
@ -1752,6 +1765,10 @@ void nsGlobalWindowInner::InitDocumentDependentState(JSContext* aCx) {
mLocalStorage = nullptr;
mSessionStorage = nullptr;
mPerformance = nullptr;
if (mWebTaskScheduler) {
mWebTaskScheduler->Disconnect();
mWebTaskScheduler = nullptr;
}
// This must be called after nullifying the internal objects because here we
// could recreate them, calling the getter methods, and store them into the JS
@ -4226,6 +4243,14 @@ Selection* nsGlobalWindowInner::GetSelection(ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr);
}
WebTaskScheduler* nsGlobalWindowInner::Scheduler() {
if (!mWebTaskScheduler) {
mWebTaskScheduler = WebTaskScheduler::CreateForMainThread(this);
}
MOZ_ASSERT(mWebTaskScheduler);
return mWebTaskScheduler;
}
bool nsGlobalWindowInner::Find(const nsAString& aString, bool aCaseSensitive,
bool aBackwards, bool aWrapAround,
bool aWholeWord, bool aSearchInFrames,
@ -6332,6 +6357,11 @@ static const char* GetTimeoutReasonString(Timeout* aTimeout) {
return "setIdleCallback handler (timed out)";
case Timeout::Reason::eAbortSignalTimeout:
return "AbortSignal timeout";
case Timeout::Reason::eDelayedWebTaskTimeout:
return "delayedWebTaskCallback handler (timed out)";
default:
MOZ_CRASH("Unexpected enum value");
return "";
}
MOZ_CRASH("Unexpected enum value");
return "";

View file

@ -130,6 +130,8 @@ struct RequestInit;
class RequestOrUSVString;
class SharedWorker;
class Selection;
class WebTaskScheduler;
class WebTaskSchedulerMainThread;
class SpeechSynthesis;
class Timeout;
class U2F;
@ -988,6 +990,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
// https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
bool CrossOriginIsolated() const override;
mozilla::dom::WebTaskScheduler* Scheduler();
protected:
// Web IDL helpers
@ -1346,6 +1350,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
private:
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;
RefPtr<mozilla::dom::WebTaskSchedulerMainThread> mWebTaskScheduler;
protected:
// Whether we need to care about orientation changes.
bool mHasOrientationChangeListeners : 1;

View file

@ -42,7 +42,8 @@
DOMInterfaces = {
'AbortSignal': {
'implicitJSContext': [ 'throwIfAborted' ]
'implicitJSContext': [ 'throwIfAborted' ],
'concrete': True,
},
'AnonymousContent': {
@ -641,6 +642,11 @@ DOMInterfaces = {
'concrete': True,
},
'TaskController' : {
'nativeType' : 'mozilla::dom::WebTaskController',
'headerFile' : 'mozilla/dom/WebTaskController.h'
},
'TransceiverImpl': {
'nativeType': 'mozilla::TransceiverImpl',
'headerFile': 'TransceiverImpl.h'
@ -747,6 +753,11 @@ DOMInterfaces = {
'headerFile': 'RTCStatsReport.h'
},
'Scheduler': {
'nativeType': 'mozilla::dom::WebTaskScheduler',
'headerFile': 'mozilla/dom/WebTaskScheduler.h',
},
'Screen': {
'nativeType': 'nsScreen',
},

View file

@ -2266,6 +2266,8 @@ GlyphCacheEntry::GlyphCacheEntry(const GlyphBuffer& aBuffer,
mBuffer.mNumGlyphs = aBuffer.mNumGlyphs;
}
GlyphCacheEntry::~GlyphCacheEntry() { delete[] mBuffer.mGlyphs; }
// Attempt to find a matching entry in the glyph cache. If one isn't found,
// a new entry will be created. The caller should check whether the contained
// texture handle is valid to determine if it will need to render the text run

View file

@ -302,6 +302,7 @@ class GlyphCacheEntry : public CacheEntryImpl<GlyphCacheEntry> {
GlyphCacheEntry(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
const Matrix& aTransform, const IntRect& aBounds,
HashNumber aHash);
~GlyphCacheEntry();
bool MatchesGlyphs(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
const Matrix& aTransform, const IntRect& aBounds,

View file

@ -49,6 +49,7 @@ support-files = test_bug336682.js
skip-if = toolkit == 'android' # android: TIMED_OUT
[test_bug412567.html]
[test_bug418986-3.html]
skip-if = e10s && os == 'win' # bug 1764560
[test_bug422132.html]
[test_bug426082.html]
[test_bug427537.html]

View file

@ -350,6 +350,11 @@ const kEventConstructors = {
return new SubmitEvent(aName, aProps);
},
},
TaskPriorityChangeEvent: { create (aName, aProps) {
aProps.previousPriority = "user-blocking";
return new TaskPriorityChangeEvent(aName, aProps);
},
},
TCPSocketErrorEvent: { create(aName, aProps) {
return new TCPSocketErrorEvent(aName, aProps);
},

View file

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1742421
-->
<head>
<title>Test for Bug 1742421</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="file_fullscreen-utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body style="background-color: gray;">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1742421">Mozilla Bug 1742421</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1742421 **/
function begin()
{
addFullscreenChangeContinuation("enter", () => {
opener.info("[resize] Entered fullscreen");
// Do not use addFullscreenChangeContinuation for fullscreen exit given that
// it expects the window will be restored to the original size.
document.addEventListener("fullscreenchange", () => {
opener.ok(!document.fullscreenElement, "[resize] Should have left full-screen due to resize");
opener.nextTest();
}, { once: true });
window.resizeBy(100,100);
});
document.body.requestFullscreen();
}
</script>
</pre>
</body>
</html>

View file

@ -472,6 +472,7 @@ support-files =
file_fullscreen-top-layer.html
file_fullscreen-utils.js
file_fullscreen-with-full-zoom.html
file_fullscreen-resize.html
[test_fullscreen_meta_viewport.html]
support-files = file_fullscreen_meta_viewport.html

View file

@ -55,6 +55,7 @@ var gTestWindows = [
{ test: "file_fullscreen-async.html" },
{ test: "file_fullscreen-sub-iframe.html" },
{ test: "file_fullscreen-with-full-zoom.html" },
{ test: "file_fullscreen-resize.html" },
];
var testWindow = null;

View file

@ -1641,7 +1641,12 @@ void ContentParent::BroadcastMediaCodecsSupportedUpdate(
const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
void ContentParent::Init() {
MOZ_ASSERT(sXPCOMShutdownClient);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
size_t length = ArrayLength(sObserverTopics);
@ -1650,8 +1655,6 @@ void ContentParent::Init() {
}
}
AddShutdownBlockers();
if (obs) {
nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
@ -2491,6 +2494,11 @@ void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
// Ensure we will not rush through our shutdown phases while launching.
// LaunchSubprocessReject will remove them in case of failure,
// otherwise ActorDestroy will take care.
AddShutdownBlockers();
// XXX: This check works only late, as GetSingleton will return nullptr
// only after ClearOnShutdown happened. See bug 1632740.
if (!ContentProcessManager::GetSingleton()) {
@ -2585,6 +2593,7 @@ void ContentParent::LaunchSubprocessReject() {
mIsAPreallocBlocker = false;
}
MarkAsDead();
RemoveShutdownBlockers();
}
bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
@ -2697,13 +2706,12 @@ bool ContentParent::LaunchSubprocessSync(
// We've started a sync content process launch.
Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
if (!BeginSubprocessLaunch(aInitialPriority)) {
return false;
}
const bool ok = mSubprocess->WaitForProcessHandle();
if (ok && LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority)) {
ContentParent::DidLaunchSubprocess();
return true;
if (BeginSubprocessLaunch(aInitialPriority)) {
const bool ok = mSubprocess->WaitForProcessHandle();
if (ok && LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority)) {
ContentParent::DidLaunchSubprocess();
return true;
}
}
LaunchSubprocessReject();
return false;
@ -3537,11 +3545,19 @@ ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
// The normal shutdown sequence is to send a shutdown message
// to the child and then just wait for ActorDestroy which will
// cleanup everything and remove our blockers.
// XXX: Check for successful dispatch, see bug 1765732
ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
} else if (IsLaunching()) {
// If we get here while we are launching, we must wait for the child to
// be able to react on our commands. Mark this process as dead. This
// will make bail out LaunchSubprocessResolve and kick off the normal
// shutdown sequence.
MarkAsDead();
} else {
// If we get here with whatever non-active state on the channel,
// we just close it and ActorDestroy will remove our blockers.
ShutDownProcess(CLOSE_CHANNEL);
MOZ_ASSERT(IsDead());
// Nothing left we can do. We must assume that we race with an ongoing
// process shutdown, such that we can expect our shutdown blockers to be
// removed normally.
}
return NS_OK;
@ -3563,9 +3579,6 @@ ContentParent::GetState(nsIPropertyBag** aResult) {
return NS_OK;
}
static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
static void InitShutdownClients() {
if (!sXPCOMShutdownClient) {
nsresult rv;

View file

@ -82,6 +82,8 @@ void DeviceInputConsumerTrack::ConnectDeviceInput(
MOZ_ASSERT(!mListener);
MOZ_ASSERT(!mDeviceInputTrack);
MOZ_ASSERT(mDeviceId.isNothing());
MOZ_ASSERT(!mDeviceInputTrack,
"Must disconnect a device input before connecting a new one");
mListener = aListener;
mDeviceId.emplace(aId);
@ -99,6 +101,7 @@ void DeviceInputConsumerTrack::DisconnectDeviceInput() {
if (!mListener) {
MOZ_ASSERT(mDeviceId.isNothing());
MOZ_ASSERT(!mDeviceInputTrack);
return;
}

View file

@ -6,10 +6,14 @@
UNIFIED_SOURCES += [
"TestContainerParser.cpp",
"TestExtractAV1CodecDetails.cpp",
"TestExtractVPXCodecDetails.cpp",
]
if CONFIG["MOZ_AV1"]:
UNIFIED_SOURCES += [
"TestExtractAV1CodecDetails.cpp",
]
LOCAL_INCLUDES += [
"/dom/media",
"/dom/media/mediasource",

View file

@ -7,7 +7,9 @@
#include "MP4Decoder.h"
#include "H264.h"
#include "VPXDecoder.h"
#include "AOMDecoder.h"
#ifdef MOZ_AV1
# include "AOMDecoder.h"
#endif
#include "MP4Demuxer.h"
#include "MediaContainerType.h"
#include "PDMFactory.h"

View file

@ -2158,6 +2158,7 @@ nsresult OggDemuxer::SeekBisection(TrackInfo::TrackType aType, int64_t aTarget,
MOZ_ASSERT(endTime >= seekTarget, "End must be after seek target");
}
(void)hops;
SEEK_LOG(LogLevel::Debug, ("Seek complete in %d bisections.", hops));
return NS_OK;

View file

@ -422,8 +422,10 @@ PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
}
if ((MP4Decoder::IsH264(config.mMimeType) ||
VPXDecoder::IsVPX(config.mMimeType) ||
AOMDecoder::IsAV1(config.mMimeType)) &&
#ifdef MOZ_AV1
AOMDecoder::IsAV1(config.mMimeType) ||
#endif
VPXDecoder::IsVPX(config.mMimeType)) &&
!aParams.mUseNullDecoder.mUse && !aParams.mNoWrapper.mDontUseWrapper) {
return MediaChangeMonitor::Create(this, aParams);
}

View file

@ -9,7 +9,9 @@
#include <psapi.h>
#include <winsdkver.h>
#include <algorithm>
#include "AOMDecoder.h"
#ifdef MOZ_AV1
# include "AOMDecoder.h"
#endif
#include "DXVA2Manager.h"
#include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place.
#include "IMFYCbCrImage.h"
@ -289,6 +291,7 @@ MediaResult WMFVideoMFTManager::ValidateVideoInfo() {
}
}
break;
#ifdef MOZ_AV1
case WMFStreamType::AV1:
if (mVideoInfo.mExtraData && !mVideoInfo.mExtraData->IsEmpty()) {
// Read AV1 codec configuration and check support for profiles and pixel
@ -304,6 +307,7 @@ MediaResult WMFVideoMFTManager::ValidateVideoInfo() {
}
}
break;
#endif
default:
break;
}

View file

@ -14,7 +14,9 @@
#include "MediaInfo.h"
#include "PDMFactory.h"
#include "VPXDecoder.h"
#include "AOMDecoder.h"
#ifdef MOZ_AV1
# include "AOMDecoder.h"
#endif
#include "gfxUtils.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/StaticPrefs_media.h"
@ -294,6 +296,7 @@ class VPXChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
double mPixelAspectRatio;
};
#ifdef MOZ_AV1
class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
public:
explicit AV1ChangeMonitor(const VideoInfo& aInfo)
@ -410,6 +413,7 @@ class AV1ChangeMonitor : public MediaChangeMonitor::CodecChangeMonitor {
RefPtr<TrackInfoSharedPtr> mTrackInfo;
double mPixelAspectRatio;
};
#endif
MediaChangeMonitor::MediaChangeMonitor(
PDMFactory* aPDMFactory,
@ -428,8 +432,10 @@ RefPtr<PlatformDecoderModule::CreateDecoderPromise> MediaChangeMonitor::Create(
const VideoInfo& currentConfig = aParams.VideoConfig();
if (VPXDecoder::IsVPX(currentConfig.mMimeType)) {
changeMonitor = MakeUnique<VPXChangeMonitor>(currentConfig);
#ifdef MOZ_AV1
} else if (AOMDecoder::IsAV1(currentConfig.mMimeType)) {
changeMonitor = MakeUnique<AV1ChangeMonitor>(currentConfig);
#endif
} else {
MOZ_ASSERT(MP4Decoder::IsH264(currentConfig.mMimeType));
changeMonitor = MakeUnique<H264ChangeMonitor>(

View file

@ -107,12 +107,9 @@ bool IsValidMessage(const MIDIMessage* aMsg) {
bool ParseMessages(const nsTArray<uint8_t>& aByteBuffer,
const TimeStamp& aTimestamp,
nsTArray<MIDIMessage>& aMsgArray) {
uint32_t bytesRead = 0;
bool inSysexMessage = false;
UniquePtr<MIDIMessage> currentMsg = nullptr;
for (const auto& byte : aByteBuffer) {
bytesRead++;
if (IsSystemRealtimeMessage(byte)) {
MIDIMessage rt_msg;
rt_msg.data().AppendElement(byte);

View file

@ -111,6 +111,7 @@ DIRS += [
"prio",
"l10n",
"origin-trials",
"webscheduling",
]

View file

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "Performance")
BUG_COMPONENT = ("Core", "DOM: Performance")
EXPORTS.mozilla.dom += [
"EventCounts.h",

View file

@ -277,6 +277,8 @@ var interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
"Response",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Scheduler", nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
"ServiceWorker",
// IMPORTANT: Do not change this list without review from a DOM peer!
"ServiceWorkerGlobalScope",
@ -287,6 +289,12 @@ var interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
"SubtleCrypto",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskController", nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskPriorityChangeEvent", nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskSignal", nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
"TextDecoder",
// IMPORTANT: Do not change this list without review from a DOM peer!
"TextEncoder",

View file

@ -1006,6 +1006,8 @@ var interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Sanitizer", disabled: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Scheduler", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Screen", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "ScreenOrientation", insecureContext: true },
@ -1262,6 +1264,12 @@ var interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "SVGViewElement", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskController", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskPriorityChangeEvent", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskSignal", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Text", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TextDecoder", insecureContext: true },

View file

@ -61,7 +61,7 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
const nsAString& aEncoderOptions,
nsIInputStream** aStream) override {
*aStream = nullptr;
return NS_OK;
return NS_ERROR_NOT_IMPLEMENTED;
}
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(

View file

@ -0,0 +1,9 @@
[Exposed=(Window, Worker), Pref="dom.enable_web_task_scheduling"]
interface TaskPriorityChangeEvent : Event {
constructor (DOMString type , TaskPriorityChangeEventInit priorityChangeEventInitDict);
readonly attribute TaskPriority previousPriority;
};
dictionary TaskPriorityChangeEventInit : EventInit {
required TaskPriority previousPriority;
};

View file

@ -0,0 +1,42 @@
enum TaskPriority {
"user-blocking",
"user-visible",
"background"
};
[Exposed=(Window, Worker), Pref="dom.enable_web_task_scheduling"]
interface TaskSignal : AbortSignal {
readonly attribute TaskPriority priority;
attribute EventHandler onprioritychange;
};
dictionary SchedulerPostTaskOptions {
AbortSignal signal;
TaskPriority priority;
[EnforceRange] unsigned long long delay = 0;
};
callback SchedulerPostTaskCallback = any ();
[Exposed=(Window, Worker), Pref="dom.enable_web_task_scheduling"]
interface Scheduler {
Promise<any> postTask(
SchedulerPostTaskCallback callback,
optional SchedulerPostTaskOptions options = {}
);
};
dictionary TaskControllerInit {
TaskPriority priority = "user-visible";
};
[Exposed=(Window,Worker), Pref="dom.enable_web_task_scheduling"]
interface TaskController : AbortController {
[Throws]
constructor(optional TaskControllerInit init = {});
[Throws]
void setPriority(TaskPriority priority);
};

View file

@ -79,3 +79,9 @@ partial interface mixin WindowOrWorkerGlobalScope {
[Throws, Pref="dom.caches.enabled", SameObject]
readonly attribute CacheStorage caches;
};
// https://wicg.github.io/scheduling-apis/#ref-for-windoworworkerglobalscope-scheduler
partial interface mixin WindowOrWorkerGlobalScope {
[Pref="dom.enable_web_task_scheduling", SameObject]
readonly attribute Scheduler scheduler;
};

View file

@ -985,6 +985,7 @@ WEBIDL_FILES = [
"WebGLRenderingContext.webidl",
"WebGPU.webidl",
"WebSocket.webidl",
"WebTaskScheduling.webidl",
"WebXR.webidl",
"WheelEvent.webidl",
"WidevineCDMManifest.webidl",
@ -1158,6 +1159,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
"SecurityPolicyViolationEvent.webidl",
"StyleSheetApplicableStateChangeEvent.webidl",
"SubmitEvent.webidl",
"TaskPriorityChangeEvent.webidl",
"TCPServerSocketEvent.webidl",
"TCPSocketErrorEvent.webidl",
"TCPSocketEvent.webidl",

View file

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#ifndef mozilla_dom_TaskSignal_h
#define mozilla_dom_TaskSignal_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/AbortSignal.h"
#include "mozilla/dom/WebTaskSchedulingBinding.h"
#include "WebTaskScheduler.h"
namespace mozilla::dom {
class TaskSignal : public AbortSignal {
public:
TaskSignal(nsIGlobalObject* aGlobal, TaskPriority aPriority)
: AbortSignal(aGlobal, false, JS::UndefinedHandleValue),
mPriority(aPriority),
mPriorityChanging(false) {}
IMPL_EVENT_HANDLER(prioritychange);
TaskPriority Priority() const { return mPriority; }
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override {
return TaskSignal_Binding::Wrap(aCx, this, aGivenProto);
}
void SetPriority(TaskPriority aPriority) { mPriority = aPriority; }
bool IsTaskSignal() const override { return true; }
bool PriorityChanging() const { return mPriorityChanging; }
void SetPriorityChanging(bool aPriorityChanging) {
mPriorityChanging = aPriorityChanging;
}
void SetWebTaskScheduler(WebTaskScheduler* aScheduler) {
mSchedulers.AppendElement(aScheduler);
}
void RunPriorityChangeAlgorithms() {
for (const WeakPtr<WebTaskScheduler>& scheduler : mSchedulers) {
scheduler->RunTaskSignalPriorityChange(this);
}
}
private:
TaskPriority mPriority;
bool mPriorityChanging;
nsTArray<WeakPtr<WebTaskScheduler>> mSchedulers;
~TaskSignal() = default;
};
} // namespace mozilla::dom
#endif

View file

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebTaskController.h"
#include "TaskSignal.h"
#include "mozilla/dom/TaskPriorityChangeEvent.h"
namespace mozilla::dom {
WebTaskController::WebTaskController(nsIGlobalObject* aGlobal,
TaskPriority aPriority)
: AbortController(aGlobal) {
MOZ_ASSERT(!mSignal);
mSignal = new TaskSignal(aGlobal, aPriority);
}
void WebTaskController::SetPriority(TaskPriority aPriority, ErrorResult& aRv) {
// https://wicg.github.io/scheduling-apis/#tasksignal-signal-priority-change
RefPtr<TaskSignal> taskSignal = static_cast<TaskSignal*>(mSignal.get());
MOZ_ASSERT(taskSignal);
if (taskSignal->PriorityChanging()) {
aRv.ThrowNotAllowedError("Signal's priority changing is true");
return;
}
if (taskSignal->Priority() == aPriority) {
return;
}
taskSignal->SetPriorityChanging(true);
TaskPriority previousPriority = taskSignal->Priority();
taskSignal->SetPriority(aPriority);
taskSignal->RunPriorityChangeAlgorithms();
TaskPriorityChangeEventInit init;
init.mPreviousPriority = previousPriority;
RefPtr<TaskPriorityChangeEvent> event = TaskPriorityChangeEvent::Constructor(
taskSignal, u"prioritychange"_ns, init);
event->SetTrusted(true);
taskSignal->DispatchEvent(*event);
taskSignal->SetPriorityChanging(false);
}
already_AddRefed<WebTaskController> WebTaskController::Constructor(
const GlobalObject& aGlobal, const TaskControllerInit& aInit,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<WebTaskController> webTaskController =
new WebTaskController(global, aInit.mPriority);
return webTaskController.forget();
}
JSObject* WebTaskController::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return TaskController_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace mozilla::dom

View file

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#ifndef mozilla_dom_WebTaskController_h
#define mozilla_dom_WebTaskController_h
#include "nsWrapperCache.h"
#include "mozilla/dom/WebTaskSchedulingBinding.h"
#include "mozilla/dom/AbortController.h"
namespace mozilla::dom {
class WebTaskController : public AbortController {
public:
explicit WebTaskController(nsIGlobalObject* aGlobal, TaskPriority aPriority);
static already_AddRefed<WebTaskController> Constructor(
const GlobalObject& aGlobal, const TaskControllerInit& aInit,
ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
void SetPriority(TaskPriority aPriority, ErrorResult& aRv);
private:
~WebTaskController() = default;
};
} // namespace mozilla::dom
#endif

View file

@ -0,0 +1,350 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsTHashMap.h"
#include "WebTaskScheduler.h"
#include "WebTaskSchedulerWorker.h"
#include "WebTaskSchedulerMainThread.h"
#include "TaskSignal.h"
#include "nsGlobalWindowInner.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/TimeoutManager.h"
namespace mozilla::dom {
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback, WebTaskQueue& aQueue,
const char* aName, uint32_t aFlags = 0) {
ImplCycleCollectionTraverse(aCallback, aQueue.Tasks(), aName, aFlags);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(WebTask)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebTask)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebTask)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebTask)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebTask)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebTask)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(DelayedWebTaskHandler)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DelayedWebTaskHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DelayedWebTaskHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DelayedWebTaskHandler)
void WebTask::RunAbortAlgorithm() {
// no-op if WebTask::Run has been called already
if (mPromise->State() == Promise::PromiseState::Pending) {
// There are two things that can keep a WebTask alive, either the abort
// signal or WebTaskQueue.
// It's possible that this task get cleared out from the WebTaskQueue first,
// and then the abort signal get aborted. For example, the callback function
// was async and there's a signal.abort() call in the callback.
if (isInList()) {
remove();
}
AutoJSAPI jsapi;
if (!jsapi.Init(mPromise->GetGlobalObject())) {
mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
} else {
JSContext* cx = jsapi.cx();
JS::RootedValue reason(cx);
Signal()->GetReason(cx, &reason);
mPromise->MaybeReject(reason);
}
}
MOZ_ASSERT(!isInList());
}
bool WebTask::Run() {
MOZ_ASSERT(HasScheduled());
remove();
ErrorResult error;
nsIGlobalObject* global = mPromise->GetGlobalObject();
if (!global || global->IsDying()) {
return false;
}
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
return false;
}
JS::Rooted<JS::Value> returnVal(jsapi.cx());
MOZ_ASSERT(mPromise->State() == Promise::PromiseState::Pending);
MOZ_KnownLive(mCallback)->Call(&returnVal, error, "WebTask",
CallbackFunction::eRethrowExceptions);
error.WouldReportJSException();
Promise::PromiseState promiseState = mPromise->State();
// If the state is Rejected, it means the above Call triggers the
// RunAbortAlgorithm method and rejected the promise
MOZ_ASSERT_IF(promiseState != Promise::PromiseState::Pending,
promiseState == Promise::PromiseState::Rejected);
if (promiseState == Promise::PromiseState::Pending) {
if (error.Failed()) {
mPromise->MaybeReject(std::move(error));
} else {
mPromise->MaybeResolve(returnVal);
}
}
MOZ_ASSERT(!isInList());
return true;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTaskScheduler, mParent,
mStaticPriorityTaskQueues,
mDynamicPriorityTaskQueues)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebTaskScheduler, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebTaskScheduler, Release)
/* static */
already_AddRefed<WebTaskSchedulerMainThread>
WebTaskScheduler::CreateForMainThread(nsGlobalWindowInner* aWindow) {
RefPtr<WebTaskSchedulerMainThread> scheduler =
new WebTaskSchedulerMainThread(aWindow->AsGlobal());
return scheduler.forget();
}
already_AddRefed<WebTaskSchedulerWorker> WebTaskScheduler::CreateForWorker(
WorkerPrivate* aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<WebTaskSchedulerWorker> scheduler =
new WebTaskSchedulerWorker(aWorkerPrivate);
return scheduler.forget();
}
WebTaskScheduler::WebTaskScheduler(nsIGlobalObject* aParent)
: mParent(aParent), mNextEnqueueOrder(1) {
MOZ_ASSERT(aParent);
}
JSObject* WebTaskScheduler::WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) {
return Scheduler_Binding::Wrap(cx, this, aGivenProto);
}
already_AddRefed<Promise> WebTaskScheduler::PostTask(
SchedulerPostTaskCallback& aCallback,
const SchedulerPostTaskOptions& aOptions) {
const Optional<OwningNonNull<AbortSignal>>& taskSignal = aOptions.mSignal;
const Optional<TaskPriority>& taskPriority = aOptions.mPriority;
ErrorResult rv;
// Instead of making WebTaskScheduler::PostTask throws, we always
// create the promise and return it. This is because we need to
// create the promise explicitly to be able to reject it with
// signal's reason.
RefPtr<Promise> promise = Promise::Create(mParent, rv);
if (rv.Failed()) {
return nullptr;
}
nsIGlobalObject* global = GetParentObject();
if (!global || global->IsDying()) {
promise->MaybeRejectWithNotSupportedError("Current window is detached");
return promise.forget();
}
if (taskSignal.WasPassed()) {
AbortSignal& signalValue = taskSignal.Value();
if (signalValue.Aborted()) {
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
JSContext* cx = jsapi.cx();
JS::RootedValue reason(cx);
signalValue.GetReason(cx, &reason);
promise->MaybeReject(reason);
return promise.forget();
}
}
// Let queue be the result of selecting the scheduler task queue for scheduler
// given signal and priority.
WebTaskQueue& taskQueue = SelectTaskQueue(taskSignal, taskPriority);
uint64_t delay = aOptions.mDelay;
RefPtr<WebTask> task = CreateTask(taskQueue, taskSignal, aCallback, promise);
if (delay > 0) {
nsresult rv = SetTimeoutForDelayedTask(task, delay);
if (NS_FAILED(rv)) {
promise->MaybeRejectWithUnknownError(
"Failed to setup timeout for delayed task");
}
return promise.forget();
}
if (!QueueTask(task)) {
promise->MaybeRejectWithNotSupportedError("Unable to queue the task");
return promise.forget();
}
return promise.forget();
}
already_AddRefed<WebTask> WebTaskScheduler::CreateTask(
WebTaskQueue& aQueue, const Optional<OwningNonNull<AbortSignal>>& aSignal,
SchedulerPostTaskCallback& aCallback, Promise* aPromise) {
uint32_t nextEnqueueOrder = mNextEnqueueOrder;
++mNextEnqueueOrder;
RefPtr<WebTask> task = new WebTask(nextEnqueueOrder, aCallback, aPromise);
aQueue.AddTask(task);
if (aSignal.WasPassed()) {
AbortSignal& signalValue = aSignal.Value();
task->Follow(&signalValue);
}
return task.forget();
}
bool WebTaskScheduler::QueueTask(WebTask* aTask) {
if (!DispatchEventLoopRunnable()) {
return false;
}
MOZ_ASSERT(!aTask->HasScheduled());
aTask->SetHasScheduled(true);
return true;
}
WebTask* WebTaskScheduler::GetNextTask() const {
// We first combine queues from both mStaticPriorityTaskQueues and
// mDynamicPriorityTaskQueues into a single hash map which the
// keys are the priorities and the values are all the queues that
// belong to this priority.
//
// Then From the queues which
// 1. Have scheduled tasks
// 2. Its priority is not less than any other queues' priority
// We pick the task which has the smallest enqueue order.
nsTHashMap<nsUint32HashKey, nsTArray<WebTaskQueue*>> allQueues;
for (auto iter = mStaticPriorityTaskQueues.ConstIter(); !iter.Done();
iter.Next()) {
const auto& queue = iter.Data();
if (!queue->Tasks().isEmpty() && queue->GetFirstScheduledTask()) {
nsTArray<WebTaskQueue*>& queuesForThisPriority =
allQueues.LookupOrInsert(static_cast<uint32_t>(iter.Key()));
queuesForThisPriority.AppendElement(queue.get());
}
}
for (auto iter = mDynamicPriorityTaskQueues.ConstIter(); !iter.Done();
iter.Next()) {
const auto& queue = iter.Data();
if (!queue->Tasks().isEmpty() && queue->GetFirstScheduledTask()) {
nsTArray<WebTaskQueue*>& queuesForThisPriority = allQueues.LookupOrInsert(
static_cast<uint32_t>(iter.Key()->Priority()));
queuesForThisPriority.AppendElement(queue.get());
}
}
if (allQueues.IsEmpty()) {
return nullptr;
}
for (uint32_t priority = static_cast<uint32_t>(TaskPriority::User_blocking);
priority < static_cast<uint32_t>(TaskPriority::EndGuard_); ++priority) {
if (auto queues = allQueues.Lookup(priority)) {
WebTaskQueue* oldestQueue = nullptr;
MOZ_ASSERT(!queues.Data().IsEmpty());
for (auto& webTaskQueue : queues.Data()) {
MOZ_ASSERT(webTaskQueue->GetFirstScheduledTask());
if (!oldestQueue) {
oldestQueue = webTaskQueue;
} else {
WebTask* firstScheduledRunnableForCurrentQueue =
webTaskQueue->GetFirstScheduledTask();
WebTask* firstScheduledRunnableForOldQueue =
oldestQueue->GetFirstScheduledTask();
if (firstScheduledRunnableForOldQueue->EnqueueOrder() >
firstScheduledRunnableForCurrentQueue->EnqueueOrder()) {
oldestQueue = webTaskQueue;
}
}
}
MOZ_ASSERT(oldestQueue);
return oldestQueue->GetFirstScheduledTask();
}
}
return nullptr;
}
void WebTaskScheduler::Disconnect() {
mStaticPriorityTaskQueues.Clear();
mDynamicPriorityTaskQueues.Clear();
}
void WebTaskScheduler::RunTaskSignalPriorityChange(TaskSignal* aTaskSignal) {
WebTaskQueue* const taskQueue = mDynamicPriorityTaskQueues.Get(aTaskSignal);
MOZ_ASSERT(taskQueue);
taskQueue->SetPriority(aTaskSignal->Priority());
}
WebTaskQueue& WebTaskScheduler::SelectTaskQueue(
const Optional<OwningNonNull<AbortSignal>>& aSignal,
const Optional<TaskPriority>& aPriority) {
bool useSignal = !aPriority.WasPassed() && aSignal.WasPassed() &&
aSignal.Value().IsTaskSignal();
if (useSignal) {
TaskSignal* taskSignal = static_cast<TaskSignal*>(&(aSignal.Value()));
WebTaskQueue* const taskQueue =
mDynamicPriorityTaskQueues.GetOrInsertNew(taskSignal);
taskQueue->SetPriority(taskSignal->Priority());
taskSignal->SetWebTaskScheduler(this);
MOZ_ASSERT(mDynamicPriorityTaskQueues.Contains(taskSignal));
return *taskQueue;
}
TaskPriority taskPriority =
aPriority.WasPassed() ? aPriority.Value() : TaskPriority::User_visible;
WebTaskQueue* const taskQueue = mStaticPriorityTaskQueues.GetOrInsertNew(
static_cast<uint32_t>(taskPriority));
taskQueue->SetPriority(taskPriority);
MOZ_ASSERT(
mStaticPriorityTaskQueues.Contains(static_cast<uint32_t>(taskPriority)));
return *taskQueue;
}
} // namespace mozilla::dom

View file

@ -0,0 +1,172 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#ifndef mozilla_dom_WebTaskScheduler_h
#define mozilla_dom_WebTaskScheduler_h
#include "nsThreadUtils.h"
#include "nsPIDOMWindow.h"
#include "nsWrapperCache.h"
#include "nsClassHashtable.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/AbortFollower.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/WebTaskSchedulingBinding.h"
namespace mozilla::dom {
class WebTask : public LinkedListElement<RefPtr<WebTask>>,
public AbortFollower,
public SupportsWeakPtr {
friend class WebTaskScheduler;
public:
MOZ_CAN_RUN_SCRIPT bool Run();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(WebTask)
WebTask(uint32_t aEnqueueOrder, SchedulerPostTaskCallback& aCallback,
Promise* aPromise)
: mEnqueueOrder(aEnqueueOrder),
mCallback(&aCallback),
mPromise(aPromise),
mHasScheduled(false) {}
void RunAbortAlgorithm() override;
bool HasScheduled() const { return mHasScheduled; }
uint32_t EnqueueOrder() const { return mEnqueueOrder; }
private:
void SetHasScheduled(bool aHasScheduled) { mHasScheduled = aHasScheduled; }
uint32_t mEnqueueOrder;
RefPtr<SchedulerPostTaskCallback> mCallback;
RefPtr<Promise> mPromise;
bool mHasScheduled;
~WebTask() = default;
};
class WebTaskQueue {
public:
WebTaskQueue() = default;
TaskPriority Priority() const { return mPriority; }
void SetPriority(TaskPriority aNewPriority) { mPriority = aNewPriority; }
LinkedList<RefPtr<WebTask>>& Tasks() { return mTasks; }
void AddTask(WebTask* aTask) { mTasks.insertBack(aTask); }
// TODO: To optimize it, we could have the scheduled and unscheduled
// tasks stored separately.
WebTask* GetFirstScheduledTask() {
for (const auto& task : mTasks) {
if (task->HasScheduled()) {
return task;
}
}
return nullptr;
}
~WebTaskQueue() { mTasks.clear(); }
private:
TaskPriority mPriority = TaskPriority::User_visible;
LinkedList<RefPtr<WebTask>> mTasks;
};
class WebTaskSchedulerMainThread;
class WebTaskSchedulerWorker;
class WebTaskScheduler : public nsWrapperCache, public SupportsWeakPtr {
friend class DelayedWebTaskHandler;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebTaskScheduler)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebTaskScheduler)
static already_AddRefed<WebTaskSchedulerMainThread> CreateForMainThread(
nsGlobalWindowInner* aWindow);
static already_AddRefed<WebTaskSchedulerWorker> CreateForWorker(
WorkerPrivate* aWorkerPrivate);
explicit WebTaskScheduler(nsIGlobalObject* aParent);
already_AddRefed<Promise> PostTask(SchedulerPostTaskCallback& aCallback,
const SchedulerPostTaskOptions& aOptions);
nsIGlobalObject* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override;
WebTask* GetNextTask() const;
void Disconnect();
void RunTaskSignalPriorityChange(TaskSignal* aTaskSignal);
protected:
virtual ~WebTaskScheduler() = default;
nsCOMPtr<nsIGlobalObject> mParent;
uint32_t mNextEnqueueOrder;
private:
already_AddRefed<WebTask> CreateTask(
WebTaskQueue& aQueue, const Optional<OwningNonNull<AbortSignal>>& aSignal,
SchedulerPostTaskCallback& aCallback, Promise* aPromise);
bool QueueTask(WebTask* aTask);
WebTaskQueue& SelectTaskQueue(
const Optional<OwningNonNull<AbortSignal>>& aSignal,
const Optional<TaskPriority>& aPriority);
virtual nsresult SetTimeoutForDelayedTask(WebTask* aTask,
uint64_t aDelay) = 0;
virtual bool DispatchEventLoopRunnable() = 0;
nsClassHashtable<nsUint32HashKey, WebTaskQueue> mStaticPriorityTaskQueues;
nsClassHashtable<nsPtrHashKey<TaskSignal>, WebTaskQueue>
mDynamicPriorityTaskQueues;
};
class DelayedWebTaskHandler final : public TimeoutHandler {
public:
DelayedWebTaskHandler(JSContext* aCx, WebTaskScheduler* aScheduler,
WebTask* aTask)
: TimeoutHandler(aCx), mScheduler(aScheduler), mWebTask(aTask) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(DelayedWebTaskHandler)
MOZ_CAN_RUN_SCRIPT bool Call(const char* /* unused */) override {
if (mScheduler && mWebTask) {
MOZ_ASSERT(!mWebTask->HasScheduled());
if (!mScheduler->QueueTask(mWebTask)) {
return false;
}
}
return true;
}
private:
~DelayedWebTaskHandler() override = default;
WeakPtr<WebTaskScheduler> mScheduler;
// WebTask gets added to WebTaskQueue, and WebTaskQueue keeps its alive.
WeakPtr<WebTask> mWebTask;
};
} // namespace mozilla::dom
#endif

View file

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/TaskController.h"
#include "mozilla/dom/TimeoutManager.h"
#include "nsContentUtils.h"
#include "WebTaskSchedulerMainThread.h"
namespace mozilla::dom {
NS_IMETHODIMP WebTaskMainThreadRunnable::Run() {
if (mScheduler) {
RefPtr<WebTask> task = mScheduler->GetNextTask();
if (task) {
task->Run();
}
}
return NS_OK;
}
nsresult WebTaskSchedulerMainThread::SetTimeoutForDelayedTask(WebTask* aTask,
uint64_t aDelay) {
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (!cx) {
return NS_ERROR_UNEXPECTED;
}
nsIGlobalObject* global = GetParentObject();
MOZ_ASSERT(global);
RefPtr<DelayedWebTaskHandler> handler =
new DelayedWebTaskHandler(cx, this, aTask);
int32_t delay = aDelay > INT32_MAX ? INT32_MAX : (int32_t)aDelay;
int32_t handle;
return global->AsInnerWindow()->TimeoutManager().SetTimeout(
handler, delay, /* aIsInterval */ false,
Timeout::Reason::eDelayedWebTaskTimeout, &handle);
}
bool WebTaskSchedulerMainThread::DispatchEventLoopRunnable() {
RefPtr<WebTaskMainThreadRunnable> runnable =
new WebTaskMainThreadRunnable(this);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThreadQueue(runnable.forget(),
EventQueuePriority::Normal));
return true;
}
} // namespace mozilla::dom

View file

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#ifndef mozilla_dom_WebSchedulerMainThread_h
#define mozilla_dom_WebSchedulerMainThread_h
#include "WebTaskScheduler.h"
#include "nsCycleCollectionParticipant.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/AbortFollower.h"
namespace mozilla::dom {
class WebTaskMainThreadRunnable final : public Runnable {
public:
explicit WebTaskMainThreadRunnable(WebTaskSchedulerMainThread* aScheduler)
: Runnable("WebTaskMainThreadRunnable"), mScheduler(aScheduler) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
private:
~WebTaskMainThreadRunnable() = default;
WeakPtr<WebTaskSchedulerMainThread> mScheduler;
};
class WebTaskSchedulerMainThread final : public WebTaskScheduler {
public:
explicit WebTaskSchedulerMainThread(nsIGlobalObject* aParent)
: WebTaskScheduler(aParent) {}
private:
nsresult SetTimeoutForDelayedTask(WebTask* aTask, uint64_t aDelay) override;
bool DispatchEventLoopRunnable() override;
~WebTaskSchedulerMainThread() = default;
};
} // namespace mozilla::dom
#endif

View file

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebTaskSchedulerWorker.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/TimeoutManager.h"
namespace mozilla::dom {
WebTaskWorkerRunnable::WebTaskWorkerRunnable(
WorkerPrivate* aWorkerPrivate, WebTaskSchedulerWorker* aSchedulerWorker)
: WorkerSameThreadRunnable(aWorkerPrivate),
mSchedulerWorker(aSchedulerWorker) {
MOZ_ASSERT(mSchedulerWorker);
}
WebTaskSchedulerWorker::WebTaskSchedulerWorker(WorkerPrivate* aWorkerPrivate)
: WebTaskScheduler(aWorkerPrivate->GlobalScope()),
mWorkerPrivate(aWorkerPrivate) {}
bool WebTaskWorkerRunnable::WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
if (mSchedulerWorker) {
RefPtr<WebTask> task = mSchedulerWorker->GetNextTask();
if (task) {
task->Run();
}
}
return true;
}
nsresult WebTaskSchedulerWorker::SetTimeoutForDelayedTask(WebTask* aTask,
uint64_t aDelay) {
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (!cx) {
return NS_ERROR_UNEXPECTED;
}
RefPtr<DelayedWebTaskHandler> handler =
new DelayedWebTaskHandler(cx, this, aTask);
ErrorResult rv;
int32_t delay = aDelay > INT32_MAX ? INT32_MAX : (int32_t)aDelay;
mWorkerPrivate->SetTimeout(cx, handler, delay,
/* aIsInterval */ false,
Timeout::Reason::eDelayedWebTaskTimeout, rv);
return rv.StealNSResult();
}
bool WebTaskSchedulerWorker::DispatchEventLoopRunnable() {
RefPtr<WebTaskWorkerRunnable> runnable =
new WebTaskWorkerRunnable(mWorkerPrivate, this);
return runnable->Dispatch();
}
} // namespace mozilla::dom

View file

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#ifndef mozilla_dom_WebTaskSchedulerWorker_h
#define mozilla_dom_WebTaskSchedulerWorker_h
#include "WebTaskScheduler.h"
#include "mozilla/LinkedList.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WebTaskSchedulingBinding.h"
namespace mozilla {
namespace dom {
class WebTaskWorkerRunnable : public WorkerSameThreadRunnable {
public:
WebTaskWorkerRunnable(WorkerPrivate* aWorkerPrivate,
WebTaskSchedulerWorker* aSchedulerWorker);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
private:
~WebTaskWorkerRunnable() = default;
WeakPtr<WebTaskSchedulerWorker> mSchedulerWorker;
};
class WebTaskSchedulerWorker final : public WebTaskScheduler {
public:
explicit WebTaskSchedulerWorker(WorkerPrivate* aWorkerPrivate);
private:
~WebTaskSchedulerWorker() = default;
nsresult SetTimeoutForDelayedTask(WebTask* aTask, uint64_t aDelay) override;
bool DispatchEventLoopRunnable() override;
CheckedUnsafePtr<WorkerPrivate> mWorkerPrivate;
};
} // namespace dom
} // namespace mozilla
#endif

View file

@ -0,0 +1,27 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Performance")
EXPORTS.mozilla.dom += [
"TaskSignal.h",
"WebTaskController.h",
"WebTaskScheduler.h",
"WebTaskSchedulerMainThread.h",
"WebTaskSchedulerWorker.h",
]
UNIFIED_SOURCES += [
"WebTaskController.cpp",
"WebTaskScheduler.cpp",
"WebTaskSchedulerMainThread.cpp",
"WebTaskSchedulerWorker.cpp",
]
include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = "xul"

View file

@ -52,6 +52,7 @@
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/WebTaskScheduler.h"
#include "mozilla/dom/JSExecutionManager.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/extensions/ExtensionBrowser.h" // extensions::Create{AndDispatchInitWorkerContext,WorkerLoaded,WorkerDestroyed}Runnable
@ -4591,10 +4592,15 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) {
// If the worker script never ran, or failed to compile, we don't need to do
// anything else.
if (!GlobalScope()) {
WorkerGlobalScope* global = GlobalScope();
if (!global) {
return true;
}
if (WebTaskScheduler* scheduler = global->GetExistingScheduler()) {
scheduler->Disconnect();
}
// Don't abort the script now, but we dispatch a runnable to do it when the
// current JS frame is executed.
if (aStatus == Closing) {
@ -4729,7 +4735,10 @@ int32_t WorkerPrivate::SetTimeout(JSContext* aCx, TimeoutHandler* aHandler,
newInfo->mOnChromeWorker = mIsChromeWorker;
newInfo->mIsInterval = aIsInterval;
newInfo->mId = timerId;
newInfo->AccumulateNestingLevel(data->mCurrentTimerNestingLevel);
if (newInfo->mReason == Timeout::Reason::eTimeoutOrInterval ||
newInfo->mReason == Timeout::Reason::eIdleCallbackTimeout) {
newInfo->AccumulateNestingLevel(data->mCurrentTimerNestingLevel);
}
if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
NS_WARNING("Timeout ids overflowed!");
@ -4872,14 +4881,25 @@ bool WorkerPrivate::RunExpiredTimeouts(JSContext* aCx) {
// break out of the loop.
RefPtr<TimeoutHandler> handler(info->mHandler);
if (info->mReason == Timeout::Reason::eTimeoutOrInterval) {
const char* reason;
if (info->mIsInterval) {
reason = "setInterval handler";
} else {
reason = "setTimeout handler";
}
const char* reason;
switch (info->mReason) {
case Timeout::Reason::eTimeoutOrInterval:
if (info->mIsInterval) {
reason = "setInterval handler";
} else {
reason = "setTimeout handler";
}
break;
case Timeout::Reason::eDelayedWebTaskTimeout:
reason = "delayedWebTask handler";
break;
default:
MOZ_ASSERT(info->mReason == Timeout::Reason::eAbortSignalTimeout);
reason = "AbortSignal Timeout";
}
if (info->mReason == Timeout::Reason::eTimeoutOrInterval ||
info->mReason == Timeout::Reason::eDelayedWebTaskTimeout) {
RefPtr<WorkerGlobalScope> scope(this->GlobalScope());
CallbackDebuggerNotificationGuard guard(
scope, info->mIsInterval
@ -4892,7 +4912,7 @@ bool WorkerPrivate::RunExpiredTimeouts(JSContext* aCx) {
}
} else {
MOZ_ASSERT(info->mReason == Timeout::Reason::eAbortSignalTimeout);
MOZ_ALWAYS_TRUE(handler->Call("AbortSignal timeout"));
MOZ_ALWAYS_TRUE(handler->Call(reason));
}
NS_ASSERTION(data->mRunningExpiredTimeouts, "Someone changed this!");

View file

@ -65,6 +65,7 @@
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/WebTaskSchedulerWorker.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SerializedStackHolder.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
@ -380,6 +381,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
WorkerGlobalScopeBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
@ -391,6 +393,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
WorkerGlobalScopeBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
if (tmp->mWebTaskScheduler) {
tmp->mWebTaskScheduler->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
@ -696,6 +702,21 @@ already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
return indexedDB.forget();
}
WebTaskScheduler* WorkerGlobalScope::Scheduler() {
mWorkerPrivate->AssertIsOnWorkerThread();
if (!mWebTaskScheduler) {
mWebTaskScheduler = WebTaskScheduler::CreateForWorker(mWorkerPrivate);
}
MOZ_ASSERT(mWebTaskScheduler);
return mWebTaskScheduler;
}
WebTaskScheduler* WorkerGlobalScope::GetExistingScheduler() const {
return mWebTaskScheduler;
}
already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
const ImageBitmapSource& aImage, const ImageBitmapOptions& aOptions,
ErrorResult& aRv) {

View file

@ -76,6 +76,8 @@ class WorkerLocation;
class WorkerNavigator;
class WorkerPrivate;
class VsyncWorkerChild;
class WebTaskScheduler;
class WebTaskSchedulerWorker;
struct RequestInit;
namespace cache {
@ -311,6 +313,9 @@ class WorkerGlobalScope : public WorkerGlobalScopeBase {
already_AddRefed<cache::CacheStorage> GetCaches(ErrorResult& aRv);
WebTaskScheduler* Scheduler();
WebTaskScheduler* GetExistingScheduler() const;
bool WindowInteractionAllowed() const;
void AllowWindowInteraction();
@ -346,6 +351,7 @@ class WorkerGlobalScope : public WorkerGlobalScopeBase {
RefPtr<IDBFactory> mIndexedDB;
RefPtr<cache::CacheStorage> mCacheStorage;
RefPtr<DebuggerNotificationManager> mDebuggerNotificationManager;
RefPtr<WebTaskSchedulerWorker> mWebTaskScheduler;
uint32_t mWindowInteractionsAllowed = 0;
};

View file

@ -277,12 +277,20 @@ var interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Response", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Scheduler", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "ServiceWorkerRegistration", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "StorageManager", fennec: false },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "SubtleCrypto" },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskController", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskPriorityChangeEvent", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TaskSignal", insecureContext: true, nightly: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TextDecoder", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "TextEncoder", insecureContext: true },

View file

@ -100,7 +100,7 @@ void APZTaskRunnable::QueueFlushCompleteNotification() {
mNeedsFlushCompleteNotification = true;
}
bool APZTaskRunnable::IsRegistereddWithCurrentPresShell() const {
bool APZTaskRunnable::IsRegisteredWithCurrentPresShell() const {
MOZ_ASSERT(mController);
uint32_t current = 0;
@ -111,7 +111,7 @@ bool APZTaskRunnable::IsRegistereddWithCurrentPresShell() const {
}
void APZTaskRunnable::EnsureRegisterAsEarlyRunner() {
if (IsRegistereddWithCurrentPresShell()) {
if (IsRegisteredWithCurrentPresShell()) {
return;
}

View file

@ -44,7 +44,7 @@ class APZTaskRunnable final : public Runnable {
private:
void EnsureRegisterAsEarlyRunner();
bool IsRegistereddWithCurrentPresShell() const;
bool IsRegisteredWithCurrentPresShell() const;
bool IsTestControllingRefreshesEnabled() const;
// Use a GeckoContentController raw pointer here since the owner of the

View file

@ -31,3 +31,20 @@ paint:
- mwoodrow@mozilla.com
expires: never
telemetry_mirror: PAINT_BUILD_DISPLAYLIST_TIME
wr:
rasterize_glyphs_time:
type: timing_distribution
description: >
The time to rasterize glyphs for consumption by WebRender.
time_unit: microsecond
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1728423
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1728423
data_sensitivity:
- technical
notification_emails:
- gfx-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: WR_RASTERIZE_GLYPHS_TIME

337
gfx/wr/Cargo.lock generated
View file

@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.0.4"
@ -64,6 +70,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "atty"
version = "0.2.14"
@ -200,6 +212,7 @@ dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"time",
"winapi",
]
@ -458,7 +471,7 @@ version = "0.99.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
]
@ -542,6 +555,32 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "ffi-support"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27838c6815cfe9de2d3aeb145ffd19e565f577414b33f3bdbf42fe040e9e0ff6"
dependencies = [
"lazy_static",
"log",
]
[[package]]
name = "flate2"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
dependencies = [
"cfg-if 1.0.0",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "fog"
version = "0.1.0"
[[package]]
name = "font-loader"
version = "0.11.0"
@ -570,6 +609,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "freetype"
version = "0.7.0"
@ -606,6 +655,17 @@ dependencies = [
"byteorder",
]
[[package]]
name = "getrandom"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
]
[[package]]
name = "gl_generator"
version = "0.13.1"
@ -646,6 +706,46 @@ dependencies = [
"gl_generator 0.14.0",
]
[[package]]
name = "glean"
version = "44.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4022e5a404be8c59f7a9649d60e907af954f5f02b736d1e58c71267b159eb1eb"
dependencies = [
"chrono",
"crossbeam-channel",
"glean-core",
"inherent",
"log",
"once_cell",
"serde",
"serde_json",
"thiserror",
"time",
"uuid",
"whatsys",
]
[[package]]
name = "glean-core"
version = "44.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bbdc6a097188ab24ba7e500b6a163fa8cf99a52c1630c240fd7a297a7271215"
dependencies = [
"bincode",
"chrono",
"ffi-support",
"flate2",
"log",
"once_cell",
"rkv",
"serde",
"serde_json",
"time",
"uuid",
"zeitstempel",
]
[[package]]
name = "glsl"
version = "4.0.3"
@ -760,6 +860,23 @@ dependencies = [
"quick-error",
]
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "image"
version = "0.23.3"
@ -783,6 +900,17 @@ dependencies = [
"adler32",
]
[[package]]
name = "inherent"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3974bf42c2050bbf0696471e4d91ecc9844845c2323b388aa7bf9d63f3b0693"
dependencies = [
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
]
[[package]]
name = "itoa"
version = "0.4.5"
@ -841,6 +969,29 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
[[package]]
name = "lmdb-rkv"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447a296f7aca299cfbb50f4e4f3d49451549af655fb7215d7f8c0c3d64bad42b"
dependencies = [
"bitflags",
"byteorder",
"libc",
"lmdb-rkv-sys",
]
[[package]]
name = "lmdb-rkv-sys"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b9ce6b3be08acefa3003c57b7565377432a89ec24476bbe72e11d101f852fe"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "lock_api"
version = "0.3.4"
@ -874,11 +1025,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e37c5d4cd9473c5f4c9c111f033f15d4df9bd378fdf615944e360a4f55a05f0b"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"syn",
"synstructure",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@ -916,6 +1073,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "647da2489d438eb707e9bcffe0e47fb6f3f355ed288120740fc1e614cfadb9e9"
[[package]]
name = "miniz_oxide"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [
"adler",
]
[[package]]
name = "mozangle"
version = "0.3.3"
@ -1011,6 +1177,12 @@ dependencies = [
"malloc_buf",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "ordered-float"
version = "1.0.2"
@ -1060,6 +1232,25 @@ dependencies = [
"winapi",
]
[[package]]
name = "paste"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
dependencies = [
"paste-impl",
"proc-macro-hack",
]
[[package]]
name = "paste-impl"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
dependencies = [
"proc-macro-hack",
]
[[package]]
name = "peek-poke"
version = "0.2.0"
@ -1072,7 +1263,7 @@ dependencies = [
name = "peek-poke-derive"
version = "0.2.1"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
"synstructure",
@ -1115,6 +1306,12 @@ dependencies = [
"inflate",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -1126,9 +1323,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.10"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid 0.2.0",
]
@ -1154,7 +1351,7 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
]
[[package]]
@ -1252,6 +1449,29 @@ version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
[[package]]
name = "rkv"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e2e15d3fff125cfc4fb3f1b226ff83af057c4715061ded16193b7142beefc9"
dependencies = [
"arrayref",
"bincode",
"bitflags",
"byteorder",
"id-arena",
"lazy_static",
"lmdb-rkv",
"log",
"ordered-float",
"paste",
"serde",
"serde_derive",
"thiserror",
"url",
"uuid",
]
[[package]]
name = "ron"
version = "0.7.0"
@ -1358,7 +1578,7 @@ version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
]
@ -1473,11 +1693,11 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.17"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"quote 1.0.3",
"unicode-xid 0.2.0",
]
@ -1488,7 +1708,7 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.10",
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
"unicode-xid 0.2.0",
@ -1512,6 +1732,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2 1.0.36",
"quote 1.0.3",
"syn",
]
[[package]]
name = "thread_local"
version = "1.0.1"
@ -1532,6 +1772,21 @@ dependencies = [
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tracy-rs"
version = "0.1.2"
@ -1541,6 +1796,21 @@ dependencies = [
"minidl",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
@ -1559,6 +1829,27 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "vec_map"
version = "0.8.1"
@ -1668,9 +1959,11 @@ dependencies = [
"dwrote",
"etagere",
"euclid",
"fog",
"freetype",
"fxhash",
"gleam 0.13.1",
"glean",
"glslopt",
"lazy_static",
"libc",
@ -1738,6 +2031,17 @@ dependencies = [
"serde",
]
[[package]]
name = "whatsys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c24fff5aa1e0973964ba23a995e8b10fa2cdeae507e0cbbbd36f8403242a765d"
dependencies = [
"cc",
"cfg-if 1.0.0",
"libc",
]
[[package]]
name = "winapi"
version = "0.3.8"
@ -1880,3 +2184,14 @@ checksum = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zeitstempel"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeea3eb6a30ed24e374f59368d3917c5180a845fdd4ed6f1b2278811a9e826f8"
dependencies = [
"cfg-if 1.0.0",
"libc",
"once_cell",
]

View file

@ -30,3 +30,4 @@ opt-level = 2
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" }

9
gfx/wr/fog/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "fog"
version = "0.1.0"
edition = "2018"
license = "MPL-2.0"
# This is a dummy crate for non-gecko builds.
[dependencies]

7
gfx/wr/fog/src/main.rs Normal file
View file

@ -0,0 +1,7 @@
/* 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/. */
fn main() {
println!("Hello, world!");
}

View file

@ -18,7 +18,7 @@ display_list_stats = ["api/display_list_stats"]
serialize_program = ["serde", "webrender_build/serialize_program"]
no_static_freetype = []
leak_checks = []
gecko = []
gecko = ["fog"]
sw_compositor = ["swgl"]
[build-dependencies]
@ -51,6 +51,8 @@ svg_fmt = "0.4"
tracy-rs = "0.1.2"
derive_more = "0.99"
etagere = "0.2.6"
glean = "44.0.0"
fog = { version = "0.1.0", optional = true }
swgl = { path = "../swgl", optional = true }
[dev-dependencies]

View file

@ -60,7 +60,7 @@ impl ApiResources {
ResourceUpdate::AddBlobImage(ref img) => {
self.blob_image_handler
.as_mut()
.unwrap()
.expect("no blob image handler")
.add(img.key, Arc::clone(&img.data), &img.visible_rect, img.tile_size);
self.blob_image_templates.insert(
@ -166,8 +166,11 @@ impl ApiResources {
visible_rect: &DeviceIntRect,
) {
if let Some(data) = data {
let dirty_rect = dirty_rect.unwrap();
self.blob_image_handler.as_mut().unwrap().update(key, data, visible_rect, dirty_rect);
let dirty_rect = dirty_rect.expect("no dirty rect");
self.blob_image_handler
.as_mut()
.expect("no blob image handler")
.update(key, data, visible_rect, dirty_rect);
}
let image = self.blob_image_templates
@ -218,7 +221,8 @@ impl ApiResources {
let mut blob_request_params = Vec::new();
for key in keys {
let template = self.blob_image_templates.get_mut(key).unwrap();
let template = self.blob_image_templates.get_mut(key)
.expect("no blob image template");
// If we know that only a portion of the blob image is in the viewport,
// only request these visible tiles since blob images can be huge.
@ -270,7 +274,8 @@ impl ApiResources {
template.valid_tiles_after_bounds_change = None;
}
let handler = self.blob_image_handler.as_mut().unwrap();
let handler = self.blob_image_handler.as_mut()
.expect("no blob image handler");
handler.prepare_resources(&self.fonts, &blob_request_params);
(Some(handler.create_blob_rasterizer()), blob_request_params)
}

View file

@ -20,6 +20,7 @@ use crate::resource_cache::CachedImageData;
use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
use crate::gpu_cache::GpuCache;
use crate::profiler::{self, TransactionProfile};
use crate::telemetry::Telemetry;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use rayon::ThreadPool;
use rayon::prelude::*;
@ -227,6 +228,7 @@ impl GlyphRasterizer {
profile: &mut TransactionProfile,
) {
profile.start_time(profiler::GLYPH_RESOLVE_TIME);
let timer_id = Telemetry::start_rasterize_glyphs_time();
// Work around the borrow checker, since we call flush_glyph_requests below
let mut pending_glyph_requests = mem::replace(
@ -314,6 +316,7 @@ impl GlyphRasterizer {
// we can schedule removing the fonts if needed.
self.remove_dead_fonts();
Telemetry::stop_and_accumulate_rasterize_glyphs_time(timer_id);
profile.end_time(profiler::GLYPH_RESOLVE_TIME);
}
}

View file

@ -74,6 +74,7 @@ extern crate svg_fmt;
#[macro_use]
mod profiler;
mod telemetry;
mod batch;
mod border;

View file

@ -5747,17 +5747,28 @@ impl PicturePrimitive {
Some(parent_surface_index) => {
let parent_surface = &surfaces[parent_surface_index.0];
let local_to_surface_scale_factors = frame_context
let local_to_surface = frame_context
.spatial_tree
.get_relative_transform(
surface_spatial_node_index,
parent_surface.surface_spatial_node_index,
)
.scale_factors();
);
// Since we can't determine reasonable scale factors for transforms
// with perspective, just use a scale of (1,1) for now, which is
// what Gecko does when it choosed to supplies a scale factor anyway.
// In future, we might be able to improve the quality here by taking
// into account the screen rect after clipping, but for now this gives
// better results than just taking the matrix scale factors.
let scale_factors = if local_to_surface.is_perspective() {
(1.0, 1.0)
} else {
local_to_surface.scale_factors()
};
(
local_to_surface_scale_factors.0 * parent_surface.world_scale_factors.0,
local_to_surface_scale_factors.1 * parent_surface.world_scale_factors.1,
scale_factors.0 * parent_surface.world_scale_factors.0,
scale_factors.1 * parent_surface.world_scale_factors.1,
)
}
None => {

View file

@ -1254,9 +1254,11 @@ impl RenderApi {
&mut self.scene_sender
};
sender.send(SceneBuilderRequest::Transactions(vec![transaction])).unwrap();
sender.send(SceneBuilderRequest::Transactions(vec![transaction]))
.expect("send by scene sender failed");
} else {
self.api_sender.send(ApiMsg::UpdateDocuments(vec![transaction])).unwrap();
self.api_sender.send(ApiMsg::UpdateDocuments(vec![transaction]))
.expect("send by api sender failed");
}
}

View file

@ -0,0 +1,24 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use glean::TimerId;
#[cfg(feature = "gecko")]
use fog::metrics::wr;
pub struct Telemetry;
/// Defines the interface for hooking up an external telemetry reporter to WR.
#[cfg(not(feature = "gecko"))]
impl Telemetry {
// Start rasterize glyph time collection
pub fn start_rasterize_glyphs_time() -> TimerId { return 0; }
// End rasterize glyph time collection
pub fn stop_and_accumulate_rasterize_glyphs_time(_id: TimerId) { }
}
#[cfg(feature = "gecko")]
impl Telemetry {
pub fn start_rasterize_glyphs_time() -> TimerId { wr::rasterize_glyphs_time.start() }
pub fn stop_and_accumulate_rasterize_glyphs_time(id: TimerId) { wr::rasterize_glyphs_time.stop_and_accumulate(id); }
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before After
Before After

View file

@ -81,7 +81,7 @@ fuzzy(1,15) platform(linux) force_subpixel_aa_where_possible(false) == text-fixe
# most pixels are off by a small amount, but a few pixels on the edge vary by a lot, pushing up the fuzzy max-diff;
# the main goal of the test is that everything is in the same place, at the same scale, clipped the same way,
# despite 4x on-the-fly scale change.
skip_on(android) fuzzy(220,7600) == raster_root_C_8192.yaml raster_root_C_ref.yaml
skip_on(android) fuzzy(110,20200) == raster_root_C_8192.yaml raster_root_C_ref.yaml
== subpx-bg-mask.yaml subpx-bg-mask-ref.yaml
platform(linux,mac) == rotate-snap-clip.yaml rotate-snap-clip-ref.yaml
platform(linux,mac) == rotate-snap-filter.yaml rotate-snap-filter-ref.yaml

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -0,0 +1,14 @@
# Verify that we select a reasonable scale factor for perspective surfaces that don't
# have a requested scale factor supplied by the caller (based on projected screen rect)
root:
items:
- type: "stacking-context"
perspective: 1000
transform-style: preserve-3d
items:
- type: "stacking-context"
transform-origin: 175 175
transform: rotate-x(-20) rotate-y(20)
items:
- image: checkerboard(2, 22, 16)
bounds: [0, 0, 350, 350]

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