Update On Tue Nov 7 19:41:39 CET 2023
This commit is contained in:
parent
3592b09145
commit
947dc8afa6
612 changed files with 27105 additions and 16510 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -235,22 +235,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "audio_thread_priority"
|
||||
version = "0.26.1"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7cd1bfd03dab20ad72e0c5e58d65818d62c0d199d8dec8361053d0f073dbae"
|
||||
checksum = "a7e6839a6e8e72338137b3126c7fe61af95b9acc3076d2b7109696f808d1234f"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.999",
|
||||
"cfg-if 1.0.0",
|
||||
"dbus",
|
||||
"libc",
|
||||
"log",
|
||||
"mach",
|
||||
"winapi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "audioipc2"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=ec6af6ecf8ba50b51f13d18f417de8cfb8460543#ec6af6ecf8ba50b51f13d18f417de8cfb8460543"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=6be424d75f1367e70f2f5ddcacd6d0237e81a6a9#6be424d75f1367e70f2f5ddcacd6d0237e81a6a9"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ashmem",
|
||||
|
@ -278,7 +278,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "audioipc2-client"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=ec6af6ecf8ba50b51f13d18f417de8cfb8460543#ec6af6ecf8ba50b51f13d18f417de8cfb8460543"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=6be424d75f1367e70f2f5ddcacd6d0237e81a6a9#6be424d75f1367e70f2f5ddcacd6d0237e81a6a9"
|
||||
dependencies = [
|
||||
"audio_thread_priority",
|
||||
"audioipc2",
|
||||
|
@ -289,7 +289,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "audioipc2-server"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=ec6af6ecf8ba50b51f13d18f417de8cfb8460543#ec6af6ecf8ba50b51f13d18f417de8cfb8460543"
|
||||
source = "git+https://github.com/mozilla/audioipc?rev=6be424d75f1367e70f2f5ddcacd6d0237e81a6a9#6be424d75f1367e70f2f5ddcacd6d0237e81a6a9"
|
||||
dependencies = [
|
||||
"audio_thread_priority",
|
||||
"audioipc2",
|
||||
|
|
|
@ -248,6 +248,11 @@ CachedTableCellAccessible* CachedTableCellAccessible::GetFrom(
|
|||
if (auto cellIdx = cachedTable->mAccToCellIdx.Lookup(aAcc)) {
|
||||
return &cachedTable->mCells[*cellIdx];
|
||||
}
|
||||
// We found a table, but it doesn't know about this cell. This can happen
|
||||
// if a cell is outside of a row due to authoring error. We must not search
|
||||
// ancestor tables, since this cell's data is not valid there and vice
|
||||
// versa.
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -400,6 +400,13 @@ MARKUPMAP(
|
|||
// A <tr> within a row isn't valid.
|
||||
return nullptr;
|
||||
}
|
||||
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement);
|
||||
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
|
||||
roleMapEntry->role != roles::ROW) {
|
||||
// There is a valid ARIA role which isn't "row". Don't treat this as an
|
||||
// HTML table row.
|
||||
return nullptr;
|
||||
}
|
||||
// Check if this <tr> is within a table. We check the grandparent because
|
||||
// it might be inside a rowgroup. We don't specifically check for an HTML
|
||||
// table because there are cases where there is a <tr> inside a
|
||||
|
|
|
@ -321,12 +321,17 @@ LayoutDeviceIntPoint nsAccUtils::GetScreenCoordsForParent(
|
|||
|
||||
LayoutDeviceIntPoint nsAccUtils::GetScreenCoordsForWindow(
|
||||
Accessible* aAccessible) {
|
||||
LayoutDeviceIntPoint coords(0, 0);
|
||||
a11y::LocalAccessible* localAcc = aAccessible->AsLocal();
|
||||
if (!localAcc) {
|
||||
localAcc = aAccessible->AsRemote()->OuterDocOfRemoteBrowser();
|
||||
if (!localAcc) {
|
||||
// This could be null if the tab is closing but the document is still
|
||||
// being shut down.
|
||||
return coords;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutDeviceIntPoint coords(0, 0);
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(
|
||||
nsCoreUtils::GetDocShellFor(localAcc->GetNode()));
|
||||
if (!treeItem) return coords;
|
||||
|
|
|
@ -2644,6 +2644,7 @@ void DocAccessible::UncacheChildrenInSubtree(LocalAccessible* aRoot) {
|
|||
}
|
||||
|
||||
void DocAccessible::ShutdownChildrenInSubtree(LocalAccessible* aAccessible) {
|
||||
MOZ_ASSERT(!nsAccessibilityService::IsShutdown());
|
||||
// Traverse through children and shutdown them before this accessible. When
|
||||
// child gets shutdown then it removes itself from children array of its
|
||||
// parent. Use jdx index to process the cases if child is not attached to the
|
||||
|
@ -2658,7 +2659,16 @@ void DocAccessible::ShutdownChildrenInSubtree(LocalAccessible* aAccessible) {
|
|||
|
||||
// Don't cross document boundaries. The outerdoc shutdown takes care about
|
||||
// its subdocument.
|
||||
if (!child->IsDoc()) ShutdownChildrenInSubtree(child);
|
||||
if (!child->IsDoc()) {
|
||||
ShutdownChildrenInSubtree(child);
|
||||
if (nsAccessibilityService::IsShutdown()) {
|
||||
// If XPCOM is the only consumer (devtools & mochitests), shutting down
|
||||
// the child's subtree can cause a11y to shut down because the last
|
||||
// xpcom accessibles will be removed. In that case, return early, our
|
||||
// work is done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnbindFromDocument(aAccessible);
|
||||
|
|
|
@ -637,3 +637,29 @@ addAccessibleTask(
|
|||
},
|
||||
{ chrome: true, topLevel: true, remoteIframe: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Verify that we don't crash for authoring error like <tr role="grid">.
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
<table id="table">
|
||||
<tr><th>a</th></tr>
|
||||
<tr role="grid"><td id="b">b</td></tr>
|
||||
</table>
|
||||
`,
|
||||
async function (browser, docAcc) {
|
||||
const table = findAccessibleChildByID(docAcc, "table", [
|
||||
nsIAccessibleTable,
|
||||
]);
|
||||
is(table.rowCount, 1, "table rowCount correct");
|
||||
is(table.columnCount, 1, "table columnCount correct");
|
||||
const b = findAccessibleChildByID(docAcc, "b");
|
||||
let queryOk = false;
|
||||
try {
|
||||
b.QueryInterface(nsIAccessibleTableCell);
|
||||
queryOk = true;
|
||||
} catch (e) {}
|
||||
ok(!queryOk, "No nsIAccessibleTableCell on invalid cell b");
|
||||
}
|
||||
);
|
||||
|
|
|
@ -383,6 +383,7 @@ var gIdentityHandler = {
|
|||
},
|
||||
_isSchemelessHttpsFirstModeActive(isWindowPrivate) {
|
||||
return (
|
||||
!this._isHttpsOnlyModeActive(isWindowPrivate) &&
|
||||
!this._isHttpsFirstModeActive(isWindowPrivate) &&
|
||||
this._schemelessHttpsFirstModeEnabled
|
||||
);
|
||||
|
|
|
@ -599,7 +599,7 @@
|
|||
</panel>
|
||||
</html:template>
|
||||
|
||||
#include ../../../toolkit/components/pictureinpicture/content/pictureInPicturePanel.xhtml
|
||||
#include ../../../toolkit/components/pictureinpicture/content/pictureInPicturePanel.inc.xhtml
|
||||
|
||||
<menupopup id="unified-extensions-context-menu"
|
||||
onpopupshowing="gUnifiedExtensions.updateContextMenu(this, event)"
|
||||
|
|
|
@ -270,7 +270,7 @@ add_task(async function test_devtools_network_on_request_finished() {
|
|||
]);
|
||||
|
||||
ok(
|
||||
callbackRes[0].startsWith("<html>"),
|
||||
callbackRes[0].startsWith("<!DOCTYPE html>"),
|
||||
"The expected content has been retrieved."
|
||||
);
|
||||
is(
|
||||
|
|
|
@ -7,6 +7,7 @@ const lazy = {};
|
|||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
|
||||
PlacesUIUtils: "resource:///modules/PlacesUIUtils.sys.mjs",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
|
||||
});
|
||||
|
||||
ChromeUtils.defineLazyGetter(lazy, "relativeTimeFormat", () => {
|
||||
|
@ -100,3 +101,49 @@ export function onToggleContainer(detailsContainer) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function doesn't just copy the link to the clipboard, it creates a
|
||||
* URL object on the clipboard, so when it's pasted into an application that
|
||||
* supports it, it displays the title as a link.
|
||||
*/
|
||||
export function placeLinkOnClipboard(title, uri) {
|
||||
let node = {
|
||||
type: 0,
|
||||
title,
|
||||
uri,
|
||||
};
|
||||
|
||||
// Copied from doCommand/placesCmd_copy in PlacesUIUtils.sys.mjs
|
||||
|
||||
// This is a little hacky, but there is a lot of code in Places that handles
|
||||
// clipboard stuff, so it's easier to reuse.
|
||||
|
||||
// This order is _important_! It controls how this and other applications
|
||||
// select data to be inserted based on type.
|
||||
let contents = [
|
||||
{ type: lazy.PlacesUtils.TYPE_X_MOZ_URL, entries: [] },
|
||||
{ type: lazy.PlacesUtils.TYPE_HTML, entries: [] },
|
||||
{ type: lazy.PlacesUtils.TYPE_PLAINTEXT, entries: [] },
|
||||
];
|
||||
|
||||
contents.forEach(function (content) {
|
||||
content.entries.push(lazy.PlacesUtils.wrapNode(node, content.type));
|
||||
});
|
||||
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
xferable.init(null);
|
||||
|
||||
function addData(type, data) {
|
||||
xferable.addDataFlavor(type);
|
||||
xferable.setTransferData(type, lazy.PlacesUtils.toISupportsString(data));
|
||||
}
|
||||
|
||||
contents.forEach(function (content) {
|
||||
addData(content.type, content.entries.join(lazy.PlacesUtils.endl));
|
||||
});
|
||||
|
||||
Services.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,7 @@ import "chrome://browser/content/firefoxview/fxview-empty-state.mjs";
|
|||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import "chrome://browser/content/firefoxview/fxview-tab-list.mjs";
|
||||
|
||||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
|
||||
});
|
||||
import { placeLinkOnClipboard } from "./helpers.mjs";
|
||||
|
||||
export class ViewPage extends MozLitElement {
|
||||
static get properties() {
|
||||
|
@ -75,52 +71,8 @@ export class ViewPage extends MozLitElement {
|
|||
return window.browsingContext.embedderWindowGlobal.browsingContext.window;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function doesn't just copy the link to the clipboard, it creates a
|
||||
* URL object on the clipboard, so when it's pasted into an application that
|
||||
* supports it, it displays the title as a link.
|
||||
*/
|
||||
copyLink(e) {
|
||||
// Copied from doCommand/placesCmd_copy in PlacesUIUtils.sys.mjs
|
||||
|
||||
// This is a little hacky, but there is a lot of code in Places that handles
|
||||
// clipboard stuff, so it's easier to reuse.
|
||||
let node = {};
|
||||
node.type = 0;
|
||||
node.title = this.triggerNode.title;
|
||||
node.uri = this.triggerNode.url;
|
||||
|
||||
// This order is _important_! It controls how this and other applications
|
||||
// select data to be inserted based on type.
|
||||
let contents = [
|
||||
{ type: lazy.PlacesUtils.TYPE_X_MOZ_URL, entries: [] },
|
||||
{ type: lazy.PlacesUtils.TYPE_HTML, entries: [] },
|
||||
{ type: lazy.PlacesUtils.TYPE_PLAINTEXT, entries: [] },
|
||||
];
|
||||
|
||||
contents.forEach(function (content) {
|
||||
content.entries.push(lazy.PlacesUtils.wrapNode(node, content.type));
|
||||
});
|
||||
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
xferable.init(null);
|
||||
|
||||
function addData(type, data) {
|
||||
xferable.addDataFlavor(type);
|
||||
xferable.setTransferData(type, lazy.PlacesUtils.toISupportsString(data));
|
||||
}
|
||||
|
||||
contents.forEach(function (content) {
|
||||
addData(content.type, content.entries.join(lazy.PlacesUtils.endl));
|
||||
});
|
||||
|
||||
Services.clipboard.setData(
|
||||
xferable,
|
||||
null,
|
||||
Ci.nsIClipboard.kGlobalClipboard
|
||||
);
|
||||
placeLinkOnClipboard(this.triggerNode.title, this.triggerNode.url);
|
||||
this.recordContextMenuTelemetry("copy-link", e);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
"test/browser/telemetry/browser.toml",
|
||||
]
|
||||
|
||||
MARIONETTE_LAYOUT_MANIFESTS += ["test/marionette/manifest.ini"]
|
||||
MARIONETTE_UNIT_MANIFESTS += ["test/marionette/manifest.ini"]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ["test/unit/xpcshell.ini"]
|
||||
|
||||
|
|
|
@ -129,12 +129,12 @@ export class ShoppingSidebarChild extends RemotePageChild {
|
|||
break;
|
||||
case "AdClicked":
|
||||
aid = event.detail.aid;
|
||||
this.#product.sendAttributionEvent("click", aid);
|
||||
ShoppingProduct.sendAttributionEvent("click", aid);
|
||||
Glean.shopping.surfaceAdsClicked.record();
|
||||
break;
|
||||
case "AdImpression":
|
||||
aid = event.detail.aid;
|
||||
this.#product.sendAttributionEvent("impression", aid);
|
||||
ShoppingProduct.sendAttributionEvent("impression", aid);
|
||||
Glean.shopping.surfaceAdsImpression.record();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { html } from "lit.all.mjs";
|
||||
// Imported for side-effects.
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import "toolkit-widgets/message-bar.js";
|
||||
|
||||
const MESSAGE_TYPES = {
|
||||
default: "",
|
||||
success: "success",
|
||||
error: "error",
|
||||
warning: "warning",
|
||||
};
|
||||
|
||||
export default {
|
||||
title: "UI Widgets/Message Bar",
|
||||
component: "message-bar",
|
||||
argTypes: {
|
||||
type: {
|
||||
options: Object.keys(MESSAGE_TYPES),
|
||||
mapping: MESSAGE_TYPES,
|
||||
control: { type: "select" },
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
status: "stable",
|
||||
fluent: `
|
||||
message-bar-text = A very expressive and slightly whimsical message goes here.
|
||||
message-bar-button = Click me, please!
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
const Template = ({ dismissable, type }) =>
|
||||
html`
|
||||
<message-bar type=${type} ?dismissable=${dismissable}>
|
||||
<span data-l10n-id="message-bar-text"></span>
|
||||
<button data-l10n-id="message-bar-button"></button>
|
||||
</message-bar>
|
||||
`;
|
||||
|
||||
export const Basic = Template.bind({});
|
||||
Basic.args = { type: "", dismissable: false };
|
||||
|
||||
export const Dismissable = Template.bind({});
|
||||
Dismissable.args = { type: "", dismissable: true };
|
|
@ -339,7 +339,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "24d6bd9eb91d63ed6a97e0ae32fe8e5cf1da0def"
|
||||
"revision": "24d70e9a9639a372e8e1e9d1647a49ce64094b9e"
|
||||
},
|
||||
"da": {
|
||||
"pin": false,
|
||||
|
@ -357,7 +357,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "ba8e876d8af866bf86941079402a109e29fa7be6"
|
||||
"revision": "0c11157c7f8e8e65ba1e148dbfc3ccc1a28e04fa"
|
||||
},
|
||||
"de": {
|
||||
"pin": false,
|
||||
|
@ -1011,7 +1011,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "e1937b0c052a740cd041aaffcd24b301e452aef8"
|
||||
"revision": "5eb85e45234ed6ba98f4fb463b4337d98e9351ce"
|
||||
},
|
||||
"kab": {
|
||||
"pin": false,
|
||||
|
@ -1623,7 +1623,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "3bdb6d8d01da0f46905c0ae96d9596f1ee3bd6a5"
|
||||
"revision": "13d670a9b7a0c71a73e13893f407036cbb211c2f"
|
||||
},
|
||||
"sl": {
|
||||
"pin": false,
|
||||
|
|
|
@ -53,17 +53,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Align the favicons and titles of rows with standard 16px icons with those
|
||||
of rich suggestions. */
|
||||
/* stylelint-disable-next-line media-query-no-invalid */
|
||||
@media (-moz-bool-pref: "browser.urlbar.richSuggestions.featureGate") {
|
||||
.urlbarView-row:not([rich-suggestion]),
|
||||
.urlbarView-row[rich-suggestion][icon-size="16"] {
|
||||
--urlbarView-icon-margin-start: calc((var(--urlbarView-rich-suggestion-default-icon-size) - 16px) / 2);
|
||||
--urlbarView-icon-margin-end: calc(var(--urlbar-icon-padding) + var(--identity-box-margin-inline) + ((var(--urlbarView-rich-suggestion-default-icon-size) - 16px) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
.urlbarView {
|
||||
/* Don't handle window drag events in case we are overlapping a toolbar */
|
||||
-moz-window-dragging: no-drag;
|
||||
|
@ -99,6 +88,17 @@
|
|||
.urlbarView-row {
|
||||
--urlbarView-second-line-indent: calc(var(--urlbarView-icon-margin-start) + var(--urlbarView-icon-margin-end) + var(--urlbarView-favicon-width));
|
||||
|
||||
/* Align the favicons and titles of rows with standard 16px icons with those
|
||||
of rich suggestions. */
|
||||
/* stylelint-disable-next-line media-query-no-invalid */
|
||||
@media (-moz-bool-pref: "browser.urlbar.richSuggestions.featureGate") {
|
||||
&:not([rich-suggestion]),
|
||||
&[rich-suggestion][icon-size="16"] {
|
||||
--urlbarView-icon-margin-start: calc((var(--urlbarView-rich-suggestion-default-icon-size) - 16px) / 2);
|
||||
--urlbarView-icon-margin-end: calc(var(--urlbar-icon-padding) + var(--identity-box-margin-inline) + ((var(--urlbarView-rich-suggestion-default-icon-size) - 16px) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
fill: currentColor;
|
||||
|
|
|
@ -653,7 +653,6 @@ _ZN4uuid6parser28_$LT$impl$u20$uuid..Uuid$GT$9parse_str17hef8066f10442e30fE
|
|||
?s_HashKey@?$nsTHashtable@V?$nsBaseHashtableET@VnsStringHashKey@@PAUMiscContainer@@@@@@KAIPBX@Z
|
||||
?s_MatchEntry@?$nsTHashtable@V?$nsBaseHashtableET@VnsStringHashKey@@V?$UniquePtr@URawServoSelectorList@@V?$DefaultDelete@URawServoSelectorList@@@mozilla@@@mozilla@@@@@@KA_NPBUPLDHashEntryHdr@@PBX@Z
|
||||
?GetOrCreate@nsRFPService@mozilla@@SAPAV12@XZ
|
||||
?OnComplete@LoginReputationParent@dom@mozilla@@UAG?AW4nsresult@@W44@I@Z
|
||||
?GetSpoofedPresentedFrames@nsRFPService@mozilla@@SAINII@Z
|
||||
?Release@nsUUIDGenerator@@UAGKXZ
|
||||
??0AutoSuppressEventHandlingAndSuspend@dom@mozilla@@QAE@PAVBrowsingContextGroup@12@@Z
|
||||
|
|
|
@ -658,7 +658,6 @@ ZN4uuid6parser28_$LT$impl$u20$uuid..Uuid$GT$9parse_str17hd6e937141c32aa4eE
|
|||
?DetermineOffsetFromReference@?$RangeBoundaryBase@V?$nsCOMPtr@VnsINode@@@@V?$nsCOMPtr@VnsIContent@@@@@mozilla@@AEBAXXZ
|
||||
?s_HashKey@?$nsTHashtable@V?$nsBaseHashtableET@VnsStringHashKey@@PEAUMiscContainer@@@@@@KAIPEBX@Z
|
||||
?GetOrCreate@nsRFPService@mozilla@@SAPEAV12@XZ
|
||||
?OnComplete@LoginReputationParent@dom@mozilla@@UEAA?AW4nsresult@@W44@I@Z
|
||||
?GetSpoofedPresentedFrames@nsRFPService@mozilla@@SAINII@Z
|
||||
?Release@nsUUIDGenerator@@UEAAKXZ
|
||||
??0AutoSuppressEventHandlingAndSuspend@dom@mozilla@@QEAA@PEAVBrowsingContextGroup@12@@Z
|
||||
|
|
|
@ -10,7 +10,6 @@ add_task(async function () {
|
|||
await pushPref("browser.safebrowsing.blockedURIs.enabled", false);
|
||||
await pushPref("browser.safebrowsing.downloads.enabled", false);
|
||||
await pushPref("browser.safebrowsing.malware.enabled", false);
|
||||
await pushPref("browser.safebrowsing.passwords.enabled", false);
|
||||
await pushPref("browser.safebrowsing.phishing.enabled", false);
|
||||
await pushPref("privacy.query_stripping.enabled", false);
|
||||
await pushPref("extensions.systemAddon.update.enabled", false);
|
||||
|
|
|
@ -64,6 +64,7 @@ support-files = [
|
|||
"test-console-stacktrace-mapped.html",
|
||||
"test-console-table.html",
|
||||
"test-console-workers.html",
|
||||
"test-console-worklet.html",
|
||||
"test-console.html",
|
||||
"test-data.json",
|
||||
"test-data.json^headers^",
|
||||
|
@ -827,4 +828,6 @@ skip-if = ["true"] # Bug 1765369
|
|||
|
||||
["browser_webconsole_worker_promise_error.js"]
|
||||
|
||||
["browser_webconsole_worklet_console.js"]
|
||||
|
||||
["browser_webconsole_worklet_error.js"]
|
||||
|
|
|
@ -10,6 +10,12 @@ const TEST_URI =
|
|||
"test/browser/test-console-workers.html";
|
||||
|
||||
add_task(async function () {
|
||||
// Allow using SharedArrayBuffer in the test without special HTTP Headers
|
||||
await pushPref(
|
||||
"dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
|
||||
true
|
||||
);
|
||||
|
||||
info("Run the test with worker events dispatched to main thread");
|
||||
await pushPref("dom.worker.console.dispatch_events_to_main_thread", true);
|
||||
await testWorkerMessage();
|
||||
|
@ -91,6 +97,11 @@ async function testWorkerMessage(directConnectionToWorkerThread = false) {
|
|||
ok(symbolMessage, "Symbol logged from worker is visible in the console");
|
||||
}
|
||||
|
||||
const sabMessage = await waitFor(() =>
|
||||
findConsoleAPIMessage(hud, "sab-from-worker")
|
||||
);
|
||||
ok(sabMessage.textContent.includes("SharedArrayBuffer"));
|
||||
|
||||
info("Click on the clear button and wait for messages to be removed");
|
||||
const onMessagesCacheCleared = hud.ui.once("messages-cache-cleared");
|
||||
hud.ui.window.document.querySelector(".devtools-clear-icon").click();
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that console api usage in worklet show in the console
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI =
|
||||
"https://example.com/browser/devtools/client/webconsole/" +
|
||||
"test/browser/test-console-worklet.html";
|
||||
|
||||
add_task(async function () {
|
||||
// Allow using SharedArrayBuffer in the test without special HTTP Headers
|
||||
await pushPref(
|
||||
"dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
|
||||
true
|
||||
);
|
||||
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
await waitFor(() => findConsoleAPIMessage(hud, "string"));
|
||||
await waitFor(() => findConsoleAPIMessage(hud, "42"));
|
||||
const objectMessage = await waitFor(() =>
|
||||
findConsoleAPIMessage(hud, "object")
|
||||
);
|
||||
ok(
|
||||
objectMessage
|
||||
.querySelector(".message-body")
|
||||
.textContent.includes(`Object { object: true }`),
|
||||
"The simple object is logged as expected"
|
||||
);
|
||||
await waitFor(() => findConsoleAPIMessage(hud, "SharedArrayBuffer"));
|
||||
ok(true, "SharedArrayBuffer object is logged");
|
||||
});
|
|
@ -17,11 +17,13 @@
|
|||
onmessage = function (e) {
|
||||
console.log("log-from-worker", e.data.msg, globalThis);
|
||||
console.log(Symbol("logged-symbol-from-worker"));
|
||||
console.log("sab-from-worker", e.data.sab);
|
||||
};
|
||||
`);
|
||||
|
||||
function logFromWorker(msg) {
|
||||
worker.postMessage({type: "log", msg});
|
||||
const sab = new SharedArrayBuffer(1024);
|
||||
worker.postMessage({type: "log", msg, sab});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Worklet console generator</title>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
</head>
|
||||
|
||||
<script type="worklet">
|
||||
registerProcessor('test-param', class param extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.port.onmessage = e => {
|
||||
console.log("worklet", "string");
|
||||
console.log("worklet", 42);
|
||||
console.log("worklet", { object: true });
|
||||
console.log("worklet", e.data.data); // Log the SharedArrayBuffer
|
||||
};
|
||||
}
|
||||
process(input, output, parameters) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
const ac = new AudioContext();
|
||||
const e = document.querySelector("script[type=worklet]")
|
||||
const blob = new Blob([e.textContent], {type: "application/javascript"});
|
||||
const url = URL.createObjectURL(blob);
|
||||
ac.audioWorklet.addModule(url).then(() => {
|
||||
const nodea = new AudioWorkletNode(ac, 'test-param');
|
||||
|
||||
// Instantiate and pass a SharedArrayBuffer to the Worklet
|
||||
const normal_sab = new SharedArrayBuffer(1024);
|
||||
nodea.port.postMessage({data: normal_sab });
|
||||
});
|
||||
</script>
|
|
@ -47,18 +47,21 @@ class BlackboxingActor extends Actor {
|
|||
*/
|
||||
blackbox(url, ranges) {
|
||||
if (!ranges.length) {
|
||||
return this.watcherActor.addDataEntry(BLACKBOXING, [
|
||||
{ url, range: null },
|
||||
]);
|
||||
return this.watcherActor.addOrSetDataEntry(
|
||||
BLACKBOXING,
|
||||
[{ url, range: null }],
|
||||
"add"
|
||||
);
|
||||
}
|
||||
return this.watcherActor.addDataEntry(
|
||||
return this.watcherActor.addOrSetDataEntry(
|
||||
BLACKBOXING,
|
||||
ranges.map(range => {
|
||||
return {
|
||||
url,
|
||||
range,
|
||||
};
|
||||
})
|
||||
}),
|
||||
"add"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,11 @@ class BreakpointListActor extends Actor {
|
|||
}
|
||||
|
||||
setBreakpoint(location, options) {
|
||||
return this.watcherActor.addDataEntry(BREAKPOINTS, [{ location, options }]);
|
||||
return this.watcherActor.addOrSetDataEntry(
|
||||
BREAKPOINTS,
|
||||
[{ location, options }],
|
||||
"add"
|
||||
);
|
||||
}
|
||||
|
||||
removeBreakpoint(location, options) {
|
||||
|
@ -53,7 +57,11 @@ class BreakpointListActor extends Actor {
|
|||
* Otherwise, should be set to any valid HTTP Method (GET, POST, ...)
|
||||
*/
|
||||
setXHRBreakpoint(path, method) {
|
||||
return this.watcherActor.addDataEntry(XHR_BREAKPOINTS, [{ path, method }]);
|
||||
return this.watcherActor.addOrSetDataEntry(
|
||||
XHR_BREAKPOINTS,
|
||||
[{ path, method }],
|
||||
"add"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,18 +84,8 @@ class BreakpointListActor extends Actor {
|
|||
* See devtools/server/actors/utils/event-breakpoints.js
|
||||
* for details.
|
||||
*/
|
||||
setActiveEventBreakpoints(ids) {
|
||||
const existingIds =
|
||||
this.watcherActor.getSessionDataForType(EVENT_BREAKPOINTS) || [];
|
||||
const addIds = ids.filter(id => !existingIds.includes(id));
|
||||
const removeIds = existingIds.filter(id => !ids.includes(id));
|
||||
|
||||
if (addIds.length) {
|
||||
this.watcherActor.addDataEntry(EVENT_BREAKPOINTS, addIds);
|
||||
}
|
||||
if (removeIds.length) {
|
||||
this.watcherActor.removeDataEntry(EVENT_BREAKPOINTS, removeIds);
|
||||
}
|
||||
async setActiveEventBreakpoints(ids) {
|
||||
await this.watcherActor.addOrSetDataEntry(EVENT_BREAKPOINTS, ids, "set");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,11 @@ class TargetConfigurationActor extends Actor {
|
|||
.map(key => ({ key, value: configuration[key] }));
|
||||
|
||||
this._updateParentProcessConfiguration(configuration);
|
||||
await this.watcherActor.addDataEntry(TARGET_CONFIGURATION, cfgArray);
|
||||
await this.watcherActor.addOrSetDataEntry(
|
||||
TARGET_CONFIGURATION,
|
||||
cfgArray,
|
||||
"add"
|
||||
);
|
||||
return this._getConfiguration();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,18 +34,31 @@ class BaseTargetActor extends Actor {
|
|||
* @param Boolean isDocumentCreation
|
||||
* Set to true if this function is called just after a new document (and its
|
||||
* associated target) is created.
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
async addSessionDataEntry(type, entries, isDocumentCreation = false) {
|
||||
async addOrSetSessionDataEntry(
|
||||
type,
|
||||
entries,
|
||||
isDocumentCreation = false,
|
||||
updateType
|
||||
) {
|
||||
const processor = SessionDataProcessors[type];
|
||||
if (processor) {
|
||||
await processor.addSessionDataEntry(this, entries, isDocumentCreation);
|
||||
await processor.addOrSetSessionDataEntry(
|
||||
this,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove data entries that have been previously added via addSessionDataEntry
|
||||
* Remove data entries that have been previously added via addOrSetSessionDataEntry
|
||||
*
|
||||
* See addSessionDataEntry for argument description.
|
||||
* See addOrSetSessionDataEntry for argument description.
|
||||
*/
|
||||
removeSessionDataEntry(type, entries) {
|
||||
const processor = SessionDataProcessors[type];
|
||||
|
|
|
@ -5,9 +5,18 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
const { sourcesManager } = targetActor;
|
||||
if (updateType == "set") {
|
||||
sourcesManager.clearAllBlackBoxing();
|
||||
}
|
||||
for (const { url, range } of entries) {
|
||||
targetActor.sourcesManager.blackBox(url, range);
|
||||
sourcesManager.blackBox(url, range);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -9,21 +9,29 @@ const {
|
|||
} = require("resource://devtools/server/actors/thread.js");
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
const isTargetCreation =
|
||||
targetActor.threadActor.state == THREAD_STATES.DETACHED;
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
const { threadActor } = targetActor;
|
||||
if (updateType == "set") {
|
||||
threadActor.removeAllBreakpoints();
|
||||
}
|
||||
const isTargetCreation = threadActor.state == THREAD_STATES.DETACHED;
|
||||
if (isTargetCreation && !targetActor.targetType.endsWith("worker")) {
|
||||
// If addSessionDataEntry is called during target creation, attach the
|
||||
// If addOrSetSessionDataEntry is called during target creation, attach the
|
||||
// thread actor automatically and pass the initial breakpoints.
|
||||
// However, do not attach the thread actor for Workers. They use a codepath
|
||||
// which releases the worker on `attach`. For them, the client will call `attach`. (bug 1691986)
|
||||
await targetActor.threadActor.attach({ breakpoints: entries });
|
||||
await threadActor.attach({ breakpoints: entries });
|
||||
} else {
|
||||
// If addSessionDataEntry is called for an existing target, set the new
|
||||
// If addOrSetSessionDataEntry is called for an existing target, set the new
|
||||
// breakpoints on the already running thread actor.
|
||||
await Promise.all(
|
||||
entries.map(({ location, options }) =>
|
||||
targetActor.threadActor.setBreakpoint(location, options)
|
||||
threadActor.setBreakpoint(location, options)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,15 +9,25 @@ const {
|
|||
} = require("resource://devtools/server/actors/thread.js");
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
const { threadActor } = targetActor;
|
||||
// Same as comments for XHR breakpoints. See lines 117-118
|
||||
if (
|
||||
targetActor.threadActor.state == THREAD_STATES.DETACHED &&
|
||||
threadActor.state == THREAD_STATES.DETACHED &&
|
||||
!targetActor.targetType.endsWith("worker")
|
||||
) {
|
||||
targetActor.threadActor.attach();
|
||||
threadActor.attach();
|
||||
}
|
||||
if (updateType == "set") {
|
||||
threadActor.setActiveEventBreakpoints(entries);
|
||||
} else {
|
||||
threadActor.addEventBreakpoints(entries);
|
||||
}
|
||||
targetActor.threadActor.addEventBreakpoints(entries);
|
||||
},
|
||||
|
||||
removeSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
|
|
|
@ -7,7 +7,15 @@
|
|||
const Resources = require("resource://devtools/server/actors/resources/index.js");
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
if (updateType == "set") {
|
||||
Resources.unwatchAllResources(targetActor);
|
||||
}
|
||||
await Resources.watchResources(targetActor, entries);
|
||||
},
|
||||
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
// Only WindowGlobalTargetActor implements updateTargetConfiguration,
|
||||
// skip targetActor data entry update for other targets.
|
||||
if (typeof targetActor.updateTargetConfiguration == "function") {
|
||||
|
@ -13,6 +18,10 @@ module.exports = {
|
|||
for (const { key, value } of entries) {
|
||||
options[key] = value;
|
||||
}
|
||||
// Regarding `updateType`, `entries` is always a partial set of configurations.
|
||||
// We will acknowledge the passed attribute, but if we had set some other attributes
|
||||
// before this call, they will stay as-is.
|
||||
// So it is as if this session data was also using "add" updateType.
|
||||
targetActor.updateTargetConfiguration(options, isDocumentCreation);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,7 +9,12 @@ const {
|
|||
} = require("resource://devtools/server/actors/thread.js");
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
const threadOptions = {};
|
||||
|
||||
for (const { key, value } of entries) {
|
||||
|
@ -22,6 +27,10 @@ module.exports = {
|
|||
) {
|
||||
await targetActor.threadActor.attach(threadOptions);
|
||||
} else {
|
||||
// Regarding `updateType`, `entries` is always a partial set of configurations.
|
||||
// We will acknowledge the passed attribute, but if we had set some other attributes
|
||||
// before this call, they will stay as-is.
|
||||
// So it is as if this session data was also using "add" updateType.
|
||||
await targetActor.threadActor.reconfigure(threadOptions);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,19 +9,29 @@ const {
|
|||
} = require("resource://devtools/server/actors/thread.js");
|
||||
|
||||
module.exports = {
|
||||
async addSessionDataEntry(targetActor, entries, isDocumentCreation) {
|
||||
async addOrSetSessionDataEntry(
|
||||
targetActor,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
updateType
|
||||
) {
|
||||
const { threadActor } = targetActor;
|
||||
if (updateType == "set") {
|
||||
threadActor.removeAllXHRBreakpoints();
|
||||
}
|
||||
|
||||
// The thread actor has to be initialized in order to correctly
|
||||
// retrieve the stack trace when hitting an XHR
|
||||
if (
|
||||
targetActor.threadActor.state == THREAD_STATES.DETACHED &&
|
||||
threadActor.state == THREAD_STATES.DETACHED &&
|
||||
!targetActor.targetType.endsWith("worker")
|
||||
) {
|
||||
await targetActor.threadActor.attach();
|
||||
await threadActor.attach();
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
entries.map(({ path, method }) =>
|
||||
targetActor.threadActor.setXHRBreakpoint(path, method)
|
||||
threadActor.setXHRBreakpoint(path, method)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
|
|
@ -66,7 +66,11 @@ class ThreadConfigurationActor extends Actor {
|
|||
})
|
||||
.map(key => ({ key, value: configuration[key] }));
|
||||
|
||||
await this.watcherActor.addDataEntry(THREAD_CONFIGURATION, configArray);
|
||||
await this.watcherActor.addOrSetDataEntry(
|
||||
THREAD_CONFIGURATION,
|
||||
configArray,
|
||||
"add"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -564,6 +564,11 @@ class ThreadActor extends Actor {
|
|||
actor.delete();
|
||||
}
|
||||
|
||||
removeAllXHRBreakpoints() {
|
||||
this._xhrBreakpoints = [];
|
||||
return this._updateNetworkObserver();
|
||||
}
|
||||
|
||||
removeXHRBreakpoint(path, method) {
|
||||
const index = this._findXHRBreakpointIndex(path, method);
|
||||
|
||||
|
@ -1518,6 +1523,10 @@ class ThreadActor extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
removeAllBreakpoints() {
|
||||
this.breakpointActorMap.removeAllBreakpoints();
|
||||
}
|
||||
|
||||
removeAllWatchpoints() {
|
||||
for (const actor of this.threadLifetimePool.poolChildren()) {
|
||||
if (actor.typeName == "obj") {
|
||||
|
|
|
@ -69,6 +69,16 @@ class BreakpointActorMap {
|
|||
const key = this._locationKey(location);
|
||||
delete this._actors[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all currently active breakpoints.
|
||||
*/
|
||||
removeAllBreakpoints() {
|
||||
for (const bpActor of Object.values(this._actors)) {
|
||||
bpActor.removeScripts();
|
||||
}
|
||||
this._actors = {};
|
||||
}
|
||||
}
|
||||
|
||||
exports.BreakpointActorMap = BreakpointActorMap;
|
||||
|
|
|
@ -279,6 +279,10 @@ class SourcesManager extends EventEmitter {
|
|||
return this.isBlackBoxed(url, line, column);
|
||||
}
|
||||
|
||||
clearAllBlackBoxing() {
|
||||
this.blackBoxedSources.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given source URL to the set of sources that are black boxed.
|
||||
*
|
||||
|
|
|
@ -517,10 +517,11 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
continue;
|
||||
}
|
||||
const targetHelperModule = TARGET_HELPERS[targetType];
|
||||
await targetHelperModule.addSessionDataEntry({
|
||||
await targetHelperModule.addOrSetSessionDataEntry({
|
||||
watcher: this,
|
||||
type: "resources",
|
||||
entries: targetResourceTypes,
|
||||
updateType: "add",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -547,9 +548,11 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
resourceTypes,
|
||||
targetActor.targetType
|
||||
);
|
||||
await targetActor.addSessionDataEntry(
|
||||
await targetActor.addOrSetSessionDataEntry(
|
||||
"resources",
|
||||
targetActorResourceTypes
|
||||
targetActorResourceTypes,
|
||||
false,
|
||||
"add"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -711,10 +714,13 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
* @param {String} type
|
||||
* Data type to contribute to.
|
||||
* @param {Array<*>} entries
|
||||
* List of values to add for this data type.
|
||||
* List of values to add or set for this data type.
|
||||
* @param {String} updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
async addDataEntry(type, entries) {
|
||||
WatcherRegistry.addSessionDataEntry(this, type, entries);
|
||||
async addOrSetDataEntry(type, entries, updateType) {
|
||||
WatcherRegistry.addOrSetSessionDataEntry(this, type, entries, updateType);
|
||||
|
||||
await Promise.all(
|
||||
Object.values(Targets.TYPES)
|
||||
|
@ -730,10 +736,11 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
)
|
||||
.map(async targetType => {
|
||||
const targetHelperModule = TARGET_HELPERS[targetType];
|
||||
await targetHelperModule.addSessionDataEntry({
|
||||
await targetHelperModule.addOrSetSessionDataEntry({
|
||||
watcher: this,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
@ -741,7 +748,12 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
// See comment in watchResources
|
||||
const targetActor = this.getTargetActorInParentProcess();
|
||||
if (targetActor) {
|
||||
await targetActor.addSessionDataEntry(type, entries);
|
||||
await targetActor.addOrSetSessionDataEntry(
|
||||
type,
|
||||
entries,
|
||||
false,
|
||||
updateType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,7 +773,7 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
Object.values(Targets.TYPES)
|
||||
.filter(
|
||||
targetType =>
|
||||
// See comment in addDataEntry
|
||||
// See comment in addOrSetDataEntry
|
||||
WatcherRegistry.isWatchingTargets(this, targetType) ||
|
||||
targetType === Targets.TYPES.FRAME
|
||||
)
|
||||
|
@ -774,7 +786,7 @@ exports.WatcherActor = class WatcherActor extends Actor {
|
|||
});
|
||||
});
|
||||
|
||||
// See comment in addDataEntry
|
||||
// See comment in addOrSetDataEntry
|
||||
const targetActor = this.getTargetActorInParentProcess();
|
||||
if (targetActor) {
|
||||
targetActor.removeSessionDataEntry(type, entries);
|
||||
|
|
|
@ -117,6 +117,36 @@ const DATA_KEY_FUNCTION = {
|
|||
return id;
|
||||
},
|
||||
};
|
||||
// Optional validation method to assert the shape of each session data entry
|
||||
const DATA_VALIDATION_FUNCTION = {
|
||||
[SUPPORTED_DATA.BREAKPOINTS]({ location }) {
|
||||
lazy.validateBreakpointLocation(location);
|
||||
},
|
||||
[SUPPORTED_DATA.XHR_BREAKPOINTS]({ path, method }) {
|
||||
if (typeof path != "string") {
|
||||
throw new Error(
|
||||
`XHR Breakpoints expect to have path string, got ${typeof path} instead.`
|
||||
);
|
||||
}
|
||||
if (typeof method != "string") {
|
||||
throw new Error(
|
||||
`XHR Breakpoints expect to have method string, got ${typeof method} instead.`
|
||||
);
|
||||
}
|
||||
},
|
||||
[SUPPORTED_DATA.EVENT_BREAKPOINTS](id) {
|
||||
if (typeof id != "string") {
|
||||
throw new Error(
|
||||
`Event Breakpoints expect the id to be a string , got ${typeof id} instead.`
|
||||
);
|
||||
}
|
||||
if (!lazy.validateEventBreakpoint(id)) {
|
||||
throw new Error(
|
||||
`The id string should be a valid event breakpoint id, ${id} is not.`
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function idFunction(v) {
|
||||
if (typeof v != "string") {
|
||||
|
@ -139,14 +169,28 @@ const SessionDataHelpers = {
|
|||
* The type of data to be added
|
||||
* @param Array<Object> entries
|
||||
* The values to be added to this type of data
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
addSessionDataEntry(sessionData, type, entries) {
|
||||
addOrSetSessionDataEntry(sessionData, type, entries, updateType) {
|
||||
const validationFunction = DATA_VALIDATION_FUNCTION[type];
|
||||
if (validationFunction) {
|
||||
entries.forEach(validationFunction);
|
||||
}
|
||||
|
||||
// When we are replacing the whole entries, things are significantly simplier
|
||||
if (updateType == "set") {
|
||||
sessionData[type] = entries;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sessionData[type]) {
|
||||
sessionData[type] = [];
|
||||
}
|
||||
const toBeAdded = [];
|
||||
const keyFunction = DATA_KEY_FUNCTION[type] || idFunction;
|
||||
for (const entry of entries) {
|
||||
if (!sessionData[type]) {
|
||||
sessionData[type] = [];
|
||||
}
|
||||
const existingIndex = sessionData[type].findIndex(existingEntry => {
|
||||
return keyFunction(existingEntry) === keyFunction(entry);
|
||||
});
|
||||
|
|
|
@ -150,7 +150,7 @@ export const WatcherRegistry = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Notify that a given watcher added an entry in a given data type.
|
||||
* Notify that a given watcher added or set some entries for given data type.
|
||||
*
|
||||
* @param WatcherActor watcher
|
||||
* The WatcherActor which starts observing.
|
||||
|
@ -158,8 +158,11 @@ export const WatcherRegistry = {
|
|||
* The type of data to be added
|
||||
* @param Array<Object> entries
|
||||
* The values to be added to this type of data
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
addSessionDataEntry(watcher, type, entries) {
|
||||
addOrSetSessionDataEntry(watcher, type, entries, updateType) {
|
||||
const sessionData = this.getSessionData(watcher, {
|
||||
createData: true,
|
||||
});
|
||||
|
@ -168,7 +171,12 @@ export const WatcherRegistry = {
|
|||
throw new Error(`Unsupported session data type: ${type}`);
|
||||
}
|
||||
|
||||
SessionDataHelpers.addSessionDataEntry(sessionData, type, entries);
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
type,
|
||||
entries,
|
||||
updateType
|
||||
);
|
||||
|
||||
// Register the JS Window Actor the first time we start watching for something (e.g. resource, target, …).
|
||||
registerJSWindowActor();
|
||||
|
@ -249,7 +257,12 @@ export const WatcherRegistry = {
|
|||
* The new target type to start listening to.
|
||||
*/
|
||||
watchTargets(watcher, targetType) {
|
||||
this.addSessionDataEntry(watcher, SUPPORTED_DATA.TARGETS, [targetType]);
|
||||
this.addOrSetSessionDataEntry(
|
||||
watcher,
|
||||
SUPPORTED_DATA.TARGETS,
|
||||
[targetType],
|
||||
"add"
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -283,7 +296,12 @@ export const WatcherRegistry = {
|
|||
* The new resource types to start listening to.
|
||||
*/
|
||||
watchResources(watcher, resourceTypes) {
|
||||
this.addSessionDataEntry(watcher, SUPPORTED_DATA.RESOURCES, resourceTypes);
|
||||
this.addOrSetSessionDataEntry(
|
||||
watcher,
|
||||
SUPPORTED_DATA.RESOURCES,
|
||||
resourceTypes,
|
||||
"add"
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -211,8 +211,16 @@ function destroyTargets(watcher, options) {
|
|||
* The type of data to be added
|
||||
* @param Array<Object> entries
|
||||
* The values to be added to this type of data
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
async function addSessionDataEntry({ watcher, type, entries }) {
|
||||
async function addOrSetSessionDataEntry({
|
||||
watcher,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
const browsingContexts = getWatchingBrowsingContexts(watcher);
|
||||
const promises = [];
|
||||
for (const browsingContext of browsingContexts) {
|
||||
|
@ -223,11 +231,12 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
|
||||
const promise = browsingContext.currentWindowGlobal
|
||||
.getActor("DevToolsFrame")
|
||||
.addSessionDataEntry({
|
||||
.addOrSetSessionDataEntry({
|
||||
watcherActorID: watcher.actorID,
|
||||
sessionContext: watcher.sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
|
@ -238,7 +247,7 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
/**
|
||||
* Notify all existing frame targets that some data entries have been removed
|
||||
*
|
||||
* See addSessionDataEntry for argument documentation.
|
||||
* See addOrSetSessionDataEntry for argument documentation.
|
||||
*/
|
||||
function removeSessionDataEntry({ watcher, type, entries }) {
|
||||
const browsingContexts = getWatchingBrowsingContexts(watcher);
|
||||
|
@ -262,7 +271,7 @@ function removeSessionDataEntry({ watcher, type, entries }) {
|
|||
module.exports = {
|
||||
createTargets,
|
||||
destroyTargets,
|
||||
addSessionDataEntry,
|
||||
addOrSetSessionDataEntry,
|
||||
removeSessionDataEntry,
|
||||
};
|
||||
|
||||
|
|
|
@ -311,8 +311,16 @@ function destroyTargets(watcher, options) {
|
|||
* The type of data to be added
|
||||
* @param {Array<Object>} options.entries
|
||||
* The values to be added to this type of data
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
async function addSessionDataEntry({ watcher, type, entries }) {
|
||||
async function addOrSetSessionDataEntry({
|
||||
watcher,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
let expectedCount = Services.ppmm.childCount - 1;
|
||||
if (expectedCount == 0) {
|
||||
return;
|
||||
|
@ -327,7 +335,7 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
maybeResolve();
|
||||
};
|
||||
Services.ppmm.addMessageListener(
|
||||
"debug:add-session-data-entry-done",
|
||||
"debug:add-or-set-session-data-entry-done",
|
||||
listener
|
||||
);
|
||||
const onContentProcessClosed = (messageManager, topic, data) => {
|
||||
|
@ -337,7 +345,7 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
const maybeResolve = () => {
|
||||
if (count == expectedCount) {
|
||||
Services.ppmm.removeMessageListener(
|
||||
"debug:add-session-data-entry-done",
|
||||
"debug:add-or-set-session-data-entry-done",
|
||||
listener
|
||||
);
|
||||
Services.obs.removeObserver(
|
||||
|
@ -350,10 +358,11 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
Services.obs.addObserver(onContentProcessClosed, "message-manager-close");
|
||||
});
|
||||
|
||||
Services.ppmm.broadcastAsyncMessage("debug:add-session-data-entry", {
|
||||
Services.ppmm.broadcastAsyncMessage("debug:add-or-set-session-data-entry", {
|
||||
watcherActorID: watcher.actorID,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
|
||||
await onAllReplied;
|
||||
|
@ -362,7 +371,7 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
/**
|
||||
* Notify all existing content processes that some data entries have been removed
|
||||
*
|
||||
* See addSessionDataEntry for argument documentation.
|
||||
* See addOrSetSessionDataEntry for argument documentation.
|
||||
*/
|
||||
function removeSessionDataEntry({ watcher, type, entries }) {
|
||||
Services.ppmm.broadcastAsyncMessage("debug:remove-session-data-entry", {
|
||||
|
@ -375,6 +384,6 @@ function removeSessionDataEntry({ watcher, type, entries }) {
|
|||
module.exports = {
|
||||
createTargets,
|
||||
destroyTargets,
|
||||
addSessionDataEntry,
|
||||
addOrSetSessionDataEntry,
|
||||
removeSessionDataEntry,
|
||||
};
|
||||
|
|
|
@ -76,8 +76,16 @@ async function destroyTargets(watcher) {
|
|||
* The type of data to be added
|
||||
* @param Array<Object> entries
|
||||
* The values to be added to this type of data
|
||||
* @param String updateType
|
||||
* "add" will only add the new entries in the existing data set.
|
||||
* "set" will update the data set with the new entries.
|
||||
*/
|
||||
async function addSessionDataEntry({ watcher, type, entries }) {
|
||||
async function addOrSetSessionDataEntry({
|
||||
watcher,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
const browsingContexts = watcher.getAllBrowsingContexts({
|
||||
acceptSameProcessIframes: true,
|
||||
forceAcceptTopLevelTarget: true,
|
||||
|
@ -86,11 +94,12 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
for (const browsingContext of browsingContexts) {
|
||||
const promise = browsingContext.currentWindowGlobal
|
||||
.getActor(DEVTOOLS_WORKER_JS_WINDOW_ACTOR_NAME)
|
||||
.addSessionDataEntry({
|
||||
.addOrSetSessionDataEntry({
|
||||
watcherActorID: watcher.actorID,
|
||||
sessionContext: watcher.sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
|
@ -101,7 +110,7 @@ async function addSessionDataEntry({ watcher, type, entries }) {
|
|||
/**
|
||||
* Notify all existing frame targets that some data entries have been removed
|
||||
*
|
||||
* See addSessionDataEntry for argument documentation.
|
||||
* See addOrSetSessionDataEntry for argument documentation.
|
||||
*/
|
||||
function removeSessionDataEntry({ watcher, type, entries }) {
|
||||
const browsingContexts = watcher.getAllBrowsingContexts({
|
||||
|
@ -123,6 +132,6 @@ function removeSessionDataEntry({ watcher, type, entries }) {
|
|||
module.exports = {
|
||||
createTargets,
|
||||
destroyTargets,
|
||||
addSessionDataEntry,
|
||||
addOrSetSessionDataEntry,
|
||||
removeSessionDataEntry,
|
||||
};
|
||||
|
|
|
@ -286,7 +286,12 @@ export class DevToolsFrameChild extends JSWindowActorChild {
|
|||
if (!Array.isArray(entries) || !entries.length) {
|
||||
continue;
|
||||
}
|
||||
targetActor.addSessionDataEntry(type, entries, isDocumentCreation);
|
||||
targetActor.addOrSetSessionDataEntry(
|
||||
type,
|
||||
entries,
|
||||
isDocumentCreation,
|
||||
"set"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,13 +436,15 @@ export class DevToolsFrameChild extends JSWindowActorChild {
|
|||
const { watcherActorID, options } = message.data;
|
||||
return this._destroyTargetActor(watcherActorID, options);
|
||||
}
|
||||
case "DevToolsFrameParent:addSessionDataEntry": {
|
||||
const { watcherActorID, sessionContext, type, entries } = message.data;
|
||||
return this._addSessionDataEntry(
|
||||
case "DevToolsFrameParent:addOrSetSessionDataEntry": {
|
||||
const { watcherActorID, sessionContext, type, entries, updateType } =
|
||||
message.data;
|
||||
return this._addOrSetSessionDataEntry(
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries
|
||||
entries,
|
||||
updateType
|
||||
);
|
||||
}
|
||||
case "DevToolsFrameParent:removeSessionDataEntry": {
|
||||
|
@ -510,7 +517,13 @@ export class DevToolsFrameChild extends JSWindowActorChild {
|
|||
return null;
|
||||
}
|
||||
|
||||
_addSessionDataEntry(watcherActorID, sessionContext, type, entries) {
|
||||
_addOrSetSessionDataEntry(
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType
|
||||
) {
|
||||
// /!\ We may have an issue here as there could be multiple targets for a given
|
||||
// (watcherActorID,browserId) pair.
|
||||
// This should be clarified as part of Bug 1725623.
|
||||
|
@ -524,7 +537,12 @@ export class DevToolsFrameChild extends JSWindowActorChild {
|
|||
`No target actor for this Watcher Actor ID:"${watcherActorID}" / BrowserId:${sessionContext.browserId}`
|
||||
);
|
||||
}
|
||||
return targetActor.addSessionDataEntry(type, entries);
|
||||
return targetActor.addOrSetSessionDataEntry(
|
||||
type,
|
||||
entries,
|
||||
false,
|
||||
updateType
|
||||
);
|
||||
}
|
||||
|
||||
_removeSessionDataEntry(watcherActorID, sessionContext, type, entries) {
|
||||
|
|
|
@ -87,13 +87,20 @@ export class DevToolsFrameParent extends JSWindowActorParent {
|
|||
/**
|
||||
* Communicate to the content process that some data have been added.
|
||||
*/
|
||||
async addSessionDataEntry({ watcherActorID, sessionContext, type, entries }) {
|
||||
async addOrSetSessionDataEntry({
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
try {
|
||||
await this.sendQuery("DevToolsFrameParent:addSessionDataEntry", {
|
||||
await this.sendQuery("DevToolsFrameParent:addOrSetSessionDataEntry", {
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
|
|
|
@ -180,9 +180,14 @@ export class DevToolsWorkerChild extends JSWindowActorChild {
|
|||
const { watcherActorID } = message.data;
|
||||
return this._destroyTargetActors(watcherActorID);
|
||||
}
|
||||
case "DevToolsWorkerParent:addSessionDataEntry": {
|
||||
const { watcherActorID, type, entries } = message.data;
|
||||
return this._addSessionDataEntry(watcherActorID, type, entries);
|
||||
case "DevToolsWorkerParent:addOrSetSessionDataEntry": {
|
||||
const { watcherActorID, type, entries, updateType } = message.data;
|
||||
return this._addOrSetSessionDataEntry(
|
||||
watcherActorID,
|
||||
type,
|
||||
entries,
|
||||
updateType
|
||||
);
|
||||
}
|
||||
case "DevToolsWorkerParent:removeSessionDataEntry": {
|
||||
const { watcherActorID, type, entries } = message.data;
|
||||
|
@ -410,16 +415,17 @@ export class DevToolsWorkerChild extends JSWindowActorChild {
|
|||
});
|
||||
}
|
||||
|
||||
async _addSessionDataEntry(watcherActorID, type, entries) {
|
||||
async _addOrSetSessionDataEntry(watcherActorID, type, entries, updateType) {
|
||||
const watcherConnectionData = this._connections.get(watcherActorID);
|
||||
if (!watcherConnectionData) {
|
||||
return;
|
||||
}
|
||||
|
||||
lazy.SessionDataHelpers.addSessionDataEntry(
|
||||
lazy.SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
watcherConnectionData.sessionData,
|
||||
type,
|
||||
entries
|
||||
entries,
|
||||
updateType
|
||||
);
|
||||
|
||||
const promises = [];
|
||||
|
@ -428,11 +434,12 @@ export class DevToolsWorkerChild extends JSWindowActorChild {
|
|||
workerThreadServerForwardingPrefix,
|
||||
} of watcherConnectionData.workers) {
|
||||
promises.push(
|
||||
addSessionDataEntryInWorkerTarget({
|
||||
addOrSetSessionDataEntryInWorkerTarget({
|
||||
dbg,
|
||||
workerThreadServerForwardingPrefix,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -508,14 +515,24 @@ export class DevToolsWorkerChild extends JSWindowActorChild {
|
|||
/**
|
||||
* Communicate the type and entries to the Worker Target actor, via the WorkerDebugger.
|
||||
*
|
||||
* @param {WorkerDebugger} dbg
|
||||
* @param {String} workerThreadServerForwardingPrefix
|
||||
* @param {String} type
|
||||
* Session data type name
|
||||
* @param {Array} entries
|
||||
* Session data entries to add or set.
|
||||
* @param {String} updateType
|
||||
* Either "add" or "set", to control if we should only add some items,
|
||||
* or replace the whole data set with the new entries.
|
||||
* @returns {Promise} Returns a Promise that resolves once the data entry were handled
|
||||
* by the worker target.
|
||||
*/
|
||||
function addSessionDataEntryInWorkerTarget({
|
||||
function addOrSetSessionDataEntryInWorkerTarget({
|
||||
dbg,
|
||||
workerThreadServerForwardingPrefix,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
if (!lazy.DevToolsUtils.isWorkerDebuggerAlive(dbg)) {
|
||||
return Promise.resolve();
|
||||
|
@ -527,7 +544,7 @@ function addSessionDataEntryInWorkerTarget({
|
|||
const listener = {
|
||||
onMessage: message => {
|
||||
message = JSON.parse(message);
|
||||
if (message.type === "session-data-entry-added") {
|
||||
if (message.type === "session-data-entry-added-or-set") {
|
||||
resolve();
|
||||
dbg.removeListener(listener);
|
||||
}
|
||||
|
@ -540,10 +557,11 @@ function addSessionDataEntryInWorkerTarget({
|
|||
|
||||
dbg.postMessage(
|
||||
JSON.stringify({
|
||||
type: "add-session-data-entry",
|
||||
type: "add-or-set-session-data-entry",
|
||||
forwardingPrefix: workerThreadServerForwardingPrefix,
|
||||
dataEntryType: type,
|
||||
entries,
|
||||
updateType,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
|
|
@ -91,13 +91,20 @@ export class DevToolsWorkerParent extends JSWindowActorParent {
|
|||
/**
|
||||
* Communicate to the content process that some data have been added.
|
||||
*/
|
||||
async addSessionDataEntry({ watcherActorID, sessionContext, type, entries }) {
|
||||
async addOrSetSessionDataEntry({
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
}) {
|
||||
try {
|
||||
await this.sendQuery("DevToolsWorkerParent:addSessionDataEntry", {
|
||||
await this.sendQuery("DevToolsWorkerParent:addOrSetSessionDataEntry", {
|
||||
watcherActorID,
|
||||
sessionContext,
|
||||
type,
|
||||
entries,
|
||||
updateType,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
|
|
|
@ -67,7 +67,7 @@ class ContentProcessStartup {
|
|||
this.receiveMessage
|
||||
);
|
||||
Services.cpmm.addMessageListener(
|
||||
"debug:add-session-data-entry",
|
||||
"debug:add-or-set-session-data-entry",
|
||||
this.receiveMessage
|
||||
);
|
||||
Services.cpmm.addMessageListener(
|
||||
|
@ -92,7 +92,7 @@ class ContentProcessStartup {
|
|||
this.receiveMessage
|
||||
);
|
||||
Services.cpmm.removeMessageListener(
|
||||
"debug:add-session-data-entry",
|
||||
"debug:add-or-set-session-data-entry",
|
||||
this.receiveMessage
|
||||
);
|
||||
Services.cpmm.removeMessageListener(
|
||||
|
@ -118,11 +118,12 @@ class ContentProcessStartup {
|
|||
case "debug:destroy-target":
|
||||
this.destroyTarget(msg.data.watcherActorID);
|
||||
break;
|
||||
case "debug:add-session-data-entry":
|
||||
this.addSessionDataEntry(
|
||||
case "debug:add-or-set-session-data-entry":
|
||||
this.addOrSetSessionDataEntry(
|
||||
msg.data.watcherActorID,
|
||||
msg.data.type,
|
||||
msg.data.entries
|
||||
msg.data.entries,
|
||||
msg.data.updateType
|
||||
);
|
||||
break;
|
||||
case "debug:remove-session-data-entry":
|
||||
|
@ -234,7 +235,7 @@ class ContentProcessStartup {
|
|||
|
||||
// Pass initialization data to the target actor
|
||||
for (const type in sessionData) {
|
||||
actor.addSessionDataEntry(type, sessionData[type]);
|
||||
actor.addOrSetSessionDataEntry(type, sessionData[type], false, "set");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,7 +251,7 @@ class ContentProcessStartup {
|
|||
this._connections.delete(watcherActorID);
|
||||
}
|
||||
|
||||
async addSessionDataEntry(watcherActorID, type, entries) {
|
||||
async addOrSetSessionDataEntry(watcherActorID, type, entries, updateType) {
|
||||
const connectionInfo = this._connections.get(watcherActorID);
|
||||
if (!connectionInfo) {
|
||||
throw new Error(
|
||||
|
@ -258,8 +259,8 @@ class ContentProcessStartup {
|
|||
);
|
||||
}
|
||||
const { actor } = connectionInfo;
|
||||
await actor.addSessionDataEntry(type, entries);
|
||||
Services.cpmm.sendAsyncMessage("debug:add-session-data-entry-done", {
|
||||
await actor.addOrSetSessionDataEntry(type, entries, false, updateType);
|
||||
Services.cpmm.sendAsyncMessage("debug:add-or-set-session-data-entry-done", {
|
||||
watcherActorID,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -115,21 +115,29 @@ this.addEventListener("message", async function (event) {
|
|||
for (const [type, entries] of Object.entries(
|
||||
packet.options.sessionData
|
||||
)) {
|
||||
promises.push(workerTargetActor.addSessionDataEntry(type, entries));
|
||||
promises.push(
|
||||
workerTargetActor.addOrSetSessionDataEntry(
|
||||
type,
|
||||
entries,
|
||||
false,
|
||||
"set"
|
||||
)
|
||||
);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "add-session-data-entry":
|
||||
case "add-or-set-session-data-entry":
|
||||
await connections
|
||||
.get(packet.forwardingPrefix)
|
||||
.workerTargetActor.addSessionDataEntry(
|
||||
.workerTargetActor.addOrSetSessionDataEntry(
|
||||
packet.dataEntryType,
|
||||
packet.entries
|
||||
packet.entries,
|
||||
packet.updateType
|
||||
);
|
||||
postMessage(JSON.stringify({ type: "session-data-entry-added" }));
|
||||
postMessage(JSON.stringify({ type: "session-data-entry-added-or-set" }));
|
||||
break;
|
||||
|
||||
case "remove-session-data-entry":
|
||||
|
|
|
@ -18,30 +18,45 @@ function run_test() {
|
|||
[TARGETS]: [],
|
||||
};
|
||||
|
||||
SessionDataHelpers.addSessionDataEntry(sessionData, TARGETS, [
|
||||
"frame",
|
||||
"worker",
|
||||
]);
|
||||
info("Test adding a new entry");
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
["frame", "worker"],
|
||||
"add"
|
||||
);
|
||||
deepEqual(
|
||||
sessionData[TARGETS],
|
||||
["frame", "worker"],
|
||||
"the two elements were added"
|
||||
);
|
||||
|
||||
SessionDataHelpers.addSessionDataEntry(sessionData, TARGETS, ["frame"]);
|
||||
info("Test adding a duplicated entry");
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
["frame"],
|
||||
"add"
|
||||
);
|
||||
deepEqual(
|
||||
sessionData[TARGETS],
|
||||
["frame", "worker"],
|
||||
"addSessionDataEntry ignore duplicates"
|
||||
"addOrSetSessionDataEntry ignore duplicates"
|
||||
);
|
||||
|
||||
SessionDataHelpers.addSessionDataEntry(sessionData, TARGETS, ["process"]);
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
["process"],
|
||||
"add"
|
||||
);
|
||||
deepEqual(
|
||||
sessionData[TARGETS],
|
||||
["frame", "worker", "process"],
|
||||
"the third element is added"
|
||||
);
|
||||
|
||||
info("Test removing an existing entry");
|
||||
let removed = SessionDataHelpers.removeSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
|
@ -54,6 +69,7 @@ function run_test() {
|
|||
"the element has been remove"
|
||||
);
|
||||
|
||||
info("Test removing non-existing entry");
|
||||
removed = SessionDataHelpers.removeSessionDataEntry(sessionData, TARGETS, [
|
||||
"not-existing",
|
||||
]);
|
||||
|
@ -76,4 +92,33 @@ function run_test() {
|
|||
"removedSessionDataEntry returned true as elements have been removed"
|
||||
);
|
||||
deepEqual(sessionData[TARGETS], [], "all elements were removed");
|
||||
|
||||
info("Test settting instead of adding data entries");
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
["frame"],
|
||||
"add"
|
||||
);
|
||||
deepEqual(sessionData[TARGETS], ["frame"], "frame was re-added");
|
||||
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(
|
||||
sessionData,
|
||||
TARGETS,
|
||||
["process", "worker"],
|
||||
"set"
|
||||
);
|
||||
deepEqual(
|
||||
sessionData[TARGETS],
|
||||
["process", "worker"],
|
||||
"frame was replaced by process and worker"
|
||||
);
|
||||
|
||||
info("Test setting an empty array");
|
||||
SessionDataHelpers.addOrSetSessionDataEntry(sessionData, TARGETS, [], "set");
|
||||
deepEqual(
|
||||
sessionData[TARGETS],
|
||||
[],
|
||||
"Setting an empty array of entries clears the data entry"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ add_task(async function () {
|
|||
info("Dynamically add a breakpoint after the debugger statement");
|
||||
const breakpointsFront = await watcher.getBreakpointListActor();
|
||||
await breakpointsFront.setBreakpoint(
|
||||
{ sourceUrl: testFile.path, line: 11 },
|
||||
{ sourceUrl: testFile.path, line: 11, column: 0 },
|
||||
{}
|
||||
);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
console.log("script evaluation");
|
||||
console.log("Here is a SAB", new SharedArrayBuffer(1024));
|
||||
|
||||
addEventListener("install", function (evt) {
|
||||
console.log("install event");
|
||||
|
|
|
@ -79,6 +79,12 @@ const expectedConsoleCalls = [
|
|||
filename: /helper_serviceworker/,
|
||||
arguments: ['script evaluation'],
|
||||
},
|
||||
{
|
||||
level: "log",
|
||||
filename: /helper_serviceworker/,
|
||||
// Note that the second argument isn't a SharedArrayBuffer, but a DevTools "Object Front" instance.
|
||||
arguments: ['Here is a SAB', { class : "SharedArrayBuffer" }],
|
||||
},
|
||||
{
|
||||
level: "log",
|
||||
filename: /helper_serviceworker/,
|
||||
|
@ -108,7 +114,11 @@ const startTest = async function () {
|
|||
await new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["devtools.webconsole.filter.serviceworkers", true]
|
||||
["devtools.webconsole.filter.serviceworkers", true],
|
||||
[
|
||||
"dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
|
||||
true
|
||||
],
|
||||
]}, resolve);
|
||||
});
|
||||
|
||||
|
|
|
@ -27,6 +27,12 @@ const firstTabExpectedCalls = [
|
|||
filename: /helper_serviceworker/,
|
||||
arguments: ['script evaluation'],
|
||||
}
|
||||
}, {
|
||||
message: {
|
||||
level: "log",
|
||||
filename: /helper_serviceworker/,
|
||||
arguments: ['Here is a SAB'],
|
||||
}
|
||||
}, {
|
||||
message: {
|
||||
level: "log",
|
||||
|
@ -58,7 +64,11 @@ const startTest = async function () {
|
|||
await new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["devtools.webconsole.filter.serviceworkers", true]
|
||||
["devtools.webconsole.filter.serviceworkers", true],
|
||||
[
|
||||
"dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
|
||||
true
|
||||
],
|
||||
]}, resolve);
|
||||
});
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ Windows dependencies
|
|||
|
||||
All the commands of this tutorial must be run in the shell provided with the MozillaBuild Package (start-shell.bat)
|
||||
|
||||
:ref:`More information <Building Firefox On Windows>`
|
||||
:ref:`More information on building Firefox on Windows <Building Firefox On Windows>`
|
||||
|
||||
Bootstrap a copy of the Firefox source code
|
||||
-------------------------------------------
|
||||
|
@ -58,7 +58,7 @@ To Setup Firefox On Windows
|
|||
$ wget https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py
|
||||
$ python3 bootstrap.py
|
||||
|
||||
More information :ref:`for Windows <Building Firefox On Windows>`
|
||||
More information on :ref:`building Firefox for Windows <Building Firefox On Windows>`.
|
||||
|
||||
To Setup Firefox On macOS and Linux
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -68,7 +68,7 @@ To Setup Firefox On macOS and Linux
|
|||
$ curl https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py -O
|
||||
$ python3 bootstrap.py
|
||||
|
||||
More information :ref:`for Linux <Building Firefox On Linux>` and :ref:`for MacOS <Building Firefox On MacOS>`
|
||||
More information on :ref:`building Firefox for Linux <Building Firefox On Linux>` and :ref:`building Firefox for MacOS <Building Firefox On MacOS>`.
|
||||
|
||||
To set up your editor
|
||||
---------------------
|
||||
|
@ -111,7 +111,11 @@ To run it:
|
|||
|
||||
$ ./mach run
|
||||
|
||||
:ref:`More information about Linux <Building Firefox On Linux>` / :ref:`More information about MacOS <Building Firefox On MacOS>`
|
||||
This command will open your locally built Firefox in a new window.
|
||||
|
||||
:ref:`More information about building Firefox on Linux <Building Firefox On Linux>` / :ref:`More information about building Firefox on MacOS <Building Firefox On MacOS>`
|
||||
|
||||
If you encounter build errors, please reference the more detailed "Building Firefox" on your specific operating system document and specifically the "Troubleshooting" section.
|
||||
|
||||
.. _write_a_patch:
|
||||
|
||||
|
|
|
@ -124,9 +124,19 @@ Now that your system is bootstrapped, you should be able to build!
|
|||
cd mozilla-unified
|
||||
hg up -C central
|
||||
./mach build
|
||||
./mach run
|
||||
|
||||
🎉 Congratulations! You've built your own home-grown Firefox!
|
||||
You should see the following message in your terminal after a successful build:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
Your build was successful!
|
||||
To take your build for a test drive, run: |mach run|
|
||||
For more information on what to do now, see https://firefox-source-docs.mozilla.org/setup/contributing_code.html
|
||||
|
||||
You can now use the ``./mach run`` command to run your locally built Firefox!
|
||||
|
||||
If your build fails, please reference the steps in the `Troubleshooting section <#troubleshooting>`_.
|
||||
|
||||
Now the fun starts
|
||||
------------------
|
||||
|
@ -141,6 +151,14 @@ send patches to Mozilla, update your source code locally, and more.
|
|||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Build errors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
If you encounter a build error when trying to setup your development environment, please follow these steps:
|
||||
1. Copy the entire build error to your clipboard
|
||||
2. Paste this error to `paste.mozilla.org <https://paste.mozilla.org>`_ in the text area and change the "Expire in one hour" option to "Expire in one week". Note: it won't take a week to get help but it's better to have the snippet be around for a bit longer than expected.
|
||||
3. Go to the `introduction channel <https://chat.mozilla.org/#/room/#introduction:mozilla.org>`__ and ask for help with your build error. Make sure to post the link to the paste.mozilla.org snippet you created!
|
||||
|
||||
Using a non-native file system (NTFS, network drive, etc)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -104,9 +104,19 @@ Now that your system is bootstrapped, you should be able to build!
|
|||
cd mozilla-unified
|
||||
hg up -C central
|
||||
./mach build
|
||||
./mach run
|
||||
|
||||
🎉 Congratulations! You've built your own home-grown Firefox!
|
||||
You should see the following message in your terminal after a successful build:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
Your build was successful!
|
||||
To take your build for a test drive, run: |mach run|
|
||||
For more information on what to do now, see https://firefox-source-docs.mozilla.org/setup/contributing_code.html
|
||||
|
||||
You can now use the ``./mach run`` command to run your locally built Firefox!
|
||||
|
||||
If your build fails, please reference the steps in the `Troubleshooting section <#troubleshooting>`_.
|
||||
|
||||
Now the fun starts
|
||||
------------------
|
||||
|
@ -117,3 +127,14 @@ say hello in the `Introduction channel
|
|||
start working on <https://codetribute.mozilla.org/>`_.
|
||||
See the :ref:`Firefox Contributors' Quick Reference` to learn how to test your changes,
|
||||
send patches to Mozilla, update your source code locally, and more.
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Build errors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
If you encounter a build error when trying to setup your development environment, please follow these steps:
|
||||
1. Copy the entire build error to your clipboard
|
||||
2. Paste this error to `paste.mozilla.org <https://paste.mozilla.org>`_ in the text area and change the "Expire in one hour" option to "Expire in one week". Note: it won't take a week to get help but it's better to have the snippet be around for a bit longer than expected.
|
||||
3. Go to the `introduction channel <https://chat.mozilla.org/#/room/#introduction:mozilla.org>`__ and ask for help with your build error. Make sure to post the link to the paste.mozilla.org snippet you created!
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Building Firefox On Windows
|
||||
===========================
|
||||
======================================
|
||||
|
||||
This document will help you get set up to build Firefox on your own
|
||||
computer. Getting set up can take a while - we need to download a
|
||||
|
@ -104,10 +104,12 @@ Microsoft Defender Antivirus manually
|
|||
|
||||
.. note::
|
||||
|
||||
If you're already missing files (you'll see them listed in ``hg status``, you can have them
|
||||
brought back by reverting your source tree: ``hg update -C``).
|
||||
If you are using Mercurial and you're already missing files (you'll see them listed in ``hg status``), you can have them
|
||||
brought back by reverting your source tree: ``hg update -C``.
|
||||
|
||||
3. Build
|
||||
If you are using Git and you're already missing files (you'll see them listed in ``git status``), you can have them brought back by discarding changes in your source tree: ``git restore .``.
|
||||
|
||||
1. Build
|
||||
--------
|
||||
|
||||
Now that your system is bootstrapped, you should be able to build!
|
||||
|
@ -117,9 +119,19 @@ Now that your system is bootstrapped, you should be able to build!
|
|||
cd c:/mozilla-source/mozilla-unified
|
||||
hg up -C central
|
||||
./mach build
|
||||
./mach run
|
||||
|
||||
🎉 Congratulations! You've built your own home-grown Firefox!
|
||||
You should see the following message in your terminal after a successful build:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
Your build was successful!
|
||||
To take your build for a test drive, run: |mach run|
|
||||
For more information on what to do now, see https://firefox-source-docs.mozilla.org/setup/contributing_code.html
|
||||
|
||||
You can now use the ``./mach run`` command to run your locally built Firefox!
|
||||
|
||||
If your build fails, please reference the steps in the `Troubleshooting section <#troubleshooting>`_.
|
||||
|
||||
Now the fun starts
|
||||
------------------
|
||||
|
@ -140,6 +152,14 @@ send patches to Mozilla, update your source code locally, and more.
|
|||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Build errors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
If you encounter a build error when trying to setup your development environment, please follow these steps:
|
||||
1. Copy the entire build error to your clipboard
|
||||
2. Paste this error on `paste.mozilla.org <https://paste.mozilla.org>`_ in the text area and change the "Expire in one hour" option to "Expire in one week". Note: it won't take a week to get help but it's better to have the snippet be around for a bit longer than expected.
|
||||
3. Go to the `introduction channel <https://chat.mozilla.org/#/room/#introduction:mozilla.org>`__ and ask for help with your build error. Make sure to post the link to the paste.mozilla.org snippet you created!
|
||||
|
||||
MozillaBuild out-of-date
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -2174,6 +2174,14 @@ void Document::AccumulatePageLoadTelemetry(
|
|||
}
|
||||
}
|
||||
|
||||
// Report the most up to date LCP time. For our histogram we actually report
|
||||
// this on page unload.
|
||||
if (TimeStamp lcpTime =
|
||||
GetNavigationTiming()->GetLargestContentfulRenderTimeStamp()) {
|
||||
aEventTelemetryDataOut.lcpTime = mozilla::Some(
|
||||
static_cast<uint32_t>((lcpTime - navigationStart).ToMilliseconds()));
|
||||
}
|
||||
|
||||
// DOM Content Loaded event
|
||||
if (TimeStamp dclEventStart =
|
||||
GetNavigationTiming()->GetDOMContentLoadedEventStartTimeStamp()) {
|
||||
|
@ -8710,15 +8718,11 @@ already_AddRefed<nsSimpleContentList> Document::BlockedNodesByClassifier()
|
|||
const {
|
||||
RefPtr<nsSimpleContentList> list = new nsSimpleContentList(nullptr);
|
||||
|
||||
const nsTArray<nsWeakPtr> blockedNodes = mBlockedNodesByClassifier.Clone();
|
||||
|
||||
for (unsigned long i = 0; i < blockedNodes.Length(); i++) {
|
||||
nsWeakPtr weakNode = blockedNodes[i];
|
||||
nsCOMPtr<nsIContent> node = do_QueryReferent(weakNode);
|
||||
// Consider only nodes to which we have managed to get strong references.
|
||||
// Coping with nullptrs since it's expected for nodes to disappear when
|
||||
// nobody else is referring to them.
|
||||
if (node) {
|
||||
for (const nsWeakPtr& weakNode : mBlockedNodesByClassifier) {
|
||||
if (nsCOMPtr<nsIContent> node = do_QueryReferent(weakNode)) {
|
||||
// Consider only nodes to which we have managed to get strong references.
|
||||
// Coping with nullptrs since it's expected for nodes to disappear when
|
||||
// nobody else is referring to them.
|
||||
list->AppendElement(node);
|
||||
}
|
||||
}
|
||||
|
@ -11465,6 +11469,7 @@ void Document::Destroy() {
|
|||
}
|
||||
|
||||
ReportDocumentUseCounters();
|
||||
ReportLCP();
|
||||
SetDevToolsWatchingDOMMutations(false);
|
||||
|
||||
mIsGoingAway = true;
|
||||
|
@ -16180,6 +16185,42 @@ void Document::ReportDocumentUseCounters() {
|
|||
}
|
||||
}
|
||||
|
||||
void Document::ReportLCP() {
|
||||
const nsDOMNavigationTiming* timing = GetNavigationTiming();
|
||||
|
||||
if (!timing) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeStamp lcpTime = timing->GetLargestContentfulRenderTimeStamp();
|
||||
|
||||
if (!lcpTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::glean::perf::largest_contentful_paint.AccumulateRawDuration(
|
||||
lcpTime - timing->GetNavigationStartTimeStamp());
|
||||
|
||||
if (!GetChannel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(GetChannel()));
|
||||
if (!timedChannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeStamp responseStart;
|
||||
timedChannel->GetResponseStart(&responseStart);
|
||||
|
||||
if (!responseStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::glean::perf::largest_contentful_paint_from_response_start
|
||||
.AccumulateRawDuration(lcpTime - responseStart);
|
||||
}
|
||||
|
||||
void Document::SendPageUseCounters() {
|
||||
if (!mShouldReportUseCounters || !mShouldSendPageUseCounters) {
|
||||
return;
|
||||
|
@ -18651,13 +18692,7 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(emilio): We use IsInChromeDocShell rather than IsChromeDoc
|
||||
// intentionally, to make chrome documents in content docshells (like about
|
||||
// pages) use the content color scheme.
|
||||
if (IsInChromeDocShell()) {
|
||||
return LookAndFeel::ColorSchemeForChrome();
|
||||
}
|
||||
return LookAndFeel::PreferredColorSchemeForContent();
|
||||
return PreferenceSheet::PrefsFor(*this).mColorScheme;
|
||||
}
|
||||
|
||||
bool Document::HasRecentlyStartedForegroundLoads() {
|
||||
|
|
|
@ -1344,6 +1344,16 @@ class Document : public nsINode,
|
|||
Maybe<ClientState> GetClientState() const;
|
||||
Maybe<ServiceWorkerDescriptor> GetController() const;
|
||||
|
||||
// Given a node, get a weak reference to it and append that reference to
|
||||
// mBlockedNodesByClassifier. Can be used later on to look up a node in it.
|
||||
// (e.g., by the UI)
|
||||
// /
|
||||
void AddBlockedNodeByClassifier(nsINode* aNode) {
|
||||
if (aNode) {
|
||||
mBlockedNodesByClassifier.AppendElement(do_GetWeakReference(aNode));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the size of the mBlockedNodesByClassifier array.
|
||||
//
|
||||
// This array contains nodes that have been blocked to prevent user tracking,
|
||||
|
@ -1359,17 +1369,14 @@ class Document : public nsINode,
|
|||
// Weak references to blocked nodes are added in the mBlockedNodesByClassifier
|
||||
// array but they are not removed when those nodes are removed from the tree
|
||||
// or even garbage collected.
|
||||
long BlockedNodeByClassifierCount() const {
|
||||
size_t BlockedNodeByClassifierCount() const {
|
||||
return mBlockedNodesByClassifier.Length();
|
||||
}
|
||||
|
||||
//
|
||||
// Returns strong references to mBlockedNodesByClassifier. (Document.h)
|
||||
//
|
||||
// This array contains nodes that have been blocked to prevent
|
||||
// user tracking. They most likely have had their nsIChannel
|
||||
// canceled by the URL classifier (Safebrowsing).
|
||||
//
|
||||
already_AddRefed<nsSimpleContentList> BlockedNodesByClassifier() const;
|
||||
|
||||
// Helper method that returns true if the document has storage-access sandbox
|
||||
|
@ -3566,23 +3573,6 @@ class Document : public nsINode,
|
|||
inline ImageDocument* AsImageDocument();
|
||||
inline const ImageDocument* AsImageDocument() const;
|
||||
|
||||
/*
|
||||
* Given a node, get a weak reference to it and append that reference to
|
||||
* mBlockedNodesByClassifier. Can be used later on to look up a node in it.
|
||||
* (e.g., by the UI)
|
||||
*/
|
||||
void AddBlockedNodeByClassifier(nsINode* node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsWeakPtr weakNode = do_GetWeakReference(node);
|
||||
|
||||
if (weakNode) {
|
||||
mBlockedNodesByClassifier.AppendElement(weakNode);
|
||||
}
|
||||
}
|
||||
|
||||
gfxUserFontSet* GetUserFontSet();
|
||||
void FlushUserFontSet();
|
||||
void MarkUserFontSetDirty();
|
||||
|
@ -3607,6 +3597,10 @@ class Document : public nsINode,
|
|||
// effect once per document, and so is called during document destruction.
|
||||
void ReportDocumentUseCounters();
|
||||
|
||||
// Reports largest contentful paint via telemetry. We want the most up to
|
||||
// date value for LCP and so this is called during document destruction.
|
||||
void ReportLCP();
|
||||
|
||||
// Report how lazyload performs for this document.
|
||||
void ReportDocumentLazyLoadCounters();
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ class PlacesBookmarkAddition final : public PlacesBookmark {
|
|||
event->mLastVisitDate.SetNull();
|
||||
}
|
||||
|
||||
event->mTargetFolderItemId = aInitDict.mTargetFolderItemId;
|
||||
event->mTargetFolderGuid = aInitDict.mTargetFolderGuid;
|
||||
event->mTargetFolderTitle = aInitDict.mTargetFolderTitle;
|
||||
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
|
@ -63,6 +67,9 @@ class PlacesBookmarkAddition final : public PlacesBookmark {
|
|||
bool Hidden() { return mHidden; }
|
||||
uint32_t VisitCount() { return mVisitCount; }
|
||||
Nullable<uint64_t> GetLastVisitDate() { return mLastVisitDate; }
|
||||
uint64_t TargetFolderItemId() { return mTargetFolderItemId; }
|
||||
void GetTargetFolderGuid(nsCString& aGuid) { aGuid = mTargetFolderGuid; }
|
||||
void GetTargetFolderTitle(nsString& aTitle) { aTitle = mTargetFolderTitle; }
|
||||
|
||||
int32_t mIndex;
|
||||
nsString mTitle;
|
||||
|
@ -72,6 +79,9 @@ class PlacesBookmarkAddition final : public PlacesBookmark {
|
|||
bool mHidden;
|
||||
uint32_t mVisitCount;
|
||||
Nullable<uint64_t> mLastVisitDate;
|
||||
int64_t mTargetFolderItemId;
|
||||
nsCString mTargetFolderGuid;
|
||||
nsString mTargetFolderTitle;
|
||||
|
||||
private:
|
||||
~PlacesBookmarkAddition() = default;
|
||||
|
|
|
@ -57,6 +57,7 @@ void nsDOMNavigationTiming::Clear() {
|
|||
mDOMContentLoadedEventEnd = TimeStamp();
|
||||
mDOMComplete = TimeStamp();
|
||||
mContentfulComposite = TimeStamp();
|
||||
mLargestContentfulRender = TimeStamp();
|
||||
mNonBlankPaint = TimeStamp();
|
||||
|
||||
mDocShellHasBeenActiveSinceNavigationStart = false;
|
||||
|
@ -478,6 +479,16 @@ void nsDOMNavigationTiming::NotifyContentfulCompositeForRootContentDocument(
|
|||
}
|
||||
}
|
||||
|
||||
void nsDOMNavigationTiming::NotifyLargestContentfulRenderForRootContentDocument(
|
||||
const DOMHighResTimeStamp& aRenderTime) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
||||
// This can get called multiple times and updates over time.
|
||||
mLargestContentfulRender =
|
||||
mNavigationStart + TimeDuration::FromMilliseconds(aRenderTime);
|
||||
}
|
||||
|
||||
void nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
|
|
@ -71,6 +71,10 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
|||
return mContentfulComposite;
|
||||
}
|
||||
|
||||
mozilla::TimeStamp GetLargestContentfulRenderTimeStamp() const {
|
||||
return mLargestContentfulRender;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec GetUnloadEventStart() {
|
||||
return TimeStampToDOM(GetUnloadEventStartTimeStamp());
|
||||
}
|
||||
|
@ -104,6 +108,9 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
|||
DOMTimeMilliSec GetTimeToContentfulComposite() const {
|
||||
return TimeStampToDOM(mContentfulComposite);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToLargestContentfulRender() const {
|
||||
return TimeStampToDOM(mLargestContentfulRender);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToTTFI() const { return TimeStampToDOM(mTTFI); }
|
||||
DOMTimeMilliSec GetTimeToDOMContentFlushed() const {
|
||||
return TimeStampToDOM(mDOMContentFlushed);
|
||||
|
@ -172,6 +179,8 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
|||
void NotifyNonBlankPaintForRootContentDocument();
|
||||
void NotifyContentfulCompositeForRootContentDocument(
|
||||
const mozilla::TimeStamp& aCompositeEndTime);
|
||||
void NotifyLargestContentfulRenderForRootContentDocument(
|
||||
const DOMHighResTimeStamp& aRenderTime);
|
||||
void NotifyDOMContentFlushedForRootContentDocument();
|
||||
void NotifyDocShellStateChanged(DocShellState aDocShellState);
|
||||
|
||||
|
@ -230,6 +239,7 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
|||
mozilla::TimeStamp mNavigationStart;
|
||||
mozilla::TimeStamp mNonBlankPaint;
|
||||
mozilla::TimeStamp mContentfulComposite;
|
||||
mozilla::TimeStamp mLargestContentfulRender;
|
||||
mozilla::TimeStamp mDOMContentFlushed;
|
||||
|
||||
mozilla::TimeStamp mBeforeUnloadStart;
|
||||
|
|
|
@ -220,7 +220,10 @@ support-files = ["captureStream_common.js"]
|
|||
|
||||
["test_capture_throttled.html"]
|
||||
support-files = ["captureStream_common.js"]
|
||||
skip-if = ["os == 'android'"] # bug 1752351
|
||||
skip-if = [
|
||||
"os == 'android'", # Bug 1752351
|
||||
"os == 'win'", # Bug 1777094
|
||||
]
|
||||
|
||||
["test_drawImageIncomplete.html"]
|
||||
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
enum PlacesEventType {
|
||||
"none",
|
||||
|
||||
|
@ -211,6 +215,9 @@ dictionary PlacesBookmarkAdditionInit {
|
|||
required boolean hidden;
|
||||
required unsigned long visitCount;
|
||||
required unsigned long long? lastVisitDate;
|
||||
required long long targetFolderItemId;
|
||||
required ByteString? targetFolderGuid;
|
||||
required DOMString? targetFolderTitle;
|
||||
};
|
||||
|
||||
[ChromeOnly, Exposed=Window]
|
||||
|
@ -256,6 +263,22 @@ interface PlacesBookmarkAddition : PlacesBookmark {
|
|||
* Date of the last visit, in milliseconds since epoch.
|
||||
*/
|
||||
readonly attribute unsigned long long? lastVisitDate;
|
||||
|
||||
/**
|
||||
* If this is a folder shortcut, the id of the target folder.
|
||||
*/
|
||||
readonly attribute long long targetFolderItemId;
|
||||
|
||||
/**
|
||||
* If this is a folder shortcut, the unique ID associated with the target folder.
|
||||
*/
|
||||
readonly attribute ByteString targetFolderGuid;
|
||||
|
||||
/**
|
||||
* If this is a folder shortcut, the title of the target folder.
|
||||
*/
|
||||
readonly attribute DOMString targetFolderTitle;
|
||||
|
||||
};
|
||||
|
||||
dictionary PlacesBookmarkRemovedInit {
|
||||
|
|
|
@ -328,8 +328,14 @@ class ConsoleRunnable : public StructuredCloneHolderBase {
|
|||
|
||||
ConsoleCommon::ClearException ce(aCx);
|
||||
|
||||
// This is the same policy as when writing from the other side, in
|
||||
// WriteData.
|
||||
JS::CloneDataPolicy cloneDataPolicy;
|
||||
cloneDataPolicy.allowIntraClusterClonableSharedObjects();
|
||||
cloneDataPolicy.allowSharedMemoryObjects();
|
||||
|
||||
JS::Rooted<JS::Value> argumentsValue(aCx);
|
||||
if (!Read(aCx, &argumentsValue)) {
|
||||
if (!Read(aCx, &argumentsValue, cloneDataPolicy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4274,7 +4274,7 @@ static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
|
|||
: Nothing();
|
||||
gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
|
||||
CursorImage result{hotspot, std::move(container),
|
||||
image.image.GetResolution(), loading};
|
||||
image.image.GetResolution(style), loading};
|
||||
if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,6 @@
|
|||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsISiteSecurityService.h"
|
||||
#include "nsISound.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIURL.h"
|
||||
|
@ -3631,47 +3630,6 @@ ContentParent::AllocPClipboardWriteRequestParent(
|
|||
return request.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvPlaySound(nsIURI* aURI) {
|
||||
// If the check here fails, it can only mean that this message was spoofed.
|
||||
if (!aURI || !aURI->SchemeIs("chrome")) {
|
||||
// PlaySound only accepts a valid chrome URI.
|
||||
return IPC_FAIL(this, "Invalid aURI passed.");
|
||||
}
|
||||
nsCOMPtr<nsIURL> soundURL(do_QueryInterface(aURI));
|
||||
if (!soundURL) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, IPC_OK());
|
||||
|
||||
sound->Play(soundURL);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvBeep() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, IPC_OK());
|
||||
|
||||
sound->Beep();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvPlayEventSound(
|
||||
const uint32_t& aEventId) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, IPC_OK());
|
||||
|
||||
sound->PlayEventSound(aEventId);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
|
||||
const nsACString& aFileExt, const uint32_t& aIconSize,
|
||||
nsTArray<uint8_t>* bits) {
|
||||
|
|
|
@ -1002,10 +1002,6 @@ class ContentParent final : public PContentParent,
|
|||
already_AddRefed<PClipboardWriteRequestParent>
|
||||
AllocPClipboardWriteRequestParent(const int32_t& aClipboardType);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPlaySound(nsIURI* aURI);
|
||||
mozilla::ipc::IPCResult RecvBeep();
|
||||
mozilla::ipc::IPCResult RecvPlayEventSound(const uint32_t& aEventId);
|
||||
|
||||
mozilla::ipc::IPCResult RecvGetIconForExtension(const nsACString& aFileExt,
|
||||
const uint32_t& aIconSize,
|
||||
nsTArray<uint8_t>* bits);
|
||||
|
|
|
@ -1240,12 +1240,6 @@ parent:
|
|||
*/
|
||||
async PClipboardWriteRequest(int32_t aClipboardType);
|
||||
|
||||
// 'Play', 'Beep' and 'PlayEventSound' are the only nsISound methods used in
|
||||
// the content process.
|
||||
[Compress] async PlaySound(nullable nsIURI aURL);
|
||||
[Compress] async Beep();
|
||||
[Compress] async PlayEventSound(uint32_t aEventId);
|
||||
|
||||
sync GetIconForExtension(nsCString aFileExt, uint32_t aIconSize)
|
||||
returns (uint8_t[] bits);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ struct ParamTraits<mozilla::glean::perf::PageLoadExtra> {
|
|||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
||||
WriteParam(aWriter, aParam.fcpTime);
|
||||
WriteParam(aWriter, aParam.lcpTime);
|
||||
WriteParam(aWriter, aParam.jsExecTime);
|
||||
WriteParam(aWriter, aParam.loadTime);
|
||||
WriteParam(aWriter, aParam.loadType);
|
||||
|
@ -32,6 +33,7 @@ struct ParamTraits<mozilla::glean::perf::PageLoadExtra> {
|
|||
|
||||
static bool Read(MessageReader* aReader, paramType* aResult) {
|
||||
return ReadParam(aReader, &aResult->fcpTime) &&
|
||||
ReadParam(aReader, &aResult->lcpTime) &&
|
||||
ReadParam(aReader, &aResult->jsExecTime) &&
|
||||
ReadParam(aReader, &aResult->loadTime) &&
|
||||
ReadParam(aReader, &aResult->loadType) &&
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "js/ForOfIterator.h" // JS::ForOfIterator
|
||||
#include "js/JSON.h" // JS_ParseJSON
|
||||
#include "json/json.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "DOMLocalization.h"
|
||||
|
@ -646,13 +646,11 @@ void DOMLocalization::ConvertStringToL10nArgs(const nsString& aInput,
|
|||
// There are no properties.
|
||||
return;
|
||||
}
|
||||
// This method uses a temporary dictionary to automate
|
||||
// converting a JSON string into an IDL Record via a dictionary.
|
||||
//
|
||||
// Once we get Record::Init(const nsAString& aJSON), we'll switch to
|
||||
// that.
|
||||
L10nArgsHelperDict helperDict;
|
||||
if (!helperDict.Init(u"{\"args\": "_ns + aInput + u"}"_ns)) {
|
||||
|
||||
Json::Value args;
|
||||
Json::Reader jsonReader;
|
||||
|
||||
if (!jsonReader.parse(NS_ConvertUTF16toUTF8(aInput).get(), args, false)) {
|
||||
nsTArray<nsCString> errors{
|
||||
"[dom/l10n] Failed to parse l10n-args JSON: "_ns +
|
||||
NS_ConvertUTF16toUTF8(aInput),
|
||||
|
@ -660,13 +658,43 @@ void DOMLocalization::ConvertStringToL10nArgs(const nsString& aInput,
|
|||
MaybeReportErrorsToGecko(errors, aRv, GetParentObject());
|
||||
return;
|
||||
}
|
||||
for (auto& entry : helperDict.mArgs.Entries()) {
|
||||
|
||||
if (!args.isObject()) {
|
||||
nsTArray<nsCString> errors{
|
||||
"[dom/l10n] Failed to parse l10n-args JSON: "_ns +
|
||||
NS_ConvertUTF16toUTF8(aInput),
|
||||
};
|
||||
MaybeReportErrorsToGecko(errors, aRv, GetParentObject());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Json::ValueConstIterator iter = args.begin(); iter != args.end();
|
||||
++iter) {
|
||||
L10nArgs::EntryType* newEntry = aRetVal.Entries().AppendElement(fallible);
|
||||
if (!newEntry) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
newEntry->mKey = entry.mKey;
|
||||
newEntry->mValue = entry.mValue;
|
||||
newEntry->mKey = iter.name().c_str();
|
||||
if (iter->isString()) {
|
||||
newEntry->mValue.SetValue().RawSetAsUTF8String().Assign(
|
||||
iter->asString().c_str(), iter->asString().length());
|
||||
} else if (iter->isDouble()) {
|
||||
newEntry->mValue.SetValue().RawSetAsDouble() = iter->asDouble();
|
||||
} else if (iter->isBool()) {
|
||||
if (iter->asBool()) {
|
||||
newEntry->mValue.SetValue().RawSetAsUTF8String().Assign("true");
|
||||
} else {
|
||||
newEntry->mValue.SetValue().RawSetAsUTF8String().Assign("false");
|
||||
}
|
||||
} else if (iter->isNull()) {
|
||||
newEntry->mValue.SetNull();
|
||||
} else {
|
||||
nsTArray<nsCString> errors{
|
||||
"[dom/l10n] Failed to convert l10n-args JSON: "_ns +
|
||||
NS_ConvertUTF16toUTF8(aInput),
|
||||
};
|
||||
MaybeReportErrorsToGecko(errors, aRv, GetParentObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ UNIFIED_SOURCES += [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
"/dom/base",
|
||||
"/toolkit/components/jsoncpp/include",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
["dom_localization/test_getAttributes.html"]
|
||||
|
||||
["dom_localization/test_l10n_args.html"]
|
||||
|
||||
["dom_localization/test_l10n_mutations.html"]
|
||||
|
||||
["dom_localization/test_overlay.html"]
|
||||
|
|
128
dom/l10n/tests/mochitest/dom_localization/test_l10n_args.html
Normal file
128
dom/l10n/tests/mochitest/dom_localization/test_l10n_args.html
Normal file
|
@ -0,0 +1,128 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test DOMLocalization's data-l10n-args handling</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
const l10nReg = new L10nRegistry();
|
||||
const fs = [
|
||||
{ path: "/localization/en-US/mock.ftl", source: `
|
||||
test-simple = Hello { $prop }
|
||||
test-selector = { $prop ->
|
||||
[true] YES
|
||||
*[other] NO
|
||||
}
|
||||
test-error = Hey
|
||||
` },
|
||||
];
|
||||
const source = L10nFileSource.createMock("test", "app", ["en-US"], "/localization/{locale}", fs);
|
||||
l10nReg.registerSources([source]);
|
||||
|
||||
const tests = [
|
||||
// [data-l10n-id, data-l10n-args, expected text content],
|
||||
|
||||
[`test-simple`, `{ "prop": "str" }`, `Hello str`],
|
||||
[`test-simple`, `{ "prop": 10 }`, `Hello 10`],
|
||||
[`test-simple`, `{ "prop": 10.1 }`, `Hello 10.1`],
|
||||
[`test-simple`, `{ "prop": -2 }`, `Hello -2`],
|
||||
[`test-simple`, `{ "prop": true }`, `Hello true`],
|
||||
[`test-simple`, `{ "prop": false }`, `Hello false`],
|
||||
|
||||
[`test-selector`, `{ "prop": "true" }`, `YES`],
|
||||
[`test-selector`, `{ "prop": "false" }`, `NO`],
|
||||
[`test-selector`, `{ "prop": 10 }`, `NO`],
|
||||
[`test-selector`, `{ "prop": true }`, `YES`],
|
||||
[`test-selector`, `{ "prop": false }`, `NO`],
|
||||
|
||||
// Passing null is also valid as long as the property is not referred.
|
||||
[`test-simple`, `{ "prop": "str", "prop2": null }`, `Hello str`],
|
||||
];
|
||||
|
||||
const errorTests = [
|
||||
// Unexpected top-level value.
|
||||
`10`,
|
||||
`"foo"`,
|
||||
`true`,
|
||||
`false`,
|
||||
`[]`,
|
||||
|
||||
// Unsupported property value types.
|
||||
`{ "prop": [] }`,
|
||||
`{ "prop": {} }`,
|
||||
|
||||
// Syntax Error.
|
||||
`a`,
|
||||
`"`,
|
||||
`'foo'`,
|
||||
`{ prop: 10 }`,
|
||||
`{ "prop" }`,
|
||||
`{ "prop": }`,
|
||||
`{ "prop": "a }`,
|
||||
`[`,
|
||||
`}`,
|
||||
`{`,
|
||||
`}`,
|
||||
`{ "prop": [ }`,
|
||||
`{ "prop": { }`,
|
||||
`{ "prop": 10, }`,
|
||||
];
|
||||
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
[],
|
||||
false,
|
||||
l10nReg,
|
||||
["en-US"],
|
||||
);
|
||||
|
||||
const container = document.querySelector("#test-container");
|
||||
|
||||
domLoc.addResourceIds(["/mock.ftl"]);
|
||||
domLoc.connectRoot(document.body);
|
||||
|
||||
for (const [id, args, expected] of tests) {
|
||||
const span = document.createElement("span");
|
||||
span.setAttribute("data-l10n-id", id);
|
||||
span.setAttribute("data-l10n-args", args);
|
||||
container.append(span);
|
||||
|
||||
await domLoc.translateRoots();
|
||||
|
||||
is(span.textContent, expected, `translation for "${id}" with ${args} should become "${expected}"`);
|
||||
|
||||
span.remove();
|
||||
}
|
||||
|
||||
for (const args of errorTests) {
|
||||
const span = document.createElement("span");
|
||||
span.setAttribute("data-l10n-id", "test-error");
|
||||
span.setAttribute("data-l10n-args", args);
|
||||
container.append(span);
|
||||
|
||||
let thrown = false;
|
||||
|
||||
try {
|
||||
await domLoc.translateRoots();
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
|
||||
ok(thrown, `${args} should throw error`);
|
||||
|
||||
span.remove();
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="test-container">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIThread.idl"
|
||||
#include "nsIDOMWindow.idl"
|
||||
#include "nsIPropertyBag2.idl"
|
||||
|
|
|
@ -11,6 +11,32 @@ $tags:
|
|||
- 'Core :: DOM: Core & HTML'
|
||||
|
||||
perf:
|
||||
largest_contentful_paint:
|
||||
type: timing_distribution
|
||||
time_unit: millisecond
|
||||
description: >
|
||||
Time from navigation start to largest contentful paint.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939#c5
|
||||
notification_emails:
|
||||
- perf-telemetry-alerts@mozilla.com
|
||||
expires: never
|
||||
telemetry_mirror: PERF_LARGEST_CONTENTFUL_PAINT_MS
|
||||
largest_contentful_paint_from_response_start:
|
||||
type: timing_distribution
|
||||
time_unit: millisecond
|
||||
description: >
|
||||
Time from response start to largest contentful paint.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939#c5
|
||||
notification_emails:
|
||||
- perf-telemetry-alerts@mozilla.com
|
||||
expires: never
|
||||
telemetry_mirror: PERF_LARGEST_CONTENTFUL_PAINT_FROM_RESPONSE_START_MS
|
||||
page_load:
|
||||
type: event
|
||||
description: >
|
||||
|
@ -19,10 +45,12 @@ perf:
|
|||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1759744
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1799727
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1834774
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1759744#c5
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1799727#c4
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1834774#c3
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1862939#c5
|
||||
notification_emails:
|
||||
- perf-telemetry-alerts@mozilla.com
|
||||
- dpalmeiro@mozilla.com
|
||||
|
@ -45,7 +73,12 @@ perf:
|
|||
unit: ms
|
||||
fcp_time:
|
||||
description:
|
||||
"Time between firstContentfulPaint and naviationStart, in ms."
|
||||
"Time between firstContentfulPaint and navigationStart, in ms."
|
||||
type: quantity
|
||||
unit: ms
|
||||
lcp_time:
|
||||
description:
|
||||
"Time between largestContentfulPaint and navigationStart, at the point of onLoad firing, in ms. This may differ from the final LCP value as reported through the LCP histogram."
|
||||
type: quantity
|
||||
unit: ms
|
||||
js_exec_time:
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "PerformanceMainThread.h"
|
||||
#include "LargestContentfulPaint.h"
|
||||
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/DOMIntersectionObserver.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
@ -54,12 +55,14 @@ LargestContentfulPaint::LargestContentfulPaint(
|
|||
PerformanceMainThread* aPerformance, const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime, const unsigned long aSize,
|
||||
nsIURI* aURI, Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey)
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey,
|
||||
bool aShouldExposeRenderTime)
|
||||
: PerformanceEntry(aPerformance->GetParentObject(), u""_ns,
|
||||
kLargestContentfulPaintName),
|
||||
mPerformance(aPerformance),
|
||||
mRenderTime(aRenderTime),
|
||||
mLoadTime(aLoadTime),
|
||||
mShouldExposeRenderTime(aShouldExposeRenderTime),
|
||||
mSize(aSize),
|
||||
mURI(aURI),
|
||||
mElement(aElement),
|
||||
|
@ -187,24 +190,11 @@ void LargestContentfulPaint::MaybeProcessImageForElementTiming(
|
|||
DOMHighResTimeStamp nowTime =
|
||||
performance->TimeStampToDOMHighResForRendering(TimeStamp::Now());
|
||||
|
||||
if (!request->IsData() && !request->ShouldReportRenderTimeForLCP()) {
|
||||
// https://wicg.github.io/element-timing/#report-image-element-timing
|
||||
LOG(" Added a pending image rendering (TAO FAILED)");
|
||||
// For TAO failed requests, the renderTime is exposed as 0 for
|
||||
// security reasons.
|
||||
LCPHelpers::CreateLCPEntryForImage(performance, aElement, aRequest, nowTime,
|
||||
0 /* aRenderTime */, entryKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, add the triple (element, imageRequest, now) to root’s images
|
||||
// pending rendering.
|
||||
//
|
||||
// At this point, the loadTime of the image is known, but
|
||||
// the renderTime is unknown, so it's added to ImagesPendingRendering
|
||||
// as a placeholder, and the corresponding LCP entry will be created
|
||||
// when the renderTime is known.
|
||||
LOG(" Added a pending image rendering (TAO PASSED)");
|
||||
LOG(" Added a pending image rendering");
|
||||
performance->AddImagesPendingRendering(
|
||||
ImagePendingRendering{entryKey, nowTime});
|
||||
}
|
||||
|
@ -270,6 +260,9 @@ void LCPHelpers::FinalizeLCPEntryForImage(
|
|||
}
|
||||
|
||||
DOMHighResTimeStamp LargestContentfulPaint::RenderTime() const {
|
||||
if (!mShouldExposeRenderTime) {
|
||||
return 0;
|
||||
}
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
mRenderTime, mPerformance->GetRandomTimelineSeed(),
|
||||
mPerformance->GetRTPCallerType());
|
||||
|
@ -282,7 +275,8 @@ DOMHighResTimeStamp LargestContentfulPaint::LoadTime() const {
|
|||
}
|
||||
|
||||
DOMHighResTimeStamp LargestContentfulPaint::StartTime() const {
|
||||
DOMHighResTimeStamp startTime = !mRenderTime ? mLoadTime : mRenderTime;
|
||||
DOMHighResTimeStamp startTime =
|
||||
mShouldExposeRenderTime ? mRenderTime : mLoadTime;
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
startTime, mPerformance->GetRandomTimelineSeed(),
|
||||
mPerformance->GetRTPCallerType());
|
||||
|
@ -299,6 +293,8 @@ Element* LargestContentfulPaint::GetContainingBlockForTextFrame(
|
|||
void LargestContentfulPaint::QueueEntry() {
|
||||
LOG("QueueEntry entry=%p", this);
|
||||
mPerformance->QueueLargestContentfulPaintEntry(this);
|
||||
|
||||
ReportLCPToNavigationTimings();
|
||||
}
|
||||
|
||||
void LargestContentfulPaint::GetUrl(nsAString& aUrl) {
|
||||
|
@ -469,11 +465,20 @@ void LCPHelpers::CreateLCPEntryForImage(
|
|||
nsCOMPtr<nsIURI> requestURI;
|
||||
aRequestProxy->GetURI(getter_AddRefs(requestURI));
|
||||
|
||||
imgRequest* request = aRequestProxy->GetOwner();
|
||||
// We should never get here unless request is valid.
|
||||
MOZ_ASSERT(request);
|
||||
|
||||
bool taoPassed = request->IsData() || request->ShouldReportRenderTimeForLCP();
|
||||
// https://wicg.github.io/element-timing/#report-image-element-timing
|
||||
// For TAO failed requests, the renderTime is exposed as 0 for
|
||||
// security reasons.
|
||||
//
|
||||
// At this point, we have all the information about the entry
|
||||
// except the size.
|
||||
RefPtr<LargestContentfulPaint> entry =
|
||||
new LargestContentfulPaint(aPerformance, aRenderTime, aLoadTime, 0,
|
||||
requestURI, aElement, Some(aImageEntryKey));
|
||||
RefPtr<LargestContentfulPaint> entry = new LargestContentfulPaint(
|
||||
aPerformance, aRenderTime, aLoadTime, 0, requestURI, aElement,
|
||||
Some(aImageEntryKey), taoPassed);
|
||||
|
||||
LOG(" Upsert a LargestContentfulPaint entry=%p to LCPEntryMap.",
|
||||
entry.get());
|
||||
|
@ -496,8 +501,9 @@ void LCPHelpers::FinalizeLCPEntryForText(
|
|||
|
||||
aContainingBlock->SetFlags(ELEMENT_PROCESSED_BY_LCP_FOR_TEXT);
|
||||
|
||||
RefPtr<LargestContentfulPaint> entry = new LargestContentfulPaint(
|
||||
aPerformance, aRenderTime, 0, 0, nullptr, aContainingBlock, Nothing());
|
||||
RefPtr<LargestContentfulPaint> entry =
|
||||
new LargestContentfulPaint(aPerformance, aRenderTime, 0, 0, nullptr,
|
||||
aContainingBlock, Nothing(), true);
|
||||
|
||||
entry->UpdateSize(aContainingBlock, aTargetRectRelativeToSelf, aPerformance,
|
||||
false);
|
||||
|
@ -512,4 +518,31 @@ void LCPHelpers::FinalizeLCPEntryForText(
|
|||
}
|
||||
entry->QueueEntry();
|
||||
}
|
||||
|
||||
void LargestContentfulPaint::ReportLCPToNavigationTimings() {
|
||||
const Document* document = mElement->OwnerDoc();
|
||||
|
||||
MOZ_ASSERT(document);
|
||||
|
||||
nsDOMNavigationTiming* timing = document->GetNavigationTiming();
|
||||
|
||||
if (MOZ_UNLIKELY(!timing)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document->IsResourceDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BrowsingContext* browsingContext = document->GetBrowsingContext()) {
|
||||
if (browsingContext->GetEmbeddedInContentDocument()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!document->IsTopLevelContentDocument()) {
|
||||
return;
|
||||
}
|
||||
timing->NotifyLargestContentfulRenderForRootContentDocument(mRenderTime);
|
||||
}
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -168,12 +168,13 @@ class LargestContentfulPaint final : public PerformanceEntry {
|
|||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LargestContentfulPaint,
|
||||
PerformanceEntry)
|
||||
|
||||
LargestContentfulPaint(
|
||||
PerformanceMainThread* aPerformance,
|
||||
const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime, const unsigned long aSize,
|
||||
nsIURI* aURI, Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey);
|
||||
LargestContentfulPaint(PerformanceMainThread* aPerformance,
|
||||
const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime,
|
||||
const unsigned long aSize, nsIURI* aURI,
|
||||
Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey,
|
||||
bool aShouldExposeRenderTime);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
@ -212,10 +213,17 @@ class LargestContentfulPaint final : public PerformanceEntry {
|
|||
private:
|
||||
~LargestContentfulPaint() = default;
|
||||
|
||||
void ReportLCPToNavigationTimings();
|
||||
|
||||
RefPtr<PerformanceMainThread> mPerformance;
|
||||
|
||||
// This is always set but only exposed to web content if
|
||||
// mShouldExposeRenderTime is true.
|
||||
DOMHighResTimeStamp mRenderTime;
|
||||
DOMHighResTimeStamp mLoadTime;
|
||||
// This is set to false when for security reasons web content it not allowed
|
||||
// to see the RenderTime.
|
||||
const bool mShouldExposeRenderTime;
|
||||
unsigned long mSize;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
|
||||
|
|
|
@ -701,7 +701,7 @@ bool nsHTTPSOnlyUtils::HttpsUpgradeUnrelatedErrorCode(nsresult aError) {
|
|||
NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
|
||||
NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
|
||||
NS_ERROR_HARMFUL_URI == aError || NS_ERROR_CONTENT_CRASHED == aError ||
|
||||
NS_ERROR_FRAME_CRASHED == aError;
|
||||
NS_ERROR_FRAME_CRASHED == aError || NS_ERROR_SUPERFLUOS_AUTH == aError;
|
||||
}
|
||||
|
||||
/* ------ Logging ------ */
|
||||
|
@ -737,11 +737,14 @@ void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
|
|||
// Allow for easy distinction in devtools code.
|
||||
auto category = aUseHttpsFirst ? "HTTPSFirst"_ns : "HTTPSOnly"_ns;
|
||||
|
||||
uint64_t innerWindowId = aLoadInfo->GetInnerWindowID();
|
||||
if (innerWindowId > 0) {
|
||||
uint64_t windowId = aLoadInfo->GetInnerWindowID();
|
||||
if (!windowId) {
|
||||
windowId = aLoadInfo->GetTriggeringWindowId();
|
||||
}
|
||||
if (windowId) {
|
||||
// Send to content console
|
||||
nsContentUtils::ReportToConsoleByWindowID(message, aFlags, category,
|
||||
innerWindowId, aURI);
|
||||
windowId, aURI);
|
||||
} else {
|
||||
// Send to browser console
|
||||
bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
|
|
|
@ -49,4 +49,6 @@ support-files = [
|
|||
"file_slow_download.sjs",
|
||||
]
|
||||
|
||||
["browser_superfluos_auth.js"]
|
||||
|
||||
["browser_upgrade_onion.js"]
|
||||
|
|
67
dom/security/test/https-first/browser_superfluos_auth.js
Normal file
67
dom/security/test/https-first/browser_superfluos_auth.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// This test checks the superfluos auth prompt when HTTPS-First is enabled (Bug 1858565).
|
||||
|
||||
const TEST_URI = "https://www.mozilla.org@example.com/";
|
||||
|
||||
const { MockRegistrar } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/MockRegistrar.sys.mjs"
|
||||
);
|
||||
|
||||
let respondMockPromptWithYes = false;
|
||||
|
||||
const gMockPromptService = {
|
||||
firstTimeCalled: false,
|
||||
confirmExBC() {
|
||||
return respondMockPromptWithYes ? 0 : 1;
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIPromptService"]),
|
||||
};
|
||||
|
||||
var gMockPromptServiceCID = MockRegistrar.register(
|
||||
"@mozilla.org/prompter;1",
|
||||
gMockPromptService
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(gMockPromptServiceCID);
|
||||
});
|
||||
|
||||
function checkBrowserLoad(browser) {
|
||||
return new Promise(resolve => {
|
||||
BrowserTestUtils.browserLoaded(browser, false, null, true).then(() => {
|
||||
resolve(true);
|
||||
});
|
||||
BrowserTestUtils.browserStopped(browser, false, null, true).then(() => {
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.security.https_first", true]],
|
||||
});
|
||||
|
||||
respondMockPromptWithYes = false;
|
||||
let didBrowserLoadPromise = checkBrowserLoad(gBrowser.selectedBrowser);
|
||||
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, TEST_URI);
|
||||
let didBrowserLoad = await didBrowserLoadPromise;
|
||||
ok(
|
||||
!didBrowserLoad,
|
||||
"The browser should stop the load when the user refuses to load a page with superfluos authentication"
|
||||
);
|
||||
|
||||
respondMockPromptWithYes = true;
|
||||
didBrowserLoadPromise = checkBrowserLoad(gBrowser.selectedBrowser);
|
||||
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, TEST_URI);
|
||||
didBrowserLoad = await didBrowserLoadPromise;
|
||||
ok(
|
||||
didBrowserLoad,
|
||||
"The browser should load when the user agrees to load a page with superfluos authentication"
|
||||
);
|
||||
});
|
|
@ -318,7 +318,6 @@ support-files = [
|
|||
["test_sizetocontent_clamp.html"]
|
||||
skip-if = [
|
||||
"os == 'android'", #Windows can't change size on Android
|
||||
"display == 'wayland' && os_version == '22.04'" # Bug 1857032
|
||||
]
|
||||
|
||||
["test_toJSON.html"]
|
||||
|
|
|
@ -35,6 +35,11 @@ var isWin8 = (navigator.userAgent.includes("Windows NT 6.2"));
|
|||
var innerWidthMin = (isWin8 ? 120 : 100);
|
||||
var innerWidthMax = (isWin8 ? 125 : 100);
|
||||
|
||||
// Window size with CSD decorations is 180 pixels
|
||||
if (navigator.platform.includes("Linux")) {
|
||||
innerWidthMax = 180;
|
||||
}
|
||||
|
||||
var isExecuted = false;
|
||||
|
||||
function test() {
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
[Func="mozilla::AddonManagerWebAPI::IsAPIEnabled",
|
||||
Exposed=Window]
|
||||
interface AddonEvent : Event {
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
[Exposed=(Window, Worker), Pref="dom.enable_web_task_scheduling"]
|
||||
interface TaskPriorityChangeEvent : Event {
|
||||
constructor (DOMString type , TaskPriorityChangeEventInit priorityChangeEventInitDict);
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
enum TaskPriority {
|
||||
"user-blocking",
|
||||
"user-visible",
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface mozIDOMWindow;
|
||||
|
|
|
@ -1,3 +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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
|
|
|
@ -3,6 +3,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[
|
||||
"dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
|
||||
true,
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
const testURL = getRootDirectory(gTestPath) + "empty.html";
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -27,17 +36,33 @@ add_task(async function test() {
|
|||
consoleListener.prototype = {
|
||||
onConsoleLogEvent(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
is(
|
||||
obj.arguments[0],
|
||||
"Hello world from a SharedWorker!",
|
||||
"A message from a SharedWorker \\o/"
|
||||
);
|
||||
is(obj.ID, "sharedWorker_console.js", "The ID is SharedWorker");
|
||||
is(obj.innerID, "SharedWorker", "The ID is SharedWorker");
|
||||
is(order++, 1, "Then a log message.");
|
||||
if (order == 1) {
|
||||
is(
|
||||
obj.arguments[0],
|
||||
"Hello world from a SharedWorker!",
|
||||
"A message from a SharedWorker \\o/"
|
||||
);
|
||||
is(obj.ID, "sharedWorker_console.js", "The ID is SharedWorker");
|
||||
is(obj.innerID, "SharedWorker", "The ID is SharedWorker");
|
||||
is(order++, 1, "Then a first log message.");
|
||||
} else {
|
||||
is(
|
||||
obj.arguments[0],
|
||||
"Here is a SAB",
|
||||
"A message from a SharedWorker \\o/"
|
||||
);
|
||||
is(
|
||||
obj.arguments[1].constructor.name,
|
||||
"SharedArrayBuffer",
|
||||
"We got a direct reference to the SharedArrayBuffer coming from the worker thread"
|
||||
);
|
||||
is(obj.ID, "sharedWorker_console.js", "The ID is SharedWorker");
|
||||
is(obj.innerID, "SharedWorker", "The ID is SharedWorker");
|
||||
is(order++, 2, "Then a second log message.");
|
||||
|
||||
ConsoleAPIStorage.removeLogEventListener(this.onConsoleLogEvent);
|
||||
resolve();
|
||||
ConsoleAPIStorage.removeLogEventListener(this.onConsoleLogEvent);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
|
||||
observe: (aSubject, aTopic) => {
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
onconnect = function (evt) {
|
||||
console.profile("Hello profiling from a SharedWorker!");
|
||||
console.log("Hello world from a SharedWorker!");
|
||||
console.log("Here is a SAB", new SharedArrayBuffer(1024));
|
||||
evt.ports[0].postMessage("ok!");
|
||||
};
|
||||
|
|
|
@ -761,7 +761,7 @@ DXGITextureHostD3D11::DXGITextureHostD3D11(
|
|||
mGpuProcessTextureId(aDescriptor.gpuProcessTextureId()),
|
||||
mArrayIndex(aDescriptor.arrayIndex()),
|
||||
mSize(aDescriptor.size()),
|
||||
mHandle(aDescriptor.handle()),
|
||||
mHandle((HANDLE)aDescriptor.handle()),
|
||||
mFormat(aDescriptor.format()),
|
||||
mHasKeyedMutex(aDescriptor.hasKeyedMutex()),
|
||||
mColorSpace(aDescriptor.colorSpace()),
|
||||
|
@ -1088,9 +1088,9 @@ DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(
|
|||
mColorDepth(aDescriptor.colorDepth()),
|
||||
mYUVColorSpace(aDescriptor.yUVColorSpace()),
|
||||
mColorRange(aDescriptor.colorRange()) {
|
||||
mHandles[0] = aDescriptor.handleY();
|
||||
mHandles[1] = aDescriptor.handleCb();
|
||||
mHandles[2] = aDescriptor.handleCr();
|
||||
mHandles[0] = (HANDLE)aDescriptor.handleY();
|
||||
mHandles[1] = (HANDLE)aDescriptor.handleCb();
|
||||
mHandles[2] = (HANDLE)aDescriptor.handleCr();
|
||||
}
|
||||
|
||||
void DXGIYCbCrTextureHostD3D11::CreateRenderTexture(
|
||||
|
|
|
@ -382,7 +382,7 @@ class DXGITextureHostD3D11 : public TextureHost {
|
|||
uint32_t mArrayIndex = 0;
|
||||
RefPtr<DataTextureSourceD3D11> mTextureSource;
|
||||
gfx::IntSize mSize;
|
||||
WindowsHandle mHandle;
|
||||
HANDLE mHandle;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
bool mHasKeyedMutex;
|
||||
|
||||
|
@ -441,7 +441,7 @@ class DXGIYCbCrTextureHostD3D11 : public TextureHost {
|
|||
gfx::IntSize mSize;
|
||||
gfx::IntSize mSizeY;
|
||||
gfx::IntSize mSizeCbCr;
|
||||
WindowsHandle mHandles[3];
|
||||
HANDLE mHandles[3];
|
||||
bool mIsLocked;
|
||||
gfx::ColorDepth mColorDepth;
|
||||
gfx::YUVColorSpace mYUVColorSpace;
|
||||
|
|
|
@ -21,8 +21,7 @@ namespace mozilla {
|
|||
namespace wr {
|
||||
|
||||
RenderDXGITextureHost::RenderDXGITextureHost(
|
||||
WindowsHandle aHandle,
|
||||
Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
|
||||
HANDLE aHandle, Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
|
||||
uint32_t aArrayIndex, gfx::SurfaceFormat aFormat,
|
||||
gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange,
|
||||
gfx::IntSize aSize, bool aHasKeyedMutex)
|
||||
|
@ -445,7 +444,7 @@ bool RenderDXGITextureHost::SyncObjectNeeded() {
|
|||
}
|
||||
|
||||
RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
|
||||
WindowsHandle (&aHandles)[3], gfx::YUVColorSpace aYUVColorSpace,
|
||||
HANDLE (&aHandles)[3], gfx::YUVColorSpace aYUVColorSpace,
|
||||
gfx::ColorDepth aColorDepth, gfx::ColorRange aColorRange,
|
||||
gfx::IntSize aSizeY, gfx::IntSize aSizeCbCr)
|
||||
: mHandles{aHandles[0], aHandles[1], aHandles[2]},
|
||||
|
|
|
@ -22,8 +22,7 @@ namespace wr {
|
|||
class RenderDXGITextureHost final : public RenderTextureHostSWGL {
|
||||
public:
|
||||
RenderDXGITextureHost(
|
||||
WindowsHandle aHandle,
|
||||
Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
|
||||
HANDLE aHandle, Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
|
||||
uint32_t aArrayIndex, gfx::SurfaceFormat aFormat, gfx::ColorSpace2,
|
||||
gfx::ColorRange aColorRange, gfx::IntSize aSize, bool aHasKeyedMutex);
|
||||
|
||||
|
@ -94,7 +93,7 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL {
|
|||
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
|
||||
WindowsHandle mHandle;
|
||||
HANDLE mHandle;
|
||||
Maybe<layers::GpuProcessTextureId> mGpuProcessTextureId;
|
||||
RefPtr<ID3D11Texture2D> mTexture;
|
||||
uint32_t mArrayIndex = 0;
|
||||
|
@ -127,7 +126,7 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL {
|
|||
|
||||
class RenderDXGIYCbCrTextureHost final : public RenderTextureHostSWGL {
|
||||
public:
|
||||
explicit RenderDXGIYCbCrTextureHost(WindowsHandle (&aHandles)[3],
|
||||
explicit RenderDXGIYCbCrTextureHost(HANDLE (&aHandles)[3],
|
||||
gfx::YUVColorSpace aYUVColorSpace,
|
||||
gfx::ColorDepth aColorDepth,
|
||||
gfx::ColorRange aColorRange,
|
||||
|
@ -190,7 +189,7 @@ class RenderDXGIYCbCrTextureHost final : public RenderTextureHostSWGL {
|
|||
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
|
||||
WindowsHandle mHandles[3];
|
||||
HANDLE mHandles[3];
|
||||
RefPtr<ID3D11Texture2D> mTextures[3];
|
||||
RefPtr<IDXGIKeyedMutex> mKeyedMutexs[3];
|
||||
|
||||
|
|
|
@ -167,9 +167,13 @@ void UPowerClient::BeginListening() {
|
|||
UpdateTrackedDevices();
|
||||
},
|
||||
[](GUniquePtr<GError>&& aError) {
|
||||
g_warning(
|
||||
"Failed to create DBus proxy for org.freedesktop.UPower: %s\n",
|
||||
aError->message);
|
||||
if (!g_error_matches(aError.get(), G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED)) {
|
||||
g_warning(
|
||||
"Failed to create DBus proxy for org.freedesktop.UPower: "
|
||||
"%s\n",
|
||||
aError->message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -275,9 +279,12 @@ void UPowerClient::UpdateTrackedDevices() {
|
|||
G_CALLBACK(DeviceChanged), this);
|
||||
},
|
||||
[this](GUniquePtr<GError>&& aError) {
|
||||
g_warning(
|
||||
"Failed to enumerate devices of org.freedesktop.UPower: %s\n",
|
||||
aError->message);
|
||||
if (!g_error_matches(aError.get(), G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED)) {
|
||||
g_warning(
|
||||
"Failed to enumerate devices of org.freedesktop.UPower: %s\n",
|
||||
aError->message);
|
||||
}
|
||||
g_signal_connect(mUPowerProxy, "g-signal",
|
||||
G_CALLBACK(DeviceChanged), this);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ static constexpr DWORD kShutdownWaitMs = 80000;
|
|||
// Sanitizers also slow things down in some cases; see bug 1806224.
|
||||
static constexpr DWORD kShutdownWaitMs = 40000;
|
||||
#else
|
||||
static constexpr DWORD kShutdownWaitMs = 8000;
|
||||
static constexpr DWORD kShutdownWaitMs = 20000;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -1703,6 +1703,13 @@ void MessageChannel::DispatchMessage(ActorLifecycleProxy* aProxy,
|
|||
|
||||
UniquePtr<Message> reply;
|
||||
|
||||
#ifdef FUZZING_SNAPSHOT
|
||||
if (IsCrossProcess()) {
|
||||
aMsg = mozilla::fuzzing::IPCFuzzController::instance().replaceIPCMessage(
|
||||
std::move(aMsg));
|
||||
}
|
||||
#endif
|
||||
|
||||
IPC_LOG("DispatchMessage: seqno=%d, xid=%d", aMsg->seqno(),
|
||||
aMsg->transaction_id());
|
||||
AddProfilerMarker(*aMsg, MessageDirection::eReceiving);
|
||||
|
@ -1736,6 +1743,12 @@ void MessageChannel::DispatchMessage(ActorLifecycleProxy* aProxy,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef FUZZING_SNAPSHOT
|
||||
if (aMsg->IsFuzzMsg()) {
|
||||
mozilla::fuzzing::IPCFuzzController::instance().syncAfterReplace();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (reply && ChannelConnected == mChannelState) {
|
||||
IPC_LOG("Sending reply seqno=%d, xid=%d", aMsg->seqno(),
|
||||
aMsg->transaction_id());
|
||||
|
|
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