Update On Fri Apr 22 20:36:49 CEST 2022
This commit is contained in:
parent
c26e94f90b
commit
d993c2304a
568 changed files with 7519 additions and 2953 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -5793,9 +5793,11 @@ dependencies = [
|
|||
"dwrote",
|
||||
"etagere",
|
||||
"euclid",
|
||||
"fog",
|
||||
"freetype",
|
||||
"fxhash",
|
||||
"gleam",
|
||||
"glean",
|
||||
"glslopt",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 }
|
||||
);
|
||||
|
|
|
@ -92,7 +92,7 @@ const PluginManager = {
|
|||
}
|
||||
|
||||
let { pluginDumpID } = report;
|
||||
CrashSubmit.submit(pluginDumpID, {
|
||||
CrashSubmit.submit(pluginDumpID, CrashSubmit.SUBMITTED_FROM_CRASH_TAB, {
|
||||
recordSubmission: true,
|
||||
extraExtraKeyVals: keyVals,
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)`
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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)`
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
Don’t 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class Timeout final : protected LinkedListElement<RefPtr<Timeout>> {
|
|||
eTimeoutOrInterval,
|
||||
eIdleCallbackTimeout,
|
||||
eAbortSignalTimeout,
|
||||
eDelayedWebTaskTimeout,
|
||||
};
|
||||
|
||||
struct TimeoutIdAndReason {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 "";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
39
dom/html/test/file_fullscreen-resize.html
Normal file
39
dom/html/test/file_fullscreen-resize.html
Normal 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>
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -111,6 +111,7 @@ DIRS += [
|
|||
"prio",
|
||||
"l10n",
|
||||
"origin-trials",
|
||||
"webscheduling",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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(
|
||||
|
|
9
dom/webidl/TaskPriorityChangeEvent.webidl
Normal file
9
dom/webidl/TaskPriorityChangeEvent.webidl
Normal 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;
|
||||
};
|
42
dom/webidl/WebTaskScheduling.webidl
Normal file
42
dom/webidl/WebTaskScheduling.webidl
Normal 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);
|
||||
};
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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",
|
||||
|
|
63
dom/webscheduling/TaskSignal.h
Normal file
63
dom/webscheduling/TaskSignal.h
Normal 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
|
70
dom/webscheduling/WebTaskController.cpp
Normal file
70
dom/webscheduling/WebTaskController.cpp
Normal 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
|
35
dom/webscheduling/WebTaskController.h
Normal file
35
dom/webscheduling/WebTaskController.h
Normal 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
|
350
dom/webscheduling/WebTaskScheduler.cpp
Normal file
350
dom/webscheduling/WebTaskScheduler.cpp
Normal 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
|
172
dom/webscheduling/WebTaskScheduler.h
Normal file
172
dom/webscheduling/WebTaskScheduler.h
Normal 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
|
54
dom/webscheduling/WebTaskSchedulerMainThread.cpp
Normal file
54
dom/webscheduling/WebTaskSchedulerMainThread.cpp
Normal 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
|
42
dom/webscheduling/WebTaskSchedulerMainThread.h
Normal file
42
dom/webscheduling/WebTaskSchedulerMainThread.h
Normal 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
|
59
dom/webscheduling/WebTaskSchedulerWorker.cpp
Normal file
59
dom/webscheduling/WebTaskSchedulerWorker.cpp
Normal 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
|
48
dom/webscheduling/WebTaskSchedulerWorker.h
Normal file
48
dom/webscheduling/WebTaskSchedulerWorker.h
Normal 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
|
27
dom/webscheduling/moz.build
Normal file
27
dom/webscheduling/moz.build
Normal 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"
|
|
@ -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!");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
337
gfx/wr/Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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
9
gfx/wr/fog/Cargo.toml
Normal 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
7
gfx/wr/fog/src/main.rs
Normal 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!");
|
||||
}
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ extern crate svg_fmt;
|
|||
|
||||
#[macro_use]
|
||||
mod profiler;
|
||||
mod telemetry;
|
||||
|
||||
mod batch;
|
||||
mod border;
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
gfx/wr/webrender/src/telemetry.rs
Normal file
24
gfx/wr/webrender/src/telemetry.rs
Normal 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 |
Binary file not shown.
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -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
|
||||
|
|
BIN
gfx/wr/wrench/reftests/transforms/perspective-surface-scale.png
Normal file
BIN
gfx/wr/wrench/reftests/transforms/perspective-surface-scale.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue