Update On 202108010529

This commit is contained in:
GitHub Actions 2021-08-01 05:29:10 +08:00
parent fc43d50a0c
commit f57cabae8c
396 changed files with 8813 additions and 4420 deletions

34
Cargo.lock generated
View file

@ -1472,6 +1472,7 @@ dependencies = [
name = "fluent-ffi"
version = "0.1.0"
dependencies = [
"cstr",
"fluent",
"fluent-fallback",
"fluent-pseudo",
@ -1481,6 +1482,7 @@ dependencies = [
"nsstring",
"thin-vec",
"unic-langid",
"xpcom",
]
[[package]]
@ -1744,6 +1746,12 @@ dependencies = [
[[package]]
name = "gecko-profiler"
version = "0.1.0"
dependencies = [
"bindgen",
"lazy_static",
"profiler-macros",
"toml",
]
[[package]]
name = "gecko_logger"
@ -1788,6 +1796,7 @@ dependencies = [
"bincode",
"cssparser",
"cstr",
"gecko-profiler",
"libc",
"log",
"malloc_size_of",
@ -2018,7 +2027,6 @@ dependencies = [
"processtools",
"profiler_helper",
"qcms",
"remote",
"rlbox_lucet_sandbox",
"rsdparsa_capi",
"rusqlite",
@ -2659,6 +2667,9 @@ dependencies = [
"async-trait",
"cstr",
"fluent",
"fluent-fallback",
"fluent-ffi",
"futures 0.3.15",
"futures-channel",
"l10nregistry",
"libc",
@ -3937,6 +3948,14 @@ dependencies = [
"xpcom",
]
[[package]]
name = "profiler-macros"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "profiler_helper"
version = "0.1.0"
@ -4175,19 +4194,6 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remote"
version = "0.1.0"
dependencies = [
"http",
"libc",
"log",
"nserror",
"nsstring",
"thiserror",
"xpcom",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"

View file

@ -1818,8 +1818,16 @@ LayoutDeviceIntRect HyperTextAccessible::GetCaretRect(nsIWidget** aWidget) {
// the character. This is important for font size transitions, and is
// necessary because the Gecko caret uses the previous character's size as
// the user moves forward in the text by character.
int32_t caretOffset = CaretOffset();
if (NS_WARN_IF(caretOffset == -1)) {
// The caret offset will be -1 if this Accessible isn't focused. Note that
// the DOM node contaning the caret might be focused, but the Accessible
// might not be; e.g. due to an autocomplete popup suggestion having a11y
// focus.
return LayoutDeviceIntRect();
}
nsIntRect charRect = CharBounds(
CaretOffset(), nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
caretOffset, nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
if (!charRect.IsEmpty()) {
caretRect.SetTopEdge(charRect.Y());
}

View file

@ -23,6 +23,7 @@ support-files =
[test_flush.html]
[test_focusable_statechange.html]
[test_focus_aria_activedescendant.html]
[test_focus_autocomplete.html]
[test_focus_autocomplete.xhtml]
# Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795
skip-if = os == 'win' || os == 'linux'

View file

@ -0,0 +1,83 @@
<!doctype html>
<head>
<title>Form Autocomplete Tests</title>
<link rel="stylesheet"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script src="../common.js"></script>
<script src="../promisified-events.js"></script>
<script src="../role.js"></script>
<script type="application/javascript">
const { TestUtils } = ChromeUtils.import(
"resource://testing-common/TestUtils.jsm");
async function waitForFocusOnOptionWithname(name) {
let event = await waitForEvent(
EVENT_FOCUS,
evt => evt.accessible.role == ROLE_COMBOBOX_OPTION
);
if (!event.accessible.name) {
// Sometimes, the name is null for a very short time after the focus
// event.
await waitForEvent(EVENT_NAME_CHANGE, event.accessible);
}
is(event.accessible.name, name, "Got focus on option with name " + name);
}
async function doTests() {
const input = getNode("input");
info("Focusing the input");
let focused = waitForEvent(EVENT_FOCUS, input);
input.focus();
await focused;
let shown = waitForEvent(EVENT_SHOW, event =>
event.accessible.role == ROLE_GROUPING &&
event.accessible.firstChild.role == ROLE_COMBOBOX_LIST);
info("Pressing ArrowDown to open the popup");
synthesizeKey("KEY_ArrowDown");
await shown;
// The popup still doesn't seem to be ready even once it's fired an a11y
// show event!
const controller = Cc["@mozilla.org/autocomplete/controller;1"].
getService(Ci.nsIAutoCompleteController);
info("Waiting for popup to be fully open and ready");
await TestUtils.waitForCondition(() => controller.input.popupOpen);
focused = waitForFocusOnOptionWithname("a");
info("Pressing ArrowDown to focus first item");
synthesizeKey("KEY_ArrowDown");
await focused;
focused = waitForFocusOnOptionWithname("b");
info("Pressing ArrowDown to focus the second item");
synthesizeKey("KEY_ArrowDown");
await focused;
focused = waitForEvent(EVENT_FOCUS, input);
info("Pressing enter to select the second item");
synthesizeKey("KEY_Enter");
await focused;
is(input.value, "b", "input value filled with second item");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<input id="input" list="list">
<datalist id="list">
<option id="a" value="a">
<option id="b" value="b">
</datalist>
</body>
</html>

View file

@ -67,10 +67,10 @@ bool XULColumnItemAccessible::DoAction(uint8_t aIndex) const {
XULListboxAccessible::XULListboxAccessible(nsIContent* aContent,
DocAccessible* aDoc)
: XULSelectControlAccessible(aContent, aDoc) {
nsIContent* parentContent = mContent->GetFlattenedTreeParent();
if (parentContent) {
dom::Element* parentEl = mContent->GetParentElement();
if (parentEl) {
nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
parentContent->AsElement()->AsAutoCompletePopup();
parentEl->AsAutoCompletePopup();
if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
}

View file

@ -31,7 +31,6 @@ pref("extensions.strictCompatibility", false);
// extensions.checkCompatibility=false has been set.
pref("extensions.checkCompatibility.temporaryThemeOverride_minAppVersion", "29.0a1");
pref("extensions.webextPermissionPrompts", true);
pref("extensions.webextOptionalPermissionPrompts", true);
// If enabled, install origin permission verification happens after addons are downloaded.
pref("extensions.postDownloadThirdPartyPrompt", true);

View file

@ -68,7 +68,7 @@
oncommand="gBrowser.selectAllTabs();"/>
<menuseparator/>
<menuitem id="context_closeTab"
data-lazy-l10n-id="tab-context-close-tabs"
data-lazy-l10n-id="tab-context-close-n-tabs"
data-l10n-args='{"tabCount": 1}'
oncommand="TabContextMenu.closeContextTabs();"/>
<menu id="context_closeTabOptions"

View file

@ -270,6 +270,8 @@ var whitelist = [
},
{ file: "chrome://browser/content/screenshots/menu-fullpage.svg" },
{ file: "chrome://browser/content/screenshots/menu-visible.svg" },
{ file: "resource://app/modules/SnapshotSelector.jsm" },
];
if (AppConstants.NIGHTLY_BUILD && AppConstants.platform != "win") {

View file

@ -11,7 +11,6 @@ skip-if =
[browser_aboutRestartRequired_buildid.js]
skip-if =
!debug
(os == 'win')
[browser_autoSubmitRequest.js]
skip-if =
apple_silicon # crash bug 1707182

View file

@ -657,6 +657,9 @@ var DownloadsCommon = {
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
message = s.unblockTypePotentiallyUnwanted2;
break;
case Downloads.Error.BLOCK_VERDICT_INSECURE:
message = s.unblockInsecure;
break;
default:
// Assume Downloads.Error.BLOCK_VERDICT_MALWARE
message = s.unblockTypeMalware;

View file

@ -24,6 +24,7 @@ add_task(async function test_unblock_dialog_unblock() {
for (let verdict of [
Downloads.Error.BLOCK_VERDICT_MALWARE,
Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
Downloads.Error.BLOCK_VERDICT_INSECURE,
Downloads.Error.BLOCK_VERDICT_UNCOMMON,
]) {
let args = { verdict, window, dialogType: "unblock" };
@ -46,54 +47,64 @@ add_task(async function test_unblock_dialog_unblock() {
* Tests the "chooseUnblock" dialog for potentially unwanted downloads.
*/
add_task(async function test_chooseUnblock_dialog() {
let args = {
verdict: Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
window,
dialogType: "chooseUnblock",
};
for (let verdict of [
Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
Downloads.Error.BLOCK_VERDICT_INSECURE,
]) {
let args = {
verdict,
window,
dialogType: "chooseUnblock",
};
// Test each of the three buttons.
await assertDialogResult({
args,
buttonToClick: "accept",
expectedResult: "unblock",
});
await assertDialogResult({
args,
buttonToClick: "cancel",
expectedResult: "cancel",
});
await assertDialogResult({
args,
buttonToClick: "extra1",
expectedResult: "confirmBlock",
});
// Test each of the three buttons.
await assertDialogResult({
args,
buttonToClick: "accept",
expectedResult: "unblock",
});
await assertDialogResult({
args,
buttonToClick: "cancel",
expectedResult: "cancel",
});
await assertDialogResult({
args,
buttonToClick: "extra1",
expectedResult: "confirmBlock",
});
}
});
/**
* Tests the "chooseOpen" dialog for uncommon downloads.
*/
add_task(async function test_chooseOpen_dialog() {
let args = {
verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
window,
dialogType: "chooseOpen",
};
for (let verdict of [
Downloads.Error.BLOCK_VERDICT_UNCOMMON,
Downloads.Error.BLOCK_VERDICT_INSECURE,
]) {
let args = {
verdict,
window,
dialogType: "chooseOpen",
};
// Test each of the three buttons.
await assertDialogResult({
args,
buttonToClick: "accept",
expectedResult: "open",
});
await assertDialogResult({
args,
buttonToClick: "cancel",
expectedResult: "cancel",
});
await assertDialogResult({
args,
buttonToClick: "extra1",
expectedResult: "confirmBlock",
});
// Test each of the three buttons.
await assertDialogResult({
args,
buttonToClick: "accept",
expectedResult: "open",
});
await assertDialogResult({
args,
buttonToClick: "cancel",
expectedResult: "cancel",
});
await assertDialogResult({
args,
buttonToClick: "extra1",
expectedResult: "confirmBlock",
});
}
});

View file

@ -22,6 +22,7 @@ async function testManifest(manifest, expectedError) {
}`
);
}
return normalized.errors;
}
const all_actions = [
@ -75,16 +76,7 @@ add_task(async function test_manifest() {
add_task(async function test_action_version() {
// The above test validates these work with the correct version,
// here we verify they fail with the incorrect version.
testManifest(
{
manifest_version: 2,
action: {
default_panel: "foo.html",
},
},
/Property "action" is unsupported in Manifest Version 2/
);
// here we verify they fail with the incorrect version for MV3.
testManifest(
{
manifest_version: 3,
@ -94,4 +86,29 @@ add_task(async function test_action_version() {
},
/Property "browser_action" is unsupported in Manifest Version 3/
);
// But we still allow previously ignored keys in MV2, just warn about them.
ExtensionTestUtils.failOnSchemaWarnings(false);
let warnings = await testManifest({
manifest_version: 2,
action: {
default_icon: "",
default_panel: "foo.html",
},
});
equal(warnings.length, 2, "Got exactly two warnings");
equal(
warnings[0],
`Property "action" is unsupported in Manifest Version 2`,
`Manifest v2 with "action" key first warning is clear.`
);
equal(
warnings[1],
"Warning processing action: An unexpected property was found in the WebExtension manifest.",
`Manifest v2 with "action" key second warning has more details.`
);
ExtensionTestUtils.failOnSchemaWarnings(true);
});

View file

@ -50,6 +50,8 @@ Please note that some targeting attributes require stricter controls on the tele
* [activeNotifications](#activenotifications)
* [isMajorUpgrade](#ismajorupgrade)
* [hasActiveEnterprisePolicies](#hasactiveenterprisepolicies)
* [mainPingSubmissions](#mainpingsubmissions)
* [userMonthlyActivity](#usermonthlyactivity)
## Detailed usage
@ -816,3 +818,23 @@ A boolean. `true` if the browser just updated to a new major version.
### `hasActiveEnterprisePolicies`
A boolean. `true` if any Enterprise Policies are active.
### `mainPingSubmissions`
Filter through the local telemetry pings archive submitted and select the `main`
pings sent at least 24 hours apart. Result is sorted in ascending order.
```javascript
interface MainTelemetryPing {
id: string,
type: "main",
timestampCreated: number,
}
declare const mainPingSubmissions: Promise<MainTelemetryPing[]>
```
### `userMonthlyActivity`
Returns an array of entries in the form `[int, unixTimestamp]` for each day of
user activity where the first entry is the total urls visited for that day.

View file

@ -28,6 +28,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
HomePage: "resource:///modules/HomePage.jsm",
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
TelemetryArchive: "resource://gre/modules/TelemetryArchive.jsm",
});
XPCOMUtils.defineLazyPreferenceGetter(
@ -243,6 +244,7 @@ const QueryCache = {
CheckBrowserNeedsUpdate: new CheckBrowserNeedsUpdate(),
RecentBookmarks: new CachedTargetingGetter("getRecentBookmarks"),
ListAttachedOAuthClients: new CacheListAttachedOAuthClients(),
UserMonthlyActivity: new CachedTargetingGetter("getUserMonthlyActivity"),
},
};
@ -634,6 +636,38 @@ const TargetingGetters = {
get hasActiveEnterprisePolicies() {
return Services.policies.status === Services.policies.ACTIVE;
},
get mainPingSubmissions() {
return (
TelemetryArchive.promiseArchivedPingList()
// Filter out non-main pings. Do it before so we compare timestamps
// between pings of same type.
.then(pings => pings.filter(p => p.type === "main"))
.then(pings => {
if (pings.length <= 1) {
return pings;
}
// Pings are returned in ascending order.
return pings.reduce(
(acc, ping) => {
if (
// Keep only main pings sent a day (or more) apart
new Date(ping.timestampCreated).toDateString() !==
new Date(acc[acc.length - 1].timestampCreated).toDateString()
) {
acc.push(ping);
}
return acc;
},
[pings[0]]
);
})
);
},
get userMonthlyActivity() {
return QueryCache.queries.UserMonthlyActivity.get();
},
};
this.ASRouterTargeting = {

View file

@ -16,7 +16,6 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
OS: "resource://gre/modules/osfile.jsm",
Services: "resource://gre/modules/Services.jsm",
});
@ -200,7 +199,7 @@ class _RemoteL10n {
// In the case that the Fluent file has not been downloaded from Remote Settings,
// `fetchFile` will return `false` and fall back to the packaged Fluent file.
const resource = await fs.fetchFile(appLocale, "asrouter.ftl");
for await (let bundle of L10nRegistry.generateBundles(
for await (let bundle of L10nRegistry.getInstance().generateBundles(
appLocales.slice(0, 1),
resourceIds
)) {

View file

@ -1103,3 +1103,10 @@ add_task(async function check_is_major_upgrade() {
"Should select the message"
);
});
add_task(async function check_userMonthlyActivity() {
ok(
Array.isArray(await ASRouterTargeting.Environment.userMonthlyActivity),
"value is an array"
);
});

View file

@ -273,6 +273,103 @@ describe("#CacheListAttachedOAuthClients", () => {
assert.calledOnce(fxAccounts.listAttachedOAuthClients);
});
});
describe("#mainPingSubmissions", () => {
let promiseArchivedPingList;
let globals;
let sandbox;
beforeEach(() => {
sandbox = sinon.createSandbox();
globals = new GlobalOverrider();
});
afterEach(() => {
sandbox.restore();
globals.restore();
});
it("should return an empty list", async () => {
promiseArchivedPingList = sandbox.stub().resolves([]);
globals.set("TelemetryArchive", { promiseArchivedPingList });
assert.typeOf(
await ASRouterTargeting.Environment.mainPingSubmissions,
"array",
"we get back an array"
);
assert.lengthOf(
await ASRouterTargeting.Environment.mainPingSubmissions,
0,
"no pings available"
);
});
it("should filter out bhr pings", async () => {
promiseArchivedPingList = sandbox.stub().resolves([
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaaf",
timestampCreated: 1622525975674,
type: "bhr",
},
]);
globals.set("TelemetryArchive", { promiseArchivedPingList });
assert.lengthOf(
await ASRouterTargeting.Environment.mainPingSubmissions,
0,
"no `main` pings available"
);
});
it("should filter out pings less than 24hrs apart", async () => {
let startTime = 0;
promiseArchivedPingList = sandbox.stub().resolves([
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaaf",
timestampCreated: 1622525975674,
type: "bhr",
},
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaaa",
timestampCreated: startTime,
type: "main",
},
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaaa",
timestampCreated: startTime + 1000,
type: "main",
},
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaac",
timestampCreated: startTime + 86400001,
type: "main",
},
]);
globals.set("TelemetryArchive", { promiseArchivedPingList });
assert.lengthOf(
await ASRouterTargeting.Environment.mainPingSubmissions,
2,
"1 main ping is removed"
);
});
it("should allow for pings < 24hrs apart but on different days", async () => {
let startTime = new Date("2020-02-20").getTime();
let oneDay = 86400000;
promiseArchivedPingList = sandbox.stub().resolves([
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaaa",
// Using oneDay / 2 because timezone of browser running the test
// affects the calculation
timestampCreated: startTime - oneDay / 2,
type: "main",
},
{
id: "5c8c786b-eca5-734b-a755-7ec0f022aaac",
timestampCreated: startTime + 1000,
type: "main",
},
]);
globals.set("TelemetryArchive", { promiseArchivedPingList });
assert.lengthOf(
await ASRouterTargeting.Environment.mainPingSubmissions,
2,
"pings are less day oneDay apart but fall on different days"
);
});
});
describe("ASRouterTargeting", () => {
let evalStub;
let sandbox;

View file

@ -235,7 +235,7 @@ class _Interactions {
* Used by tests.
*/
async reset() {
logConsole.debug("Reset");
logConsole.debug("Database reset");
this.#interactions = new WeakMap();
this.#userIsIdle = false;
this._pageViewStartTime = Cu.now();
@ -270,11 +270,11 @@ class _Interactions {
}
if (InteractionsBlocklist.isUrlBlocklisted(docInfo.url)) {
logConsole.debug("URL is blocklisted", docInfo);
logConsole.debug("Ignoring a page as the URL is blocklisted", docInfo);
return;
}
logConsole.debug("New interaction", docInfo);
logConsole.debug("Tracking a new interaction", docInfo);
let now = monotonicNow();
interaction = {
url: docInfo.url,
@ -312,7 +312,7 @@ class _Interactions {
if (!browser) {
return;
}
logConsole.debug("End of interaction");
logConsole.debug("Saw the end of an interaction");
this.#updateInteraction(browser);
this.#interactions.delete(browser);
@ -331,7 +331,7 @@ class _Interactions {
!this.#activeWindow ||
(browser && browser.ownerGlobal != this.#activeWindow)
) {
logConsole.debug("No update due to no active window");
logConsole.debug("Not updating interaction as there is no active window");
return;
}
@ -340,7 +340,7 @@ class _Interactions {
// Sometimes an interaction may be signalled before idle is cleared, however
// worst case we'd only loose approx 2 seconds of interaction detail.
if (this.#userIsIdle) {
logConsole.debug("No update due to user is idle");
logConsole.debug("Not updating interaction as the user is idle");
return;
}
@ -362,7 +362,6 @@ class _Interactions {
interaction.keypresses += typingInteraction.keypresses;
interaction.updated_at = monotonicNow();
logConsole.debug("Add to store: ", interaction);
this.store.add(interaction);
}
@ -372,7 +371,7 @@ class _Interactions {
* @param {DOMWindow} win
*/
#onActivateWindow(win) {
logConsole.debug("Activate window");
logConsole.debug("Window activated");
if (PrivateBrowsingUtils.isWindowPrivate(win)) {
return;
@ -388,7 +387,7 @@ class _Interactions {
* @param {DOMWindow} win
*/
#onDeactivateWindow(win) {
logConsole.debug("Deactivate window");
logConsole.debug("Window deactivate");
this.#updateInteraction();
this.#activeWindow = undefined;
@ -403,7 +402,7 @@ class _Interactions {
* The instance of the browser that the user switched away from.
*/
#onTabSelect(previousBrowser) {
logConsole.debug("Tab switch notified");
logConsole.debug("Tab switched");
this.#updateInteraction(previousBrowser);
this._pageViewStartTime = Cu.now();
@ -444,14 +443,14 @@ class _Interactions {
this.#onWindowOpen(subject);
break;
case "idle":
logConsole.debug("idle");
logConsole.debug("User went idle");
// We save the state of the current interaction when we are notified
// that the user is idle.
this.#updateInteraction();
this.#userIsIdle = true;
break;
case "active":
logConsole.debug("active");
logConsole.debug("User became active");
this.#userIsIdle = false;
this._pageViewStartTime = Cu.now();
break;
@ -620,6 +619,8 @@ class InteractionsStore {
* The document information to write.
*/
add(interaction) {
logConsole.debug("Preparing interaction for storage", interaction);
let interactionsForUrl = this.#interactions.get(interaction.url);
if (!interactionsForUrl) {
interactionsForUrl = new Map();
@ -631,7 +632,6 @@ class InteractionsStore {
let promise = new Promise(resolve => {
this.#timerResolve = resolve;
this.#timer = setTimeout(() => {
logConsole.debug("Save Timer");
this.#updateDatabase()
.catch(Cu.reportError)
.then(resolve);
@ -704,7 +704,9 @@ class InteractionsStore {
i++;
}
}
logConsole.debug(`Storing ${i} entries in the database`);
this.progress.pendingUpdates = i;
await PlacesUtils.withConnectionWrapper(
"Interactions.jsm::updateDatabase",
@ -724,6 +726,8 @@ class InteractionsStore {
);
this.progress.pendingUpdates = 0;
Services.obs.notifyObservers(null, "places-metadata-updated");
if (this.#userIsIdle) {
this.updateSnapshots();
}

View file

@ -0,0 +1,186 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const EXPORTED_SYMBOLS = ["SnapshotSelector"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
Services: "resource://gre/modules/Services.jsm",
Snapshots: "resource:///modules/Snapshots.jsm",
});
XPCOMUtils.defineLazyGetter(this, "logConsole", function() {
return console.createInstance({
prefix: "SnapshotSelector",
maxLogLevel: Services.prefs.getBoolPref(
"browser.places.interactions.log",
false
)
? "Debug"
: "Warn",
});
});
/**
* A snapshot selector is responsible for generating a list of snapshots based
* on the current context. The context initially is just the url of the page
* being viewed but will evolve to include things like the search terms that
* brought the user to that page etc.
*
* Individual snapshots can be told to rebuild their set of snapshots and a
* global function is provided that triggers all current selectors to rebuild.
*
* The selector is an event emitter that will emit a "snapshots-updated" event
* when a new list is generated.
*
* This component is intentionally decoupled from where the context comes from
* so it can be unit tested.
*/
class SnapshotSelector extends EventEmitter {
/**
* All of the active selectors.
*/
static #selectors = new Set();
/**
* Triggers a rebuild of all selectors.
*/
static rebuildAll() {
for (let selector of SnapshotSelector.#selectors) {
selector.rebuild();
}
}
/**
* The context should be thought of as the current state for this specific
* selector. Global state that impacts all selectors should not be kept here.
*/
#context = {
/**
* The number of snapshots desired.
* @type {number}
*/
count: undefined,
/**
* The page the snapshots are for.
* @type {string | undefined}
*/
url: undefined,
/**
* The type of snapshots desired.
* @type {PageDataCollector.DATA_TYPE | undefined}
*/
type: undefined,
};
/**
* A DeferredTask that runs the task to generate snapshots.
*/
#task = null;
/**
* @param {number} count
* The maximum number of snapshots we ever need to generate. This should not
* affect the actual snapshots generated and their order but may speed up
* calculations.
*/
constructor(count = 5) {
super();
this.#task = new DeferredTask(() => this.#buildSnapshots(), 500);
this.#context.count = count;
SnapshotSelector.#selectors.add(this);
}
/**
* Call to destroy the selector.
*/
destroy() {
this.#task.disarm();
this.#task.finalize();
this.#task = null;
SnapshotSelector.#selectors.delete(this);
}
rebuild() {
this.#task.arm();
}
/**
* Called internally when the set of snapshots has been generated.
*
* @param {Snapshot[]} snapshots
*/
#snapshotsGenerated(snapshots) {
logConsole.debug(
"Generated snapshots",
snapshots.map(s => s.url)
);
this.emit("snapshots-updated", snapshots);
}
/**
* Starts the process of building snapshots.
*/
async #buildSnapshots() {
// Task a copy of the context to avoid it changing while we are generating
// the list.
let context = { ...this.#context };
logConsole.debug("Building snapshots", context);
// Query for one more than we need in case the current url is returned.
let snapshots = await Snapshots.query({
limit: context.count + 1,
type: context.type,
});
snapshots = snapshots
.filter(snapshot => snapshot.url != context.url)
.slice(0, context.count);
this.#snapshotsGenerated(snapshots);
}
/**
* Sets the current context's url for this selector.
*
* @param {string} url
*/
setUrl(url) {
if (this.#context.url == url) {
return;
}
this.#context.url = url;
this.rebuild();
}
/**
* Sets the type of snapshots for this selector.
*
* @param {PageDataCollector.DATA_TYPE | undefined} type
*/
async setType(type) {
if (this.#context.type === type) {
return;
}
this.#context.type = type;
this.rebuild();
}
}
// Listen for global events that may affect the snapshots generated.
Services.obs.addObserver(SnapshotSelector.rebuildAll, "places-snapshots-added");
Services.obs.addObserver(
SnapshotSelector.rebuildAll,
"places-snapshots-deleted"
);
Services.obs.addObserver(
SnapshotSelector.rebuildAll,
"places-metadata-updated"
);

View file

@ -467,7 +467,7 @@ const Snapshots = new (class Snapshots {
}
logConsole.debug(
`Updating ${urls ? urls.length : "all"} potential snapshots`
`Testing ${urls ? urls.length : "all"} potential snapshots`
);
let model;
@ -475,7 +475,9 @@ const Snapshots = new (class Snapshots {
model = JSON.parse(snapshotCriteria);
if (!model.length) {
logConsole.debug(`No model provided, falling back to default`);
logConsole.debug(
`No snapshot criteria provided, falling back to default`
);
model = DEFAULT_CRITERIA;
}
} catch (e) {
@ -576,7 +578,7 @@ const Snapshots = new (class Snapshots {
);
if (insertedUrls.length) {
logConsole.debug(`Inserted ${insertedUrls.length} snapshots.`);
logConsole.debug(`${insertedUrls.length} snapshots created`);
await this.#addPageData(insertedUrls);
this.#notify(
"places-snapshots-added",

View file

@ -21,6 +21,7 @@ EXTRA_JS_MODULES += [
"InteractionsBlocklist.jsm",
"PlacesUIUtils.jsm",
"Snapshots.jsm",
"SnapshotSelector.jsm",
]
FINAL_TARGET_FILES.actors += [

View file

@ -206,6 +206,26 @@ function assertSnapshot(actual, expected) {
}
}
/**
* Asserts that the list of snapshots match the expected values.
*
* @param {Snapshot[]} received
* The received snapshots.
* @param {Snapshot[]} expected
* The expected snapshots.
*/
async function assertSnapshotList(received, expected) {
info(`Found ${received.length} snapshots:\n ${JSON.stringify(received)}`);
Assert.equal(
received.length,
expected.length,
"Should have the expected number of snapshots"
);
for (let i = 0; i < expected.length; i++) {
assertSnapshot(received[i], expected[i]);
}
}
/**
* Asserts that the snapshots in the database match the expected values.
*
@ -217,15 +237,7 @@ function assertSnapshot(actual, expected) {
async function assertSnapshots(expected, options) {
let snapshots = await Snapshots.query(options);
info(`Found ${snapshots.length} snapshots:\n ${JSON.stringify(snapshots)}`);
Assert.equal(
snapshots.length,
expected.length,
"Should have the expected number of snapshots"
);
for (let i = 0; i < expected.length; i++) {
assertSnapshot(snapshots[i], expected[i]);
}
await assertSnapshotList(snapshots, expected);
}
/**

View file

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that we select the most recent set of snapshots excluding the current
* url.
*/
const TEST_URL1 = "https://example.com/";
const TEST_URL2 = "https://example.com/12345";
const TEST_URL3 = "https://example.com/14235";
const TEST_URL4 = "https://example.com/14345";
XPCOMUtils.defineLazyModuleGetters(this, {
SnapshotSelector: "resource:///modules/SnapshotSelector.jsm",
});
add_task(async function setup() {
let now = Date.now();
await addInteractions([
{ url: TEST_URL1, created_at: now - 2000 },
{ url: TEST_URL2, created_at: now - 1000 },
{ url: TEST_URL3, created_at: now - 3000 },
]);
let selector = new SnapshotSelector(2);
let snapshotPromise = selector.once("snapshots-updated");
selector.rebuild();
let snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, []);
snapshotPromise = selector.once("snapshots-updated");
await Snapshots.add({ url: TEST_URL1 });
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, [{ url: TEST_URL1 }]);
// Changing the url should generate new snapshots and should exclude the
// current url.
snapshotPromise = selector.once("snapshots-updated");
selector.setUrl(TEST_URL1);
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, []);
snapshotPromise = selector.once("snapshots-updated");
selector.setUrl(TEST_URL2);
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, [{ url: TEST_URL1 }]);
snapshotPromise = selector.once("snapshots-updated");
await Snapshots.add({ url: TEST_URL2 });
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, [{ url: TEST_URL1 }]);
snapshotPromise = selector.once("snapshots-updated");
await Snapshots.add({ url: TEST_URL3 });
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, [{ url: TEST_URL1 }, { url: TEST_URL3 }]);
snapshotPromise = selector.once("snapshots-updated");
selector.setUrl(TEST_URL3);
snapshots = await snapshotPromise;
await assertSnapshotList(snapshots, [{ url: TEST_URL2 }, { url: TEST_URL1 }]);
snapshotPromise = selector.once("snapshots-updated");
selector.setUrl(TEST_URL4);
snapshots = await snapshotPromise;
// The snapshot count is limited to 2.
await assertSnapshotList(snapshots, [{ url: TEST_URL2 }, { url: TEST_URL1 }]);
await reset();
});

View file

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that we select the most recent set of snapshots excluding the current
* url.
*/
const TEST_URL1 = "https://example.com/";
const TEST_URL2 = "https://example.com/12345";
const TEST_URL3 = "https://example.com/14235";
const TEST_URL4 = "https://example.com/14345";
XPCOMUtils.defineLazyModuleGetters(this, {
SnapshotSelector: "resource:///modules/SnapshotSelector.jsm",
PageDataService: "resource:///modules/pagedata/PageDataService.jsm",
PageDataCollector: "resource:///modules/pagedata/PageDataCollector.jsm",
});
add_task(async () => {
let now = Date.now();
await addInteractions([
{ url: TEST_URL1, created_at: now - 2000 },
{ url: TEST_URL2, created_at: now - 1000 },
{ url: TEST_URL3, created_at: now - 3000 },
]);
PageDataService.pageDataDiscovered(TEST_URL1, [
{
type: PageDataCollector.DATA_TYPE.PRODUCT,
data: {
price: 276,
},
},
]);
await Snapshots.add({ url: TEST_URL1 });
await Snapshots.add({ url: TEST_URL2 });
await Snapshots.add({ url: TEST_URL3 });
let selector = new SnapshotSelector(5);
let snapshotPromise = selector.once("snapshots-updated");
selector.setUrl(TEST_URL4);
let snapshots = await snapshotPromise;
// Finds any snapshot.
await assertSnapshotList(snapshots, [
{ url: TEST_URL2 },
{ url: TEST_URL1 },
{ url: TEST_URL3 },
]);
snapshotPromise = selector.once("snapshots-updated");
selector.setType(PageDataCollector.DATA_TYPE.PRODUCT);
snapshots = await snapshotPromise;
// Only finds the product snapshot.
await assertSnapshotList(snapshots, [{ url: TEST_URL1 }]);
snapshotPromise = selector.once("snapshots-updated");
selector.setType(undefined);
snapshots = await snapshotPromise;
// Back to any.
await assertSnapshotList(snapshots, [
{ url: TEST_URL2 },
{ url: TEST_URL1 },
{ url: TEST_URL3 },
]);
await reset();
});

View file

@ -2,6 +2,7 @@
prefs =
browser.places.interactions.enabled=true
browser.places.interactions.log=true
browser.pagedata.enabled=true
browser.pagedata.log=true
head = head_interactions.js
firefox-appdir = browser
@ -12,3 +13,5 @@ skip-if = toolkit == 'android'
[test_snapshots_create_criteria.js]
[test_snapshots_pagedata.js]
[test_snapshots_queries.js]
[test_snapshotselection_recent.js]
[test_snapshotselection_typed.js]

View file

@ -17,9 +17,6 @@ var { TransientPrefs } = ChromeUtils.import(
var { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
var { L10nRegistry } = ChromeUtils.import(
"resource://gre/modules/L10nRegistry.jsm"
);
var { HomePage } = ChromeUtils.import("resource:///modules/HomePage.jsm");
ChromeUtils.defineModuleGetter(
this,
@ -263,7 +260,7 @@ function getBundleForLocales(newLocales) {
])
);
function generateBundles(resourceIds) {
return L10nRegistry.generateBundles(locales, resourceIds);
return L10nRegistry.getInstance().generateBundles(locales, resourceIds);
}
return new Localization(
["browser/preferences/preferences.ftl", "branding/brand.ftl"],

View file

@ -17,7 +17,9 @@ support-files =
[browser_cross_origin_isolated_reduce_time_precision.js]
[browser_dynamical_window_rounding.js]
https_first_disabled = true
skip-if = (os == "mac") #Bug 1570812
skip-if =
(os == "mac") #Bug 1570812
os == 'linux' && bits == 64 && !debug # Bug 1570812
[browser_navigator.js]
https_first_disabled = true
skip-if =

View file

@ -63,10 +63,6 @@ ChromeUtils.defineModuleGetter(
// with region names based on en-US. This is
// necessary for tests that expect to match
// on region code display names.
const { L10nRegistry } = ChromeUtils.import(
"resource://gre/modules/L10nRegistry.jsm"
);
const fs = [
{
path: "toolkit/intl/regionNames.ftl",
@ -87,7 +83,7 @@ region-name-tw = Taiwan
"resource://mock_path",
fs
);
L10nRegistry.registerSources([mockSource]);
L10nRegistry.getInstance().registerSources([mockSource]);
}
do_get_profile();

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "24.13.0",
"version": "24.14.0",
"applications": {
"gecko": {
@ -97,6 +97,7 @@
"shims/bmauth.js",
"shims/chartbeat.js",
"shims/criteo.js",
"shims/cxense.js",
"shims/eluminate.js",
"shims/empty-script.js",
"shims/empty-shim.txt",

View file

@ -86,6 +86,7 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["shims"] += [
"shims/bmauth.js",
"shims/chartbeat.js",
"shims/criteo.js",
"shims/cxense.js",
"shims/eluminate.js",
"shims/empty-script.js",
"shims/empty-shim.txt",

View file

@ -0,0 +1,593 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Bug 1713721 - Shim Cxense
*
* Sites relying on window.cX can experience breakage if it is blocked.
* Stubbing out the API in a shim can mitigate this breakage. There are
* two versions of the API, one including window.cX.CCE, but both appear
* to be very similar so we use one shim for both.
*/
if (window.cX?.getUserSegmentIds === undefined) {
const callQueue = window.cX?.callQueue || [];
const callQueueCCE = window.cX?.CCE?.callQueue || [];
function getRandomString(l = 16) {
const v = crypto.getRandomValues(new Uint8Array(l));
const s = Array.from(v, c => c.toString(16)).join("");
return s.slice(0, l);
}
const call = (cb, ...args) => {
if (typeof cb !== "function") {
return;
}
try {
cb(...args);
} catch (e) {
console.error(e);
}
};
const invokeOn = lib => {
return (fn, ...args) => {
try {
lib[fn](...args);
} catch (e) {
console.error(e);
}
};
};
const userId = getRandomString();
const cxUserId = `cx:${getRandomString(25)}:${getRandomString(12)}`;
const topLeft = { left: 0, top: 0 };
const margins = { left: 0, top: 0, right: 0, bottom: 0 };
const ccePushUrl =
"https://comcluster.cxense.com/cce/push?callback={{callback}}";
const displayWidget = (divId, a, ctx, callback) => call(callback, ctx, divId);
const getUserSegmentIds = a => call(a?.callback, a?.defaultValue || []);
const init = (a, b, c, d, callback) => call(callback);
const render = (a, data, ctx, callback) => call(callback, data, ctx);
const run = (params, ctx, callback) => call(callback, params, ctx);
const runCtrlVersion = (a, b, callback) => call(callback);
const runCxVersion = (a, data, b, ctx, callback) => call(callback, data, ctx);
const runTest = (a, divId, b, c, ctx, callback) => call(callback, divId, ctx);
const sendConversionEvent = (a, options) => call(options?.callback, {});
const sendEvent = (a, b, args) => call(args?.callback, {});
const getDivId = className => {
const e = document.querySelector(`.${className}`);
if (e) {
return `${className}-01`;
}
return null;
};
const getDocumentSize = () => {
const width = document.body.clientWidth;
const height = document.body.clientHeight;
return { width, height };
};
const getNowSeconds = () => {
return Math.round(new Date().getTime() / 1000);
};
const getPageContext = () => {
return {
location: location.href,
pageViewRandom: "",
userId,
};
};
const getWindowSize = () => {
const width = window.innerWidth;
const height = window.innerHeight;
return { width, height };
};
const isObject = i => {
return typeof i === "object" && i !== null && !Array.isArray(i);
};
const runMulti = widgets => {
widgets?.forEach(({ widgetParams, widgetContext, widgetCallback }) => {
call(widgetCallback, widgetParams, widgetContext);
});
};
let testGroup = -1;
let snapPoints = [];
const startTime = new Date();
const library = {
addCustomerScript() {},
addEventListener() {},
addExternalId() {},
afterInitializePage() {},
allUserConsents() {},
backends: {
production: {
baseAdDeliveryUrl: "http://adserver.cxad.cxense.com/adserver/search",
secureBaseAdDeliveryUrl:
"https://s-adserver.cxad.cxense.com/adserver/search",
},
sandbox: {
baseAdDeliveryUrl:
"http://adserver.sandbox.cxad.cxense.com/adserver/search",
secureBaseAdDeliveryUrl:
"https://s-adserver.sandbox.cxad.cxense.com/adserver/search",
},
},
calculateAdSpaceSize(adCount, adUnitSize, marginA, marginB) {
return adCount * (adUnitSize + marginA + marginB);
},
cdn: {
template: {
direct: {
http: "http://cdn.cxpublic.com/",
https: "https://cdn.cxpublic.com/",
},
mapped: {
http: "http://cdn-templates.cxpublic.com/",
https: "https://cdn-templates.cxpublic.com/",
},
},
},
cint() {},
cleanUpGlobalIds: [],
clearBaseUrl: "https://scdn.cxense.com/sclear.html",
clearCustomParameters() {},
clearIdUrl: "https://scomcluster.cxense.com/public/clearid",
clearIds() {},
clickTracker: (a, b, callback) => call(callback),
clientStorageUrl: "https://clientstorage.cxense.com",
combineArgs: () => Object.create(),
combineKeywordsIntoArray: () => [],
consentClasses: ["pv", "segment", "ad", "recs"],
consentClassesV2: ["geo", "device"],
cookieSyncRUrl: "csyn-r.cxense.com",
createDelegate() {},
csdUrls: {
domainScriptUrl: "//csd.cxpublic.com/d/",
customerScriptUrl: "//csd.cxpublic.com/t/",
},
cxenseGlobalIdIframeUrl: "https://scdn.cxense.com/sglobal.html",
cxenseUserIdUrl: "https://id.cxense.com/public/user/id",
decodeUrlEncodedNameValuePairs: () => Object.create(),
defaultAdRenderer: () => "",
deleteCookie() {},
denyWithoutConsent: {
addExternalId: "pv",
getUserSegmentIds: "segment",
insertAdSpace: "ad",
insertMultipleAdSpaces: "ad",
sendEvent: "pv",
sendPageViewEvent: "pv",
sync: "ad",
},
dmpPushUrl: "https://comcluster.cxense.com/dmp/push?callback={{callback}}",
emptyWidgetUrl: "https://scdn.cxense.com/empty.html",
eventReceiverBaseUrl: "https://scomcluster.cxense.com/Repo/rep.html",
eventReceiverBaseUrlGif: "https://scomcluster.cxense.com/Repo/rep.gif",
getAllText: () => "",
getClientStorageVariable() {},
getCookie: () => null,
getCxenseUserId: () => cxUserId,
getDocumentSize,
getElementPosition: () => topLeft,
getHashFragment: () => location.hash.substr(1),
getLocalStats: () => Object.create(),
getNodeValue: n => n.nodeValue,
getNowSeconds,
getPageContext,
getRandomString,
getScrollPos: () => topLeft,
getSessionId: () => "",
getSiteId: () => "",
getTimezoneOffset: () => new Date().getTimezoneOffset(),
getTopLevelDomain: () => location.hostname,
getUserId: () => userId,
getUserSegmentIds,
getWindowSize,
hasConsent: () => true,
hasHistory: () => true,
hasLocalStorage: () => true,
hasPassiveEventListeners: () => true,
hasPostMessage: () => true,
hasSessionStorage() {},
initializePage() {},
insertAdSpace() {},
insertMultipleAdSpaces() {},
insertWidget() {},
invoke: invokeOn(library),
isAmpIFrame() {},
isArray() {},
isCompatModeActive() {},
isConsentRequired() {},
isEdge: () => false,
isFirefox: () => true,
isIE6Or7: () => false,
isObject,
isRecsDestination: () => false,
isSafari: () => false,
isTextNode: n => n?.nodeType === 3,
isTopWindow: () => window === top,
jsonpRequest: () => false,
loadScript() {},
m_accountId: "0",
m_activityEvents: false,
m_activityState: {
activeTime: startTime,
currScrollLeft: 0,
currScrollTop: 0,
exitLink: "",
hadHIDActivity: false,
maxViewLeft: 1,
maxViewTop: 1,
parentMetrics: undefined,
prevActivityTime: startTime + 2,
prevScreenX: 0,
prevScreenY: 0,
prevScrollLeft: 0,
prevScrollTop: 0,
prevTime: startTime + 1,
prevWindowHeight: 1,
prevWindowWidth: 1,
scrollDepthPercentage: 0,
scrollDepthPixels: 0,
},
m_atfr: null,
m_c1xTpWait: 0,
m_clientStorage: {
iframeEl: null,
iframeIsLoaded: false,
iframeOrigin: "https://clientstorage.cxense.com",
iframePath: "/clientstorage_v2.html",
messageContexts: {},
messageQueue: [],
},
m_compatMode: {},
m_compatModeActive: false,
m_compatPvSent: false,
m_consentVersion: 1,
m_customParameters: [],
m_documentSizeRequestedFromChild: false,
m_externalUserIds: [],
m_globalIdLoading: {
globalIdIFrameEl: null,
globalIdIFrameElLoaded: false,
},
m_isSpaRecsDestination: false,
m_knownMessageSources: [],
m_p1Complete: false,
m_prevLocationHash: "",
m_previousPageViewReport: null,
m_rawCustomParameters: {},
m_rnd: getRandomString(),
m_scriptStartTime: startTime,
m_siteId: "0",
m_spaRecsClickUrl: null,
m_thirdPartyIds: true,
m_usesConsent: false,
m_usesIabConsent: false,
m_usesSecureCookies: true,
m_usesTcf20Consent: false,
m_widgetSpecs: {},
Object,
onClearIds() {},
onFFP1() {},
onP1() {},
p1BaseUrl: "https://scdn.cxense.com/sp1.html",
p1JsUrl: "https://p1cluster.cxense.com/p1.js",
parseHashArgs: () => Object.create(),
parseMargins: () => margins,
parseUrlArgs: () => Object.create(),
postMessageToParent() {},
publicWidgetDataUrl: "https://api.cxense.com/public/widget/data",
removeClientStorageVariable() {},
removeEventListener() {},
renderContainedImage: () => "<div/>",
renderTemplate: () => "<div/>",
reportActivity() {},
requireActivityEvents() {},
requireConsent() {},
requireOnlyFirstPartyIds() {},
requireSecureCookies() {},
requireTcf20() {},
sendEvent,
sendSpaRecsClick: (a, callback) => call(callback),
setAccountId() {},
setAllConsentsTo() {},
setClientStorageVariable() {},
setCompatMode() {},
setConsent() {},
setCookie() {},
setCustomParameters() {},
setEventAttributes() {},
setGeoPosition() {},
setNodeValue() {},
setRandomId() {},
setRestrictionsToConsentClasses() {},
setRetargetingParameters() {},
setSiteId() {},
setUserProfileParameters() {},
setupIabCmp() {},
setupTcfApi() {},
shouldPollActivity() {},
startLocalStats() {},
startSessionAnnotation() {},
stopAllSessionAnnotations() {},
stopSessionAnnotation() {},
sync() {},
trackAmpIFrame() {},
trackElement() {},
trim: s => s.trim(),
tsridUrl: "https://tsrid.cxense.com/lookup?callback={{callback}}",
userSegmentUrl:
"https://api.cxense.com/profile/user/segment?callback={{callback}}",
};
const libraryCCE = {
"__cx-toolkit__": {
isShown: true,
data: [],
},
activeSnapPoint: null,
activeWidgets: [],
ccePushUrl,
clickTracker: () => "",
displayResult() {},
displayWidget,
getDivId,
getTestGroup: () => testGroup,
init,
insertMaster() {},
instrumentClickLinks() {},
invoke: invokeOn(libraryCCE),
noCache: false,
offerProductId: null,
persistedQueryId: null,
prefix: null,
previewCampaign: null,
previewDiv: null,
previewId: null,
previewTestId: null,
processCxResult() {},
render,
reportTestImpression() {},
run,
runCtrlVersion,
runCxVersion,
runMulti,
runTest,
sendConversionEvent,
sendPageViewEvent: (a, b, c, callback) => call(callback),
setSnapPoints(x) {
snapPoints = x;
},
setTestGroup(x) {
testGroup = x;
},
setVisibilityField() {},
get snapPoints() {
return snapPoints;
},
startTime,
get testGroup() {
return testGroup;
},
testVariant: null,
trackTime: 0.5,
trackVisibility() {},
updateRecsClickUrls() {},
utmParams: [],
version: "2.42",
visibilityField: "timeHalf",
};
const CCE = {
activeSnapPoint: null,
activeWidgets: [],
callQueue: callQueueCCE,
ccePushUrl,
clickTracker: () => "",
displayResult() {},
displayWidget,
getDivId,
getTestGroup: () => testGroup,
init,
insertMaster() {},
instrumentClickLinks() {},
invoke: invokeOn(libraryCCE),
library: libraryCCE,
noCache: false,
offerProductId: null,
persistedQueryId: null,
prefix: null,
previewCampaign: null,
previewDiv: null,
previewId: null,
previewTestId: null,
processCxResult() {},
render,
reportTestImpression() {},
run,
runCtrlVersion,
runCxVersion,
runMulti,
runTest,
sendConversionEvent,
sendPageViewEvent: (a, b, c, callback) => call(callback),
setSnapPoints(x) {
snapPoints = x;
},
setTestGroup(x) {
testGroup = x;
},
setVisibilityField() {},
get snapPoints() {
return snapPoints;
},
startTime,
get testGroup() {
return testGroup;
},
testVariant: null,
trackTime: 0.5,
trackVisibility() {},
updateRecsClickUrls() {},
utmParams: [],
version: "2.42",
visibilityField: "timeHalf",
};
window.cX = {
addCustomerScript() {},
addEventListener() {},
addExternalId() {},
afterInitializePage() {},
allUserConsents: () => undefined,
Array,
calculateAdSpaceSize: () => 0,
callQueue,
CCE,
cint: () => undefined,
clearCustomParameters() {},
clearIds() {},
clickTracker: () => "",
combineArgs: () => Object.create(),
combineKeywordsIntoArray: () => [],
createDelegate() {},
decodeUrlEncodedNameValuePairs: () => Object.create(),
defaultAdRenderer: () => "",
deleteCookie() {},
getAllText: () => "",
getClientStorageVariable() {},
getCookie: () => null,
getCxenseUserId: () => cxUserId,
getDocumentSize,
getElementPosition: () => topLeft,
getHashFragment: () => location.hash.substr(1),
getLocalStats: () => Object.create(),
getNodeValue: n => n.nodeValue,
getNowSeconds,
getPageContext,
getRandomString,
getScrollPos: () => topLeft,
getSessionId: () => "",
getSiteId: () => "",
getTimezoneOffset: () => new Date().getTimezoneOffset(),
getTopLevelDomain: () => location.hostname,
getUserId: () => userId,
getUserSegmentIds,
getWindowSize,
hasConsent: () => true,
hasHistory: () => true,
hasLocalStorage: () => true,
hasPassiveEventListeners: () => true,
hasPostMessage: () => true,
hasSessionStorage() {},
initializePage() {},
insertAdSpace() {},
insertMultipleAdSpaces() {},
insertWidget() {},
invoke: invokeOn(library),
isAmpIFrame() {},
isArray() {},
isCompatModeActive() {},
isConsentRequired() {},
isEdge: () => false,
isFirefox: () => true,
isIE6Or7: () => false,
isObject,
isRecsDestination: () => false,
isSafari: () => false,
isTextNode: n => n?.nodeType === 3,
isTopWindow: () => window === top,
JSON,
jsonpRequest: () => false,
library,
loadScript() {},
Object,
onClearIds() {},
onFFP1() {},
onP1() {},
parseHashArgs: () => Object.create(),
parseMargins: () => margins,
parseUrlArgs: () => Object.create(),
postMessageToParent() {},
removeClientStorageVariable() {},
removeEventListener() {},
renderContainedImage: () => "<div/>",
renderTemplate: () => "<div/>",
reportActivity() {},
requireActivityEvents() {},
requireConsent() {},
requireOnlyFirstPartyIds() {},
requireSecureCookies() {},
requireTcf20() {},
sendEvent,
sendPageViewEvent: (a, callback) => call(callback, {}),
sendSpaRecsClick() {},
setAccountId() {},
setAllConsentsTo() {},
setClientStorageVariable() {},
setCompatMode() {},
setConsent() {},
setCookie() {},
setCustomParameters() {},
setEventAttributes() {},
setGeoPosition() {},
setNodeValue() {},
setRandomId() {},
setRestrictionsToConsentClasses() {},
setRetargetingParameters() {},
setSiteId() {},
setUserProfileParameters() {},
setupIabCmp() {},
setupTcfApi() {},
shouldPollActivity() {},
startLocalStats() {},
startSessionAnnotation() {},
stopAllSessionAnnotations() {},
stopSessionAnnotation() {},
sync() {},
trackAmpIFrame() {},
trackElement() {},
trim: s => s.trim(),
};
window.cxTest = window.cX;
window.cx_pollActiveTime = () => undefined;
window.cx_pollActivity = () => undefined;
window.cx_pollFragmentMessage = () => undefined;
const execQueue = (lib, queue) => {
return () => {
const invoke = invokeOn(lib);
setTimeout(() => {
queue.push = cmd => {
setTimeout(() => invoke(...cmd), 1);
};
for (const cmd of queue) {
invoke(...cmd);
}
}, 25);
};
};
window.cx_callQueueExecute = execQueue(library, callQueue);
window.cxCCE_callQueueExecute = execQueue(libraryCCE, callQueueCCE);
window.cx_callQueueExecute();
window.cxCCE_callQueueExecute();
}

View file

@ -197,8 +197,6 @@
; WebDriver (Marionette, Remote Agent) remote protocols
#ifdef ENABLE_WEBDRIVER
@RESPATH@/components/marionette.manifest
@RESPATH@/components/marionette.js
@RESPATH@/chrome/remote@JAREXT@
@RESPATH@/chrome/remote.manifest
#endif

View file

@ -80,11 +80,11 @@ tab-context-reopen-closed-tabs =
*[other] Reopen Closed Tabs
}
.accesskey = o
tab-context-close-tabs =
tab-context-close-n-tabs =
.label =
{ $tabCount ->
[1] Close Tab
*[other] Close Tabs
*[other] Close { $tabCount } Tabs
}
.accesskey = C
tab-context-move-tabs =

View file

@ -67,6 +67,7 @@ const TOTAL_URI_COUNT_NORMAL_AND_PRIVATE_MODE_SCALAR_NAME =
"browser.engagement.total_uri_count_normal_and_private_mode";
const CONTENT_PROCESS_COUNT = "CONTENT_PROCESS_COUNT";
const CONTENT_PROCESS_PRECISE_COUNT = "CONTENT_PROCESS_PRECISE_COUNT";
const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms
const CONTENT_PROCESS_COUNT_INTERVAL_MS = 5 * 60 * 1000;
@ -433,7 +434,8 @@ let BrowserUsageTelemetry = {
Services.prefs.addObserver("browser.tabs.drawInTitlebar", this);
this._recordUITelemetry();
this._contentProcessCountInterval = setInterval(
this._recordContentProcessCountInterval = setInterval(
() => this._recordContentProcessCount(),
CONTENT_PROCESS_COUNT_INTERVAL_MS
);
@ -480,7 +482,6 @@ let BrowserUsageTelemetry = {
Services.obs.removeObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC);
clearInterval(this._recordContentProcessCountInterval);
this._recordContentProcessCountDelayed = null;
},
observe(subject, topic, data) {
@ -1276,6 +1277,9 @@ let BrowserUsageTelemetry = {
const count = ChromeUtils.getAllDOMProcesses().length - 1;
Services.telemetry.getHistogramById(CONTENT_PROCESS_COUNT).add(count);
Services.telemetry
.getHistogramById(CONTENT_PROCESS_PRECISE_COUNT)
.add(count);
},
};

View file

@ -22,13 +22,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
});
XPCOMUtils.defineLazyPreferenceGetter(
this,
"WEBEXT_PERMISSION_PROMPTS",
"extensions.webextPermissionPrompts",
false
);
const DEFAULT_EXTENSION_ICON =
"chrome://mozapps/skin/extensions/extensionGeneric.svg";
@ -84,31 +77,29 @@ var ExtensionsUI = {
// happening in a specific order.
sideloaded.sort((a, b) => a.id.localeCompare(b.id));
if (WEBEXT_PERMISSION_PROMPTS) {
if (!this.sideloadListener) {
this.sideloadListener = {
onEnabled: addon => {
if (!this.sideloaded.has(addon)) {
return;
}
if (!this.sideloadListener) {
this.sideloadListener = {
onEnabled: addon => {
if (!this.sideloaded.has(addon)) {
return;
}
this.sideloaded.delete(addon);
this._updateNotifications();
this.sideloaded.delete(addon);
this._updateNotifications();
if (this.sideloaded.size == 0) {
AddonManager.removeAddonListener(this.sideloadListener);
this.sideloadListener = null;
}
},
};
AddonManager.addAddonListener(this.sideloadListener);
}
for (let addon of sideloaded) {
this.sideloaded.add(addon);
}
this._updateNotifications();
if (this.sideloaded.size == 0) {
AddonManager.removeAddonListener(this.sideloadListener);
this.sideloadListener = null;
}
},
};
AddonManager.addAddonListener(this.sideloadListener);
}
for (let addon of sideloaded) {
this.sideloaded.add(addon);
}
this._updateNotifications();
},
_updateNotifications() {

View file

@ -38,6 +38,7 @@
#include "mozilla/ContentBlocking.h"
#include "nsPIDOMWindow.h"
#include "nsIURIMutator.h"
#include "mozilla/PermissionManager.h"
#include "json/json.h"
#include "nsSerializationHelper.h"
@ -391,8 +392,36 @@ BasePrincipal::EqualsForPermission(nsIPrincipal* aOther, bool aExactHost,
NS_ENSURE_ARG_POINTER(aOther);
NS_ENSURE_ARG_POINTER(aResult);
// If the principals are equal, then they match.
if (FastEquals(aOther)) {
auto* other = Cast(aOther);
if (Kind() != other->Kind()) {
// Principals of different kinds can't be equal.
return NS_OK;
}
if (Kind() == eSystemPrincipal) {
*aResult = this == other;
return NS_OK;
}
if (Kind() == eNullPrincipal) {
// We don't store permissions for NullPrincipals.
return NS_OK;
}
MOZ_ASSERT(Kind() == eExpandedPrincipal || Kind() == eContentPrincipal);
// Certain origin attributes should not be used to isolate permissions.
// Create a stripped copy of both OA sets to compare.
mozilla::OriginAttributes ourAttrs = mOriginAttributes;
PermissionManager::MaybeStripOriginAttributes(false, ourAttrs);
mozilla::OriginAttributes theirAttrs = aOther->OriginAttributesRef();
PermissionManager::MaybeStripOriginAttributes(false, theirAttrs);
if (ourAttrs != theirAttrs) {
return NS_OK;
}
if (mOriginNoSuffix == other->mOriginNoSuffix) {
*aResult = true;
return NS_OK;
}
@ -403,22 +432,18 @@ BasePrincipal::EqualsForPermission(nsIPrincipal* aOther, bool aExactHost,
return NS_OK;
}
// Compare their OriginAttributes
const mozilla::OriginAttributes& theirAttrs = aOther->OriginAttributesRef();
const mozilla::OriginAttributes& ourAttrs = OriginAttributesRef();
if (theirAttrs != ourAttrs) {
return NS_OK;
}
nsCOMPtr<nsIURI> ourURI;
nsresult rv = GetURI(getter_AddRefs(ourURI));
NS_ENSURE_SUCCESS(rv, rv);
auto* basePrin = BasePrincipal::Cast(aOther);
// Some principal types may indicate success, but still return nullptr for
// URI.
NS_ENSURE_TRUE(ourURI, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> otherURI;
rv = basePrin->GetURI(getter_AddRefs(otherURI));
rv = other->GetURI(getter_AddRefs(otherURI));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(otherURI, NS_ERROR_FAILURE);
// Compare schemes
nsAutoCString otherScheme;
rv = otherURI->GetScheme(otherScheme);

View file

@ -9,8 +9,8 @@ origin:
description: rlbox integration for the wasm2c sandboxed code
url: https://github.com/PLSysSec/rlbox_wasm2c_sandbox
release: commit 3ed74da56a45bc6e556eea60d83995ee2ab962f8 (2021-07-11T21:18:27Z).
revision: 3ed74da56a45bc6e556eea60d83995ee2ab962f8
release: commit 1cd3e4165d30d3ecc30974744e6fd52caa2a3f1d (2021-07-23T02:53:22Z).
revision: 1cd3e4165d30d3ecc30974744e6fd52caa2a3f1d
license: MIT
license-file: LICENSE

View file

@ -9,8 +9,8 @@ origin:
description: wasm2c fork used for rlbox sandboxing
url: https://github.com/PLSysSec/wasm2c_sandbox_compiler
release: commit 498f15980a553dd41bc6ff97fb22b5ee1c52f701 (2021-07-11T23:33:38Z).
revision: 498f15980a553dd41bc6ff97fb22b5ee1c52f701
release: commit df7630a80686c1e3bc775a6cb261841e99484b54 (2021-07-28T00:22:29Z).
revision: df7630a80686c1e3bc775a6cb261841e99484b54
license: Apache-2.0
license-file: LICENSE

View file

@ -503,7 +503,7 @@ $(LIBRARY): $(OBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(WASM_ARCHIVE): $(CWASMOBJS) $(CPPWASMOBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD_VERBOSE)
$(RM) $(WASM_ARCHIVE)
$(WASM_CXX) $(OUTOPTION)$@ -Wl,--export-all $(if $(LUCETC),,-Wl,--no-entry -Wl,--growable-table) $(CWASMOBJS) $(CPPWASMOBJS)
$(WASM_CXX) $(OUTOPTION)$@ -Wl,--export-all -Wl,--stack-first -Wl,-z,stack-size=$(if $(MOZ_OPTIMIZE),262144,1048576) $(if $(LUCETC),,-Wl,--no-entry -Wl,--growable-table) $(CWASMOBJS) $(CPPWASMOBJS)
ifdef LUCETC
lucet_options := \

View file

@ -589,7 +589,6 @@ system_headers = [
'Palettes.h',
'PALM_CMN.H',
'pango/pango-break.h',
'pango/pangocairo.h',
'pango/pangofc-decoder.h',
'pango/pangofc-font.h',
'pango/pangofc-fontmap.h',

View file

@ -4,7 +4,6 @@
"use strict";
const Services = require("Services");
const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
const EventEmitter = require("devtools/shared/event-emitter");
@ -146,7 +145,7 @@ AccessibilityPanel.prototype = {
*/
async createFluentBundles() {
const locales = Services.locale.appLocalesAsBCP47;
const generator = L10nRegistry.generateBundles(locales, [
const generator = L10nRegistry.getInstance().generateBundles(locales, [
"devtools/client/accessibility.ftl",
]);

View file

@ -4,22 +4,26 @@
PromiseTestUtils.allowMatchingRejectionsGlobally(/Connection closed/);
// Test that sources appear in the debugger when navigating using the BFCache.
// Test the debugger when navigating using the BFCache.
add_task(async function() {
info("Run test with bfcacheInParent DISABLED");
await pushPref("fission.bfcacheInParent", false);
await testCase();
await testSourcesOnNavigation();
await testDebuggerPauseStateOnNavigation();
// bfcacheInParent only works if sessionHistoryInParent is enable
// so only test it if both settings are enabled.
if (Services.appinfo.sessionHistoryInParent) {
info("Run test with bfcacheInParent ENABLED");
await pushPref("fission.bfcacheInParent", true);
await testCase();
await testSourcesOnNavigation();
await testDebuggerPauseStateOnNavigation();
}
});
async function testCase() {
async function testSourcesOnNavigation() {
info("Test that sources appear in the debugger when navigating using the BFCache")
const dbg = await initDebugger("doc-bfcache1.html");
await navigate(dbg, "doc-bfcache2.html", "doc-bfcache2.html");
@ -33,3 +37,54 @@ async function testCase() {
await dbg.toolbox.closeToolbox();
}
async function testDebuggerPauseStateOnNavigation() {
info("Test the debugger pause state when navigating using the BFCache");
if (Services.appinfo.sessionHistoryInParent) {
enableTargetSwitching();
}
const dbg = await initDebugger("doc-bfcache1.html");
await addBreakpoint(dbg, "doc-bfcache1.html", 4);
await navigate(dbg, "doc-bfcache2.html");
await waitForSources(dbg, "doc-bfcache2.html");
await goBack(EXAMPLE_URL + "doc-bfcache1.html");
await waitForSources(dbg, "doc-bfcache1.html");
await reload(dbg);
await waitForPaused(dbg);
ok(dbg.toolbox.isHighlighted("jsdebugger"), "Debugger is highlighted");
await goForward(EXAMPLE_URL + "doc-bfcache2.html");
// This check should be removed when Bug 1722305 is fixed, which would cause will-navigate
// to start firing properly with fission.
if (!Services.appinfo.sessionHistoryInParent) {
await waitUntil(() => !dbg.toolbox.isHighlighted("jsdebugger"));
ok(true, "Debugger is not highlighted");
}
dbg.toolbox.closeToolbox();
}
async function goBack(expectedUrl) {
const onLocationChange = BrowserTestUtils.waitForLocationChange(
gBrowser,
expectedUrl
);
gBrowser.goBack();
await onLocationChange;
}
async function goForward(expectedUrl) {
const onLocationChange = BrowserTestUtils.waitForLocationChange(
gBrowser,
expectedUrl
);
gBrowser.goForward();
await onLocationChange;
}

View file

@ -145,20 +145,3 @@ add_task(async function() {
});
async function assertDebuggerIsHighlightedAndPaused(toolbox) {
info("Wait for the debugger to be automatically selected on pause");
await waitUntil(() => toolbox.currentToolId == "jsdebugger");
ok(true, "Debugger selected");
// Wait for the debugger to finish loading.
await toolbox.getPanelWhenReady("jsdebugger");
// And to be fully paused
const dbg = createDebuggerContext(toolbox);
await waitForPaused(dbg);
ok(toolbox.isHighlighted("jsdebugger"), "Debugger is highlighted");
return dbg;
}

View file

@ -1,6 +1,7 @@
<body>
First Page!
<script>
console.log("First Page!");
function goForward() { history.go(1); }
</script>
</body>

View file

@ -1940,6 +1940,29 @@ async function assertNodeIsFocused(dbg, index) {
ok(node.classList.contains("focused"), `node ${index} is focused`);
}
/**
* Asserts that the debugger is paused and the debugger tab is
* highlighted.
* @param {*} toolbox
* @returns
*/
async function assertDebuggerIsHighlightedAndPaused(toolbox) {
info("Wait for the debugger to be automatically selected on pause");
await waitUntil(() => toolbox.currentToolId == "jsdebugger");
ok(true, "Debugger selected");
// Wait for the debugger to finish loading.
await toolbox.getPanelWhenReady("jsdebugger");
// And to be fully paused
const dbg = createDebuggerContext(toolbox);
await waitForPaused(dbg);
ok(toolbox.isHighlighted("jsdebugger"), "Debugger is highlighted");
return dbg;
}
async function addExpression(dbg, input) {
info("Adding an expression");

View file

@ -3013,6 +3013,18 @@ Toolbox.prototype = {
* Fired when user just started navigating away to another web page.
*/
async _onWillNavigate() {
// On navigate, the server will resume all paused threads, but due to an
// issue which can cause loosing outgoing messages/RDP packets, the THREAD_STATE
// resources for the resumed state might not get received. So let assume it happens
// make use the UI is the appropriate state.
if (this._pausedTargets > 0) {
this.emit("toolbox-resumed");
this._pausedTargets = 0;
if (this.isHighlighted("jsdebugger")) {
this.unhighlightTool("jsdebugger");
}
}
// Clearing the error count as soon as we navigate
this.setErrorCount(0);
this.updateToolboxButtons();

View file

@ -544,3 +544,16 @@ export type SymbolicationWorkerReplyData<R> =
| {
error: SymbolicationWorkerError;
};
// This type is used in the symbolication worker for the return type of the
// FileAndPathHelper's readFile method.
// FIXME: Or rather, this type *would* be used if the worker code was checked
// by TypeScript.
export interface FileHandle {
// Return the length of the file in bytes.
getLength: () => number;
// Synchronously read the bytes at offset `offset` into the array `dest`.
readBytesInto: (dest: Uint8Array, offset: number) => void;
// Called when the file is no longer needed, to allow closing the file.
drop: () => void;
}

View file

@ -6,213 +6,32 @@
// THIS FILE IS AUTOGENERATED by wasm-bindgen.
//
// Generated from:
// https://github.com/mstange/profiler-get-symbols/commit/90ee39f1d18d2727f07dc57bd93cff6bc73ce8a0
// https://github.com/mstange/profiler-get-symbols/commit/c1dca28a2a506df40f0a6f32c12ba51ec54b02be
// by following the instructions in that repository's Readme.md
//
let wasm_bindgen;
(function() {
const __exports = {};
let wasm;
let cachegetInt32Memory = null;
function getInt32Memory() {
if (cachegetInt32Memory === null || cachegetInt32Memory.buffer !== wasm.memory.buffer) {
cachegetInt32Memory = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory;
}
let cachegetUint32Memory = null;
function getUint32Memory() {
if (cachegetUint32Memory === null || cachegetUint32Memory.buffer !== wasm.memory.buffer) {
cachegetUint32Memory = new Uint32Array(wasm.memory.buffer);
}
return cachegetUint32Memory;
}
function getArrayU32FromWasm(ptr, len) {
return getUint32Memory().subarray(ptr / 4, ptr / 4 + len);
}
let cachegetUint8Memory = null;
function getUint8Memory() {
if (cachegetUint8Memory === null || cachegetUint8Memory.buffer !== wasm.memory.buffer) {
cachegetUint8Memory = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory;
}
function getArrayU8FromWasm(ptr, len) {
return getUint8Memory().subarray(ptr / 1, ptr / 1 + len);
}
const heap = new Array(32);
heap.fill(undefined);
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
let stack_pointer = 32;
function addBorrowedObject(obj) {
if (stack_pointer == 1) throw new Error('out of js stack');
heap[--stack_pointer] = obj;
return stack_pointer;
}
function _assertClass(instance, klass) {
if (!(instance instanceof klass)) {
throw new Error(`expected instance of ${klass.name}`);
}
return instance.ptr;
}
let WASM_VECTOR_LEN = 0;
let cachedTextEncoder = new TextEncoder('utf-8');
let passStringToWasm;
if (typeof cachedTextEncoder.encodeInto === 'function') {
passStringToWasm = function(arg) {
let size = arg.length;
let ptr = wasm.__wbindgen_malloc(size);
let offset = 0;
{
const mem = getUint8Memory();
for (; offset < arg.length; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
}
if (offset !== arg.length) {
arg = arg.slice(offset);
ptr = wasm.__wbindgen_realloc(ptr, size, size = offset + arg.length * 3);
const view = getUint8Memory().subarray(ptr + offset, ptr + size);
const ret = cachedTextEncoder.encodeInto(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
};
} else {
passStringToWasm = function(arg) {
let size = arg.length;
let ptr = wasm.__wbindgen_malloc(size);
let offset = 0;
{
const mem = getUint8Memory();
for (; offset < arg.length; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
}
if (offset !== arg.length) {
const buf = cachedTextEncoder.encode(arg.slice(offset));
ptr = wasm.__wbindgen_realloc(ptr, size, size = offset + buf.length);
getUint8Memory().set(buf, ptr + offset);
offset += buf.length;
}
WASM_VECTOR_LEN = offset;
return ptr;
};
}
/**
* @param {WasmMemBuffer} binary_data
* @param {WasmMemBuffer} debug_data
* @param {string} breakpad_id
* @returns {CompactSymbolTable}
*/
__exports.get_compact_symbol_table = function(binary_data, debug_data, breakpad_id) {
_assertClass(binary_data, WasmMemBuffer);
_assertClass(debug_data, WasmMemBuffer);
const ret = wasm.get_compact_symbol_table(binary_data.ptr, debug_data.ptr, passStringToWasm(breakpad_id), WASM_VECTOR_LEN);
return CompactSymbolTable.__wrap(ret);
};
function getObject(idx) { return heap[idx]; }
function debugString(val) {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `"${val}"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
}
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
} else {
return 'Function';
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debugString(val[0]);
}
for(let i = 1; i < length; i++) {
debug += ', ' + debugString(val[i]);
}
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
let cachedTextDecoder = new TextDecoder('utf-8');
function getStringFromWasm(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory().subarray(ptr, ptr + len));
}
let heap_next = heap.length;
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
@ -225,202 +44,413 @@ function takeObject(idx) {
return ret;
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
heap[idx] = obj;
return idx;
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function handleError(e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
/**
*/
class CompactSymbolTable {
static __wrap(ptr) {
const obj = Object.create(CompactSymbolTable.prototype);
obj.ptr = ptr;
let WASM_VECTOR_LEN = 0;
return obj;
}
let cachedTextEncoder = new TextEncoder('utf-8');
free() {
const ptr = this.ptr;
this.ptr = 0;
wasm.__wbg_compactsymboltable_free(ptr);
}
/**
* @returns {CompactSymbolTable}
*/
constructor() {
const ret = wasm.compactsymboltable_new();
return CompactSymbolTable.__wrap(ret);
}
/**
* @returns {Uint32Array}
*/
take_addr() {
const retptr = 8;
const ret = wasm.compactsymboltable_take_addr(retptr, this.ptr);
const memi32 = getInt32Memory();
const v0 = getArrayU32FromWasm(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1]).slice();
wasm.__wbindgen_free(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1] * 4);
return v0;
}
/**
* @returns {Uint32Array}
*/
take_index() {
const retptr = 8;
const ret = wasm.compactsymboltable_take_index(retptr, this.ptr);
const memi32 = getInt32Memory();
const v0 = getArrayU32FromWasm(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1]).slice();
wasm.__wbindgen_free(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1] * 4);
return v0;
}
/**
* @returns {Uint8Array}
*/
take_buffer() {
const retptr = 8;
const ret = wasm.compactsymboltable_take_buffer(retptr, this.ptr);
const memi32 = getInt32Memory();
const v0 = getArrayU8FromWasm(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1]).slice();
wasm.__wbindgen_free(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1] * 1);
return v0;
}
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
__exports.CompactSymbolTable = CompactSymbolTable;
/**
* WasmMemBuffer lets you allocate a chunk of memory on the wasm heap and
* directly initialize it from JS without a copy. The constructor takes the
* allocation size and a callback function which does the initialization.
* This is useful if you need to get very large amounts of data from JS into
* wasm (for example, the contents of a 1.7GB libxul.so).
*/
class WasmMemBuffer {
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
static __wrap(ptr) {
const obj = Object.create(WasmMemBuffer.prototype);
obj.ptr = ptr;
function passStringToWasm0(arg, malloc, realloc) {
return obj;
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
free() {
const ptr = this.ptr;
this.ptr = 0;
let len = arg.length;
let ptr = malloc(len);
wasm.__wbg_wasmmembuffer_free(ptr);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
/**
* Create the buffer and initialize it synchronously in the callback function.
* f is called with one argument: the Uint8Array that wraps our buffer.
* f should not return anything; its return value is ignored.
* f must not call any exported wasm functions! Anything that causes the
* wasm heap to resize will invalidate the typed array\'s internal buffer!
* Do not hold on to the array that is passed to f after f completes.
* @param {number} byte_length
* @param {any} f
* @returns {WasmMemBuffer}
*/
constructor(byte_length, f) {
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
function makeMutClosure(arg0, arg1, dtor, f) {
const state = { a: arg0, b: arg1, cnt: 1, dtor };
const real = (...args) => {
// First up with a closure we increment the internal reference
// count. This ensures that the Rust closure environment won't
// be deallocated while we're invoking it.
state.cnt++;
const a = state.a;
state.a = 0;
try {
const ret = wasm.wasmmembuffer_new(byte_length, addBorrowedObject(f));
return WasmMemBuffer.__wrap(ret);
return f(a, state.b, ...args);
} finally {
heap[stack_pointer++] = undefined;
if (--state.cnt === 0) {
wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
} else {
state.a = a;
}
}
};
real.original = state;
return real;
}
function __wbg_adapter_18(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0f6e06591fd1eecd(arg0, arg1, addHeapObject(arg2));
}
function handleError(f, args) {
try {
return f.apply(this, args);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
}
function __wbg_adapter_33(arg0, arg1, arg2, arg3) {
wasm.wasm_bindgen__convert__closures__invoke2_mut__hb11591fa7d9b8977(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
}
/**
* Usage:
*
* ```js
* async function getSymbolTable(debugName, breakpadId, libKeyToPathMap) {
* const helper = {
* getCandidatePathsForBinaryOrPdb: (debugName, breakpadId) => {
* const path = libKeyToPathMap.get(`${debugName}/${breakpadId}`);
* if (path !== undefined) {
* return [path];
* }
* return [];
* },
* readFile: async (filename) => {
* const byteLength = await getFileSizeInBytes(filename);
* const fileHandle = getFileHandle(filename);
* return {
* getLength: () => byteLength,
* readBytesInto: (array, offset) => {
* syncReadFilePartIntoBuffer(fileHandle, array, offset);
* },
* drop: () => {},
* };
* },
* };
*
* const [addr, index, buffer] = await getCompactSymbolTable(debugName, breakpadId, helper);
* return [addr, index, buffer];
* }
* ```
* @param {string} debug_name
* @param {string} breakpad_id
* @param {any} helper
* @returns {Promise<any>}
*/
__exports.getCompactSymbolTable = function(debug_name, breakpad_id, helper) {
var ptr0 = passStringToWasm0(debug_name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ptr1 = passStringToWasm0(breakpad_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
var ret = wasm.getCompactSymbolTable(ptr0, len0, ptr1, len1, addHeapObject(helper));
return takeObject(ret);
};
/**
* Usage:
*
* ```js
* async function getSymbolTable(url, requestJSONString, libKeyToPathMap) {
* const helper = {
* getCandidatePathsForBinaryOrPdb: (debugName, breakpadId) => {
* const path = libKeyToPathMap.get(`${debugName}/${breakpadId}`);
* if (path !== undefined) {
* return [path];
* }
* return [];
* },
* readFile: async (filename) => {
* const byteLength = await getFileSizeInBytes(filename);
* const fileHandle = getFileHandle(filename);
* return {
* getLength: () => byteLength,
* readBytesInto: (array, offset) => {
* syncReadFilePartIntoBuffer(fileHandle, array, offset);
* },
* drop: () => {},
* };
* },
* };
*
* const responseJSONString = await queryAPI(deburlugName, requestJSONString, helper);
* return responseJSONString;
* }
* ```
* @param {string} url
* @param {string} request_json
* @param {any} helper
* @returns {Promise<any>}
*/
__exports.queryAPI = function(url, request_json, helper) {
var ptr0 = passStringToWasm0(url, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ptr1 = passStringToWasm0(request_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
var ret = wasm.queryAPI(ptr0, len0, ptr1, len1, addHeapObject(helper));
return takeObject(ret);
};
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else {
throw e;
}
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
}
__exports.WasmMemBuffer = WasmMemBuffer;
function init(module) {
let result;
async function init(input) {
if (typeof input === 'undefined') {
let src;
if (typeof document === 'undefined') {
src = location.href;
} else {
src = document.currentScript.src;
}
input = src.replace(/\.js$/, '_bg.wasm');
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
const ret = debugString(getObject(arg1));
const ret0 = passStringToWasm(ret);
const ret1 = WASM_VECTOR_LEN;
getInt32Memory()[arg0 / 4 + 0] = ret0;
getInt32Memory()[arg0 / 4 + 1] = ret1;
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm(arg0, arg1));
};
imports.wbg.__wbindgen_rethrow = function(arg0) {
throw takeObject(arg0);
};
imports.wbg.__wbindgen_memory = function() {
const ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbg_buffer_aa8ebea80955a01a = function(arg0) {
const ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithbyteoffsetandlength_3e607c21646a8aef = function(arg0, arg1, arg2) {
const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
var ret = getObject(arg0);
return addHeapObject(ret);
};
imports.wbg.__wbg_drop_6095f5f9a28379e4 = function() { return handleError(function (arg0) {
getObject(arg0).drop();
}, arguments) };
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbg_call_9c879b23724d007e = function(arg0, arg1, arg2) {
try {
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
} catch (e) {
handleError(e)
imports.wbg.__wbg_call_3fc07b7d5fc9022d = function() { return handleError(function (arg0, arg1, arg2) {
var ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
var ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
imports.wbg.__wbg_readFile_1005cc171b90cf75 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).readFile(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_then_6c9a4bf55755f9b8 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_cb_drop = function(arg0) {
const obj = takeObject(arg0).original;
if (obj.cnt-- == 1) {
obj.a = 0;
return true;
}
var ret = false;
return ret;
};
imports.wbg.__wbg_getLength_83c461bbda972f3b = function() { return handleError(function (arg0) {
var ret = getObject(arg0).getLength();
return ret;
}, arguments) };
imports.wbg.__wbg_name_966f168ad0e59c92 = function(arg0) {
var ret = getObject(arg0).name;
return addHeapObject(ret);
};
imports.wbg.__wbg_message_e440fbd911a845a2 = function(arg0) {
var ret = getObject(arg0).message;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_memory = function() {
var ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbg_buffer_9e184d6f785de5ed = function(arg0) {
var ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithbyteoffsetandlength_d92dfdd78c30c55a = function(arg0, arg1, arg2) {
var ret = new Uint32Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_new_71de2365d17503e7 = function(arg0) {
var ret = new Uint32Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithbyteoffsetandlength_e57ad1f2ce812c03 = function(arg0, arg1, arg2) {
var ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_new_e8101319e4cf95fc = function(arg0) {
var ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_of_7c797480f9ceac60 = function(arg0, arg1, arg2) {
var ret = Array.of(getObject(arg0), getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_json_parse = function(arg0, arg1) {
const ret = JSON.parse(getStringFromWasm(arg0, arg1));
var ret = JSON.parse(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_readBytesInto_02ee0cacc563822d = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).readBytesInto(takeObject(arg1), arg2);
}, arguments) };
imports.wbg.__wbg_getCandidatePathsForBinaryOrPdb_6ff1ea4b13b7cbee = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
var ret = getObject(arg0).getCandidatePathsForBinaryOrPdb(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_from_f4f6c9225e58242f = function(arg0) {
var ret = Array.from(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_length_555f836564bf148d = function(arg0) {
var ret = getObject(arg0).length;
return ret;
};
imports.wbg.__wbg_get_b7bbf50adcc94294 = function(arg0, arg1) {
var ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
};
imports.wbg.__wbg_new_c143a4f563f78c4e = function(arg0, arg1) {
try {
var state0 = {a: arg0, b: arg1};
var cb0 = (arg0, arg1) => {
const a = state0.a;
state0.a = 0;
try {
return __wbg_adapter_33(a, state0.b, arg0, arg1);
} finally {
state0.a = a;
}
};
var ret = new Promise(cb0);
return addHeapObject(ret);
} finally {
state0.a = state0.b = 0;
}
};
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
var ret = typeof(obj) === 'string' ? obj : undefined;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
imports.wbg.__wbg_then_c2361a9d5c9a4fcb = function(arg0, arg1) {
var ret = getObject(arg0).then(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_resolve_cae3d8f752f5db88 = function(arg0) {
var ret = Promise.resolve(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper230 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 70, __wbg_adapter_18);
return addHeapObject(ret);
};
if (module instanceof URL || typeof module === 'string' || module instanceof Request) {
const response = fetch(module);
if (typeof WebAssembly.instantiateStreaming === 'function') {
result = WebAssembly.instantiateStreaming(response, imports)
.catch(e => {
console.warn("`WebAssembly.instantiateStreaming` failed. Assuming this is because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
return response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
});
} else {
result = response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
}
} else {
result = WebAssembly.instantiate(module, imports)
.then(result => {
if (result instanceof WebAssembly.Instance) {
return { instance: result, module };
} else {
return result;
}
});
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
return result.then(({instance, module}) => {
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
return wasm;
});
const { instance, module } = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
return wasm;
}
self.wasm_bindgen = Object.assign(init, __exports);
wasm_bindgen = Object.assign(init, __exports);
})();

View file

@ -19,6 +19,7 @@ importScripts(
/**
* @typedef {import("./@types/perf").SymbolicationWorkerInitialMessage} SymbolicationWorkerInitialMessage
* @typedef {import("./@types/perf").FileHandle} FileHandle
*/
// This worker uses the wasm module that was generated from https://github.com/mstange/profiler-get-symbols.
@ -29,60 +30,55 @@ importScripts(
// itself.
/* eslint camelcase: 0*/
const { WasmMemBuffer, get_compact_symbol_table } = wasm_bindgen;
const { getCompactSymbolTable } = wasm_bindgen;
// Read an open OS.File instance into the Uint8Array dataBuf.
function readFileInto(file, dataBuf) {
// Ideally we'd be able to call file.readTo(dataBuf) here, but readTo no
// longer exists.
// So instead, we copy the file over into wasm memory in 4MB chunks. This
// will take 425 invocations for a a 1.7GB file (such as libxul.so for a
// Firefox for Android build) and not take up too much memory per call.
const dataBufLen = dataBuf.byteLength;
// Read parts of an open OS.File instance into the Uint8Array dataBuf.
// This reads destBuf.byteLength bytes at offset offset.
function readFileBytesInto(file, offset, destBuf) {
file.setPosition(offset);
// We read the file in 4MB chunks. This limits the amount of temporary
// memory we use while we copy the file contents into wasm memory.
const chunkSize = 4 * 1024 * 1024;
let pos = 0;
while (pos < dataBufLen) {
const chunkData = file.read({ bytes: chunkSize });
let posInDestBuf = 0;
let remainingBytes = destBuf.byteLength;
while (remainingBytes > 0) {
const bytes = remainingBytes > chunkSize ? chunkSize : remainingBytes;
const chunkData = file.read({ bytes });
const chunkBytes = chunkData.byteLength;
if (chunkBytes === 0) {
break;
}
dataBuf.set(chunkData, pos);
pos += chunkBytes;
destBuf.set(chunkData, posInDestBuf);
posInDestBuf += chunkBytes;
remainingBytes -= chunkBytes;
}
}
// Returns a plain object that is Structured Cloneable and has name and
// description properties.
// message properties.
function createPlainErrorObject(e) {
// OS.File.Error has an empty message property; it constructs the error
// message on-demand in its toString() method. So we handle those errors
// specially.
if (!(e instanceof OS.File.Error)) {
// Regular errors: just rewrap the object.
if (e instanceof Error) {
const { name, message, fileName, lineNumber } = e;
return { name, message, fileName, lineNumber };
}
// The WebAssembly code throws errors with fields error_type and error_msg.
if (e.error_type) {
return {
name: e.error_type,
message: e.error_msg,
};
}
if (e instanceof OS.File.Error) {
// OS.File.Error has an empty message property; it constructs the error
// message on-demand in its toString() method. So we handle those errors
// specially.
return {
name: "OSFileError",
message: e.toString(),
fileName: e.fileName,
lineNumber: e.lineNumber,
};
}
return {
name: e instanceof OS.File.Error ? "OSFileError" : "Error",
message: e.toString(),
fileName: e.fileName,
lineNumber: e.lineNumber,
};
// Regular errors: just rewrap the object.
const { name, message, fileName, lineNumber } = e;
return { name, message, fileName, lineNumber };
}
class PathHelper {
/**
* A FileAndPathHelper object is passed to getCompactSymbolTable, which calls
* the methods `getCandidatePathsForBinaryOrPdb` and `readFile` on it.
*/
class FileAndPathHelper {
constructor(libInfoMap, objdirs) {
this._libInfoMap = libInfoMap;
this._objdirs = objdirs;
@ -90,12 +86,13 @@ class PathHelper {
/**
* Enumerate all paths at which we could find files with symbol information.
* This method is called by wasm code (via the bindings).
*
* @param {string} debugName
* @param {string} breakpadId
* @returns {Array<{ path: string, debugPath: string }>}
* @returns {Array<string>}
*/
getCandidatePaths(debugName, breakpadId) {
getCandidatePathsForBinaryOrPdb(debugName, breakpadId) {
const key = `${debugName}:${breakpadId}`;
const lib = this._libInfoMap.get(key);
if (!lib) {
@ -121,91 +118,66 @@ class PathHelper {
// a system library.
for (const objdirPath of this._objdirs) {
// Binaries are usually expected to exist at objdir/dist/bin/filename.
candidatePaths.push({
path: OS.Path.join(objdirPath, "dist", "bin", name),
debugPath: OS.Path.join(objdirPath, "dist", "bin", name),
});
candidatePaths.push(OS.Path.join(objdirPath, "dist", "bin", name));
// Also search in the "objdir" directory itself (not just in dist/bin).
// If, for some unforeseen reason, the relevant binary is not inside the
// objdirs dist/bin/ directory, this provides a way out because it lets the
// user specify the actual location.
candidatePaths.push({
path: OS.Path.join(objdirPath, name),
debugPath: OS.Path.join(objdirPath, name),
});
candidatePaths.push(OS.Path.join(objdirPath, name));
}
// Check the absolute paths of the library file(s) last.
// Check the absolute paths of the library last.
// We do this after the objdir search because the library's path may point
// to a stripped binary, which will have fewer symbols than the original
// binaries in the objdir.
candidatePaths.push({ path, debugPath });
if (debugPath !== path) {
// We're on Windows, and debugPath points to a PDB file.
// On non-Windows, path and debugPath are always the same.
// Check the PDB file before the binary because the PDB has the symbol
// information. The binary is only used as a last-ditch fallback
// for things like Windows system libraries (e.g. graphics drivers).
candidatePaths.push(debugPath);
}
// The location of the binary. If the profile was obtained on this machine
// (and not, for example, on an Android device), this file should always
// exist.
candidatePaths.push(path);
return candidatePaths;
}
}
function getCompactSymbolTableFromPath(binaryPath, debugPath, breakpadId) {
// Read the binary file into WASM memory.
const binaryFile = OS.File.open(binaryPath, { read: true });
const binaryData = new WasmMemBuffer(binaryFile.stat().size, array => {
readFileInto(binaryFile, array);
});
binaryFile.close();
// Do the same for the debug file, if it is supplied and different from the
// binary file. This is only the case on Windows.
let debugData = binaryData;
if (debugPath && debugPath !== binaryPath) {
const debugFile = OS.File.open(debugPath, { read: true });
debugData = new WasmMemBuffer(debugFile.stat().size, array => {
readFileInto(debugFile, array);
});
debugFile.close();
}
try {
const output = get_compact_symbol_table(binaryData, debugData, breakpadId);
const result = [
output.take_addr(),
output.take_index(),
output.take_buffer(),
];
output.free();
return result;
} finally {
binaryData.free();
if (debugData != binaryData) {
debugData.free();
/**
* Asynchronously prepare the file at `path` for synchronous reading.
* This method is called by wasm code (via the bindings).
*
* @param {string} path
* @returns {FileHandle}
*/
async readFile(path) {
const file = OS.File.open(path, { read: true });
const info = file.stat();
if (info.isDir) {
throw new Error(`Path "${path}" is a directory.`);
}
const fileSize = info.size;
// Create and return a FileHandle object. The methods of this object are
// called by wasm code (via the bindings).
return {
getLength: () => fileSize,
readBytesInto: (dest, offset) => {
readFileBytesInto(file, offset, dest);
},
drop: () => {
file.close();
},
};
}
}
function getSymbolTableInWorker(debugName, breakpadId, libInfoMap, objdirs) {
const helper = new PathHelper(libInfoMap, objdirs);
const candidatePaths = helper.getCandidatePaths(debugName, breakpadId);
const errors = [];
for (const { path, debugPath } of candidatePaths) {
try {
return getCompactSymbolTableFromPath(path, debugPath, breakpadId);
} catch (e) {
// getCompactSymbolTableFromPath was unsuccessful. So either the
// file wasn't parseable or its contents didn't match the specified
// breakpadId, or some other error occurred.
// Advance to the next candidate path.
errors.push(e);
}
}
throw new Error(
`Could not obtain symbols for the library ${debugName} ${breakpadId} ` +
`because there was no matching file at any of the candidate paths: ${JSON.stringify(
candidatePaths
)}. Errors: ${errors.map(e => e.message).join(", ")}`
);
}
/** @param {MessageEvent<SymbolicationWorkerInitialMessage>} e */
onmessage = async e => {
try {
@ -218,12 +190,8 @@ onmessage = async e => {
// Instantiate the WASM module.
await wasm_bindgen(module);
const result = getSymbolTableInWorker(
debugName,
breakpadId,
libInfoMap,
objdirs
);
const helper = new FileAndPathHelper(libInfoMap, objdirs);
const result = await getCompactSymbolTable(debugName, breakpadId, helper);
postMessage(
{ result },
result.map(r => r.buffer)

View file

@ -45,12 +45,15 @@ const global = this;
// The hash check ensures that the contents of the wasm module are what we
// expect them to be.
// The source code is at https://github.com/mstange/profiler-get-symbols/ .
// Documentation is at https://docs.rs/profiler-get-symbols/ .
// The sha384 sum can be computed with the following command (tested on macOS):
// shasum -b -a 384 profiler_get_symbols_wasm_bg.wasm | awk '{ print $1 }' | xxd -r -p | base64
// Generated from https://github.com/mstange/profiler-get-symbols/commit/90ee39f1d18d2727f07dc57bd93cff6bc73ce8a0
// Generated from https://github.com/mstange/profiler-get-symbols/commit/c1dca28a2a506df40f0a6f32c12ba51ec54b02be
const WASM_MODULE_URL =
"https://zealous-rosalind-a98ce8.netlify.com/wasm/8f7ca2f70e1cd21b5a2dbe96545672752887bfbd4e7b3b9437e9fc7c3da0a3bedae4584ff734f0c9f08c642e6b66ffab.wasm";
"https://storage.googleapis.com/firefox-profiler-get-symbols/c1dca28a2a506df40f0a6f32c12ba51ec54b02be.wasm";
const WASM_MODULE_INTEGRITY =
"sha384-j3yi9w4c0htaLb6WVFZydSiHv71OezuUN+n8fD2go77a5FhP9zTwyfCMZC5rZv+r";
"sha384-ZWi2jwcKJr20rE2gmHjFQGHgsCF9CagkyPLsrIZfmf5QKD2oXgkLa8tMKHK6zPA1";
const EXPIRY_TIME_IN_MS = 5 * 60 * 1000; // 5 minutes

View file

@ -448,6 +448,12 @@ function withAboutProfiling(callback) {
"about:profiling",
async contentBrowser => {
info("about:profiling is now open in a tab.");
await BrowserTestUtils.waitForCondition(
() =>
contentBrowser.contentDocument.getElementById("root")
.firstElementChild,
"Document's root has been populated"
);
return callback(contentBrowser.contentDocument);
}
);

View file

@ -7,7 +7,6 @@
const Services = require("Services");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
/**
* Wrapper over FluentReact. It encapsulates instantiation of the localization
@ -30,7 +29,10 @@ class FluentL10n {
}
const locales = Services.locale.appLocalesAsBCP47;
const generator = L10nRegistry.generateBundles(locales, resourceIds);
const generator = L10nRegistry.getInstance().generateBundles(
locales,
resourceIds
);
this._bundles = [];
for await (const bundle of generator) {

View file

@ -95,6 +95,8 @@ const URL_ROOT_MOCHI_8888 = CHROME_URL_ROOT.replace(
"http://mochi.test:8888/"
);
const TARGET_SWITCHING_PREF = "devtools.target-switching.server.enabled";
try {
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/telemetry-test-helpers.js",
@ -1124,6 +1126,13 @@ function isWindows() {
return Services.appinfo.OS === "WINNT";
}
/**
* Enables server target switching
*/
async function enableTargetSwitching() {
await pushPref(TARGET_SWITCHING_PREF, true);
}
/**
* Wait for a given toolbox to get its title updated.
*/

View file

@ -53,7 +53,6 @@ const STORAGE_PREF = "devtools.storage.enabled";
const DOM_CACHE = "dom.caches.enabled";
const DUMPEMIT_PREF = "devtools.dump.emit";
const DEBUGGERLOG_PREF = "devtools.debugger.log";
const TARGET_SWITCHING_PREF = "devtools.target-switching.server.enabled";
// Allows Cache API to be working on usage `http` test page
const CACHES_ON_HTTP_PREF = "dom.caches.testing.enabled";
@ -226,13 +225,6 @@ function forceCollections() {
Cu.forceShrinkingGC();
}
/**
* Enables server target switching
*/
async function enableTargetSwitching() {
await pushPref(TARGET_SWITCHING_PREF, true);
}
// Sends a click event on the passed DOM node in an async manner
function click(node) {
node.scrollIntoView();

View file

@ -29,6 +29,7 @@ const {
DOMQuad,
DOMRect,
HeapSnapshot,
L10nRegistry,
NamedNodeMap,
NodeFilter,
StructuredCloneHolder,
@ -266,6 +267,7 @@ exports.globals = {
FileReader,
FormData,
isWorker: false,
L10nRegistry,
loader: {
lazyGetter: defineLazyGetter,
lazyImporter: defineLazyModuleGetter,

View file

@ -71,7 +71,7 @@ exports.CommandsFactory = {
},
/**
* For now, this method is only used by browser_target_list_various_descriptors.js
* For now, this method is only used by browser_target_command_various_descriptors.js
* in order to cover about:debugging codepath, where we connect to remote tabs via
* their current outerWindowID.
* But:

View file

@ -179,7 +179,7 @@ class LegacyServiceWorkersWatcher extends LegacyWorkersWatcher {
// has cleaned up its reducers, which happens on "will-navigate".
// On the other end, "dom-complete", which is a better mapping of "navigate", is
// happening too late (because of resources being throttled), and would cause failures
// in test (like browser_target_list_service_workers_navigation.js), as the new worker
// in test (like browser_target_command_service_workers_navigation.js), as the new worker
// target would already be registered at this point, and seen as something that would
// need to be destroyed.
if (resource.name === "dom-loading") {

View file

@ -15,22 +15,22 @@ support-files =
test_sw_page_worker.js
test_worker.js
[browser_target_command_bfcache.js]
[browser_target_command_browser_workers.js]
[browser_target_command_frames.js]
[browser_target_command_getAllTargets.js]
[browser_target_command_invalid_api_usage.js]
[browser_target_command_preffedoff.js]
[browser_target_command_processes.js]
[browser_target_command_reload.js]
[browser_target_invalid_api_usage.js]
[browser_target_list_bfcache.js]
[browser_target_list_browser_workers.js]
[browser_target_list_frames.js]
[browser_target_list_getAllTargets.js]
[browser_target_list_preffedoff.js]
[browser_target_list_processes.js]
[browser_target_list_service_workers.js]
[browser_target_list_service_workers_navigation.js]
[browser_target_list_switchToTarget.js]
[browser_target_list_tab_workers.js]
[browser_target_list_tab_workers_bfcache_navigation.js]
[browser_target_command_service_workers.js]
[browser_target_command_service_workers_navigation.js]
[browser_target_command_switchToTarget.js]
[browser_target_command_tab_workers.js]
[browser_target_command_tab_workers_bfcache_navigation.js]
skip-if = debug # Bug 1721859
[browser_target_list_various_descriptors.js]
[browser_target_command_various_descriptors.js]
skip-if =
os == "linux" && bits == 64 && !debug #Bug 1701056
[browser_target_list_watchTargets.js]
[browser_target_command_watchTargets.js]
[browser_watcher_actor_getter_caching.js]

View file

@ -91,10 +91,12 @@ add_task(async function() {
);
info("Check that navigating away does destroy all targets");
const onBrowserLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
BrowserTestUtils.loadURI(
tab.linkedBrowser,
"data:text/html,<meta charset=utf8>Away"
);
await onBrowserLoaded;
await waitFor(
() => destroyedTargets.length === 2,
@ -104,29 +106,26 @@ add_task(async function() {
info("Navigate back to the first page");
gBrowser.goBack();
// Bug 1722709 - Disable the following assertions until we figure out what's wrong with WorkerDebugger API
if (!isFissionEnabled()) {
await waitFor(
() => targets.length === 4,
"Wait for the target list to notify us about the first page workers, restored from the BF Cache"
);
await waitFor(
() => targets.length === 4,
"Wait for the target list to notify us about the first page workers, restored from the BF Cache"
);
const mainPageWorkerTargetAfterGoingBack = targets.find(
t => t !== mainPageWorkerTarget && t.url == `${WORKER_URL}#simple-worker`
);
const iframeWorkerTargetAfterGoingBack = targets.find(
t =>
t !== iframeWorkerTarget &&
t.url == `${IFRAME_WORKER_URL}#simple-worker-in-iframe`
);
const mainPageWorkerTargetAfterGoingBack = targets.find(
t => t !== mainPageWorkerTarget && t.url == `${WORKER_URL}#simple-worker`
);
const iframeWorkerTargetAfterGoingBack = targets.find(
t =>
t !== iframeWorkerTarget &&
t.url == `${IFRAME_WORKER_URL}#simple-worker-in-iframe`
);
ok(
mainPageWorkerTargetAfterGoingBack,
"The target list handled the worker created from the BF Cache"
);
ok(
iframeWorkerTargetAfterGoingBack,
"The target list handled the worker created in the iframe from the BF Cache"
);
}
ok(
mainPageWorkerTargetAfterGoingBack,
"The target list handled the worker created from the BF Cache"
);
ok(
iframeWorkerTargetAfterGoingBack,
"The target list handled the worker created in the iframe from the BF Cache"
);
});

View file

@ -47,6 +47,7 @@
#include "SessionStoreFunctions.h"
#include "nsIXPConnect.h"
#include "nsImportModule.h"
#include "UnitTransforms.h"
#ifdef NS_PRINTING
# include "mozilla/embedding/printingui/PrintingParent.h"
@ -2551,6 +2552,86 @@ void CanonicalBrowsingContext::CloneDocumentTreeInto(
[self = RefPtr{this}]() { self->mClonePromise = nullptr; });
}
bool CanonicalBrowsingContext::StartApzAutoscroll(float aAnchorX,
float aAnchorY,
nsViewID aScrollId,
uint32_t aPresShellId) {
nsCOMPtr<nsIWidget> widget;
mozilla::layers::LayersId layersId{0};
if (IsInProcess()) {
nsCOMPtr<nsPIDOMWindowOuter> outer = GetDOMWindow();
if (!outer) {
return false;
}
widget = widget::WidgetUtils::DOMWindowToWidget(outer);
if (widget) {
layersId = widget->GetRootLayerTreeId();
}
} else {
RefPtr<BrowserParent> parent = GetBrowserParent();
if (!parent) {
return false;
}
widget = parent->GetWidget();
layersId = parent->GetLayersId();
}
if (!widget || !widget->AsyncPanZoomEnabled()) {
return false;
}
// The anchor coordinates that are passed in are relative to the origin
// of the screen, but we are sending them to APZ which only knows about
// coordinates relative to the widget, so convert them accordingly.
CSSPoint anchorCss{aAnchorX, aAnchorY};
LayoutDeviceIntPoint anchor =
RoundedToInt(anchorCss * widget->GetDefaultScale());
anchor -= widget->WidgetToScreenOffset();
mozilla::layers::ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
return widget->StartAsyncAutoscroll(
ViewAs<ScreenPixel>(
anchor, PixelCastJustification::LayoutDeviceIsScreenForBounds),
guid);
}
void CanonicalBrowsingContext::StopApzAutoscroll(nsViewID aScrollId,
uint32_t aPresShellId) {
nsCOMPtr<nsIWidget> widget;
mozilla::layers::LayersId layersId{0};
if (IsInProcess()) {
nsCOMPtr<nsPIDOMWindowOuter> outer = GetDOMWindow();
if (!outer) {
return;
}
widget = widget::WidgetUtils::DOMWindowToWidget(outer);
if (widget) {
layersId = widget->GetRootLayerTreeId();
}
} else {
RefPtr<BrowserParent> parent = GetBrowserParent();
if (!parent) {
return;
}
widget = parent->GetWidget();
layersId = parent->GetLayersId();
}
if (!widget || !widget->AsyncPanZoomEnabled()) {
return;
}
mozilla::layers::ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
widget->StopAsyncAutoscroll(guid);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(CanonicalBrowsingContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CanonicalBrowsingContext,

View file

@ -345,6 +345,10 @@ class CanonicalBrowsingContext final : public BrowsingContext {
return mClonePromise;
}
bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId,
uint32_t aPresShellId);
void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId);
protected:
// Called when the browsing context is being discarded.
void CanonicalDiscard();

View file

@ -259,7 +259,7 @@ load 1619322.html
asserts(0-1) load 1623918.html # May hit an assertion if the <input> element's anonymous tree hasn't been flushed when IMEContentObserver handles focus
load 1656925.html
skip-if(Android) load 1665792.html # Print preview on android doesn't fly
load 1681729.html
load 1693049.html
load 1697525.html
skip-if(ThreadSanitizer) load 1681729.html
skip-if(ThreadSanitizer) load 1693049.html
skip-if(ThreadSanitizer) load 1697525.html
skip-if(ThreadSanitizer) load 1712198.html # Mysterious failure that should be investigated (bug 1712866).

View file

@ -3189,16 +3189,6 @@ void nsFrameLoader::AttributeChanged(mozilla::dom::Element* aElement,
}
}
/**
* Send the RequestNotifyAfterRemotePaint message to the current Tab.
*/
void nsFrameLoader::RequestNotifyAfterRemotePaint() {
// If remote browsing (e10s), handle this with the BrowserParent.
if (auto* browserParent = GetBrowserParent()) {
Unused << browserParent->SendRequestNotifyAfterRemotePaint();
}
}
void nsFrameLoader::RequestUpdatePosition(ErrorResult& aRv) {
if (auto* browserParent = GetBrowserParent()) {
nsresult rv = browserParent->UpdatePosition();

View file

@ -218,8 +218,6 @@ class nsFrameLoader final : public nsStubMutationObserver,
void ActivateFrameEvent(const nsAString& aType, bool aCapture,
mozilla::ErrorResult& aRv);
void RequestNotifyAfterRemotePaint();
void RequestUpdatePosition(mozilla::ErrorResult& aRv);
already_AddRefed<Promise> RequestTabStateFlush(mozilla::ErrorResult& aRv);

View file

@ -280,6 +280,16 @@ DOMInterfaces = {
'nativeType': 'mozilla::intl::FluentBundle',
},
'FluentBundleAsyncIterator': {
'headerFile': 'mozilla/intl/L10nRegistry.h',
'nativeType': 'mozilla::intl::FluentBundleAsyncIterator',
},
'FluentBundleIterator': {
'headerFile': 'mozilla/intl/L10nRegistry.h',
'nativeType': 'mozilla::intl::FluentBundleIterator',
},
'FluentPattern': {
'headerFile': 'mozilla/intl/FluentBundle.h',
'nativeType': 'mozilla::intl::FluentPattern',
@ -445,6 +455,10 @@ DOMInterfaces = {
'nativeType': 'mozilla::intl::L10nFileSource',
},
'L10nRegistry': {
'nativeType': 'mozilla::intl::L10nRegistry',
},
'LegacyMozTCPSocket': {
'headerFile': 'TCPSocket.h',
'wrapperCache': False,

View file

@ -3730,20 +3730,26 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
assert needInterfacePrototypeObject
def defineAlias(alias):
if alias == "@@iterator":
symbolJSID = "SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::iterator))"
if alias == "@@iterator" or alias == "@@asyncIterator":
name = alias[2:]
symbolJSID = (
"SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::%s))"
% name
)
prop = "%sId" % name
getSymbolJSID = CGGeneric(
fill(
"JS::Rooted<jsid> iteratorId(aCx, ${symbolJSID});",
"JS::Rooted<jsid> ${prop}(aCx, ${symbolJSID});",
prop=prop,
symbolJSID=symbolJSID,
)
)
defineFn = "JS_DefinePropertyById"
prop = "iteratorId"
enumFlags = "0" # Not enumerable, per spec.
elif alias.startswith("@@"):
raise TypeError(
"Can't handle any well-known Symbol other than @@iterator"
"Can't handle any well-known Symbol other than @@iterator and @@asyncIterator"
)
else:
getSymbolJSID = None

View file

@ -43,7 +43,7 @@ class CacheInvalidator {
// -
class AbstractCache {
typedef std::vector<const CacheInvalidator*> InvalidatorListT;
using InvalidatorListT = std::vector<const CacheInvalidator*>;
private:
InvalidatorListT mInvalidators;
@ -122,9 +122,8 @@ class CacheWeakMap final {
}
};
typedef std::unordered_map<const KeyT*, UniquePtr<Entry>, DerefHash,
DerefEqual>
MapT;
using MapT =
std::unordered_map<const KeyT*, UniquePtr<Entry>, DerefHash, DerefEqual>;
MapT mMap;
public:

View file

@ -62,8 +62,8 @@ struct ImageCacheEntryData {
class ImageCacheEntry : public PLDHashEntryHdr {
public:
typedef ImageCacheKey KeyType;
typedef const ImageCacheKey* KeyTypePointer;
using KeyType = ImageCacheKey;
using KeyTypePointer = const ImageCacheKey*;
explicit ImageCacheEntry(const KeyType* aKey)
: mData(new ImageCacheEntryData(*aKey)) {}
@ -95,8 +95,8 @@ struct AllCanvasImageCacheKey {
class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
public:
typedef AllCanvasImageCacheKey KeyType;
typedef const AllCanvasImageCacheKey* KeyTypePointer;
using KeyType = AllCanvasImageCacheKey;
using KeyTypePointer = const AllCanvasImageCacheKey*;
explicit AllCanvasImageCacheEntry(const KeyType* aKey)
: mImage(aKey->mImage) {}

View file

@ -23,7 +23,7 @@ class imgIContainer;
namespace mozilla {
class CanvasImageCache {
typedef mozilla::gfx::SourceSurface SourceSurface;
using SourceSurface = mozilla::gfx::SourceSurface;
public:
/**

View file

@ -259,8 +259,8 @@ bool CanvasRenderingContext2D::PatternIsOpaque(
// GeneralPattern class in gfxContext.cpp with this one.
class CanvasGeneralPattern {
public:
typedef CanvasRenderingContext2D::Style Style;
typedef CanvasRenderingContext2D::ContextState ContextState;
using Style = CanvasRenderingContext2D::Style;
using ContextState = CanvasRenderingContext2D::ContextState;
Pattern& ForStyle(CanvasRenderingContext2D* aCtx, Style aStyle,
DrawTarget* aRT) {
@ -341,7 +341,7 @@ class CanvasGeneralPattern {
*/
class AdjustedTargetForFilter {
public:
typedef CanvasRenderingContext2D::ContextState ContextState;
using ContextState = CanvasRenderingContext2D::ContextState;
AdjustedTargetForFilter(CanvasRenderingContext2D* aCtx,
DrawTarget* aFinalTarget,
@ -488,7 +488,7 @@ class AdjustedTargetForFilter {
*/
class AdjustedTargetForShadow {
public:
typedef CanvasRenderingContext2D::ContextState ContextState;
using ContextState = CanvasRenderingContext2D::ContextState;
AdjustedTargetForShadow(CanvasRenderingContext2D* aCtx,
DrawTarget* aFinalTarget, const gfx::Rect& aBounds,
@ -574,7 +574,7 @@ class AdjustedTargetForShadow {
*/
class AdjustedTarget {
public:
typedef CanvasRenderingContext2D::ContextState ContextState;
using ContextState = CanvasRenderingContext2D::ContextState;
explicit AdjustedTarget(CanvasRenderingContext2D* aCtx,
const gfx::Rect* aBounds = nullptr) {
@ -3490,7 +3490,7 @@ bool CanvasRenderingContext2D::GetHitRegionRect(Element* aElement,
*/
struct MOZ_STACK_CLASS CanvasBidiProcessor
: public nsBidiPresUtils::BidiProcessor {
typedef CanvasRenderingContext2D::Style Style;
using Style = CanvasRenderingContext2D::Style;
CanvasBidiProcessor()
: nsBidiPresUtils::BidiProcessor(),
@ -3512,7 +3512,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor
}
}
typedef CanvasRenderingContext2D::ContextState ContextState;
using ContextState = CanvasRenderingContext2D::ContextState;
virtual void SetText(const char16_t* aText, int32_t aLength,
nsBidiDirection aDirection) override {

View file

@ -42,8 +42,8 @@ enum class LayersBackend : int8_t;
namespace dom {
class
HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
CanvasImageSource;
using CanvasImageSource =
HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
class ImageBitmap;
class ImageData;
class UTF8StringOrCanvasGradientOrCanvasPattern;

View file

@ -598,9 +598,9 @@ class WebGLVertexArrayJS final : public nsWrapperCache, public webgl::ObjectJS {
////////////////////////////////////
typedef dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence Float32ListU;
typedef dom::MaybeSharedInt32ArrayOrLongSequence Int32ListU;
typedef dom::MaybeSharedUint32ArrayOrUnsignedLongSequence Uint32ListU;
using Float32ListU = dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence;
using Int32ListU = dom::MaybeSharedInt32ArrayOrLongSequence;
using Uint32ListU = dom::MaybeSharedUint32ArrayOrUnsignedLongSequence;
inline Range<const float> MakeRange(const Float32ListU& list) {
if (list.IsFloat32Array()) return MakeRangeAbv(list.GetAsFloat32Array());

View file

@ -612,7 +612,7 @@ namespace ipc {
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlProducer<Actor>> {
typedef mozilla::dom::IpdlProducer<Actor> paramType;
using paramType = mozilla::dom::IpdlProducer<Actor>;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
@ -629,7 +629,7 @@ struct IPDLParamTraits<mozilla::dom::IpdlProducer<Actor>> {
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlConsumer<Actor>> {
typedef mozilla::dom::IpdlConsumer<Actor> paramType;
using paramType = mozilla::dom::IpdlConsumer<Actor>;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
@ -648,7 +648,7 @@ struct IPDLParamTraits<mozilla::dom::IpdlConsumer<Actor>> {
template <>
struct IPDLParamTraits<mozilla::dom::IpdlQueueBuffer> {
typedef mozilla::dom::IpdlQueueBuffer paramType;
using paramType = mozilla::dom::IpdlQueueBuffer;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {

View file

@ -51,8 +51,8 @@ inline bool operator!(const QueueStatus status) { return !IsSuccess(status); }
template <typename T>
struct RemoveCVR {
typedef typename std::remove_reference<typename std::remove_cv<T>::type>::type
Type;
using Type =
typename std::remove_reference<typename std::remove_cv<T>::type>::type;
};
inline size_t UsedBytes(size_t aQueueBufferSize, size_t aRead, size_t aWrite) {
@ -341,8 +341,8 @@ struct QueueParamTraits<bool> {
// (namely ContiguousEnumValidator and ContiguousEnumValidatorInclusive).
template <typename E, typename EnumValidator>
struct EnumSerializer {
typedef E ParamType;
typedef typename std::underlying_type<E>::type DataType;
using ParamType = E;
using DataType = typename std::underlying_type<E>::type;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,

View file

@ -343,7 +343,7 @@ bool WebGLContext::CreateAndInitGL(
// --
typedef decltype(gl::GLContextProviderEGL::CreateHeadless) fnCreateT;
using fnCreateT = decltype(gl::GLContextProviderEGL::CreateHeadless);
const auto fnCreate = [&](fnCreateT* const pfnCreate,
const char* const info) {
nsCString failureId;

View file

@ -15,7 +15,7 @@
namespace mozilla {
namespace webgl {
typedef uint8_t EffectiveFormatValueT;
using EffectiveFormatValueT = uint8_t;
enum class EffectiveFormat : EffectiveFormatValueT {
// GLES 3.0.4, p128-129, "Required Texture Formats"

View file

@ -140,17 +140,17 @@ class WebGLImageConverter {
// gather some compile-time meta-data about the formats at hand.
typedef typename DataTypeForFormat<SrcFormat>::Type SrcType;
typedef typename DataTypeForFormat<DstFormat>::Type DstType;
using SrcType = typename DataTypeForFormat<SrcFormat>::Type;
using DstType = typename DataTypeForFormat<DstFormat>::Type;
const WebGLTexelFormat IntermediateSrcFormat =
IntermediateFormat<SrcFormat>::Value;
const WebGLTexelFormat IntermediateDstFormat =
IntermediateFormat<DstFormat>::Value;
typedef typename DataTypeForFormat<IntermediateSrcFormat>::Type
IntermediateSrcType;
typedef typename DataTypeForFormat<IntermediateDstFormat>::Type
IntermediateDstType;
using IntermediateSrcType =
typename DataTypeForFormat<IntermediateSrcFormat>::Type;
using IntermediateDstType =
typename DataTypeForFormat<IntermediateDstFormat>::Type;
const size_t NumElementsPerSrcTexel =
NumElementsPerTexelForFormat<SrcFormat>();

View file

@ -314,27 +314,27 @@ template <WebGLTexelFormat Format, bool IsFloat = IsFloatFormat<Format>::Value,
bool Is16bpp = Is16bppFormat<Format>::Value,
bool IsHalfFloat = IsHalfFloatFormat<Format>::Value>
struct DataTypeForFormat {
typedef uint8_t Type;
using Type = uint8_t;
};
template <WebGLTexelFormat Format>
struct DataTypeForFormat<Format, true, false, false> {
typedef float Type;
using Type = float;
};
template <WebGLTexelFormat Format>
struct DataTypeForFormat<Format, false, true, false> {
typedef uint16_t Type;
using Type = uint16_t;
};
template <WebGLTexelFormat Format>
struct DataTypeForFormat<Format, false, false, true> {
typedef uint16_t Type;
using Type = uint16_t;
};
template <>
struct DataTypeForFormat<WebGLTexelFormat::RGB11F11F10F, true, false, false> {
typedef uint32_t Type;
using Type = uint32_t;
};
template <WebGLTexelFormat Format>

View file

@ -34,9 +34,9 @@
// Manual reflection of WebIDL typedefs that are different from their
// OpenGL counterparts.
typedef int64_t WebGLsizeiptr;
typedef int64_t WebGLintptr;
typedef bool WebGLboolean;
using WebGLsizeiptr = int64_t;
using WebGLintptr = int64_t;
using WebGLboolean = bool;
// -
@ -326,7 +326,7 @@ enum class UniformBaseType : uint8_t {
};
const char* ToString(UniformBaseType);
typedef uint64_t ObjectId;
using ObjectId = uint64_t;
enum class BufferKind : uint8_t {
Undefined,
@ -491,10 +491,10 @@ struct avec3 {
bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
};
typedef avec2<int32_t> ivec2;
typedef avec3<int32_t> ivec3;
typedef avec2<uint32_t> uvec2;
typedef avec3<uint32_t> uvec3;
using ivec2 = avec2<int32_t>;
using ivec3 = avec3<int32_t>;
using uvec2 = avec2<uint32_t>;
using uvec3 = avec3<uint32_t>;
inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }

View file

@ -52,13 +52,13 @@ class SourceSurface;
class nsICanvasRenderingContextInternal : public nsISupports,
public nsAPostRefreshObserver {
public:
typedef mozilla::layers::CanvasLayer CanvasLayer;
typedef mozilla::layers::CanvasRenderer CanvasRenderer;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::WebRenderCanvasData WebRenderCanvasData;
typedef mozilla::layers::CompositableHandle CompositableHandle;
typedef mozilla::layers::LayerTransactionChild LayerTransactionChild;
using CanvasLayer = mozilla::layers::CanvasLayer;
using CanvasRenderer = mozilla::layers::CanvasRenderer;
using Layer = mozilla::layers::Layer;
using LayerManager = mozilla::layers::LayerManager;
using WebRenderCanvasData = mozilla::layers::WebRenderCanvasData;
using CompositableHandle = mozilla::layers::CompositableHandle;
using LayerTransactionChild = mozilla::layers::LayerTransactionChild;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)

View file

@ -313,6 +313,30 @@ interface CanonicalBrowsingContext : BrowsingContext {
[SetterThrows] inherit attribute TouchEventsOverride touchEventsOverride;
readonly attribute boolean isReplaced;
/**
* Notify APZ to start autoscrolling.
*
* (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor, in CSS
* coordinates relative to the screen.
* aScrollId and aPresShellId identify the scroll frame that content chose to
* scroll.
*
* Returns whether we were successfully able to notify APZ.
* If this function returns true, APZ (which may live in another process)
* may still reject the autoscroll, but it's then APZ's reponsibility
* to notify content via an "autoscroll-rejected-by-apz" message.
*/
boolean startApzAutoscroll(float aAnchorX, float aAnchorY,
unsigned long long aScrollId,
unsigned long aPresShellId);
/**
* Notify APZ to stop autoscrolling.
*/
void stopApzAutoscroll(unsigned long long aScrollId,
unsigned long aPresShellId);
};
[Exposed=Window, ChromeOnly]

View file

@ -76,13 +76,6 @@ interface FrameLoader {
// Note, when frameloaders are swapped, also messageManagers are swapped.
readonly attribute MessageSender? messageManager;
/**
* Request that the next time a remote layer transaction has been
* received by the Compositor, a MozAfterRemoteFrame event be sent
* to the window.
*/
void requestNotifyAfterRemotePaint();
/**
* Force a remote browser to recompute its dimension and screen position.
*/

View file

@ -87,3 +87,46 @@ interface L10nFileSource {
FluentResource? fetchFileSync(UTF8String locale, UTF8String path);
};
dictionary FluentBundleIteratorResult
{
required FluentBundle? value;
required boolean done;
};
[LegacyNoInterfaceObject, Exposed=Window]
interface FluentBundleIterator {
FluentBundleIteratorResult next();
[Alias="@@iterator"] FluentBundleIterator values();
};
[LegacyNoInterfaceObject, Exposed=Window]
interface FluentBundleAsyncIterator {
Promise<FluentBundleIteratorResult> next();
[Alias="@@asyncIterator"] FluentBundleAsyncIterator values();
};
[ChromeOnly, Exposed=Window]
interface L10nRegistry {
constructor();
static L10nRegistry getInstance();
sequence<UTF8String> getAvailableLocales();
void registerSources(sequence<L10nFileSource> aSources);
void updateSources(sequence<L10nFileSource> aSources);
void removeSources(sequence<UTF8String> aSources);
[Throws]
boolean hasSource(UTF8String aName);
[Throws]
L10nFileSource? getSource(UTF8String aName);
sequence<UTF8String> getSourceNames();
void clearSources();
[Throws, NewObject]
FluentBundleIterator generateBundlesSync(sequence<UTF8String> aLocales, sequence<UTF8String> aResourceIds);
[Throws, NewObject]
FluentBundleAsyncIterator generateBundles(sequence<UTF8String> aLocales, sequence<UTF8String> aResourceIds);
};

View file

@ -71,7 +71,9 @@ support-files = wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.htm
[test_wpt_pointerevent_drag_interaction-manual.html]
support-files = wpt/html/pointerevent_drag_interaction-manual.html
[test_wpt_touch_action.html]
skip-if = os == 'android' # Bug 1312791
skip-if =
os == 'android' # Bug 1312791
os == 'linux' && headless # Bug 1722906
support-files =
../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js
../../../../gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js

View file

@ -73,26 +73,6 @@ interface nsIRemoteTab : nsISupports
void createAboutBlankContentViewer(in nsIPrincipal aPrincipal,
in nsIPrincipal aPartitionedPrincipal);
/**
* Notify APZ to start autoscrolling.
* (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor,
* in CSS coordinates relative to the screen. aScrollId and
* aPresShellId identify the scroll frame that content chose to scroll.
* Returns whether we were successfully able to notify APZ.
* If this function returns true, APZ (which may live in another process)
* may still reject the autoscroll, but it's then APZ's reponsibility
* to notify content via an "autoscroll-rejected-by-apz" message.
*/
boolean startApzAutoscroll(in float aAnchorX, in float aAnchorY,
in nsViewID aScrollId, in uint32_t aPresShellId);
/**
* Notify APZ to stop autoscrolling.
* aScrollId and aPresShellId identify the scroll frame that is being
* autoscrolled.
*/
void stopApzAutoscroll(in nsViewID aScrollId, in uint32_t aPresShellId);
cenum NavigationType : 8 {
NAVIGATE_BACK = 0,
NAVIGATE_FORWARD = 1,

View file

@ -930,11 +930,6 @@ void BrowserChild::ActorDestroy(ActorDestroyReason why) {
}
}
CompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
if (compositorChild) {
compositorChild->CancelNotifyAfterRemotePaint(this);
}
if (GetTabId() != 0) {
NestedBrowserChildMap().erase(GetTabId());
}
@ -3316,17 +3311,6 @@ void BrowserChild::NotifyJankedAnimations(
lm->UpdatePartialPrerenderedAnimations(aJankedAnimations);
}
mozilla::ipc::IPCResult BrowserChild::RecvRequestNotifyAfterRemotePaint() {
// Get the CompositorBridgeChild instance for this content thread.
CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
// Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady
// message that it should forward it us so that we can bounce it to our
// BrowserParent.
compositor->RequestNotifyAfterRemotePaint(this);
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged(
const float& aDpi, const int32_t& aRounding, const double& aScale) {
nsCOMPtr<Document> document(GetTopLevelDocument());

View file

@ -721,8 +721,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvNavigateByKey(const bool& aForward,
const bool& aForDocumentNavigation);
mozilla::ipc::IPCResult RecvRequestNotifyAfterRemotePaint();
mozilla::ipc::IPCResult RecvSuppressDisplayport(const bool& aEnabled);
mozilla::ipc::IPCResult RecvScrollbarPreferenceChanged(ScrollbarPreference);

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