mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 12:15:33 +00:00
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
7ca067da6d
@ -335,8 +335,15 @@ uint64_t Accessible::VisibilityState() const {
|
||||
nsIFrame* parentFrame = curFrame->GetParent();
|
||||
nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
|
||||
if (deckFrame && deckFrame->GetSelectedBox() != curFrame) {
|
||||
#if defined(ANDROID)
|
||||
// In Fennec instead of a <tabpanels> container there is a <deck>
|
||||
// with direct <browser> children.
|
||||
if (curFrame->GetContent()->IsXULElement(nsGkAtoms::browser))
|
||||
return states::OFFSCREEN;
|
||||
#else
|
||||
if (deckFrame->GetContent()->IsXULElement(nsGkAtoms::tabpanels))
|
||||
return states::OFFSCREEN;
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"Children of not selected deck panel are not accessible.");
|
||||
|
@ -63,6 +63,7 @@ tags = blocklist
|
||||
[browser_CTP_hide_overlay.js]
|
||||
tags = blocklist
|
||||
[browser_CTP_iframe.js]
|
||||
skip-if = os == 'win' && !debug # Bug 1519868
|
||||
tags = blocklist
|
||||
[browser_CTP_nonplugins.js]
|
||||
skip-if = verify
|
||||
|
@ -177,6 +177,7 @@ skip-if = !e10s || !crashreporter # the tab's process is killed during the test.
|
||||
[browser_ext_sidebarAction_browser_style.js]
|
||||
[browser_ext_sidebarAction_click.js]
|
||||
[browser_ext_sidebarAction_context.js]
|
||||
skip-if = true # 1349892
|
||||
[browser_ext_sidebarAction_contextMenu.js]
|
||||
[browser_ext_sidebarAction_incognito.js]
|
||||
[browser_ext_sidebarAction_runtime.js]
|
||||
|
@ -36,21 +36,7 @@ function debugTargetListenerMiddleware(store) {
|
||||
clientWrapper.addListener("addonListChanged", onExtensionsUpdated);
|
||||
|
||||
// Workers
|
||||
clientWrapper.addListener("workerListChanged", onWorkersUpdated);
|
||||
clientWrapper.onFront("contentProcessTarget", front => {
|
||||
clientWrapper.contentProcessFronts.push(front);
|
||||
front.on("workerListChanged", onWorkersUpdated);
|
||||
});
|
||||
|
||||
clientWrapper.onFront("serviceWorkerRegistration", front => {
|
||||
clientWrapper.serviceWorkerRegistrationFronts.push(front);
|
||||
front.on("push-subscription-modified", onWorkersUpdated);
|
||||
front.on("registration-changed", onWorkersUpdated);
|
||||
});
|
||||
|
||||
clientWrapper.addListener("serviceWorkerRegistrationListChanged",
|
||||
onWorkersUpdated);
|
||||
clientWrapper.addListener("processListChanged", onWorkersUpdated);
|
||||
clientWrapper.addListener("workersUpdated", onWorkersUpdated);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -65,22 +51,7 @@ function debugTargetListenerMiddleware(store) {
|
||||
clientWrapper.removeListener("addonListChanged", onExtensionsUpdated);
|
||||
|
||||
// Workers
|
||||
clientWrapper.removeListener("workerListChanged", onWorkersUpdated);
|
||||
clientWrapper.removeListener("serviceWorkerRegistrationListChanged",
|
||||
onWorkersUpdated);
|
||||
|
||||
for (const front of clientWrapper.contentProcessFronts) {
|
||||
front.off("workerListChanged", onWorkersUpdated);
|
||||
}
|
||||
clientWrapper.contentProcessFronts = [];
|
||||
|
||||
for (const front of clientWrapper.serviceWorkerRegistrationFronts) {
|
||||
front.off("push-subscription-modified", onWorkersUpdated);
|
||||
front.off("registration-changed", onWorkersUpdated);
|
||||
}
|
||||
clientWrapper.serviceWorkerRegistrationFronts = [];
|
||||
|
||||
clientWrapper.removeListener("processListChanged", onWorkersUpdated);
|
||||
clientWrapper.removeListener("workersUpdated", onWorkersUpdated);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const { RUNTIME_PREFERENCE } = require("../constants");
|
||||
const { WorkersListener } = require("./workers-listener");
|
||||
|
||||
const PREF_TYPES = {
|
||||
BOOL: "BOOL",
|
||||
@ -20,10 +21,7 @@ const PREF_TO_TYPE = {
|
||||
// Some events are fired by mainRoot rather than client.
|
||||
const MAIN_ROOT_EVENTS = [
|
||||
"addonListChanged",
|
||||
"processListChanged",
|
||||
"serviceWorkerRegistrationListChanged",
|
||||
"tabListChanged",
|
||||
"workerListChanged",
|
||||
];
|
||||
|
||||
/**
|
||||
@ -33,9 +31,7 @@ const MAIN_ROOT_EVENTS = [
|
||||
class ClientWrapper {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
// Array of contentProcessTarget fronts on which we will listen for worker events.
|
||||
this.contentProcessFronts = [];
|
||||
this.serviceWorkerRegistrationFronts = [];
|
||||
this.workersListener = new WorkersListener(client.mainRoot);
|
||||
}
|
||||
|
||||
addOneTimeListener(evt, listener) {
|
||||
@ -47,7 +43,9 @@ class ClientWrapper {
|
||||
}
|
||||
|
||||
addListener(evt, listener) {
|
||||
if (MAIN_ROOT_EVENTS.includes(evt)) {
|
||||
if (evt === "workersUpdated") {
|
||||
this.workersListener.addListener(listener);
|
||||
} else if (MAIN_ROOT_EVENTS.includes(evt)) {
|
||||
this.client.mainRoot.on(evt, listener);
|
||||
} else {
|
||||
this.client.addListener(evt, listener);
|
||||
@ -55,7 +53,9 @@ class ClientWrapper {
|
||||
}
|
||||
|
||||
removeListener(evt, listener) {
|
||||
if (MAIN_ROOT_EVENTS.includes(evt)) {
|
||||
if (evt === "workersUpdated") {
|
||||
this.workersListener.removeListener(listener);
|
||||
} else if (MAIN_ROOT_EVENTS.includes(evt)) {
|
||||
this.client.mainRoot.off(evt, listener);
|
||||
} else {
|
||||
this.client.removeListener(evt, listener);
|
||||
|
@ -12,4 +12,5 @@ DevToolsModules(
|
||||
'runtime-client-factory.js',
|
||||
'runtimes-state-helper.js',
|
||||
'usb-runtimes.js',
|
||||
'workers-listener.js',
|
||||
)
|
||||
|
@ -0,0 +1,70 @@
|
||||
/* 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";
|
||||
|
||||
/**
|
||||
* Listening to worker updates requires watching various sources. This class provides
|
||||
* a single addListener/removeListener API that will aggregate all possible worker update
|
||||
* events.
|
||||
*
|
||||
* Only supports one listener at a time.
|
||||
*/
|
||||
class WorkersListener {
|
||||
constructor(rootFront) {
|
||||
this.rootFront = rootFront;
|
||||
|
||||
// Array of contentProcessTarget fronts on which we will listen for worker events.
|
||||
this._contentProcessFronts = [];
|
||||
this._serviceWorkerRegistrationFronts = [];
|
||||
this._listener = null;
|
||||
}
|
||||
|
||||
addListener(listener) {
|
||||
if (this._listener) {
|
||||
throw new Error("WorkersListener addListener called twice.");
|
||||
}
|
||||
|
||||
this._listener = listener;
|
||||
this.rootFront.on("workerListChanged", this._listener);
|
||||
this.rootFront.onFront("contentProcessTarget", front => {
|
||||
this._contentProcessFronts.push(front);
|
||||
front.on("workerListChanged", this._listener);
|
||||
});
|
||||
|
||||
this.rootFront.onFront("serviceWorkerRegistration", front => {
|
||||
this._serviceWorkerRegistrationFronts.push(front);
|
||||
front.on("push-subscription-modified", this._listener);
|
||||
front.on("registration-changed", this._listener);
|
||||
});
|
||||
|
||||
this.rootFront.on("serviceWorkerRegistrationListChanged", this._listener);
|
||||
this.rootFront.on("processListChanged", this._listener);
|
||||
}
|
||||
|
||||
removeListener(listener) {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rootFront.off("workerListChanged", this._listener);
|
||||
|
||||
for (const front of this._contentProcessFronts) {
|
||||
front.off("workerListChanged", this._listener);
|
||||
}
|
||||
|
||||
for (const front of this._serviceWorkerRegistrationFronts) {
|
||||
front.off("push-subscription-modified", this._listener);
|
||||
front.off("registration-changed", this._listener);
|
||||
}
|
||||
|
||||
this.rootFront.off("serviceWorkerRegistrationListChanged", this._listener);
|
||||
this.rootFront.off("processListChanged", this._listener);
|
||||
|
||||
this._contentProcessFronts = [];
|
||||
this._serviceWorkerRegistrationFronts = [];
|
||||
this._listener = null;
|
||||
}
|
||||
}
|
||||
exports.WorkersListener = WorkersListener;
|
@ -9,9 +9,6 @@ const USB_RUNTIME_ID = "test-runtime-id";
|
||||
const USB_RUNTIME_DEVICE_NAME = "test device name";
|
||||
const USB_RUNTIME_APP_NAME = "TestUsbApp";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
// Test that addons are displayed and updated for USB runtimes when expected.
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
/**
|
||||
* Check whether can toggle enable/disable connection prompt setting.
|
||||
*/
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
/* import-globals-from helper-collapsibilities.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-collapsibilities.js", this);
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const RUNTIME_ID = "test-runtime-id";
|
||||
const RUNTIME_DEVICE_NAME = "test device name";
|
||||
|
@ -26,7 +26,6 @@ add_task(async function() {
|
||||
|
||||
info("DevTools starts workers, wait for requests to settle");
|
||||
const store = window.AboutDebugging.store;
|
||||
await waitForDispatch(store, "REQUEST_WORKERS_SUCCESS");
|
||||
await waitForRequestsToSettle(store);
|
||||
|
||||
info("Click on the Connect item in the sidebar");
|
||||
|
@ -9,9 +9,6 @@ const USB_RUNTIME_ID = "test-runtime-id";
|
||||
const USB_DEVICE_NAME = "test device name";
|
||||
const USB_APP_NAME = "TestApp";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
// Test that remote runtime connections are persisted across about:debugging reloads.
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
/**
|
||||
* Test opening and closing the profiler dialog.
|
||||
*/
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
/**
|
||||
* Test that the initial route is /runtime/this-firefox
|
||||
*/
|
||||
|
@ -3,10 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
/**
|
||||
* Test that remote runtimes show action buttons that are hidden for 'This Firefox'.
|
||||
*/
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const NETWORK_RUNTIME_HOST = "localhost:6080";
|
||||
const NETWORK_RUNTIME_APP_NAME = "TestNetworkApp";
|
||||
const USB_RUNTIME_ID = "test-runtime-id";
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const NETWORK_RUNTIME_HOST = "localhost:6080";
|
||||
const NETWORK_RUNTIME_APP_NAME = "TestNetworkApp";
|
||||
const NETWORK_RUNTIME_CHANNEL = "SomeChannel";
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const NETWORK_RUNTIME_HOST = "localhost:6080";
|
||||
const NETWORK_RUNTIME_APP_NAME = "TestNetworkApp";
|
||||
const WORKER_NAME = "testserviceworker";
|
||||
@ -18,7 +15,8 @@ const WORKER_NAME = "testserviceworker";
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { document, tab, window } =
|
||||
await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
info("Prepare Network client mock");
|
||||
const networkClient = mocks.createNetworkRuntime(NETWORK_RUNTIME_HOST, {
|
||||
@ -39,7 +37,7 @@ add_task(async function() {
|
||||
sharedWorkers: [],
|
||||
};
|
||||
networkClient.listWorkers = () => workers;
|
||||
networkClient._eventEmitter.emit("workerListChanged");
|
||||
networkClient._eventEmitter.emit("workersUpdated");
|
||||
|
||||
info("Wait until the service worker is displayed");
|
||||
await waitUntil(() => findDebugTargetByText(WORKER_NAME, document));
|
||||
|
@ -17,7 +17,7 @@ const EMPTY_SW_HTML = URL_ROOT + "resources/service-workers/empty-sw.html";
|
||||
*/
|
||||
add_task(async function() {
|
||||
await enableServiceWorkerDebugging();
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
info("Test fetch status for a service worker listening to fetch events");
|
||||
await testServiceWorkerFetchStatus(document, FETCH_SW_HTML, FETCH_SW_JS, true);
|
||||
|
@ -35,7 +35,7 @@ async function testDebuggingSW(enableMultiE10sFn, disableMultiE10sFn) {
|
||||
// enable service workers
|
||||
await pushPref("dom.serviceWorkers.testing.enabled", true);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// disable multi e10s
|
||||
info("Disabling multi e10s");
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
// Test migrated from
|
||||
// devtools/client/aboutdebugging/test/browser_service_workers_not_compatible.js
|
||||
|
||||
@ -47,7 +44,7 @@ add_task(async function testLocalRuntime() {
|
||||
await pushPref("dom.serviceWorkers.enabled", serviceWorkersEnabled);
|
||||
await pushPref("browser.privatebrowsing.autostart", privateBrowsingEnabled);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
assertWarningMessage(document, expectedMessage);
|
||||
await removeTab(tab);
|
||||
}
|
||||
@ -74,7 +71,7 @@ add_task(async function testRemoteRuntime() {
|
||||
client.setPreference("dom.serviceWorkers.enabled", serviceWorkersEnabled);
|
||||
client.setPreference("browser.privatebrowsing.autostart", privateBrowsingEnabled);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
info("Checking a USB runtime");
|
||||
mocks.emitUSBUpdate();
|
||||
|
@ -13,7 +13,7 @@ const TAB_URL = URL_ROOT + "resources/service-workers/push-sw.html";
|
||||
// It should trigger a "push" notification in the worker.
|
||||
add_task(async function() {
|
||||
await enableServiceWorkerDebugging();
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// Open a tab that registers a push service worker.
|
||||
const swTab = await addTab(TAB_URL);
|
||||
|
@ -19,7 +19,7 @@ add_task(async function() {
|
||||
info("Mock the push service");
|
||||
mockPushService(FAKE_ENDPOINT);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// Open a tab that registers a push service worker.
|
||||
const swTab = await addTab(TAB_URL);
|
||||
|
@ -21,7 +21,8 @@ const SW_URL = URL_ROOT + "resources/service-workers/push-sw.js";
|
||||
add_task(async function() {
|
||||
prepareCollapsibilitiesTest();
|
||||
await enableServiceWorkerDebugging();
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { document, tab, window } =
|
||||
await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
const store = window.AboutDebugging.store;
|
||||
|
||||
await selectThisFirefoxPage(document, store);
|
||||
|
@ -25,7 +25,7 @@ add_task(async function() {
|
||||
await pushPref("dom.serviceWorkers.idle_timeout", 1000);
|
||||
await pushPref("dom.serviceWorkers.idle_extended_timeout", 1000);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// Open a tab that registers a basic service worker.
|
||||
const swTab = await addTab(SW_TAB_URL);
|
||||
|
@ -16,7 +16,7 @@ const SW_URL = URL_ROOT + "resources/service-workers/controlled-sw.js";
|
||||
add_task(async function() {
|
||||
await enableServiceWorkerDebugging();
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
info("Open tab with a service worker that never leaves `registering` status");
|
||||
const swTab = await addTab(SW_TAB_URL);
|
||||
|
@ -31,7 +31,7 @@ add_task(async function() {
|
||||
await pushPref("dom.serviceWorkers.idle_timeout", SW_TIMEOUT);
|
||||
await pushPref("dom.serviceWorkers.idle_extended_timeout", SW_TIMEOUT);
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// Open a tab that registers a basic service worker.
|
||||
const swTab = await addTab(SW_TAB_URL);
|
||||
|
@ -18,7 +18,7 @@ const SW_URL = URL_ROOT + "resources/service-workers/empty-sw.js";
|
||||
add_task(async function() {
|
||||
await enableServiceWorkerDebugging();
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
// Open a tab that registers a basic service worker.
|
||||
const swTab = await addTab(SW_TAB_URL);
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
// Test that USB runtimes appear and disappear from the sidebar.
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const RUNTIME_ID = "test-runtime-id";
|
||||
const RUNTIME_DEVICE_NAME = "test device name";
|
||||
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const RUNTIME_ID = "test-runtime-id";
|
||||
const RUNTIME_DEVICE_NAME = "test device name";
|
||||
const RUNTIME_APP_NAME = "TestApp";
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const RUNTIME_DEVICE_ID = "1234";
|
||||
const RUNTIME_DEVICE_NAME = "A device";
|
||||
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const RUNTIME_NAME = "Firefox 123";
|
||||
|
||||
// Test that unknown runtimes:
|
||||
|
@ -3,13 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from mocks/helper-client-wrapper-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-client-wrapper-mock.js", this);
|
||||
/* import-globals-from mocks/helper-runtime-client-factory-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-runtime-client-factory-mock.js", this);
|
||||
|
||||
// Test that system addons are only displayed when the showSystemAddons preference is
|
||||
// true.
|
||||
|
||||
|
@ -2,9 +2,6 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
/* import-globals-from helper-telemetry.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-telemetry.js", this);
|
||||
|
||||
|
@ -3,13 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from mocks/helper-client-wrapper-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-client-wrapper-mock.js", this);
|
||||
/* import-globals-from mocks/helper-runtime-client-factory-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-runtime-client-factory-mock.js", this);
|
||||
|
||||
/**
|
||||
* Check that the runtime info is correctly displayed for ThisFirefox.
|
||||
* Also acts as basic sanity check for the default mock of the this-firefox client.
|
||||
|
@ -3,13 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from mocks/helper-client-wrapper-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-client-wrapper-mock.js", this);
|
||||
/* import-globals-from mocks/helper-runtime-client-factory-mock.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
CHROME_URL_ROOT + "mocks/helper-runtime-client-factory-mock.js", this);
|
||||
|
||||
const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
|
||||
|
||||
add_task(async function() {
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
const NETWORK_RUNTIME_HOST = "localhost:6080";
|
||||
const NETWORK_RUNTIME_APP_NAME = "TestNetworkApp";
|
||||
const USB_RUNTIME_ID = "test-runtime-id";
|
||||
@ -38,7 +35,7 @@ const EMPTY_WORKERS_RESPONSE = {
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
const { document, tab } = await openAboutDebugging({ enableWorkerUpdates: true });
|
||||
|
||||
info("Prepare USB client mock");
|
||||
const usbClient = mocks.createUSBRuntime(USB_RUNTIME_ID, {
|
||||
@ -95,7 +92,7 @@ async function testWorkerOnMockedRemoteClient(testData, remoteClient, firefoxCli
|
||||
}],
|
||||
});
|
||||
remoteClient.listWorkers = () => workers;
|
||||
remoteClient._eventEmitter.emit("workerListChanged");
|
||||
remoteClient._eventEmitter.emit("workersUpdated");
|
||||
|
||||
info("Wait until the worker appears");
|
||||
await waitUntil(() => !workersPane.querySelector(".js-debug-target-list-empty"));
|
||||
@ -104,12 +101,12 @@ async function testWorkerOnMockedRemoteClient(testData, remoteClient, firefoxCli
|
||||
ok(workerTarget, "Worker target appeared for the remote runtime");
|
||||
|
||||
// Check that the list of REMOTE workers are NOT updated when the local this-firefox
|
||||
// emits a workerListChanged event.
|
||||
// emits a workersUpdated event.
|
||||
info("Remove the worker from the remote client WITHOUT sending an event");
|
||||
remoteClient.listWorkers = () => EMPTY_WORKERS_RESPONSE;
|
||||
|
||||
info("Simulate a worker update on the ThisFirefox client");
|
||||
firefoxClient._eventEmitter.emit("workerListChanged");
|
||||
firefoxClient._eventEmitter.emit("workersUpdated");
|
||||
|
||||
// To avoid wait for a set period of time we trigger another async update, adding a new
|
||||
// tab. We assume that if the worker update mechanism had started, it would also be done
|
||||
@ -123,7 +120,7 @@ async function testWorkerOnMockedRemoteClient(testData, remoteClient, firefoxCli
|
||||
ok(findDebugTargetByText(workerName, document),
|
||||
"The test worker is still visible");
|
||||
|
||||
info("Emit `workerListChanged` on remoteClient and wait for the target list to update");
|
||||
remoteClient._eventEmitter.emit("workerListChanged");
|
||||
info("Emit `workersUpdated` on remoteClient and wait for the target list to update");
|
||||
remoteClient._eventEmitter.emit("workersUpdated");
|
||||
await waitUntil(() => !findDebugTargetByText(workerName, document));
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/shared/test/shared-redux-head.js",
|
||||
this);
|
||||
|
||||
/* import-globals-from helper-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
||||
|
||||
// Make sure the ADB addon is removed and ADB is stopped when the test ends.
|
||||
registerCleanupFunction(async function() {
|
||||
try {
|
||||
@ -41,12 +44,16 @@ async function enableNewAboutDebugging() {
|
||||
await pushPref("devtools.aboutdebugging.network", true);
|
||||
}
|
||||
|
||||
async function openAboutDebugging(page, win) {
|
||||
async function openAboutDebugging({ enableWorkerUpdates } = {}) {
|
||||
if (!enableWorkerUpdates) {
|
||||
silenceWorkerUpdates();
|
||||
}
|
||||
|
||||
await enableNewAboutDebugging();
|
||||
|
||||
info("opening about:debugging");
|
||||
|
||||
const tab = await addTab("about:debugging", { window: win });
|
||||
const tab = await addTab("about:debugging");
|
||||
const browser = tab.linkedBrowser;
|
||||
const document = browser.contentDocument;
|
||||
const window = browser.contentWindow;
|
||||
|
@ -163,3 +163,23 @@ class Mocks {
|
||||
}
|
||||
/* exported Mocks */
|
||||
|
||||
const silenceWorkerUpdates = function() {
|
||||
const { removeMockedModule, setMockedModule } =
|
||||
require("devtools/client/shared/browser-loader-mocks");
|
||||
|
||||
const mock = {
|
||||
WorkersListener: () => {
|
||||
return {
|
||||
addListener: () => {},
|
||||
removeListener: () => {},
|
||||
};
|
||||
},
|
||||
};
|
||||
setMockedModule(mock,
|
||||
"devtools/client/aboutdebugging-new/src/modules/workers-listener");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
removeMockedModule("devtools/client/aboutdebugging-new/src/modules/workers-listener");
|
||||
});
|
||||
};
|
||||
/* exported silenceWorkerUpdates */
|
||||
|
@ -39,7 +39,6 @@ function createClientMock() {
|
||||
removeListener: (evt, listener) => {
|
||||
eventEmitter.off(evt, listener);
|
||||
},
|
||||
|
||||
client: {
|
||||
addOneTimeListener: (evt, listener) => {
|
||||
eventEmitter.once(evt, listener);
|
||||
|
@ -0,0 +1,21 @@
|
||||
/* 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/. */
|
||||
|
||||
.error-page {
|
||||
--base-unit: 4px; /* from photon */
|
||||
|
||||
padding: calc(var(--base-unit) * 4);
|
||||
font-size: 15px; /* from photon */
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.error-page__title {
|
||||
margin: 0;
|
||||
font-size: 36px; /* from photon */
|
||||
font-weight: 200; /* from photon */
|
||||
}
|
||||
|
||||
.error-page__details {
|
||||
font-family: monospace;
|
||||
}
|
50
devtools/client/framework/components/DebugTargetErrorPage.js
Normal file
50
devtools/client/framework/components/DebugTargetErrorPage.js
Normal file
@ -0,0 +1,50 @@
|
||||
/* 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";
|
||||
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
/**
|
||||
* This component is displayed when the about:devtools-toolbox fails to load
|
||||
* properly due to wrong parameters or debug targets that don't exist.
|
||||
*/
|
||||
class DebugTargetErrorPage extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
L10N: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { errorMessage, L10N } = this.props;
|
||||
|
||||
return dom.article(
|
||||
{
|
||||
className: "error-page js-error-page",
|
||||
},
|
||||
dom.h1(
|
||||
{
|
||||
className: "error-page__title",
|
||||
},
|
||||
L10N.getStr("toolbox.debugTargetErrorPage.title"),
|
||||
),
|
||||
dom.p(
|
||||
{},
|
||||
L10N.getStr("toolbox.debugTargetErrorPage.description"),
|
||||
),
|
||||
dom.output(
|
||||
{
|
||||
className: "error-page__details",
|
||||
},
|
||||
errorMessage,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DebugTargetErrorPage;
|
@ -6,6 +6,8 @@
|
||||
|
||||
|
||||
DevToolsModules(
|
||||
'DebugTargetErrorPage.css',
|
||||
'DebugTargetErrorPage.js',
|
||||
'DebugTargetInfo.js',
|
||||
'MeatballMenu.js',
|
||||
'ToolboxController.js',
|
||||
|
@ -137,7 +137,11 @@ async function clientFromURL(url) {
|
||||
// If a remote id was provided we should already have a connected client available.
|
||||
const remoteId = params.get("remoteId");
|
||||
if (remoteId) {
|
||||
return remoteClientManager.getClientByRemoteId(remoteId);
|
||||
const client = remoteClientManager.getClientByRemoteId(remoteId);
|
||||
if (!client) {
|
||||
throw new Error(`Could not find client with remote id: ${remoteId}`);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
const host = params.get("host");
|
||||
|
@ -54,6 +54,7 @@ support-files =
|
||||
!/devtools/client/shared/test/shared-redux-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
|
||||
[browser_about-devtools-toolbox_load.js]
|
||||
[browser_browser_toolbox.js]
|
||||
skip-if = coverage # Bug 1387827
|
||||
[browser_browser_toolbox_debugger.js]
|
||||
|
@ -0,0 +1,42 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test that about:devtools-toolbox shows error an page when opened with invalid
|
||||
* paramters
|
||||
*/
|
||||
add_task(async function() {
|
||||
// test that error is shown when missing `type` param
|
||||
let { document, tab } = await openAboutToolbox({ invalid: "invalid" });
|
||||
await assertErrorIsShown(document);
|
||||
await removeTab(tab);
|
||||
// test that error is shown if `id` is not provided
|
||||
({ document, tab } = await openAboutToolbox({ type: "tab" }));
|
||||
await assertErrorIsShown(document);
|
||||
await removeTab(tab);
|
||||
// test that error is shown if `remoteId` refers to an unexisting target
|
||||
({ document, tab } = await openAboutToolbox({ type: "tab", remoteId: "13371337" }));
|
||||
await assertErrorIsShown(document);
|
||||
await removeTab(tab);
|
||||
|
||||
async function assertErrorIsShown(doc) {
|
||||
await waitUntil(() => doc.querySelector(".js-error-page"));
|
||||
ok(doc.querySelector(".js-error-page"), "Error page is rendered");
|
||||
}
|
||||
});
|
||||
|
||||
async function openAboutToolbox(params) {
|
||||
info("opening about:devtools-toolbox");
|
||||
const querystring = new URLSearchParams();
|
||||
Object.keys(params).forEach(x => querystring.append(x, params[x]));
|
||||
|
||||
const tab = await addTab(`about:devtools-toolbox?${querystring}`);
|
||||
const browser = tab.linkedBrowser;
|
||||
|
||||
return {
|
||||
tab,
|
||||
document: browser.contentDocument,
|
||||
};
|
||||
}
|
@ -7,43 +7,78 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
|
||||
// URL constructor doesn't support about: scheme
|
||||
const href = window.location.href.replace("about:", "http://");
|
||||
const url = new window.URL(href);
|
||||
|
||||
// Only use this method to attach the toolbox if some query parameters are given
|
||||
if (url.search.length > 1) {
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
// `host` is the frame element loading the toolbox.
|
||||
let host = window.windowUtils.containerElement;
|
||||
|
||||
// If there's no containerElement (which happens when loading about:devtools-toolbox as
|
||||
// a top level document), use the current window.
|
||||
if (!host) {
|
||||
host = {
|
||||
contentWindow: window,
|
||||
contentDocument: document,
|
||||
// toolbox-host-manager.js wants to set attributes on the frame that contains it,
|
||||
// but that is fine to skip and doesn't make sense when using the current window.
|
||||
setAttribute() {},
|
||||
ownerDocument: document,
|
||||
// toolbox-host-manager.js wants to listen for unload events from outside the frame,
|
||||
// but this is fine to skip since the toolbox code listens inside the frame as well,
|
||||
// and there is no outer document in this case.
|
||||
addEventListener() {},
|
||||
};
|
||||
}
|
||||
|
||||
const onLoad = new Promise(r => {
|
||||
host.contentWindow.addEventListener("DOMContentLoaded", r, { once: true });
|
||||
});
|
||||
|
||||
async function showErrorPage(doc, errorMessage) {
|
||||
const win = doc.defaultView;
|
||||
const { BrowserLoader } =
|
||||
ChromeUtils.import("resource://devtools/client/shared/browser-loader.js");
|
||||
const browserRequire = BrowserLoader({
|
||||
window: win,
|
||||
useOnlyShared: true,
|
||||
}).require;
|
||||
|
||||
const React = browserRequire("devtools/client/shared/vendor/react");
|
||||
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
|
||||
const DebugTargetErrorPage = React.createFactory(
|
||||
require("devtools/client/framework/components/DebugTargetErrorPage"));
|
||||
const { LocalizationHelper } = browserRequire("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
|
||||
|
||||
// mount the React component into our XUL container once the DOM is ready
|
||||
await onLoad;
|
||||
const mountEl = doc.querySelector("#toolbox-error-mount");
|
||||
const element = DebugTargetErrorPage({
|
||||
errorMessage,
|
||||
L10N,
|
||||
});
|
||||
ReactDOM.render(element, mountEl);
|
||||
|
||||
// make sure we unmount the component when the page is destroyed
|
||||
win.addEventListener("unload", () => {
|
||||
ReactDOM.unmountComponentAtNode(mountEl);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
async function initToolbox(url, host) {
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const { targetFromURL } = require("devtools/client/framework/target-from-url");
|
||||
const { Toolbox } = require("devtools/client/framework/toolbox");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DebuggerClient } = require("devtools/shared/client/debugger-client");
|
||||
|
||||
// `host` is the frame element loading the toolbox.
|
||||
let host = window.windowUtils.containerElement;
|
||||
|
||||
// If there's no containerElement (which happens when loading about:devtools-toolbox as
|
||||
// a top level document), use the current window.
|
||||
if (!host) {
|
||||
host = {
|
||||
contentWindow: window,
|
||||
contentDocument: document,
|
||||
// toolbox-host-manager.js wants to set attributes on the frame that contains it,
|
||||
// but that is fine to skip and doesn't make sense when using the current window.
|
||||
setAttribute() {},
|
||||
ownerDocument: document,
|
||||
// toolbox-host-manager.js wants to listen for unload events from outside the frame,
|
||||
// but this is fine to skip since the toolbox code listens inside the frame as well,
|
||||
// and there is no outer document in this case.
|
||||
addEventListener() {},
|
||||
};
|
||||
}
|
||||
|
||||
// Specify the default tool to open
|
||||
const tool = url.searchParams.get("tool");
|
||||
|
||||
(async function() {
|
||||
try {
|
||||
let target;
|
||||
if (url.searchParams.has("target")) {
|
||||
// Attach toolbox to a given browser iframe (<xul:browser> or <html:iframe
|
||||
@ -76,7 +111,16 @@ if (url.search.length > 1) {
|
||||
}
|
||||
const options = { customIframe: host };
|
||||
await gDevTools.showToolbox(target, tool, Toolbox.HostType.PAGE, options);
|
||||
})().catch(error => {
|
||||
} catch (error) {
|
||||
// When an error occurs, show error page with message.
|
||||
console.error("Exception while loading the toolbox", error);
|
||||
});
|
||||
showErrorPage(host.contentDocument, `${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Only use this method to attach the toolbox if some query parameters are given
|
||||
if (url.search.length > 1) {
|
||||
initToolbox(url, host);
|
||||
}
|
||||
// TODO: handle no params in about:devtool-toolbox
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1526996
|
||||
|
@ -5,6 +5,7 @@
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/toolbox.css" type="text/css"?>
|
||||
<?xml-stylesheet href="resource://devtools/client/shared/components/NotificationBox.css" type="text/css"?>
|
||||
<?xml-stylesheet href="resource://devtools/client/framework/components/DebugTargetErrorPage.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % toolboxDTD SYSTEM "chrome://devtools/locale/toolbox.dtd" >
|
||||
@ -27,6 +28,7 @@
|
||||
src="chrome://devtools/content/framework/toolbox-init.js"/>
|
||||
|
||||
<vbox id="toolbox-container" flex="1">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-error-mount"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-notificationbox"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-toolbar-mount"
|
||||
role="toolbar" />
|
||||
|
@ -123,8 +123,4 @@ async function waitUntilDebuggerReady(debuggerContext) {
|
||||
// We have to wait until the debugger has fully loaded the source otherwise
|
||||
// we will get unhandled promise rejections.
|
||||
await waitForLoadedSource(debuggerContext, "data:");
|
||||
|
||||
// Have to wait until https://github.com/devtools-html/debugger.html/pull/6189
|
||||
// is released to avoid unhandled promise rejections.
|
||||
await waitForTime(1000);
|
||||
}
|
||||
|
@ -244,3 +244,13 @@ browserToolbox.statusMessage=Browser Toolbox connection status:
|
||||
# LOCALIZATION NOTE (toolbox.replay.jumpMessage): This is the label
|
||||
# shown in the web replay timeline marker
|
||||
toolbox.replay.jumpMessage=Jump to message %1$S
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.debugTargetErrorPage.title): This is the title
|
||||
# for the Error view shown by the toolbox when a connection to a debug target
|
||||
# could not be made
|
||||
toolbox.debugTargetErrorPage.title = Error
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.debugTargetErrorPage.description): This is the
|
||||
# text that appears in the Error view and explains to the user that an error
|
||||
# has happened while trying to connect to a debug target
|
||||
toolbox.debugTargetErrorPage.description = Cannot connect to the debug target. See error details below:
|
||||
|
@ -9,9 +9,6 @@ loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true);
|
||||
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
|
||||
loader.lazyRequireGetter(this, "WebConsole", "devtools/client/webconsole/webconsole");
|
||||
|
||||
// The preference prefix for all of the Browser Console filters.
|
||||
const BC_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
|
||||
|
||||
/**
|
||||
* A BrowserConsole instance is an interactive console initialized *per target*
|
||||
* that displays console log data as well as provides an interactive terminal to
|
||||
@ -59,8 +56,6 @@ BrowserConsole.prototype = extend(WebConsole.prototype, {
|
||||
// Only add the shutdown observer if we've opened a Browser Console window.
|
||||
ShutdownObserver.init(this.hudService);
|
||||
|
||||
this.ui._filterPrefsPrefix = BC_FILTER_PREFS_PREFIX;
|
||||
|
||||
const window = this.iframeWindow;
|
||||
|
||||
// Make sure that the closing of the Browser Console window destroys this
|
||||
|
@ -40,6 +40,9 @@ nsIContent* ExplicitChildIterator::GetNextChild() {
|
||||
mChild = (mIndexInInserted < assignedNodes.Length())
|
||||
? assignedNodes[mIndexInInserted++]->AsContent()
|
||||
: nullptr;
|
||||
if (!mChild) {
|
||||
mIndexInInserted = 0;
|
||||
}
|
||||
return mChild;
|
||||
}
|
||||
|
||||
|
@ -3146,6 +3146,8 @@ nsIContent* nsFocusManager::GetNextTabbableContentInAncestorScopes(
|
||||
int32_t tabIndex = 0;
|
||||
if (IsHostOrSlot(startContent)) {
|
||||
tabIndex = HostOrSlotTabIndexValue(startContent);
|
||||
} else if (nsIFrame* frame = startContent->GetPrimaryFrame()) {
|
||||
frame->IsFocusable(&tabIndex);
|
||||
} else {
|
||||
startContent->IsFocusable(&tabIndex);
|
||||
}
|
||||
|
@ -653,6 +653,127 @@
|
||||
input1.remove();
|
||||
}
|
||||
|
||||
function testTabbingThroughScrollableShadowDOM() {
|
||||
opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
|
||||
|
||||
var host0 = document.createElement("div");
|
||||
host0.setAttribute("style", "height: 50px; overflow: auto;");
|
||||
host0.onfocus = focusLogger;
|
||||
document.body.appendChild(host0);
|
||||
|
||||
var sr0 = host0.attachShadow({mode: "open"});
|
||||
sr0.innerHTML = `
|
||||
<style>
|
||||
div,slot {
|
||||
height: 30px;
|
||||
display: block;
|
||||
overflow: auto;
|
||||
}
|
||||
input {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
var input00 = document.createElement("input");
|
||||
input00.setAttribute("style", "background-color: red;");
|
||||
input00.onfocus = focusLogger;
|
||||
sr0.appendChild(input00);
|
||||
|
||||
var container01 = document.createElement("div");
|
||||
container01.onfocus = focusLogger;
|
||||
sr0.appendChild(container01);
|
||||
|
||||
var input010 = document.createElement("input");
|
||||
input010.onfocus = focusLogger;
|
||||
container01.appendChild(input010);
|
||||
|
||||
var input011 = document.createElement("input");
|
||||
input011.onfocus = focusLogger;
|
||||
container01.appendChild(input011);
|
||||
|
||||
var slot02 = document.createElement("slot");
|
||||
slot02.onfocus = focusLogger;
|
||||
sr0.appendChild(slot02);
|
||||
|
||||
var input020 = document.createElement("input");
|
||||
input020.setAttribute("style", "display: block;");
|
||||
input020.onfocus = focusLogger;
|
||||
host0.appendChild(input020);
|
||||
|
||||
var input021 = document.createElement("input");
|
||||
input021.setAttribute("style", "display: block;");
|
||||
input021.onfocus = focusLogger;
|
||||
host0.appendChild(input021);
|
||||
|
||||
var input1 = document.createElement("input");
|
||||
input1.onfocus = focusLogger;
|
||||
document.body.appendChild(input1);
|
||||
|
||||
document.body.offsetLeft;
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, host0, "Should have focused shadow host element. (1)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input00, "Should have focused input element in shadow dom. (2)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, container01, "Should have focused scrollable element in shadow dom. (3)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input010, "Should have focused input element in shadow dom. (4)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input011, "Should have focused input element in shadow dom. (5)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, slot02, "Should have focused slot element in shadow dom. (6)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input020, "Should have focused input element in slot. (7)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input021, "Should have focused input element in slot. (8)");
|
||||
|
||||
synthesizeKey("KEY_Tab");
|
||||
opener.is(lastFocusTarget, input1, "Should have focused input element in light dom. (9)");
|
||||
|
||||
// Backwards
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, input021, "Should have focused input element in slot. (10)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, input020, "Should have focused input element in slot. (11)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, slot02, "Should have focused slot element in shadow dom. (12)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, input011, "Should have focused input element in shadow dom. (13)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, input010, "Should have focused input element in shadow dom. (14)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, container01, "Should have focused scrollable element in shadow dom. (15)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(lastFocusTarget, input00, "Should have focused input element in shadow dom. (16)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
// focus is already on host
|
||||
opener.is(sr0.activeElement, null,
|
||||
"Focus should have left input element in shadow DOM. (7)");
|
||||
|
||||
synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
opener.is(document.activeElement, document.body.firstChild,
|
||||
"body's first child should have focus.");
|
||||
|
||||
host0.remove();
|
||||
input1.remove();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
testTabbingThroughShadowDOMWithTabIndexes();
|
||||
@ -665,6 +786,7 @@
|
||||
testTabbingThroughNestedSlot();
|
||||
testTabbingThroughSlotInLightDOM();
|
||||
testTabbingThroughFocusableSlotInLightDOM();
|
||||
testTabbingThroughScrollableShadowDOM();
|
||||
|
||||
opener.didRunTests();
|
||||
window.close();
|
||||
|
@ -397,12 +397,11 @@ nsresult AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
|
||||
void AudioStream::SetVolume(double aVolume) {
|
||||
MOZ_ASSERT(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
MOZ_ASSERT(mState != SHUTDOWN, "Don't set volume after shutdown.");
|
||||
MOZ_DIAGNOSTIC_ASSERT(mState != ERRORED, "Don't set volume if stream got error.");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cubeb_stream_set_volume(mCubebStream.get(),
|
||||
aVolume * CubebUtils::GetVolumeScale()) !=
|
||||
|
@ -1384,11 +1384,15 @@ class RTCPeerConnection {
|
||||
}
|
||||
|
||||
getSenders() {
|
||||
return this.getTransceivers().map(transceiver => transceiver.sender);
|
||||
return this.getTransceivers()
|
||||
.filter(transceiver => !transceiver.stopped)
|
||||
.map(transceiver => transceiver.sender);
|
||||
}
|
||||
|
||||
getReceivers() {
|
||||
return this.getTransceivers().map(transceiver => transceiver.receiver);
|
||||
return this.getTransceivers()
|
||||
.filter(transceiver => !transceiver.stopped)
|
||||
.map(transceiver => transceiver.receiver);
|
||||
}
|
||||
|
||||
// test-only: get the current time using the webrtc clock
|
||||
|
@ -2572,11 +2572,16 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
|
||||
nsIDocShell* docShell = window ? window->GetDocShell() : nullptr;
|
||||
nsAutoCString profilerLabelString;
|
||||
GetProfilerLabelForRequest(aRequest, profilerLabelString);
|
||||
AUTO_PROFILER_TEXT_MARKER_DOCSHELL("Script", profilerLabelString, JS,
|
||||
docShell);
|
||||
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||
nsAutoMicroTask mt;
|
||||
nsAutoCString profilerLabelString;
|
||||
GetProfilerLabelForRequest(aRequest, profilerLabelString);
|
||||
AutoEntryScript aes(globalObject, profilerLabelString.get(), true);
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
|
@ -59,6 +59,14 @@ void VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp) {
|
||||
// Called on the vsync thread
|
||||
MutexAutoLock lock(mDispatcherLock);
|
||||
|
||||
// mRefreshTimerVsyncDispatcher might be null here if MoveListenersToNewSource
|
||||
// was called concurrently with this function and won the race to acquire
|
||||
// mDispatcherLock. In this case the new VsyncSource that is replacing this
|
||||
// one will handle notifications from now on, so we can abort.
|
||||
if (!mRefreshTimerVsyncDispatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
mVsyncId = mVsyncId.Next();
|
||||
VsyncEvent event(mVsyncId, aVsyncTimestamp);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/ObjectOperations-inl.h"
|
||||
|
@ -61,11 +61,9 @@ namespace frontend {
|
||||
*/
|
||||
#define FOR_EACH_BIN_KIND(F) \
|
||||
F(_Null, "") \
|
||||
F(Arguments, "Arguments") \
|
||||
F(ArrayAssignmentTarget, "ArrayAssignmentTarget") \
|
||||
F(ArrayBinding, "ArrayBinding") \
|
||||
F(ArrayExpression, "ArrayExpression") \
|
||||
F(ArrowExpression, "ArrowExpression") \
|
||||
F(ArrowExpressionContentsWithExpression, \
|
||||
"ArrowExpressionContentsWithExpression") \
|
||||
F(ArrowExpressionContentsWithFunctionBody, \
|
||||
@ -73,10 +71,7 @@ namespace frontend {
|
||||
F(AssertedBlockScope, "AssertedBlockScope") \
|
||||
F(AssertedBoundName, "AssertedBoundName") \
|
||||
F(AssertedBoundNamesScope, "AssertedBoundNamesScope") \
|
||||
F(AssertedDeclaredKind, "AssertedDeclaredKind") \
|
||||
F(AssertedDeclaredName, "AssertedDeclaredName") \
|
||||
F(AssertedMaybePositionalParameterName, \
|
||||
"AssertedMaybePositionalParameterName") \
|
||||
F(AssertedParameterName, "AssertedParameterName") \
|
||||
F(AssertedParameterScope, "AssertedParameterScope") \
|
||||
F(AssertedPositionalParameterName, "AssertedPositionalParameterName") \
|
||||
@ -84,23 +79,13 @@ namespace frontend {
|
||||
F(AssertedScriptGlobalScope, "AssertedScriptGlobalScope") \
|
||||
F(AssertedVarScope, "AssertedVarScope") \
|
||||
F(AssignmentExpression, "AssignmentExpression") \
|
||||
F(AssignmentTarget, "AssignmentTarget") \
|
||||
F(AssignmentTargetIdentifier, "AssignmentTargetIdentifier") \
|
||||
F(AssignmentTargetOrAssignmentTargetWithInitializer, \
|
||||
"AssignmentTargetOrAssignmentTargetWithInitializer") \
|
||||
F(AssignmentTargetPattern, "AssignmentTargetPattern") \
|
||||
F(AssignmentTargetProperty, "AssignmentTargetProperty") \
|
||||
F(AssignmentTargetPropertyIdentifier, "AssignmentTargetPropertyIdentifier") \
|
||||
F(AssignmentTargetPropertyProperty, "AssignmentTargetPropertyProperty") \
|
||||
F(AssignmentTargetWithInitializer, "AssignmentTargetWithInitializer") \
|
||||
F(AwaitExpression, "AwaitExpression") \
|
||||
F(BinaryExpression, "BinaryExpression") \
|
||||
F(BinaryOperator, "BinaryOperator") \
|
||||
F(Binding, "Binding") \
|
||||
F(BindingIdentifier, "BindingIdentifier") \
|
||||
F(BindingOrBindingWithInitializer, "BindingOrBindingWithInitializer") \
|
||||
F(BindingPattern, "BindingPattern") \
|
||||
F(BindingProperty, "BindingProperty") \
|
||||
F(BindingPropertyIdentifier, "BindingPropertyIdentifier") \
|
||||
F(BindingPropertyProperty, "BindingPropertyProperty") \
|
||||
F(BindingWithInitializer, "BindingWithInitializer") \
|
||||
@ -112,7 +97,6 @@ namespace frontend {
|
||||
F(ClassElement, "ClassElement") \
|
||||
F(ClassExpression, "ClassExpression") \
|
||||
F(CompoundAssignmentExpression, "CompoundAssignmentExpression") \
|
||||
F(CompoundAssignmentOperator, "CompoundAssignmentOperator") \
|
||||
F(ComputedMemberAssignmentTarget, "ComputedMemberAssignmentTarget") \
|
||||
F(ComputedMemberExpression, "ComputedMemberExpression") \
|
||||
F(ComputedPropertyName, "ComputedPropertyName") \
|
||||
@ -133,45 +117,25 @@ namespace frontend {
|
||||
F(EmptyStatement, "EmptyStatement") \
|
||||
F(Export, "Export") \
|
||||
F(ExportAllFrom, "ExportAllFrom") \
|
||||
F(ExportDeclaration, "ExportDeclaration") \
|
||||
F(ExportDefault, "ExportDefault") \
|
||||
F(ExportFrom, "ExportFrom") \
|
||||
F(ExportFromSpecifier, "ExportFromSpecifier") \
|
||||
F(ExportLocalSpecifier, "ExportLocalSpecifier") \
|
||||
F(ExportLocals, "ExportLocals") \
|
||||
F(Expression, "Expression") \
|
||||
F(ExpressionOrSuper, "ExpressionOrSuper") \
|
||||
F(ExpressionOrTemplateElement, "ExpressionOrTemplateElement") \
|
||||
F(ExpressionStatement, "ExpressionStatement") \
|
||||
F(ForInOfBinding, "ForInOfBinding") \
|
||||
F(ForInOfBindingOrAssignmentTarget, "ForInOfBindingOrAssignmentTarget") \
|
||||
F(ForInStatement, "ForInStatement") \
|
||||
F(ForOfStatement, "ForOfStatement") \
|
||||
F(ForStatement, "ForStatement") \
|
||||
F(FormalParameters, "FormalParameters") \
|
||||
F(FunctionBody, "FunctionBody") \
|
||||
F(FunctionDeclaration, "FunctionDeclaration") \
|
||||
F(FunctionDeclarationOrClassDeclarationOrExpression, \
|
||||
"FunctionDeclarationOrClassDeclarationOrExpression") \
|
||||
F(FunctionDeclarationOrClassDeclarationOrVariableDeclaration, \
|
||||
"FunctionDeclarationOrClassDeclarationOrVariableDeclaration") \
|
||||
F(FunctionExpression, "FunctionExpression") \
|
||||
F(FunctionExpressionContents, "FunctionExpressionContents") \
|
||||
F(FunctionOrMethodContents, "FunctionOrMethodContents") \
|
||||
F(Getter, "Getter") \
|
||||
F(GetterContents, "GetterContents") \
|
||||
F(Identifier, "Identifier") \
|
||||
F(IdentifierExpression, "IdentifierExpression") \
|
||||
F(IdentifierName, "IdentifierName") \
|
||||
F(IfStatement, "IfStatement") \
|
||||
F(Import, "Import") \
|
||||
F(ImportDeclaration, "ImportDeclaration") \
|
||||
F(ImportDeclarationOrExportDeclarationOrStatement, \
|
||||
"ImportDeclarationOrExportDeclarationOrStatement") \
|
||||
F(ImportNamespace, "ImportNamespace") \
|
||||
F(ImportSpecifier, "ImportSpecifier") \
|
||||
F(IterationStatement, "IterationStatement") \
|
||||
F(Label, "Label") \
|
||||
F(LabelledStatement, "LabelledStatement") \
|
||||
F(LazyArrowExpressionWithExpression, "LazyArrowExpressionWithExpression") \
|
||||
F(LazyArrowExpressionWithFunctionBody, \
|
||||
@ -181,32 +145,6 @@ namespace frontend {
|
||||
F(LazyGetter, "LazyGetter") \
|
||||
F(LazyMethod, "LazyMethod") \
|
||||
F(LazySetter, "LazySetter") \
|
||||
F(ListOfAssertedBoundName, "ListOfAssertedBoundName") \
|
||||
F(ListOfAssertedDeclaredName, "ListOfAssertedDeclaredName") \
|
||||
F(ListOfAssertedMaybePositionalParameterName, \
|
||||
"ListOfAssertedMaybePositionalParameterName") \
|
||||
F(ListOfAssignmentTargetOrAssignmentTargetWithInitializer, \
|
||||
"ListOfAssignmentTargetOrAssignmentTargetWithInitializer") \
|
||||
F(ListOfAssignmentTargetProperty, "ListOfAssignmentTargetProperty") \
|
||||
F(ListOfBindingProperty, "ListOfBindingProperty") \
|
||||
F(ListOfClassElement, "ListOfClassElement") \
|
||||
F(ListOfDirective, "ListOfDirective") \
|
||||
F(ListOfExportFromSpecifier, "ListOfExportFromSpecifier") \
|
||||
F(ListOfExportLocalSpecifier, "ListOfExportLocalSpecifier") \
|
||||
F(ListOfExpressionOrTemplateElement, "ListOfExpressionOrTemplateElement") \
|
||||
F(ListOfImportDeclarationOrExportDeclarationOrStatement, \
|
||||
"ListOfImportDeclarationOrExportDeclarationOrStatement") \
|
||||
F(ListOfImportSpecifier, "ListOfImportSpecifier") \
|
||||
F(ListOfObjectProperty, "ListOfObjectProperty") \
|
||||
F(ListOfOptionalBindingOrBindingWithInitializer, \
|
||||
"ListOfOptionalBindingOrBindingWithInitializer") \
|
||||
F(ListOfOptionalSpreadElementOrExpression, \
|
||||
"ListOfOptionalSpreadElementOrExpression") \
|
||||
F(ListOfParameter, "ListOfParameter") \
|
||||
F(ListOfStatement, "ListOfStatement") \
|
||||
F(ListOfSwitchCase, "ListOfSwitchCase") \
|
||||
F(ListOfVariableDeclarator, "ListOfVariableDeclarator") \
|
||||
F(Literal, "Literal") \
|
||||
F(LiteralBooleanExpression, "LiteralBooleanExpression") \
|
||||
F(LiteralInfinityExpression, "LiteralInfinityExpression") \
|
||||
F(LiteralNullExpression, "LiteralNullExpression") \
|
||||
@ -214,42 +152,17 @@ namespace frontend {
|
||||
F(LiteralPropertyName, "LiteralPropertyName") \
|
||||
F(LiteralRegExpExpression, "LiteralRegExpExpression") \
|
||||
F(LiteralStringExpression, "LiteralStringExpression") \
|
||||
F(Method, "Method") \
|
||||
F(MethodDefinition, "MethodDefinition") \
|
||||
F(Module, "Module") \
|
||||
F(NewExpression, "NewExpression") \
|
||||
F(NewTargetExpression, "NewTargetExpression") \
|
||||
F(ObjectAssignmentTarget, "ObjectAssignmentTarget") \
|
||||
F(ObjectBinding, "ObjectBinding") \
|
||||
F(ObjectExpression, "ObjectExpression") \
|
||||
F(ObjectProperty, "ObjectProperty") \
|
||||
F(OptionalAssignmentTarget, "OptionalAssignmentTarget") \
|
||||
F(OptionalBinding, "OptionalBinding") \
|
||||
F(OptionalBindingIdentifier, "OptionalBindingIdentifier") \
|
||||
F(OptionalBindingOrBindingWithInitializer, \
|
||||
"OptionalBindingOrBindingWithInitializer") \
|
||||
F(OptionalCatchClause, "OptionalCatchClause") \
|
||||
F(OptionalExpression, "OptionalExpression") \
|
||||
F(OptionalIdentifierName, "OptionalIdentifierName") \
|
||||
F(OptionalLabel, "OptionalLabel") \
|
||||
F(OptionalPropertyKey, "OptionalPropertyKey") \
|
||||
F(OptionalSpreadElementOrExpression, "OptionalSpreadElementOrExpression") \
|
||||
F(OptionalStatement, "OptionalStatement") \
|
||||
F(OptionalVariableDeclarationOrExpression, \
|
||||
"OptionalVariableDeclarationOrExpression") \
|
||||
F(Parameter, "Parameter") \
|
||||
F(Program, "Program") \
|
||||
F(PropertyKey, "PropertyKey") \
|
||||
F(PropertyName, "PropertyName") \
|
||||
F(ReturnStatement, "ReturnStatement") \
|
||||
F(Script, "Script") \
|
||||
F(Setter, "Setter") \
|
||||
F(SetterContents, "SetterContents") \
|
||||
F(ShorthandProperty, "ShorthandProperty") \
|
||||
F(SimpleAssignmentTarget, "SimpleAssignmentTarget") \
|
||||
F(SpreadElement, "SpreadElement") \
|
||||
F(SpreadElementOrExpression, "SpreadElementOrExpression") \
|
||||
F(Statement, "Statement") \
|
||||
F(StaticMemberAssignmentTarget, "StaticMemberAssignmentTarget") \
|
||||
F(StaticMemberExpression, "StaticMemberExpression") \
|
||||
F(Super, "Super") \
|
||||
@ -264,18 +177,13 @@ namespace frontend {
|
||||
F(TryCatchStatement, "TryCatchStatement") \
|
||||
F(TryFinallyStatement, "TryFinallyStatement") \
|
||||
F(UnaryExpression, "UnaryExpression") \
|
||||
F(UnaryOperator, "UnaryOperator") \
|
||||
F(UpdateExpression, "UpdateExpression") \
|
||||
F(UpdateOperator, "UpdateOperator") \
|
||||
F(VariableDeclaration, "VariableDeclaration") \
|
||||
F(VariableDeclarationKind, "VariableDeclarationKind") \
|
||||
F(VariableDeclarationOrExpression, "VariableDeclarationOrExpression") \
|
||||
F(VariableDeclarator, "VariableDeclarator") \
|
||||
F(WhileStatement, "WhileStatement") \
|
||||
F(WithStatement, "WithStatement") \
|
||||
F(YieldExpression, "YieldExpression") \
|
||||
F(YieldStarExpression, "YieldStarExpression") \
|
||||
F(String, "string")
|
||||
F(YieldStarExpression, "YieldStarExpression")
|
||||
|
||||
enum class BinKind {
|
||||
#define EMIT_ENUM(name, _) name,
|
||||
@ -284,7 +192,7 @@ enum class BinKind {
|
||||
};
|
||||
|
||||
// The number of distinct values of BinKind.
|
||||
const size_t BINKIND_LIMIT = 200;
|
||||
const size_t BINKIND_LIMIT = 120;
|
||||
|
||||
/**
|
||||
* The different fields of Binary AST nodes, as per the specifications of
|
||||
|
@ -933,9 +933,11 @@ impl CPPExporter {
|
||||
buffer.push_str(&self.rules.hpp_tokens_kind_doc.reindent(""));
|
||||
}
|
||||
|
||||
let node_names = self.syntax.node_names()
|
||||
let node_names = self.syntax.interfaces_by_name()
|
||||
.keys()
|
||||
.map(|n| n.to_string())
|
||||
.sorted();
|
||||
let kind_limit = node_names.len();
|
||||
buffer.push_str(&format!("\n#define FOR_EACH_BIN_KIND(F) \\\n{nodes}\n",
|
||||
nodes = node_names.iter()
|
||||
.map(|name| format!(" F({enum_name}, \"{spec_name}\")",
|
||||
@ -950,7 +952,7 @@ enum class BinKind {
|
||||
};
|
||||
");
|
||||
|
||||
buffer.push_str(&format!("\n// The number of distinct values of BinKind.\nconst size_t BINKIND_LIMIT = {};\n\n\n", self.syntax.node_names().len()));
|
||||
buffer.push_str(&format!("\n// The number of distinct values of BinKind.\nconst size_t BINKIND_LIMIT = {};\n\n\n", kind_limit));
|
||||
buffer.push_str("\n\n");
|
||||
if self.rules.hpp_tokens_field_doc.is_some() {
|
||||
buffer.push_str(&self.rules.hpp_tokens_field_doc.reindent(""));
|
||||
@ -959,6 +961,7 @@ enum class BinKind {
|
||||
let field_names = self.syntax.field_names()
|
||||
.keys()
|
||||
.sorted();
|
||||
let field_limit = field_names.len();
|
||||
buffer.push_str(&format!("\n#define FOR_EACH_BIN_FIELD(F) \\\n{nodes}\n",
|
||||
nodes = field_names.iter()
|
||||
.map(|name| format!(" F({enum_name}, \"{spec_name}\")",
|
||||
@ -972,7 +975,7 @@ enum class BinField {
|
||||
#undef EMIT_ENUM
|
||||
};
|
||||
");
|
||||
buffer.push_str(&format!("\n// The number of distinct values of BinField.\nconst size_t BINFIELD_LIMIT = {};\n\n\n", self.syntax.field_names().len()));
|
||||
buffer.push_str(&format!("\n// The number of distinct values of BinField.\nconst size_t BINFIELD_LIMIT = {};\n\n\n", field_limit));
|
||||
|
||||
if self.rules.hpp_tokens_variants_doc.is_some() {
|
||||
buffer.push_str(&self.rules.hpp_tokens_variants_doc.reindent(""));
|
||||
@ -983,6 +986,7 @@ enum class BinField {
|
||||
Ord::cmp(name_1, name_2)
|
||||
.then_with(|| Ord::cmp(symbol_1, symbol_2))
|
||||
});
|
||||
let variants_limit = enum_variants.len();
|
||||
|
||||
buffer.push_str(&format!("\n#define FOR_EACH_BIN_VARIANT(F) \\\n{nodes}\n",
|
||||
nodes = enum_variants.into_iter()
|
||||
@ -999,7 +1003,7 @@ enum class BinVariant {
|
||||
};
|
||||
");
|
||||
buffer.push_str(&format!("\n// The number of distinct values of BinVariant.\nconst size_t BINVARIANT_LIMIT = {};\n\n\n",
|
||||
self.variants_by_symbol.len()));
|
||||
variants_limit));
|
||||
|
||||
buffer.push_str(&self.rules.hpp_tokens_footer.reindent(""));
|
||||
buffer.push_str("\n");
|
||||
|
@ -3132,16 +3132,15 @@ void BaselineInterpreterCodeGen::getEnvironmentCoordinateObject(Register reg) {
|
||||
template <>
|
||||
Address BaselineCompilerCodeGen::getEnvironmentCoordinateAddressFromObject(
|
||||
Register objReg, Register reg) {
|
||||
JSScript* script = handler.script();
|
||||
EnvironmentCoordinate ec(handler.pc());
|
||||
Shape* shape = EnvironmentCoordinateToEnvironmentShape(script, handler.pc());
|
||||
|
||||
if (shape->numFixedSlots() <= ec.slot()) {
|
||||
masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), reg);
|
||||
return Address(reg, (ec.slot() - shape->numFixedSlots()) * sizeof(Value));
|
||||
if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
|
||||
return Address(objReg, NativeObject::getFixedSlotOffset(ec.slot()));
|
||||
}
|
||||
|
||||
return Address(objReg, NativeObject::getFixedSlotOffset(ec.slot()));
|
||||
uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
|
||||
masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), reg);
|
||||
return Address(reg, slot * sizeof(Value));
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -13155,16 +13155,15 @@ MDefinition* IonBuilder::walkEnvironmentChain(unsigned hops) {
|
||||
MDefinition* IonBuilder::getAliasedVar(EnvironmentCoordinate ec) {
|
||||
MDefinition* obj = walkEnvironmentChain(ec.hops());
|
||||
|
||||
Shape* shape = EnvironmentCoordinateToEnvironmentShape(script(), pc);
|
||||
|
||||
MInstruction* load;
|
||||
if (shape->numFixedSlots() <= ec.slot()) {
|
||||
if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
|
||||
load = MLoadFixedSlot::New(alloc(), obj, ec.slot());
|
||||
} else {
|
||||
MInstruction* slots = MSlots::New(alloc(), obj);
|
||||
current->add(slots);
|
||||
|
||||
load = MLoadSlot::New(alloc(), slots, ec.slot() - shape->numFixedSlots());
|
||||
} else {
|
||||
load = MLoadFixedSlot::New(alloc(), obj, ec.slot());
|
||||
uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
|
||||
load = MLoadSlot::New(alloc(), slots, slot);
|
||||
}
|
||||
|
||||
current->add(load);
|
||||
@ -13187,21 +13186,19 @@ AbortReasonOr<Ok> IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec) {
|
||||
MDefinition* rval = current->peek(-1);
|
||||
MDefinition* obj = walkEnvironmentChain(ec.hops());
|
||||
|
||||
Shape* shape = EnvironmentCoordinateToEnvironmentShape(script(), pc);
|
||||
|
||||
if (needsPostBarrier(rval)) {
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, rval));
|
||||
}
|
||||
|
||||
MInstruction* store;
|
||||
if (shape->numFixedSlots() <= ec.slot()) {
|
||||
if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
|
||||
store = MStoreFixedSlot::NewBarriered(alloc(), obj, ec.slot(), rval);
|
||||
} else {
|
||||
MInstruction* slots = MSlots::New(alloc(), obj);
|
||||
current->add(slots);
|
||||
|
||||
store = MStoreSlot::NewBarriered(alloc(), slots,
|
||||
ec.slot() - shape->numFixedSlots(), rval);
|
||||
} else {
|
||||
store = MStoreFixedSlot::NewBarriered(alloc(), obj, ec.slot(), rval);
|
||||
uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
|
||||
store = MStoreSlot::NewBarriered(alloc(), slots, slot, rval);
|
||||
}
|
||||
|
||||
current->add(store);
|
||||
|
@ -34,6 +34,14 @@ inline JSObject& GetVariablesObject(JSObject* envChain) {
|
||||
return *envChain;
|
||||
}
|
||||
|
||||
inline const Value& EnvironmentObject::aliasedBinding(
|
||||
EnvironmentCoordinate ec) {
|
||||
MOZ_ASSERT(!IsExtensibleLexicalEnvironment(this));
|
||||
MOZ_ASSERT(nonExtensibleIsFixedSlot(ec) ==
|
||||
NativeObject::isFixedSlot(ec.slot()));
|
||||
return getSlot(ec.slot());
|
||||
}
|
||||
|
||||
inline void EnvironmentObject::setAliasedBinding(JSContext* cx, uint32_t slot,
|
||||
const Value& v) {
|
||||
MOZ_ASSERT(!isSingleton());
|
||||
@ -43,6 +51,9 @@ inline void EnvironmentObject::setAliasedBinding(JSContext* cx, uint32_t slot,
|
||||
inline void EnvironmentObject::setAliasedBinding(JSContext* cx,
|
||||
EnvironmentCoordinate ec,
|
||||
const Value& v) {
|
||||
MOZ_ASSERT(!IsExtensibleLexicalEnvironment(this));
|
||||
MOZ_ASSERT(nonExtensibleIsFixedSlot(ec) ==
|
||||
NativeObject::isFixedSlot(ec.slot()));
|
||||
setAliasedBinding(cx, ec.slot(), v);
|
||||
}
|
||||
|
||||
|
@ -278,10 +278,18 @@ class EnvironmentObject : public NativeObject {
|
||||
initReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
|
||||
}
|
||||
|
||||
// Get or set a name contained in this environment.
|
||||
const Value& aliasedBinding(EnvironmentCoordinate ec) {
|
||||
return getSlot(ec.slot());
|
||||
static bool nonExtensibleIsFixedSlot(EnvironmentCoordinate ec) {
|
||||
// For non-extensible environment objects isFixedSlot(slot) is equivalent to
|
||||
// slot < MAX_FIXED_SLOTS.
|
||||
return ec.slot() < MAX_FIXED_SLOTS;
|
||||
}
|
||||
static size_t nonExtensibleDynamicSlotIndex(EnvironmentCoordinate ec) {
|
||||
MOZ_ASSERT(!nonExtensibleIsFixedSlot(ec));
|
||||
return ec.slot() - MAX_FIXED_SLOTS;
|
||||
}
|
||||
|
||||
// Get or set a name contained in this environment.
|
||||
inline const Value& aliasedBinding(EnvironmentCoordinate ec);
|
||||
|
||||
const Value& aliasedBinding(const BindingIter& bi) {
|
||||
MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment);
|
||||
|
@ -395,6 +395,8 @@ const mozilla::Module* mozJSComponentLoader::LoadModule(FileLocation& aFile) {
|
||||
}
|
||||
}
|
||||
|
||||
AUTO_PROFILER_TEXT_MARKER_CAUSE("JS XPCOM", spec, JS,
|
||||
profiler_get_backtrace());
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("mozJSComponentLoader::LoadModule",
|
||||
OTHER, spec);
|
||||
|
||||
@ -1268,8 +1270,9 @@ nsresult mozJSComponentLoader::Import(JSContext* aCx,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("mozJSComponentLoader::Import", JS,
|
||||
aLocation);
|
||||
AUTO_PROFILER_TEXT_MARKER_CAUSE("ChromeUtils.import", aLocation, JS,
|
||||
profiler_get_backtrace());
|
||||
|
||||
ComponentLoaderInfo info(aLocation);
|
||||
|
||||
rv = info.EnsureKey();
|
||||
|
@ -590,6 +590,8 @@ nsresult mozJSSubScriptLoader::DoLoadSubScriptWithOptions(
|
||||
}
|
||||
|
||||
NS_LossyConvertUTF16toASCII asciiUrl(url);
|
||||
AUTO_PROFILER_TEXT_MARKER_CAUSE("SubScript", asciiUrl, JS,
|
||||
profiler_get_backtrace());
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
|
||||
"mozJSSubScriptLoader::DoLoadSubScriptWithOptions", OTHER, asciiUrl);
|
||||
|
||||
|
@ -19,5 +19,5 @@ origin:
|
||||
license: "ISC"
|
||||
|
||||
# update.sh will update this value
|
||||
release: "feec7e2e893c6dc4188fcb95e15dcf8c19890f46 (2019-01-23 17:15:35 +0200)"
|
||||
release: "3afc3350063ce1d68bbd0287fde4f70b4803d2eb (2019-02-13 10:28:58 +1300)"
|
||||
|
||||
|
@ -146,9 +146,23 @@ static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
|
||||
|
||||
}
|
||||
|
||||
class wasapi_collection_notification_client;
|
||||
class monitor_device_notifications;
|
||||
|
||||
struct cubeb {
|
||||
cubeb_ops const * ops = &wasapi_ops;
|
||||
cubeb_strings * device_ids;
|
||||
/* Device enumerator to get notifications when the
|
||||
device collection change. */
|
||||
com_ptr<IMMDeviceEnumerator> device_collection_enumerator;
|
||||
com_ptr<wasapi_collection_notification_client> collection_notification_client;
|
||||
/* Collection changed for input (capture) devices. */
|
||||
cubeb_device_collection_changed_callback input_collection_changed_callback = nullptr;
|
||||
void * input_collection_changed_user_ptr = nullptr;
|
||||
/* Collection changed for output (render) devices. */
|
||||
cubeb_device_collection_changed_callback output_collection_changed_callback = nullptr;
|
||||
void * output_collection_changed_user_ptr = nullptr;
|
||||
std::unique_ptr<monitor_device_notifications> monitor_notifications;
|
||||
};
|
||||
|
||||
class wasapi_endpoint_notification_client;
|
||||
@ -270,6 +284,251 @@ struct cubeb_stream {
|
||||
std::atomic<std::atomic<bool>*> emergency_bailout;
|
||||
};
|
||||
|
||||
class monitor_device_notifications {
|
||||
public:
|
||||
monitor_device_notifications(cubeb * context)
|
||||
: cubeb_context(context)
|
||||
{
|
||||
create_thread();
|
||||
}
|
||||
|
||||
~monitor_device_notifications()
|
||||
{
|
||||
SetEvent(shutdown);
|
||||
WaitForSingleObject(thread, 5000);
|
||||
CloseHandle(thread);
|
||||
|
||||
CloseHandle(input_changed);
|
||||
CloseHandle(output_changed);
|
||||
CloseHandle(shutdown);
|
||||
}
|
||||
|
||||
void notify(EDataFlow flow)
|
||||
{
|
||||
if (flow == eCapture && cubeb_context->input_collection_changed_callback) {
|
||||
bool res = SetEvent(input_changed);
|
||||
if (!res) {
|
||||
LOG("Failed to set input changed event");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (flow == eRender && cubeb_context->output_collection_changed_callback) {
|
||||
bool res = SetEvent(output_changed);
|
||||
if (!res) {
|
||||
LOG("Failed to set output changed event");
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
static unsigned int __stdcall
|
||||
thread_proc(LPVOID args)
|
||||
{
|
||||
XASSERT(args);
|
||||
static_cast<monitor_device_notifications*>(args)
|
||||
->notification_thread_loop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void notification_thread_loop()
|
||||
{
|
||||
struct auto_com {
|
||||
auto_com() {
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
XASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
~auto_com() {
|
||||
CoUninitialize();
|
||||
}
|
||||
} com;
|
||||
|
||||
HANDLE wait_array[3] = {
|
||||
input_changed,
|
||||
output_changed,
|
||||
shutdown,
|
||||
};
|
||||
|
||||
while (true) {
|
||||
Sleep(200);
|
||||
|
||||
DWORD wait_result = WaitForMultipleObjects(ARRAY_LENGTH(wait_array),
|
||||
wait_array,
|
||||
FALSE,
|
||||
INFINITE);
|
||||
if (wait_result == WAIT_OBJECT_0) { // input changed
|
||||
cubeb_context->input_collection_changed_callback(cubeb_context,
|
||||
cubeb_context->input_collection_changed_user_ptr);
|
||||
} else if (wait_result == WAIT_OBJECT_0 + 1) { // output changed
|
||||
cubeb_context->output_collection_changed_callback(cubeb_context,
|
||||
cubeb_context->output_collection_changed_user_ptr);
|
||||
} else if (wait_result == WAIT_OBJECT_0 + 2) { // shutdown
|
||||
break;
|
||||
} else {
|
||||
LOG("Unexpected result %lu", wait_result);
|
||||
}
|
||||
} // loop
|
||||
}
|
||||
|
||||
void create_thread()
|
||||
{
|
||||
output_changed = CreateEvent(nullptr, 0, 0, nullptr);
|
||||
if (!output_changed) {
|
||||
LOG("Failed to create output changed event.");
|
||||
return;
|
||||
}
|
||||
|
||||
input_changed = CreateEvent(nullptr, 0, 0, nullptr);
|
||||
if (!input_changed) {
|
||||
LOG("Failed to create input changed event.");
|
||||
return;
|
||||
}
|
||||
|
||||
shutdown = CreateEvent(nullptr, 0, 0, nullptr);
|
||||
if (!shutdown) {
|
||||
LOG("Failed to create shutdown event.");
|
||||
return;
|
||||
}
|
||||
|
||||
thread = (HANDLE) _beginthreadex(nullptr,
|
||||
256 * 1024,
|
||||
thread_proc,
|
||||
this,
|
||||
STACK_SIZE_PARAM_IS_A_RESERVATION,
|
||||
nullptr);
|
||||
if (!thread) {
|
||||
LOG("Failed to create thread.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE thread = INVALID_HANDLE_VALUE;
|
||||
HANDLE output_changed = INVALID_HANDLE_VALUE;
|
||||
HANDLE input_changed = INVALID_HANDLE_VALUE;
|
||||
HANDLE shutdown = INVALID_HANDLE_VALUE;
|
||||
|
||||
cubeb * cubeb_context = nullptr;
|
||||
};
|
||||
|
||||
class wasapi_collection_notification_client : public IMMNotificationClient
|
||||
{
|
||||
public:
|
||||
/* The implementation of MSCOM was copied from MSDN. */
|
||||
ULONG STDMETHODCALLTYPE
|
||||
AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count);
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE
|
||||
Release()
|
||||
{
|
||||
ULONG ulRef = InterlockedDecrement(&ref_count);
|
||||
if (0 == ulRef) {
|
||||
delete this;
|
||||
}
|
||||
return ulRef;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
QueryInterface(REFIID riid, VOID **ppvInterface)
|
||||
{
|
||||
if (__uuidof(IUnknown) == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IUnknown*)this;
|
||||
} else if (__uuidof(IMMNotificationClient) == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IMMNotificationClient*)this;
|
||||
} else {
|
||||
*ppvInterface = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
wasapi_collection_notification_client(cubeb * context)
|
||||
: ref_count(1)
|
||||
, cubeb_context(context)
|
||||
{
|
||||
XASSERT(cubeb_context);
|
||||
}
|
||||
|
||||
virtual ~wasapi_collection_notification_client()
|
||||
{ }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device_id)
|
||||
{
|
||||
LOG("collection: Audio device default changed, id = %S.", device_id);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* The remaining methods are not implemented, they simply log when called (if
|
||||
log is enabled), for debugging. */
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR device_id)
|
||||
{
|
||||
LOG("collection: Audio device added.");
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR device_id)
|
||||
{
|
||||
LOG("collection: Audio device removed.");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state)
|
||||
{
|
||||
XASSERT(cubeb_context->output_collection_changed_callback ||
|
||||
cubeb_context->input_collection_changed_callback);
|
||||
LOG("collection: Audio device state changed, id = %S, state = %lu.", device_id, new_state);
|
||||
if (new_state == DEVICE_STATE_ACTIVE ||
|
||||
new_state == DEVICE_STATE_NOTPRESENT ||
|
||||
new_state == DEVICE_STATE_UNPLUGGED) {
|
||||
EDataFlow flow;
|
||||
HRESULT hr = GetDataFlow(device_id, &flow);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
cubeb_context->monitor_notifications->notify(flow);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key)
|
||||
{
|
||||
//Audio device property value changed.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
HRESULT GetDataFlow(LPCWSTR device_id, EDataFlow * flow)
|
||||
{
|
||||
com_ptr<IMMDevice> device;
|
||||
com_ptr<IMMEndpoint> endpoint;
|
||||
|
||||
HRESULT hr = cubeb_context->device_collection_enumerator
|
||||
->GetDevice(device_id, device.receive());
|
||||
if (FAILED(hr)) {
|
||||
LOG("collection: Could not get device: %lx", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = device->QueryInterface(IID_PPV_ARGS(endpoint.receive()));
|
||||
if (FAILED(hr)) {
|
||||
LOG("collection: Could not get endpoint: %lx", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
return endpoint->GetDataFlow(flow);
|
||||
}
|
||||
|
||||
/* refcount for this instance, necessary to implement MSCOM semantics. */
|
||||
LONG ref_count;
|
||||
|
||||
cubeb * cubeb_context = nullptr;
|
||||
};
|
||||
|
||||
class wasapi_endpoint_notification_client : public IMMNotificationClient
|
||||
{
|
||||
public:
|
||||
@ -317,7 +576,7 @@ public:
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device_id)
|
||||
{
|
||||
LOG("Audio device default changed.");
|
||||
LOG("endpoint: Audio device default changed.");
|
||||
|
||||
/* we only support a single stream type for now. */
|
||||
if (flow != eRender && role != eConsole) {
|
||||
@ -326,7 +585,7 @@ public:
|
||||
|
||||
BOOL ok = SetEvent(reconfigure_event);
|
||||
if (!ok) {
|
||||
LOG("SetEvent on reconfigure_event failed: %lx", GetLastError());
|
||||
LOG("endpoint: SetEvent on reconfigure_event failed: %lx", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@ -336,27 +595,27 @@ public:
|
||||
log is enabled), for debugging. */
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR device_id)
|
||||
{
|
||||
LOG("Audio device added.");
|
||||
LOG("endpoint: Audio device added.");
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR device_id)
|
||||
{
|
||||
LOG("Audio device removed.");
|
||||
LOG("endpoint: Audio device removed.");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state)
|
||||
{
|
||||
LOG("Audio device state changed.");
|
||||
LOG("endpoint: Audio device state changed.");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key)
|
||||
{
|
||||
LOG("Audio device property value changed.");
|
||||
//Audio device property value changed.
|
||||
return S_OK;
|
||||
}
|
||||
private:
|
||||
@ -1052,6 +1311,46 @@ HRESULT get_endpoint(com_ptr<IMMDevice> & device, LPCWSTR devid)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT register_collection_notification_client(cubeb * context)
|
||||
{
|
||||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
||||
NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(context->device_collection_enumerator.receive()));
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get device enumerator: %lx", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
context->collection_notification_client.reset(new wasapi_collection_notification_client(context));
|
||||
|
||||
hr = context->device_collection_enumerator->RegisterEndpointNotificationCallback(
|
||||
context->collection_notification_client.get());
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not register endpoint notification callback: %lx", hr);
|
||||
context->collection_notification_client.reset();
|
||||
context->device_collection_enumerator.reset();
|
||||
}
|
||||
|
||||
context->monitor_notifications.reset(new monitor_device_notifications(context));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT unregister_collection_notification_client(cubeb * context)
|
||||
{
|
||||
HRESULT hr = context->device_collection_enumerator->
|
||||
UnregisterEndpointNotificationCallback(context->collection_notification_client.get());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
context->collection_notification_client = nullptr;
|
||||
context->device_collection_enumerator = nullptr;
|
||||
|
||||
context->monitor_notifications.reset();
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
|
||||
{
|
||||
com_ptr<IMMDeviceEnumerator> enumerator;
|
||||
@ -2375,6 +2674,79 @@ wasapi_device_collection_destroy(cubeb * /*ctx*/, cubeb_device_collection * coll
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
wasapi_register_device_collection_changed(cubeb * context,
|
||||
cubeb_device_type devtype,
|
||||
cubeb_device_collection_changed_callback collection_changed_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
if (devtype == CUBEB_DEVICE_TYPE_UNKNOWN) {
|
||||
return CUBEB_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (collection_changed_callback) {
|
||||
// Make sure it has been unregistered first.
|
||||
XASSERT(((devtype & CUBEB_DEVICE_TYPE_INPUT) &&
|
||||
!context->input_collection_changed_callback) ||
|
||||
((devtype & CUBEB_DEVICE_TYPE_OUTPUT) &&
|
||||
!context->output_collection_changed_callback));
|
||||
|
||||
// Stop the notification client. Notifications arrive on
|
||||
// a separate thread. We stop them here to avoid
|
||||
// synchronization issues during the update.
|
||||
if (context->device_collection_enumerator.get()) {
|
||||
HRESULT hr = unregister_collection_notification_client(context);
|
||||
if (FAILED(hr)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (devtype & CUBEB_DEVICE_TYPE_INPUT) {
|
||||
context->input_collection_changed_callback = collection_changed_callback;
|
||||
context->input_collection_changed_user_ptr = user_ptr;
|
||||
}
|
||||
if (devtype & CUBEB_DEVICE_TYPE_OUTPUT) {
|
||||
context->output_collection_changed_callback = collection_changed_callback;
|
||||
context->output_collection_changed_user_ptr = user_ptr;
|
||||
}
|
||||
|
||||
HRESULT hr = register_collection_notification_client(context);
|
||||
if (FAILED(hr)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (!context->device_collection_enumerator.get()) {
|
||||
// Already unregistered, ignore it.
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
HRESULT hr = unregister_collection_notification_client(context);
|
||||
if (FAILED(hr)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
if (devtype & CUBEB_DEVICE_TYPE_INPUT) {
|
||||
context->input_collection_changed_callback = nullptr;
|
||||
context->input_collection_changed_user_ptr = nullptr;
|
||||
}
|
||||
if (devtype & CUBEB_DEVICE_TYPE_OUTPUT) {
|
||||
context->output_collection_changed_callback = nullptr;
|
||||
context->output_collection_changed_user_ptr = nullptr;
|
||||
}
|
||||
|
||||
// If after the updates we still have registered
|
||||
// callbacks restart the notification client.
|
||||
if (context->input_collection_changed_callback ||
|
||||
context->output_collection_changed_callback) {
|
||||
hr = register_collection_notification_client(context);
|
||||
if (FAILED(hr)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
cubeb_ops const wasapi_ops = {
|
||||
/*.init =*/ wasapi_init,
|
||||
/*.get_backend_id =*/ wasapi_get_backend_id,
|
||||
@ -2396,6 +2768,6 @@ cubeb_ops const wasapi_ops = {
|
||||
/*.stream_get_current_device =*/ NULL,
|
||||
/*.stream_device_destroy =*/ NULL,
|
||||
/*.stream_register_device_changed_callback =*/ NULL,
|
||||
/*.register_device_collection_changed =*/ NULL
|
||||
/*.register_device_collection_changed =*/ wasapi_register_device_collection_changed,
|
||||
};
|
||||
} // namespace anonymous
|
||||
|
@ -207,6 +207,7 @@ package org.mozilla.geckoview {
|
||||
|
||||
@android.support.annotation.AnyThread public final class GeckoRuntimeSettings extends org.mozilla.geckoview.RuntimeSettings {
|
||||
method @android.support.annotation.NonNull public java.lang.String[] getArguments();
|
||||
method public int getAutoplayDefault();
|
||||
method public boolean getConsoleOutputEnabled();
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.ContentBlocking.Settings getContentBlocking();
|
||||
method @android.support.annotation.Nullable public java.lang.Class<?> getCrashHandler();
|
||||
@ -222,17 +223,21 @@ package org.mozilla.geckoview {
|
||||
method public boolean getUseContentProcessHint();
|
||||
method public boolean getUseMaxScreenDepth();
|
||||
method public boolean getWebFontsEnabled();
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setAutoplayDefault(int);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setConsoleOutputEnabled(boolean);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setJavaScriptEnabled(boolean);
|
||||
method public void setLocales(@android.support.annotation.Nullable java.lang.String[]);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setRemoteDebuggingEnabled(boolean);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setWebFontsEnabled(boolean);
|
||||
field public static final int AUTOPLAY_DEFAULT_ALLOWED = 0;
|
||||
field public static final int AUTOPLAY_DEFAULT_BLOCKED = 1;
|
||||
field public static final android.os.Parcelable.Creator<org.mozilla.geckoview.GeckoRuntimeSettings> CREATOR;
|
||||
}
|
||||
|
||||
@android.support.annotation.AnyThread public static final class GeckoRuntimeSettings.Builder extends org.mozilla.geckoview.RuntimeSettings.Builder<Settings extends org.mozilla.geckoview.RuntimeSettings> {
|
||||
ctor public Builder();
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder arguments(@android.support.annotation.NonNull java.lang.String[]);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder autoplayDefault(int);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder consoleOutput(boolean);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder contentBlocking(@android.support.annotation.NonNull org.mozilla.geckoview.ContentBlocking.Settings);
|
||||
method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder crashHandler(java.lang.Class<?>);
|
||||
@ -416,7 +421,6 @@ package org.mozilla.geckoview {
|
||||
method @android.support.annotation.UiThread public void onAndroidPermissionsRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
|
||||
method @android.support.annotation.UiThread public void onContentPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
|
||||
method @android.support.annotation.UiThread public void onMediaPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaCallback);
|
||||
field public static final int PERMISSION_AUTOPLAY_MEDIA = 2;
|
||||
field public static final int PERMISSION_DESKTOP_NOTIFICATION = 1;
|
||||
field public static final int PERMISSION_GEOLOCATION = 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head><title>WEBM Video</title></head>
|
||||
<body>
|
||||
<video preload autoplay>
|
||||
<source src="videos/gizmo.webm"></source>
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
@ -51,6 +51,7 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
|
||||
const val VIEWPORT_PATH = "/assets/www/viewport.html"
|
||||
const val IFRAME_REDIRECT_LOCAL = "/assets/www/iframe_redirect_local.html"
|
||||
const val IFRAME_REDIRECT_AUTOMATION = "/assets/www/iframe_redirect_automation.html"
|
||||
const val AUTOPLAY_PATH = "/assets/www/autoplay.html"
|
||||
}
|
||||
|
||||
@get:Rule val sessionRule = GeckoSessionTestRule()
|
||||
|
@ -18,6 +18,8 @@ import org.junit.Assume.assumeThat
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@TimeoutMillis(45000)
|
||||
@ -36,12 +38,15 @@ class MediaElementTest : BaseSessionTest() {
|
||||
override fun onError(mediaElement: MediaElement, errorCode: Int) {}
|
||||
}
|
||||
|
||||
private fun setupPrefsAndDelegates(path: String) {
|
||||
private fun setupPrefs() {
|
||||
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf(
|
||||
"media.autoplay.enabled.user-gestures-needed" to false,
|
||||
"media.autoplay.default" to 0,
|
||||
"full-screen-api.allow-trusted-requests-only" to false))
|
||||
|
||||
}
|
||||
|
||||
private fun setupDelegate(path: String) {
|
||||
sessionRule.session.loadTestPath(path)
|
||||
sessionRule.waitUntilCalled(object : Callbacks.MediaDelegate {
|
||||
@AssertCalled
|
||||
@ -55,8 +60,12 @@ class MediaElementTest : BaseSessionTest() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun waitUntilVideoReady(path: String, waitState: Int = MediaElement.MEDIA_READY_STATE_HAVE_ENOUGH_DATA): MediaElement {
|
||||
setupPrefsAndDelegates(path)
|
||||
private fun setupPrefsAndDelegates(path: String) {
|
||||
setupPrefs()
|
||||
setupDelegate(path)
|
||||
}
|
||||
|
||||
private fun waitUntilState(waitState: Int = MediaElement.MEDIA_READY_STATE_HAVE_ENOUGH_DATA): MediaElement {
|
||||
var ready = false
|
||||
var result: MediaElement? = null
|
||||
while (!ready) {
|
||||
@ -76,6 +85,16 @@ class MediaElementTest : BaseSessionTest() {
|
||||
return result!!
|
||||
}
|
||||
|
||||
private fun waitUntilVideoReady(path: String, waitState: Int = MediaElement.MEDIA_READY_STATE_HAVE_ENOUGH_DATA): MediaElement {
|
||||
setupPrefsAndDelegates(path)
|
||||
return waitUntilState(waitState)
|
||||
}
|
||||
|
||||
private fun waitUntilVideoReadyNoPrefs(path: String, waitState: Int = MediaElement.MEDIA_READY_STATE_HAVE_ENOUGH_DATA): MediaElement {
|
||||
setupDelegate(path)
|
||||
return waitUntilState(waitState)
|
||||
}
|
||||
|
||||
private fun waitForPlaybackStateChange(waitState: Int, lambda: (element: MediaElement, state: Int) -> Unit = { _: MediaElement, _: Int -> }) {
|
||||
var waiting = true
|
||||
while (waiting) {
|
||||
@ -409,4 +428,54 @@ class MediaElementTest : BaseSessionTest() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@WithDevToolsAPI
|
||||
@Test fun autoplayBlocked() {
|
||||
sessionRule.runtime.settings.autoplayDefault = GeckoRuntimeSettings.AUTOPLAY_DEFAULT_BLOCKED
|
||||
|
||||
val media = waitUntilVideoReadyNoPrefs(AUTOPLAY_PATH)
|
||||
val promise = sessionRule.evaluateJS(mainSession, "$('video').play()").asJSPromise()
|
||||
var exceptionCaught = false
|
||||
try {
|
||||
val result = promise.value as Boolean
|
||||
assertThat("Promise should not resolve", result, equalTo(false))
|
||||
} catch (e: GeckoSessionTestRule.RejectedPromiseException) {
|
||||
exceptionCaught = true;
|
||||
}
|
||||
|
||||
assertThat("video.play() failed with exception", exceptionCaught, equalTo(true))
|
||||
media.play()
|
||||
/*
|
||||
// Fails due to bug 1524092
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAY)
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAYING)
|
||||
*/
|
||||
}
|
||||
|
||||
@WithDevToolsAPI
|
||||
@Test fun autoplayAllowed() {
|
||||
sessionRule.runtime.settings.autoplayDefault = GeckoRuntimeSettings.AUTOPLAY_DEFAULT_ALLOWED
|
||||
|
||||
val media = waitUntilVideoReadyNoPrefs(VIDEO_WEBM_PATH)
|
||||
val promise = sessionRule.evaluateJS(mainSession, "$('video').play()").asJSPromise()
|
||||
var exceptionCaught = false
|
||||
try {
|
||||
promise.value
|
||||
} catch (e: GeckoSessionTestRule.RejectedPromiseException) {
|
||||
exceptionCaught = true;
|
||||
}
|
||||
|
||||
assertThat("video.play() did not fail", exceptionCaught, equalTo(false))
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAY)
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAYING)
|
||||
media.pause()
|
||||
|
||||
media.play()
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAY)
|
||||
waitForPlaybackStateChange(MediaElement.MEDIA_STATE_PLAYING)
|
||||
|
||||
// Restore default runtime settings
|
||||
sessionRule.runtime.settings.autoplayDefault = GeckoRuntimeSettings.AUTOPLAY_DEFAULT_BLOCKED
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -168,7 +168,8 @@ public class TestRunnerActivity extends Activity {
|
||||
runtimeSettingsBuilder
|
||||
.arguments(new String[] { "-purgecaches" })
|
||||
.displayDpiOverride(160)
|
||||
.displayDensityOverride(1.0f);
|
||||
.displayDensityOverride(1.0f)
|
||||
.autoplayDefault(GeckoRuntimeSettings.AUTOPLAY_DEFAULT_ALLOWED);
|
||||
|
||||
final Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
|
@ -243,6 +243,17 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
getSettings().mContentBlocking = cb;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets video autoplay mode.
|
||||
* May be either {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_ALLOWED} or {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_BLOCKED}
|
||||
* @param autoplay Allows or blocks video autoplay.
|
||||
* @return This Builder instance.
|
||||
*/
|
||||
public @NonNull Builder autoplayDefault(@AutoplayDefault int autoplay) {
|
||||
getSettings().mAutoplayDefault.set(autoplay);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private GeckoRuntime mRuntime;
|
||||
@ -264,6 +275,8 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
"browser.display.use_document_fonts", 1);
|
||||
/* package */ final Pref<Boolean> mConsoleOutput = new Pref<Boolean>(
|
||||
"geckoview.console.enabled", false);
|
||||
/* package */ final Pref<Integer> mAutoplayDefault = new Pref<Integer>(
|
||||
"media.autoplay.default", AUTOPLAY_DEFAULT_BLOCKED);
|
||||
|
||||
/* package */ boolean mDebugPause;
|
||||
/* package */ boolean mUseMaxScreenDepth;
|
||||
@ -525,6 +538,41 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
return mConsoleOutput.get();
|
||||
}
|
||||
|
||||
// Sync values with dom/media/nsIAutoplay.idl.
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({ AUTOPLAY_DEFAULT_ALLOWED, AUTOPLAY_DEFAULT_BLOCKED })
|
||||
/* package */ @interface AutoplayDefault {}
|
||||
|
||||
/**
|
||||
* Autoplay video is allowed.
|
||||
*/
|
||||
public static final int AUTOPLAY_DEFAULT_ALLOWED = 0;
|
||||
|
||||
/**
|
||||
* Autoplay video is blocked.
|
||||
*/
|
||||
public static final int AUTOPLAY_DEFAULT_BLOCKED = 1;
|
||||
|
||||
/**
|
||||
* Sets video autoplay mode.
|
||||
* May be either {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_ALLOWED} or {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_BLOCKED}
|
||||
* @param autoplay Allows or blocks video autoplay.
|
||||
* @return This GeckoRuntimeSettings instance.
|
||||
*/
|
||||
public @NonNull GeckoRuntimeSettings setAutoplayDefault(@AutoplayDefault int autoplay) {
|
||||
mAutoplayDefault.commit(autoplay);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current video autoplay mode.
|
||||
* @return The current video autoplay mode. Will be either {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_ALLOWED}
|
||||
* or {@link GeckoRuntimeSettings#AUTOPLAY_DEFAULT_BLOCKED}
|
||||
*/
|
||||
public @AutoplayDefault int getAutoplayDefault() {
|
||||
return mAutoplayDefault.get();
|
||||
}
|
||||
|
||||
@Override // Parcelable
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
|
@ -652,8 +652,6 @@ public class GeckoSession implements Parcelable {
|
||||
type = PermissionDelegate.PERMISSION_GEOLOCATION;
|
||||
} else if ("desktop-notification".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION;
|
||||
} else if ("autoplay-media".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_MEDIA;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown permission request: " + typeString);
|
||||
}
|
||||
@ -3811,7 +3809,7 @@ public class GeckoSession implements Parcelable {
|
||||
**/
|
||||
public interface PermissionDelegate {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PERMISSION_GEOLOCATION, PERMISSION_DESKTOP_NOTIFICATION, PERMISSION_AUTOPLAY_MEDIA})
|
||||
@IntDef({PERMISSION_GEOLOCATION, PERMISSION_DESKTOP_NOTIFICATION})
|
||||
/* package */ @interface Permission {}
|
||||
|
||||
/**
|
||||
@ -3826,11 +3824,6 @@ public class GeckoSession implements Parcelable {
|
||||
*/
|
||||
public static final int PERMISSION_DESKTOP_NOTIFICATION = 1;
|
||||
|
||||
/**
|
||||
* Permission for allowing auto-playing media.
|
||||
*/
|
||||
public static final int PERMISSION_AUTOPLAY_MEDIA = 2;
|
||||
|
||||
/**
|
||||
* Callback interface for notifying the result of a permission request.
|
||||
*/
|
||||
@ -3874,7 +3867,6 @@ public class GeckoSession implements Parcelable {
|
||||
* @param type The type of the requested permission; possible values are,
|
||||
* PERMISSION_GEOLOCATION
|
||||
* PERMISSION_DESKTOP_NOTIFICATION
|
||||
* PERMISSION_AUTOPLAY_MEDIA
|
||||
* @param callback Callback interface.
|
||||
*/
|
||||
@UiThread
|
||||
|
@ -9,6 +9,10 @@ exclude: true
|
||||
<h1> GeckoView API Changelog. </h1>
|
||||
|
||||
## v67
|
||||
- Updated video autoplay API to reflect changes in Gecko. Instead of being a per-video
|
||||
permission in the PermissionDelegate, it is a runtime setting that either allows or
|
||||
blocks autoplay videos.
|
||||
|
||||
- Change `ContentBlocking.AT_ALL` and `ContentBlocking.SB_ALL` values to mirror
|
||||
the actual constants they encompass.
|
||||
|
||||
@ -128,4 +132,4 @@ exclude: true
|
||||
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: ../GeckoResult.html
|
||||
|
||||
[api-version]: 1a31e792d4802cb18219b7ac5281a63a89a1df75
|
||||
[api-version]: a42a6f4481dd690ac46f14d8e692785bb00e8b04
|
||||
|
@ -619,8 +619,6 @@ public class GeckoViewActivity extends AppCompatActivity {
|
||||
resId = R.string.request_geolocation;
|
||||
} else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
||||
resId = R.string.request_notification;
|
||||
} else if (PERMISSION_AUTOPLAY_MEDIA == type) {
|
||||
resId = R.string.request_autoplay;
|
||||
} else {
|
||||
Log.w(LOGTAG, "Unknown permission: " + type);
|
||||
callback.reject();
|
||||
|
@ -5,7 +5,6 @@
|
||||
<string name="username">Username</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="clear_field">Clear</string>
|
||||
<string name="request_autoplay">Allow media to play on "%1$s"?</string>
|
||||
<string name="request_geolocation">Share location with "%1$s"?</string>
|
||||
<string name="request_notification">Allow notifications for "%1$s"?</string>
|
||||
<string name="request_video">Share video with "%1$s"</string>
|
||||
|
@ -1171,4 +1171,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
||||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1558354645894000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1558613934969000);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,2 @@
|
||||
[RTCPeerConnection-connectionState.html]
|
||||
expected: TIMEOUT
|
||||
[Initial connectionState should be new]
|
||||
expected: FAIL
|
||||
|
||||
[connection with one data channel should eventually have connected connection state]
|
||||
expected: TIMEOUT
|
||||
|
||||
[connection with one data channel should eventually have transports in connected state]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Closing the connection should set connectionState to closed]
|
||||
expected: FAIL
|
||||
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1265827
|
||||
|
@ -1,11 +1,5 @@
|
||||
[RTCPeerConnection-remote-track-mute.https.html]
|
||||
expected: TIMEOUT
|
||||
[Changing transceiver direction to 'sendrecv' unmutes the remote track]
|
||||
expected: NOTRUN
|
||||
|
||||
[pc.close() mutes remote tracks]
|
||||
expected: NOTRUN
|
||||
|
||||
[Changing transceiver direction to 'inactive' mutes the remote track]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
[RTCPeerConnection-setDescription-transceiver.html]
|
||||
[setRemoteDescription should stop the transceiver if its corresponding m section is rejected]
|
||||
expected: FAIL
|
||||
|
@ -1,5 +1,4 @@
|
||||
[RTCPeerConnection-setRemoteDescription-tracks.https.html]
|
||||
expected: TIMEOUT
|
||||
[addTrack() with a track and no stream makes ontrack fire with a track and no stream.]
|
||||
expected: FAIL
|
||||
|
||||
@ -15,18 +14,6 @@
|
||||
[addTrack() with a track and a stream makes ontrack fire with a track and a stream.]
|
||||
expected: FAIL
|
||||
|
||||
[removeTrack() causes onremovetrack and the track to be removed from the stream.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[removeTrack() causes onmute and the track to be muted.]
|
||||
[removeTrack() twice is safe.]
|
||||
expected: FAIL
|
||||
|
||||
[removeTrack() makes track.onmute fire and the track to be muted.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[track.onmute fires before setRemoteDescription resolves.]
|
||||
expected: NOTRUN
|
||||
|
||||
[removeTrack() twice is safe.]
|
||||
expected: NOTRUN
|
||||
|
||||
|
@ -1,121 +1,18 @@
|
||||
[RTCPeerConnection-transceivers.https.html]
|
||||
disabled: Bug 1515043
|
||||
expected:
|
||||
if e10s and (os == "linux"): TIMEOUT
|
||||
[addTransceiver(track, init): initialize sendEncodings[0\].active to false]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
|
||||
[addTrack(0 streams): ontrack fires with no stream]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
|
||||
[addTrack(2 streams): ontrack fires with corresponding two streams]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
|
||||
[setRemoteDescription(offer): ontrack's track.id is the same as track.id]
|
||||
expected:
|
||||
if not debug and e10s and (os == "linux") and (processor == "x86"): NOTRUN
|
||||
if not debug and webrender and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
expected: FAIL
|
||||
|
||||
[addTransceiver(track, init): initialize sendEncodings\[0\].active to false]
|
||||
expected: FAIL
|
||||
|
||||
[addTransceiver(2 streams): ontrack fires with corresponding two streams]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
expected: FAIL
|
||||
|
||||
[addTrack(0 streams): ontrack fires with no stream]
|
||||
expected: FAIL
|
||||
|
||||
[addTrack(2 streams): ontrack fires with corresponding two streams]
|
||||
expected: FAIL
|
||||
|
||||
[Closing the PC stops the transceivers]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
|
||||
[setLocalDescription(answer): transceiver.currentDirection is recvonly]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[Can setup two-way call using a single transceiver]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('video'): transceiver.receiver.track.kind == 'video']
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('audio'): transceiver.stopped is false]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[setLocalDescription(answer): transceiver.currentDirection is sendonly]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[Changing transceiver direction to 'sendrecv' makes ontrack fire]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTrack(1 stream): ontrack fires with corresponding stream]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver(track, init): initialize direction to inactive]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver(0 streams): ontrack fires with no stream]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver(1 stream): ontrack fires with corresponding stream]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver does not reuse reusable transceivers]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver(track): "transceiver == {sender,receiver}"]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('audio'): transceiver.sender.track == null]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('audio'): creates a transceiver with direction sendrecv]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('audio'): transceiver.currentDirection is null]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver('audio'): transceiver.receiver.track.kind == 'audio']
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[setRemoteDescription(offer): transceiver.stopped is false]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTransceiver(track): creates a transceiver for the track]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[addTrack reuses reusable transceivers]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[setRemoteDescription(offer): transceiver.direction is recvonly]
|
||||
expected:
|
||||
if e10s and (os == "linux") and (processor == "x86"): NOTRUN
|
||||
if webrender and (os == "linux"): NOTRUN
|
||||
if not debug and not webrender and e10s and (os == "linux") and (processor == "x86_64"): NOTRUN
|
||||
|
||||
[setRemoteDescription(offer): transceiver.currentDirection is null]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
expected: FAIL
|
||||
|
@ -1,62 +0,0 @@
|
||||
[RTCRtpTransceiver.https.html]
|
||||
disabled: Bug 1515043
|
||||
expected:
|
||||
if e10s and (os == "linux"): TIMEOUT
|
||||
[checkStop]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
FAIL
|
||||
|
||||
[checkMsectionReuse]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkRemoteRollback]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkAddTransceiverNoTrackDoesntPair]
|
||||
expected:
|
||||
if not debug and e10s and (os == "linux") and (processor == "x86"): NOTRUN
|
||||
|
||||
[checkStopAfterClose]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkStopAfterCreateOffer]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkLocalRollback]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkSendrecvWithTracklessStream]
|
||||
expected:
|
||||
if not debug and e10s and (os == "linux") and (processor == "x86"): NOTRUN
|
||||
|
||||
[checkStopAfterCreateAnswer]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkStopAfterSetLocalAnswer]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkStopAfterSetRemoteOffer]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkSendrecvWithNoSendTrack]
|
||||
expected:
|
||||
if not debug and webrender and (os == "linux"): NOTRUN
|
||||
if not debug and e10s and (os == "linux") and (processor == "x86"): NOTRUN
|
||||
|
||||
[checkStopAfterSetLocalOffer]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
||||
[checkRollbackAndSetRemoteOfferWithDifferentType]
|
||||
expected:
|
||||
if e10s and (os == "linux"): NOTRUN
|
||||
|
@ -552,7 +552,7 @@ function createPeerConnectionWithCleanup(t) {
|
||||
async function createTrackAndStreamWithCleanup(t, kind = 'audio') {
|
||||
let constraints = {};
|
||||
constraints[kind] = true;
|
||||
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
const stream = await getNoiseStream(constraints);
|
||||
const [track] = stream.getTracks();
|
||||
t.add_cleanup(() => track.stop());
|
||||
return [track, stream];
|
||||
|
@ -50,9 +50,13 @@ promise_test(async t => {
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
|
||||
const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
|
||||
// Need to wait for the initial unmute event before renegotiating, otherwise
|
||||
// there will be no transition from unmuted->muted.
|
||||
const muteWatcher = new EventWatcher(t, e.track, ['mute', 'unmute']);
|
||||
const unmutePromise = muteWatcher.wait_for('unmute');
|
||||
await exchangeAnswer(pc1, pc2);
|
||||
await unmutePromise;
|
||||
|
||||
const muteWatcher = new EventWatcher(t, e.track, ['mute']);
|
||||
const mutePromise = muteWatcher.wait_for('mute');
|
||||
localTransceiver.direction = 'inactive';
|
||||
await exchangeOfferAnswer(pc1, pc2);
|
||||
@ -88,8 +92,13 @@ promise_test(async t => {
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
|
||||
const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
|
||||
// Need to wait for the initial unmute event before closing, otherwise
|
||||
// there will be no transition from unmuted->muted.
|
||||
const muteWatcher = new EventWatcher(t, e.track, ['mute', 'unmute']);
|
||||
const unmutePromise = muteWatcher.wait_for('unmute');
|
||||
await exchangeAnswer(pc1, pc2);
|
||||
const muteWatcher = new EventWatcher(t, e.track, ['mute']);
|
||||
await unmutePromise;
|
||||
|
||||
const mutePromise = muteWatcher.wait_for('mute');
|
||||
pc2.close();
|
||||
await mutePromise;
|
||||
|
@ -61,6 +61,7 @@
|
||||
|
||||
promise_test(async t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
@ -92,6 +93,7 @@
|
||||
*/
|
||||
promise_test(async t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
@ -99,6 +101,7 @@
|
||||
const { sender } = transceiver;
|
||||
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
assert_throws('InvalidAccessError', () => pc2.removeTrack(sender));
|
||||
}, 'addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError');
|
||||
|
||||
@ -112,6 +115,7 @@
|
||||
const sender = pc.addTrack(track, stream);
|
||||
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
assert_throws('InvalidAccessError', () => pc2.removeTrack(sender));
|
||||
}, 'addTrack - Calling removeTrack on different connection should throw InvalidAccessError')
|
||||
|
||||
@ -121,6 +125,7 @@
|
||||
*/
|
||||
promise_test(async t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
|
@ -142,6 +142,7 @@
|
||||
if (!remoteStreams.includes(e.streams[0]))
|
||||
remoteStreams.push(e.streams[0]);
|
||||
};
|
||||
exchangeIceCandidates(caller, callee);
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
assert_equals(remoteStreams.length, 1, 'One remote stream created.');
|
||||
assert_equals(remoteStreams[0].getTracks()[0].id,
|
||||
@ -176,6 +177,7 @@
|
||||
if (!remoteStreams.includes(e.streams[0]))
|
||||
remoteStreams.push(e.streams[0]);
|
||||
};
|
||||
exchangeIceCandidates(caller, callee);
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
assert_equals(remoteStreams.length, 1, 'One remote stream created.');
|
||||
const onaddtrackPromise =
|
||||
@ -247,6 +249,7 @@
|
||||
t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
|
||||
const sender = caller.addTrack(localStream.getTracks()[0], localStream);
|
||||
const ontrackPromise = addEventListenerPromise(t, callee, 'track');
|
||||
exchangeIceCandidates(caller, callee);
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
await ontrackPromise;
|
||||
assert_equals(callee.getReceivers().length, 1, 'One receiver created.');
|
||||
@ -269,6 +272,7 @@
|
||||
assert_equals(e.streams.length, 1);
|
||||
return e.streams[0];
|
||||
});
|
||||
exchangeIceCandidates(caller, callee);
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
const remoteStream = await ontrackPromise;
|
||||
const remoteTrack = remoteStream.getTracks()[0];
|
||||
@ -297,6 +301,7 @@
|
||||
assert_equals(e.streams.length, 1);
|
||||
return e.streams[0];
|
||||
});
|
||||
exchangeIceCandidates(caller, callee);
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
const remoteStream = await ontrackPromise;
|
||||
const remoteTrack = remoteStream.getTracks()[0];
|
||||
@ -320,13 +325,19 @@
|
||||
await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
|
||||
const sender = caller.addTrack(localStream.getTracks()[0], localStream);
|
||||
const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
|
||||
assert_equals(e.streams.length, 1);
|
||||
return e.streams[0];
|
||||
exchangeIceCandidates(caller, callee);
|
||||
const e = await exchangeOfferAndListenToOntrack(t, caller, callee);
|
||||
const remoteTrack = e.track;
|
||||
|
||||
// Need to wait for unmute, otherwise there's no event for the transition
|
||||
// back to muted.
|
||||
const onunmutePromise =
|
||||
addEventListenerPromise(t, remoteTrack, 'unmute', () => {
|
||||
assert_false(remoteTrack.muted);
|
||||
});
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
const remoteStream = await ontrackPromise;
|
||||
const remoteTrack = remoteStream.getTracks()[0];
|
||||
await exchangeAnswer(caller, callee);
|
||||
await onunmutePromise;
|
||||
|
||||
const onmutePromise =
|
||||
addEventListenerPromise(t, remoteTrack, 'mute', () => {
|
||||
assert_true(remoteTrack.muted);
|
||||
@ -350,9 +361,19 @@
|
||||
assert_equals(e.streams.length, 1);
|
||||
return e.streams[0];
|
||||
});
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
const remoteStream = await ontrackPromise;
|
||||
const remoteTrack = remoteStream.getTracks()[0];
|
||||
exchangeIceCandidates(caller, callee);
|
||||
const e = await exchangeOfferAndListenToOntrack(t, caller, callee);
|
||||
const remoteTrack = e.track;
|
||||
|
||||
// Need to wait for unmute, otherwise there's no event for the transition
|
||||
// back to muted.
|
||||
const onunmutePromise =
|
||||
addEventListenerPromise(t, remoteTrack, 'unmute', () => {
|
||||
assert_false(remoteTrack.muted);
|
||||
});
|
||||
await exchangeAnswer(caller, callee);
|
||||
await onunmutePromise;
|
||||
|
||||
const onmutePromise =
|
||||
addEventListenerPromise(t, remoteTrack, 'mute', () => {
|
||||
eventSequence += 'track.onmute;';
|
||||
|
@ -25,6 +25,7 @@
|
||||
let track;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
track = tracks[0];
|
||||
pc.addTrack(track, streams[0]);
|
||||
return pc.getStats();
|
||||
@ -50,6 +51,7 @@
|
||||
let stream;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let track = tracks[0];
|
||||
stream = streams[0];
|
||||
pc.addTrack(track, stream);
|
||||
@ -72,6 +74,7 @@
|
||||
let track;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
track = tracks[0];
|
||||
pc.addTrack(track, streams[0]);
|
||||
return pc.createOffer();
|
||||
@ -99,6 +102,7 @@
|
||||
let stream;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let track = tracks[0];
|
||||
stream = streams[0];
|
||||
pc.addTrack(track, stream);
|
||||
@ -128,6 +132,7 @@
|
||||
let stream;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
track = tracks[0];
|
||||
stream = streams[0];
|
||||
pc.addTrack(track, stream);
|
||||
@ -162,6 +167,7 @@
|
||||
let stream;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
track = tracks[0];
|
||||
stream = streams[0];
|
||||
stream.addTrack(track);
|
||||
@ -199,6 +205,7 @@
|
||||
let sendingTrack;
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
sendingTrack = tracks[0];
|
||||
caller.addTrack(sendingTrack, streams[0]);
|
||||
return doSignalingHandshake(caller, callee);
|
||||
@ -233,6 +240,7 @@
|
||||
};
|
||||
return getUserMediaTracksAndStreams(1)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
caller.addTrack(tracks[0], streams[0]);
|
||||
return doSignalingHandshake(caller, callee);
|
||||
}))
|
||||
@ -265,6 +273,7 @@
|
||||
let sender;
|
||||
return getUserMediaTracksAndStreams(2)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
sendingTrack1 = tracks[0];
|
||||
sendingTrack2 = tracks[1];
|
||||
sender = caller.addTrack(sendingTrack1, streams[0]);
|
||||
@ -294,6 +303,7 @@
|
||||
let sender;
|
||||
return getUserMediaTracksAndStreams(2)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
sendingTrack1 = tracks[0];
|
||||
sendingTrack2 = tracks[1];
|
||||
sender = caller.addTrack(sendingTrack1, streams[0]);
|
||||
@ -331,6 +341,7 @@
|
||||
let sender;
|
||||
return getUserMediaTracksAndStreams(2)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
sendingTrack1 = tracks[0];
|
||||
sendingTrack2 = tracks[1];
|
||||
sender = caller.addTrack(sendingTrack1, streams[0]);
|
||||
@ -367,6 +378,7 @@
|
||||
let sender;
|
||||
return getUserMediaTracksAndStreams(2)
|
||||
.then(t.step_func(([tracks, streams]) => {
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
sendingTrack1 = tracks[0];
|
||||
sendingTrack2 = tracks[1];
|
||||
sender = caller.addTrack(sendingTrack1, streams[0]);
|
||||
@ -400,6 +412,7 @@
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(2);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let sender = caller.addTrack(tracks[0], streams[0]);
|
||||
callee.addTrack(tracks[1], streams[1]);
|
||||
exchangeIceCandidates(caller, callee);
|
||||
@ -448,6 +461,7 @@
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(2);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let sender = caller.addTrack(tracks[0], streams[0]);
|
||||
callee.addTrack(tracks[1], streams[1]);
|
||||
exchangeIceCandidates(caller, callee);
|
||||
@ -496,6 +510,7 @@
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(2);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let sender = caller.addTrack(tracks[0], streams[0]);
|
||||
callee.addTrack(tracks[1], streams[1]);
|
||||
exchangeIceCandidates(caller, callee);
|
||||
@ -527,6 +542,7 @@
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(2);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let sender = caller.addTrack(tracks[0], streams[0]);
|
||||
callee.addTrack(tracks[1], streams[1]);
|
||||
exchangeIceCandidates(caller, callee);
|
||||
@ -557,6 +573,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(1);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
await promise_rejects(t, 'InvalidAccessError', pc.getStats(tracks[0]));
|
||||
}, 'RTCPeerConnection.getStats(track) throws InvalidAccessError when there ' +
|
||||
'are zero senders or receivers for the track');
|
||||
@ -565,6 +582,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
let [tracks, streams] = await getUserMediaTracksAndStreams(2);
|
||||
t.add_cleanup(() => tracks.forEach(track => track.stop()));
|
||||
let sender1 = pc.addTrack(tracks[0], streams[0]);
|
||||
let sender2 = pc.addTrack(tracks[1], streams[1]);
|
||||
await sender2.replaceTrack(sender1.track);
|
||||
|
@ -1,4 +1,5 @@
|
||||
<!doctype html>
|
||||
<meta name="timeout" content="long"/>
|
||||
<meta charset=utf-8>
|
||||
<title>RTCPeerConnection-transceivers.https.html</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
|
@ -215,7 +215,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||
const stream = await getNoiseStream({audio: true, video: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const audio = stream.getAudioTracks()[0];
|
||||
const video = stream.getVideoTracks()[0];
|
||||
@ -248,7 +248,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||
const stream = await getNoiseStream({audio: true, video: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const audio = stream.getAudioTracks()[0];
|
||||
const video = stream.getVideoTracks()[0];
|
||||
@ -311,7 +311,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTransceiver(track, {streams: [stream]});
|
||||
@ -346,7 +346,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTransceiver(track);
|
||||
@ -392,7 +392,7 @@
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -413,7 +413,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -474,7 +474,7 @@
|
||||
t.add_cleanup(() => pc2.close());
|
||||
pc1.addTransceiver("audio");
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc2.addTransceiver(track);
|
||||
@ -504,7 +504,7 @@
|
||||
pc1.addTransceiver("audio");
|
||||
pc2.addTransceiver("audio");
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc2.getTransceivers()[0].sender.replaceTrack(track);
|
||||
@ -534,7 +534,7 @@
|
||||
pc1.addTransceiver("audio");
|
||||
pc2.addTransceiver("audio");
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc2.addTrack(track, stream);
|
||||
@ -562,7 +562,7 @@
|
||||
t.add_cleanup(() => pc2.close());
|
||||
pc1.addTransceiver("audio");
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc2.addTrack(track, stream);
|
||||
@ -590,7 +590,7 @@
|
||||
t.add_cleanup(() => pc2.close());
|
||||
pc1.addTransceiver("audio");
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc2.addTrack(track, stream);
|
||||
@ -617,7 +617,7 @@
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -685,7 +685,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
pc.addTransceiver("audio");
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
const audio = stream.getAudioTracks()[0];
|
||||
let sender = pc.addTrack(audio, stream);
|
||||
pc.removeTrack(sender);
|
||||
@ -705,7 +705,7 @@
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||
const stream = await getNoiseStream({audio: true, video: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const audio = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(audio, stream);
|
||||
@ -860,7 +860,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -962,7 +962,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTransceiver("audio");
|
||||
@ -1026,7 +1026,7 @@
|
||||
const checkMute = async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const stream1 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||
const stream1 = await getNoiseStream({audio: true, video: true});
|
||||
t.add_cleanup(() => stopTracks(stream1));
|
||||
const audio1 = stream1.getAudioTracks()[0];
|
||||
pc1.addTrack(audio1, stream1);
|
||||
@ -1040,7 +1040,7 @@
|
||||
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
const stream2 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||
const stream2 = await getNoiseStream({audio: true, video: true});
|
||||
t.add_cleanup(() => stopTracks(stream2));
|
||||
const audio2 = stream2.getAudioTracks()[0];
|
||||
pc2.addTrack(audio2, stream2);
|
||||
@ -1152,7 +1152,7 @@
|
||||
const checkStop = async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1197,7 +1197,7 @@
|
||||
transceiver.sender.getParameters()),
|
||||
"InvalidStateError", "setParameters on stopped transceiver");
|
||||
|
||||
const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream2 = await getNoiseStream({audio: true});
|
||||
const track2 = stream.getAudioTracks()[0];
|
||||
checkThrows(() => transceiver.sender.replaceTrack(track2),
|
||||
"InvalidStateError", "replaceTrack on stopped transceiver");
|
||||
@ -1251,7 +1251,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1321,7 +1321,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1391,7 +1391,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1426,7 +1426,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1496,7 +1496,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1566,7 +1566,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1589,7 +1589,7 @@
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc.addTrack(track, stream);
|
||||
@ -1610,7 +1610,7 @@
|
||||
|
||||
// Verify that rollback doesn't stomp things it should not
|
||||
pc.getTransceivers()[0].direction = "sendonly";
|
||||
const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream2 = await getNoiseStream({audio: true});
|
||||
const track2 = stream2.getAudioTracks()[0];
|
||||
await pc.getTransceivers()[0].sender.replaceTrack(track2);
|
||||
|
||||
@ -1641,7 +1641,7 @@
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
|
||||
const audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const audioStream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(audioStream));
|
||||
const audioTrack = audioStream.getAudioTracks()[0];
|
||||
pc1.addTrack(audioTrack, audioStream);
|
||||
@ -1649,7 +1649,7 @@
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const videoStream = await navigator.mediaDevices.getUserMedia({video: true});
|
||||
const videoStream = await getNoiseStream({video: true});
|
||||
t.add_cleanup(() => stopTracks(videoStream));
|
||||
const videoTrack = videoStream.getVideoTracks()[0];
|
||||
pc2.addTrack(videoTrack, videoStream);
|
||||
@ -1720,7 +1720,7 @@
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1777,7 +1777,7 @@
|
||||
const mid0 = pc2.getTransceivers()[0].mid;
|
||||
|
||||
// Give pc2 a track with replaceTrack
|
||||
const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream2 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream2));
|
||||
const track2 = stream2.getAudioTracks()[0];
|
||||
await pc2.getTransceivers()[0].sender.replaceTrack(track2);
|
||||
@ -1937,7 +1937,7 @@
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream));
|
||||
const track = stream.getAudioTracks()[0];
|
||||
pc1.addTrack(track, stream);
|
||||
@ -1973,7 +1973,7 @@
|
||||
]);
|
||||
|
||||
// Check that m-section is reused on both ends
|
||||
const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream2 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream2));
|
||||
const track2 = stream2.getAudioTracks()[0];
|
||||
|
||||
@ -2044,7 +2044,7 @@
|
||||
// new one for the new track)
|
||||
const stoppedMid1 = pc1.getTransceivers()[1].mid;
|
||||
pc1.getTransceivers()[1].stop();
|
||||
const stream3 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream3 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream3));
|
||||
const track3 = stream3.getAudioTracks()[0];
|
||||
pc1.addTrack(track3, stream3);
|
||||
@ -2114,7 +2114,7 @@
|
||||
]);
|
||||
|
||||
// Add _another_ track; this should reuse the disabled m-section
|
||||
const stream4 = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
const stream4 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream4));
|
||||
const track4 = stream4.getAudioTracks()[0];
|
||||
pc2.addTrack(track4, stream4);
|
||||
|
@ -24,7 +24,7 @@ async function checkIconInView(view, name, findIcon) {
|
||||
const icon = findIcon(manager.document);
|
||||
const size = Number(icon.src.match(/icon(\d+)\.png/)[1]);
|
||||
is(icon.clientWidth, icon.clientHeight, `The icon should be square in ${name}`);
|
||||
is(size, icon.clientWidth, `The correct icon size should have been chosen in ${name}`);
|
||||
is(size, icon.clientWidth * window.devicePixelRatio, `The correct icon size should have been chosen in ${name}`);
|
||||
await close_manager(manager);
|
||||
}
|
||||
|
||||
|
@ -3832,6 +3832,19 @@ void profiler_tracing(const char* aCategoryString, const char* aMarkerName,
|
||||
racy_profiler_add_marker(aMarkerName, aCategory, std::move(payload));
|
||||
}
|
||||
|
||||
void profiler_add_text_marker(
|
||||
const char* aMarkerName, const nsACString& aText,
|
||||
js::ProfilingStackFrame::Category aCategory,
|
||||
const mozilla::TimeStamp& aStartTime, const mozilla::TimeStamp& aEndTime,
|
||||
const mozilla::Maybe<nsID>& aDocShellId,
|
||||
const mozilla::Maybe<uint32_t>& aDocShellHistoryId,
|
||||
UniqueProfilerBacktrace aCause) {
|
||||
profiler_add_marker(
|
||||
aMarkerName, aCategory,
|
||||
MakeUnique<TextMarkerPayload>(aText, aStartTime, aEndTime, aDocShellId,
|
||||
aDocShellHistoryId, std::move(aCause)));
|
||||
}
|
||||
|
||||
void profiler_set_js_context(JSContext* aCx) {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
|
@ -60,6 +60,11 @@
|
||||
# define AUTO_PROFILER_TRACING(categoryString, markerName, category)
|
||||
# define AUTO_PROFILER_TRACING_DOCSHELL(categoryString, markerName, category, \
|
||||
docShell)
|
||||
# define AUTO_PROFILER_TEXT_MARKER_CAUSE(markerName, text, category, cause)
|
||||
# define AUTO_PROFILER_TEXT_MARKER_DOCSHELL(markerName, text, category, \
|
||||
docShell)
|
||||
# define AUTO_PROFILER_TEXT_MARKER_DOCSHELL_CAUSE(markerName, text, category, \
|
||||
docShell, cause)
|
||||
|
||||
#else // !MOZ_GECKO_PROFILER
|
||||
|
||||
@ -695,6 +700,76 @@ void profiler_tracing(
|
||||
js::ProfilingStackFrame::Category::category, docShellId, \
|
||||
docShellHistoryId)
|
||||
|
||||
// Add a text marker. Text markers are similar to tracing markers, with the
|
||||
// difference that text markers have their "text" separate from the marker name;
|
||||
// multiple text markers with the same name can have different text, and these
|
||||
// markers will still be displayed in the same "row" in the UI.
|
||||
// Another difference is that text markers combine the start and end markers
|
||||
// into one marker.
|
||||
void profiler_add_text_marker(
|
||||
const char* aMarkerName, const nsACString& aText,
|
||||
js::ProfilingStackFrame::Category aCategory,
|
||||
const mozilla::TimeStamp& aStartTime, const mozilla::TimeStamp& aEndTime,
|
||||
const mozilla::Maybe<nsID>& aDocShellId = mozilla::Nothing(),
|
||||
const mozilla::Maybe<uint32_t>& aDocShellHistoryId = mozilla::Nothing(),
|
||||
UniqueProfilerBacktrace aCause = nullptr);
|
||||
|
||||
class MOZ_RAII AutoProfilerTextMarker {
|
||||
public:
|
||||
AutoProfilerTextMarker(const char* aMarkerName, const nsACString& aText,
|
||||
js::ProfilingStackFrame::Category aCategory,
|
||||
const mozilla::Maybe<nsID>& aDocShellId,
|
||||
const mozilla::Maybe<uint32_t>& aDocShellHistoryId,
|
||||
UniqueProfilerBacktrace&& aCause =
|
||||
nullptr MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mMarkerName(aMarkerName),
|
||||
mText(aText),
|
||||
mCategory(aCategory),
|
||||
mStartTime(mozilla::TimeStamp::Now()),
|
||||
mCause(std::move(aCause)),
|
||||
mDocShellId(aDocShellId),
|
||||
mDocShellHistoryId(aDocShellHistoryId) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
~AutoProfilerTextMarker() {
|
||||
profiler_add_text_marker(mMarkerName, mText,
|
||||
js::ProfilingStackFrame::Category::LAYOUT,
|
||||
mStartTime, mozilla::TimeStamp::Now(), mDocShellId,
|
||||
mDocShellHistoryId, std::move(mCause));
|
||||
}
|
||||
|
||||
protected:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
const char* mMarkerName;
|
||||
nsCString mText;
|
||||
const js::ProfilingStackFrame::Category mCategory;
|
||||
mozilla::TimeStamp mStartTime;
|
||||
UniqueProfilerBacktrace mCause;
|
||||
const mozilla::Maybe<nsID> mDocShellId;
|
||||
const mozilla::Maybe<uint32_t> mDocShellHistoryId;
|
||||
};
|
||||
|
||||
# define AUTO_PROFILER_TEXT_MARKER_CAUSE(markerName, text, category, \
|
||||
cause) \
|
||||
AutoProfilerTextMarker PROFILER_RAII( \
|
||||
markerName, text, js::ProfilingStackFrame::Category::category, \
|
||||
Nothing(), Nothing(), cause)
|
||||
|
||||
# define AUTO_PROFILER_TEXT_MARKER_DOCSHELL(markerName, text, category, \
|
||||
docShell) \
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(docShell); \
|
||||
AutoProfilerTextMarker PROFILER_RAII( \
|
||||
markerName, text, js::ProfilingStackFrame::Category::category, \
|
||||
docShellId, docShellHistoryId)
|
||||
|
||||
# define AUTO_PROFILER_TEXT_MARKER_DOCSHELL_CAUSE(markerName, text, category, \
|
||||
docShell, cause) \
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(docShell); \
|
||||
AutoProfilerTextMarker PROFILER_RAII( \
|
||||
markerName, text, js::ProfilingStackFrame::Category::category, \
|
||||
docShellId, docShellHistoryId, cause)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Output profiles
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -385,9 +385,10 @@ class TextMarkerPayload : public ProfilerMarkerPayload {
|
||||
const mozilla::TimeStamp& aStartTime,
|
||||
const mozilla::TimeStamp& aEndTime,
|
||||
const mozilla::Maybe<nsID>& aDocShellId,
|
||||
const mozilla::Maybe<uint32_t>& aDocShellHistoryId)
|
||||
const mozilla::Maybe<uint32_t>& aDocShellHistoryId,
|
||||
UniqueProfilerBacktrace aCause = nullptr)
|
||||
: ProfilerMarkerPayload(aStartTime, aEndTime, aDocShellId,
|
||||
aDocShellHistoryId),
|
||||
aDocShellHistoryId, std::move(aCause)),
|
||||
mText(aText) {}
|
||||
|
||||
DECL_STREAM_PAYLOAD
|
||||
|
@ -72,14 +72,6 @@ class VibrancyManager {
|
||||
|
||||
bool HasVibrantRegions() { return !mVibrantRegions.IsEmpty(); }
|
||||
|
||||
/**
|
||||
* Clear the vibrant areas that we know about.
|
||||
* The clearing happens in the current NSGraphicsContext. If you call this
|
||||
* from within an -[NSView drawRect:] implementation, the currrent
|
||||
* NSGraphicsContext is already correctly set to the window drawing context.
|
||||
*/
|
||||
void ClearVibrantAreas() const;
|
||||
|
||||
/**
|
||||
* Return the fill color that should be drawn on top of the cleared window
|
||||
* parts. Usually this would be drawn by -[NSVisualEffectView drawRect:].
|
||||
@ -108,8 +100,6 @@ class VibrancyManager {
|
||||
static NSView* CreateEffectView(VibrancyType aType, BOOL aIsContainer = NO);
|
||||
|
||||
protected:
|
||||
void ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const;
|
||||
|
||||
const nsChildView& mCoordinateConverter;
|
||||
NSView* mContainerView;
|
||||
nsClassHashtable<nsUint32HashKey, ViewRegion> mVibrantRegions;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user