Merge mozilla-central to autoland a=merge on a CLOSED TREE

This commit is contained in:
Coroiu Cristina 2018-10-26 01:02:15 +03:00
Родитель 72450b73d0 4258c167d5
Коммит 6455148cff
91 изменённых файлов: 1053 добавлений и 997 удалений

Просмотреть файл

@ -98,6 +98,8 @@ devtools/client/inspector/markup/test/doc_markup_events_*.html
devtools/client/inspector/rules/test/doc_media_queries.html
devtools/client/performance/components/test/test_jit_optimizations_01.html
devtools/client/responsive.html/test/browser/touch.html
devtools/client/shared/test/*.html
devtools/client/shared/test/code_*.js
devtools/client/shared/components/test/mochitest/*.html
!devtools/client/shared/components/test/mochitest/test_stack-trace.html
devtools/client/storage/test/*.html

Просмотреть файл

@ -27,7 +27,10 @@ add_task(async function findbar_test() {
ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " +
"subdocument changes");
let findBarClosePromise = promiseWaitForEvent(gBrowser, "findbarclose");
gFindBar.close();
await findBarClosePromise;
gBrowser.removeTab(newTab);
});

Просмотреть файл

@ -192,24 +192,27 @@ var PdfjsChromeUtils = {
},
handleEvent(aEvent) {
const type = aEvent.type;
// Handle the tab find initialized event specially:
if (aEvent.type == "TabFindInitialized") {
if (type == "TabFindInitialized") {
let browser = aEvent.target.linkedBrowser;
this._hookupEventListeners(browser);
aEvent.target.removeEventListener(aEvent.type, this);
aEvent.target.removeEventListener(type, this);
return;
}
// To avoid forwarding the message as a CPOW, create a structured cloneable
// version of the event for both performance, and ease of usage, reasons.
let type = aEvent.type;
let detail = {
query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive,
entireWord: aEvent.detail.entireWord,
highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious,
};
let detail = null;
if (type !== "findbarclose") {
detail = {
query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive,
entireWord: aEvent.detail.entireWord,
highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious,
};
}
let browser = aEvent.currentTarget.browser;
if (!this._browsers.has(browser)) {
@ -222,10 +225,13 @@ var PdfjsChromeUtils = {
aEvent.preventDefault();
},
_types: ["find",
"findagain",
"findhighlightallchange",
"findcasesensitivitychange"],
_types: [
"find",
"findagain",
"findhighlightallchange",
"findcasesensitivitychange",
"findbarclose",
],
_addEventListener(aMsg) {
let browser = aMsg.target;

Просмотреть файл

@ -1,40 +1,15 @@
# Tests in this directory are split into two manifests (this and browser2.ini)
# to facilitate better chunking; see bug 1294489.
[DEFAULT]
tags = devtools
subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
addon4.xpi
code_listworkers-worker1.js
code_listworkers-worker2.js
code_WorkerTargetActor.attachThread-worker.js
doc_event-listeners-01.html
doc_event-listeners-03.html
doc_inline-debugger-statement.html
doc_listworkers-tab.html
doc_native-event-handler.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_terminate-on-tab-close.html
doc_WorkerTargetActor.attachThread-tab.html
head.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
[browser_dbg_addon-console.js]
skip-if = (e10s && debug || os == 'win' || verify) || true # bug 1005274
tags = addons
[browser_dbg_debugger-statement.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-01.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-02.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-03.js]
skip-if = e10s && debug
[browser_dbg_listworkers.js]
[browser_dbg_promises-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true
@ -50,5 +25,3 @@ skip-if = true
[browser_dbg_terminate-on-tab-close.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_worker-window.js]
skip-if = (e10s && debug) || true # Bug 1486974

Просмотреть файл

@ -1,47 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the we can see console messages from the add-on
const ADDON_ID = "browser_dbg_addon4@tests.mozilla.org";
const ADDON_PATH = "addon4.xpi";
function getCachedMessages(webConsole) {
let deferred = promise.defer();
webConsole.getCachedMessages(["ConsoleAPI"], (aResponse) => {
if (aResponse.error) {
deferred.reject(aResponse.error);
return;
}
deferred.resolve(aResponse.messages);
});
return deferred.promise;
}
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let addonDebugger = yield initAddonDebugger(ADDON_ID);
let webConsole = addonDebugger.webConsole;
let messages = yield getCachedMessages(webConsole);
is(messages.length, 1, "Should be one cached message");
is(messages[0].arguments[0].type, "object", "Should have logged an object");
is(messages[0].arguments[0].preview.ownProperties.msg.value, "Hello from the test add-on", "Should have got the right message");
let consolePromise = addonDebugger.once("console");
console.log("Bad message");
Services.obs.notifyObservers(null, "addon-test-ping");
let messageGrip = yield consolePromise;
is(messageGrip.arguments[0].type, "object", "Should have logged an object");
is(messageGrip.arguments[0].preview.ownProperties.msg.value, "Hello again", "Should have got the right message");
yield addonDebugger.destroy();
yield removeAddon(addon);
finish();
});
}

Просмотреть файл

@ -1,59 +0,0 @@
var TAB_URL = EXAMPLE_URL + "doc_listworkers-tab.html";
var WORKER1_URL = "code_listworkers-worker1.js";
var WORKER2_URL = "code_listworkers-worker2.js";
function test() {
Task.spawn(function* () {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let tab = yield addTab(TAB_URL);
let { tabs } = yield listTabs(client);
let [, targetFront] = yield attachTarget(client, findTab(tabs, TAB_URL));
let { workers } = yield listWorkers(targetFront);
is(workers.length, 0);
executeSoon(() => {
evalInTab(tab, "var worker1 = new Worker('" + WORKER1_URL + "');");
});
yield waitForWorkerListChanged(targetFront);
({ workers } = yield listWorkers(targetFront));
is(workers.length, 1);
is(workers[0].url, WORKER1_URL);
executeSoon(() => {
evalInTab(tab, "var worker2 = new Worker('" + WORKER2_URL + "');");
});
yield waitForWorkerListChanged(targetFront);
({ workers } = yield listWorkers(targetFront));
is(workers.length, 2);
is(workers[0].url, WORKER1_URL);
is(workers[1].url, WORKER2_URL);
executeSoon(() => {
evalInTab(tab, "worker1.terminate()");
});
yield waitForWorkerListChanged(targetFront);
({ workers } = yield listWorkers(targetFront));
is(workers.length, 1);
is(workers[0].url, WORKER2_URL);
executeSoon(() => {
evalInTab(tab, "worker2.terminate()");
});
yield waitForWorkerListChanged(targetFront);
({ workers } = yield listWorkers(targetFront));
is(workers.length, 0);
yield close(client);
finish();
});
}

Просмотреть файл

@ -1,16 +0,0 @@
"use strict";
function f() {
var a = 1;
var b = 2;
var c = 3;
}
self.onmessage = function (event) {
if (event.data == "ping") {
f();
postMessage("pong");
}
};
postMessage("load");

Просмотреть файл

@ -1,3 +0,0 @@
"use strict";
self.onmessage = function () {};

Просмотреть файл

@ -1,3 +0,0 @@
"use strict";
self.onmessage = function () {};

Просмотреть файл

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -591,157 +591,6 @@ let initDebugger = Task.async(function*(urlOrTab, options) {
return [tab, debuggerPanel, window];
});
// Creates an add-on debugger for a given add-on. The returned AddonDebugger
// object must be destroyed before finishing the test
function initAddonDebugger(aAddonId) {
let addonDebugger = new AddonDebugger();
return addonDebugger.init(aAddonId).then(() => addonDebugger);
}
function AddonDebugger() {
this._onMessage = this._onMessage.bind(this);
this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
EventEmitter.decorate(this);
}
AddonDebugger.prototype = {
init: Task.async(function* (aAddonId) {
info("Initializing an addon debugger panel.");
DebuggerServer.init();
DebuggerServer.registerAllActors();
DebuggerServer.allowChromeProcess = true;
this.frame = document.createElement("iframe");
this.frame.setAttribute("height", 400);
document.documentElement.appendChild(this.frame);
window.addEventListener("message", this._onMessage);
let transport = DebuggerServer.connectPipe();
this.client = new DebuggerClient(transport);
yield this.client.connect();
let addonTargetActor = yield getAddonActorForId(this.client, aAddonId);
let targetOptions = {
form: addonTargetActor,
client: this.client,
chrome: true,
};
let toolboxOptions = {
customIframe: this.frame
};
this.target = yield TargetFactory.forRemoteTab(targetOptions);
let toolbox = yield gDevTools.showToolbox(this.target, "jsdebugger", Toolbox.HostType.CUSTOM, toolboxOptions);
info("Addon debugger panel shown successfully.");
this.debuggerPanel = toolbox.getCurrentPanel();
yield waitForSourceShown(this.debuggerPanel, "");
prepareDebugger(this.debuggerPanel);
yield this._attachConsole();
}),
destroy: Task.async(function* () {
yield this.client.close();
yield this.debuggerPanel._toolbox.destroy();
this.frame.remove();
window.removeEventListener("message", this._onMessage);
}),
_attachConsole: function () {
let deferred = promise.defer();
this.client.attachConsole(this.target.form.consoleActor, ["ConsoleAPI"])
.then(([aResponse, aWebConsoleClient]) => {
this.webConsole = aWebConsoleClient;
this.client.addListener("consoleAPICall", this._onConsoleAPICall);
deferred.resolve();
}, e => {
deferred.reject(e);
});
return deferred.promise;
},
_onConsoleAPICall: function (aType, aPacket) {
if (aPacket.from != this.webConsole.actor)
return;
this.emit("console", aPacket.message);
},
/**
* Returns a list of the groups and sources in the UI. The returned array
* contains objects for each group with properties name and sources. The
* sources property contains an array with objects for each source for that
* group with properties label and url.
*/
getSourceGroups: Task.async(function* () {
let debuggerWin = this.debuggerPanel.panelWin;
let sources = yield getSources(debuggerWin.gThreadClient);
ok(sources.length, "retrieved sources");
// groups will be the return value, groupmap and the maps we put in it will
// be used as quick lookups to add the url information in below
let groups = [];
let groupmap = new Map();
let uigroups = this.debuggerPanel.panelWin.document.querySelectorAll(".side-menu-widget-group");
for (let g of uigroups) {
let name = g.querySelector(".side-menu-widget-group-title .name").value;
let group = {
name: name,
sources: []
};
groups.push(group);
let labelmap = new Map();
groupmap.set(name, labelmap);
for (let l of g.querySelectorAll(".dbg-source-item")) {
let source = {
label: l.value,
url: null
};
labelmap.set(l.value, source);
group.sources.push(source);
}
}
for (let source of sources) {
let { label, group } = debuggerWin.DebuggerView.Sources.getItemByValue(source.actor).attachment;
if (!groupmap.has(group)) {
ok(false, "Saw a source group not in the UI: " + group);
continue;
}
if (!groupmap.get(group).has(label)) {
ok(false, "Saw a source label not in the UI: " + label);
continue;
}
groupmap.get(group).get(label).url = source.url.split(" -> ").pop();
}
return groups;
}),
_onMessage: function(event) {
if (!event.data) {
return;
}
const msg = event.data;
switch (msg.name) {
case "toolbox-title":
this.title = msg.data.value;
break;
}
}
};
function initChromeDebugger(aOnClose) {
info("Initializing a chrome debugger process.");

Просмотреть файл

@ -4,7 +4,10 @@ subsuite = devtools
support-files =
addon1.xpi
addon2.xpi
addon4.xpi
browser_devices.json
code_listworkers-worker1.js
code_listworkers-worker2.js
code_WorkerTargetActor.attach-worker1.js
code_WorkerTargetActor.attach-worker2.js
code_WorkerTargetActor.attachThread-worker.js
@ -13,6 +16,8 @@ support-files =
doc_cubic-bezier-02.html
doc_empty-tab-01.html
doc_empty-tab-02.html
doc_event-listeners-01.html
doc_event-listeners-03.html
doc_filter-editor-01.html
doc_html_tooltip-02.xul
doc_html_tooltip-03.xul
@ -25,9 +30,12 @@ support-files =
doc_html_tooltip_doorhanger-02.xul
doc_html_tooltip_hover.xul
doc_html_tooltip_rtl.xul
doc_inline-debugger-statement.html
doc_inplace-editor_autocomplete_offset.xul
doc_layoutHelpers-getBoxQuads.html
doc_layoutHelpers.html
doc_listworkers-tab.html
doc_native-event-handler.html
doc_options-view.xul
doc_script-switching-01.html
doc_script-switching-02.html
@ -42,6 +50,7 @@ support-files =
dummy.html
frame-script-utils.js
head.js
helper_addons.js
helper_color_data.js
helper_html_tooltip.js
helper_inplace_editor.js
@ -67,8 +76,20 @@ support-files =
[browser_cubic-bezier-05.js]
[browser_cubic-bezier-06.js]
[browser_cubic-bezier-07.js]
[browser_dbg_addon-console.js]
skip-if = (e10s && debug || os == 'win' || verify)
tags = addons
[browser_dbg_debugger-statement.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-01.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-02.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-03.js]
skip-if = e10s && debug
[browser_dbg_globalactor.js]
skip-if = e10s
[browser_dbg_listworkers.js]
[browser_filter-editor-01.js]
[browser_filter-editor-02.js]
[browser_filter-editor-03.js]
@ -246,3 +267,5 @@ skip-if = debug # bug 1334683
skip-if = e10s && debug
[browser_dbg_WorkerTargetActor.attach.js]
skip-if = e10s && debug
[browser_dbg_worker-window.js]
skip-if = (e10s && debug) || true # Bug 1486974

Просмотреть файл

@ -0,0 +1,151 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* import-globals-from helper_addons.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_addons.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
var { Toolbox } = require("devtools/client/framework/toolbox");
var { Task } = require("devtools/shared/task");
// Test that the we can see console messages from the add-on
const ADDON_ID = "browser_dbg_addon4@tests.mozilla.org";
const ADDON_PATH = "addon4.xpi";
function getCachedMessages(webConsole) {
const deferred = getDeferredPromise().defer();
webConsole.getCachedMessages(["ConsoleAPI"], response => {
if (response.error) {
deferred.reject(response.error);
return;
}
deferred.resolve(response.messages);
});
return deferred.promise;
}
// Creates an add-on debugger for a given add-on. The returned AddonDebugger
// object must be destroyed before finishing the test
function initAddonDebugger(addonId) {
const addonDebugger = new AddonDebugger();
return addonDebugger.init(addonId).then(() => addonDebugger);
}
function AddonDebugger() {
this._onMessage = this._onMessage.bind(this);
this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
EventEmitter.decorate(this);
}
AddonDebugger.prototype = {
init: Task.async(function* (addonId) {
info("Initializing an addon debugger panel.");
DebuggerServer.init();
DebuggerServer.registerAllActors();
DebuggerServer.allowChromeProcess = true;
this.frame = document.createElement("iframe");
this.frame.setAttribute("height", 400);
document.documentElement.appendChild(this.frame);
window.addEventListener("message", this._onMessage);
const transport = DebuggerServer.connectPipe();
this.client = new DebuggerClient(transport);
yield this.client.connect();
const addonTargetActor = yield getAddonActorForId(this.client, addonId);
const targetOptions = {
form: addonTargetActor,
client: this.client,
chrome: true,
};
const toolboxOptions = {
customIframe: this.frame,
};
this.target = yield TargetFactory.forRemoteTab(targetOptions);
const toolbox = yield gDevTools.showToolbox(
this.target, "jsdebugger", Toolbox.HostType.CUSTOM, toolboxOptions);
info("Addon debugger panel shown successfully.");
this.debuggerPanel = toolbox.getCurrentPanel();
yield this._attachConsole();
}),
destroy: Task.async(function* () {
yield this.client.close();
this.frame.remove();
window.removeEventListener("message", this._onMessage);
}),
_attachConsole: function() {
const deferred = getDeferredPromise().defer();
this.client.attachConsole(this.target.form.consoleActor, ["ConsoleAPI"])
.then(([aResponse, aWebConsoleClient]) => {
this.webConsole = aWebConsoleClient;
this.client.addListener("consoleAPICall", this._onConsoleAPICall);
deferred.resolve();
}, e => {
deferred.reject(e);
});
return deferred.promise;
},
_onConsoleAPICall: function(type, packet) {
if (packet.from != this.webConsole.actor) {
return;
}
this.emit("console", packet.message);
},
_onMessage: function(event) {
if (!event.data) {
return;
}
const msg = event.data;
switch (msg.name) {
case "toolbox-title":
this.title = msg.data.value;
break;
}
},
};
add_task(async function test() {
const addon = await addTemporaryAddon(ADDON_PATH);
const addonDebugger = await initAddonDebugger(ADDON_ID);
const webConsole = addonDebugger.webConsole;
const messages = await getCachedMessages(webConsole);
is(messages.length, 1, "Should be one cached message");
is(messages[0].arguments[0].type, "object", "Should have logged an object");
is(messages[0].arguments[0].preview.ownProperties.msg.value,
"Hello from the test add-on", "Should have got the right message");
const consolePromise = addonDebugger.once("console");
console.log("Bad message");
Services.obs.notifyObservers(null, "addon-test-ping");
const messageGrip = await consolePromise;
is(messageGrip.arguments[0].type, "object", "Should have logged an object");
is(messageGrip.arguments[0].preview.ownProperties.msg.value,
"Hello again", "Should have got the right message");
await addonDebugger.destroy();
await removeAddon(addon);
finish();
});

Просмотреть файл

@ -3,11 +3,22 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests the behavior of the debugger statement.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
const TAB_URL = TEST_URI_ROOT + "doc_inline-debugger-statement.html";
var gClient;
var gTab;
@ -16,31 +27,31 @@ function test() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let transport = DebuggerServer.connectPipe();
const transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then((aTab) => {
gTab = aTab;
.then(tab => {
gTab = tab;
return attachTargetActorForUrl(gClient, TAB_URL);
})
.then(testEarlyDebuggerStatement)
.then(testDebuggerStatement)
.then(() => gClient.close())
.then(finish)
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
.catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
});
}
function testEarlyDebuggerStatement([aGrip, aResponse]) {
let deferred = promise.defer();
const deferred = getDeferredPromise().defer();
let onPaused = function (aEvent, aPacket) {
const onPaused = function(event, packet) {
ok(false, "Pause shouldn't be called before we've attached!");
deferred.reject();
};
@ -65,9 +76,9 @@ function testEarlyDebuggerStatement([aGrip, aResponse]) {
}
function testDebuggerStatement([aGrip, aResponse]) {
let deferred = promise.defer();
const deferred = getDeferredPromise().defer();
gClient.addListener("paused", (aEvent, aPacket) => {
gClient.addListener("paused", (event, packet) => {
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
ok(true, "The pause handler was triggered on a debugger statement.");
deferred.resolve();
@ -80,6 +91,6 @@ function testDebuggerStatement([aGrip, aResponse]) {
return deferred.promise;
}
registerCleanupFunction(function () {
registerCleanupFunction(function() {
gClient = null;
});

Просмотреть файл

@ -3,92 +3,104 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that the eventListeners request works.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-01.html";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-01.html";
add_task(async function() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
let [type, traits] = await client.connect();
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
const [type] = await client.connect();
Assert.equal(type, "browser",
"Root actor should identify itself as a browser.");
let tab = await addTab(TAB_URL);
let threadClient = await attachThreadActorForUrl(client, TAB_URL);
const tab = await addTab(TAB_URL);
const threadClient = await attachThreadActorForUrl(client, TAB_URL);
await pauseDebuggee(tab, client, threadClient);
await testEventListeners(client, threadClient);
await client.close();
});
function pauseDebuggee(aTab, aClient, aThreadClient) {
let deferred = promise.defer();
function pauseDebuggee(tab, client, threadClient) {
const deferred = getDeferredPromise().defer();
aClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
client.addOneTimeListener("paused", (event, packet) => {
is(packet.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
is(packet.why.type, "debuggerStatement",
"The debugger statement was hit.");
deferred.resolve(aThreadClient);
deferred.resolve(threadClient);
});
generateMouseClickInTab(aTab, "content.document.querySelector('button')");
generateMouseClickInTab(tab, "content.document.querySelector('button')");
return deferred.promise;
}
async function testEventListeners(aClient, aThreadClient) {
let packet = await aThreadClient.eventListeners();
async function testEventListeners(client, threadClient) {
const packet = await threadClient.eventListeners();
if (packet.error) {
let msg = "Error getting event listeners: " + packet.message;
const msg = "Error getting event listeners: " + packet.message;
Assert.ok(false, msg);
return;
}
is(packet.listeners.length, 3, "Found all event listeners.");
let listeners = await promise.all(packet.listeners.map(listener => {
const lDeferred = promise.defer();
aThreadClient.pauseGrip(listener.function).getDefinitionSite(aResponse => {
if (aResponse.error) {
const msg = "Error getting function definition site: " + aResponse.message;
const listeners = await getDeferredPromise().all(packet.listeners.map(listener => {
const lDeferred = getDeferredPromise().defer();
threadClient.pauseGrip(listener.function).getDefinitionSite(response => {
if (response.error) {
const msg = "Error getting function definition site: " + response.message;
ok(false, msg);
lDeferred.reject(msg);
return;
}
listener.function.url = aResponse.source.url;
listener.function.url = response.source.url;
lDeferred.resolve(listener);
});
return lDeferred.promise;
}));
let types = [];
const types = [];
for (let l of listeners) {
for (const l of listeners) {
info("Listener for the " + l.type + " event.");
let node = l.node;
const node = l.node;
ok(node, "There is a node property.");
ok(node.object, "There is a node object property.");
if (node.selector != "window") {
let nodeCount =
await ContentTask.spawn(gBrowser.selectedBrowser, node.selector, async (selector) => {
return content.document.querySelectorAll(selector).length;
});
const nodeCount =
await ContentTask.spawn(gBrowser.selectedBrowser, node.selector,
async (selector) => {
return content.document.querySelectorAll(selector).length;
});
Assert.equal(nodeCount, 1, "The node property is a unique CSS selector.");
} else {
Assert.ok(true, "The node property is a unique CSS selector.");
}
let func = l.function;
const func = l.function;
ok(func, "There is a function property.");
is(func.type, "object", "The function form is of type 'object'.");
is(func.class, "Function", "The function form is of class 'Function'.");
@ -128,5 +140,5 @@ async function testEventListeners(aClient, aThreadClient) {
Assert.ok(types.includes("change"), "Found the change handler.");
Assert.ok(types.includes("keyup"), "Found the keyup handler.");
await aThreadClient.resume();
await threadClient.resume();
}

Просмотреть файл

@ -3,54 +3,64 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that the eventListeners request works when bound functions are used as
* event listeners.
*/
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-03.html";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-03.html";
add_task(async function() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
let [type, traits] = await client.connect();
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
const [type] = await client.connect();
Assert.equal(type, "browser",
"Root actor should identify itself as a browser.");
let tab = await addTab(TAB_URL);
let threadClient = await attachThreadActorForUrl(client, TAB_URL);
const tab = await addTab(TAB_URL);
const threadClient = await attachThreadActorForUrl(client, TAB_URL);
await pauseDebuggee(tab, client, threadClient);
await testEventListeners(client, threadClient);
await client.close();
});
function pauseDebuggee(aTab, aClient, aThreadClient) {
let deferred = promise.defer();
function pauseDebuggee(tab, client, threadClient) {
const deferred = getDeferredPromise().defer();
aClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
client.addOneTimeListener("paused", (event, packet) => {
is(packet.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
is(packet.why.type, "debuggerStatement",
"The debugger statement was hit.");
deferred.resolve(aThreadClient);
deferred.resolve(threadClient);
});
generateMouseClickInTab(aTab, "content.document.querySelector('button')");
generateMouseClickInTab(tab, "content.document.querySelector('button')");
return deferred.promise;
}
async function testEventListeners(aClient, aThreadClient) {
let packet = await aThreadClient.eventListeners();
async function testEventListeners(client, threadClient) {
const packet = await threadClient.eventListeners();
if (packet.error) {
let msg = "Error getting event listeners: " + aPacket.message;
const msg = "Error getting event listeners: " + packet.message;
ok(false, msg);
return;
}
@ -58,16 +68,16 @@ async function testEventListeners(aClient, aThreadClient) {
is(packet.listeners.length, 3,
"Found all event listeners.");
let listeners = await promise.all(packet.listeners.map(listener => {
const lDeferred = promise.defer();
aThreadClient.pauseGrip(listener.function).getDefinitionSite(aResponse => {
if (aResponse.error) {
const msg = "Error getting function definition site: " + aResponse.message;
const listeners = await getDeferredPromise().all(packet.listeners.map(listener => {
const lDeferred = getDeferredPromise().defer();
threadClient.pauseGrip(listener.function).getDefinitionSite(response => {
if (response.error) {
const msg = "Error getting function definition site: " + response.message;
ok(false, msg);
lDeferred.reject(msg);
return;
}
listener.function.url = aResponse.source.url;
listener.function.url = response.source.url;
lDeferred.resolve(listener);
});
return lDeferred.promise;
@ -75,22 +85,23 @@ async function testEventListeners(aClient, aThreadClient) {
Assert.equal(listeners.length, 3, "Found three event listeners.");
for (let l of listeners) {
let node = l.node;
for (const l of listeners) {
const node = l.node;
ok(node, "There is a node property.");
ok(node.object, "There is a node object property.");
if (node.selector != "window") {
let nodeCount =
await ContentTask.spawn(gBrowser.selectedBrowser, node.selector, async (selector) => {
return content.document.querySelectorAll(selector).length;
});
const nodeCount =
await ContentTask.spawn(gBrowser.selectedBrowser, node.selector,
async (selector) => {
return content.document.querySelectorAll(selector).length;
});
Assert.equal(nodeCount, 1, "The node property is a unique CSS selector.");
} else {
Assert.ok(true, "The node property is a unique CSS selector.");
}
let func = l.function;
const func = l.function;
ok(func, "There is a function property.");
is(func.type, "object", "The function form is of type 'object'.");
is(func.class, "Function", "The function form is of class 'Function'.");
@ -107,5 +118,5 @@ async function testEventListeners(aClient, aThreadClient) {
"Capturing property has the right value.");
}
await aThreadClient.resume();
await threadClient.resume();
}

Просмотреть файл

@ -3,12 +3,23 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that the eventListeners request works when there are event handlers
* that the debugger cannot unwrap.
*/
const TAB_URL = EXAMPLE_URL + "doc_native-event-handler.html";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
const TAB_URL = TEST_URI_ROOT + "doc_native-event-handler.html";
var gClient;
var gTab;
@ -17,37 +28,37 @@ function test() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let transport = DebuggerServer.connectPipe();
const transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser",
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then((aTab) => {
gTab = aTab;
.then((tab) => {
gTab = tab;
return attachThreadActorForUrl(gClient, TAB_URL);
})
.then(pauseDebuggee)
.then(testEventListeners)
.then(() => gClient.close())
.then(finish)
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
.catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
});
}
function pauseDebuggee(aThreadClient) {
let deferred = promise.defer();
function pauseDebuggee(threadClient) {
const deferred = getDeferredPromise().defer();
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
is(aPacket.type, "paused",
gClient.addOneTimeListener("paused", (event, packet) => {
is(packet.type, "paused",
"We should now be paused.");
is(aPacket.why.type, "debuggerStatement",
is(packet.why.type, "debuggerStatement",
"The debugger statement was hit.");
deferred.resolve(aThreadClient);
deferred.resolve(threadClient);
});
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
@ -55,12 +66,12 @@ function pauseDebuggee(aThreadClient) {
return deferred.promise;
}
function testEventListeners(aThreadClient) {
let deferred = promise.defer();
function testEventListeners(threadClient) {
const deferred = getDeferredPromise().defer();
aThreadClient.eventListeners(aPacket => {
if (aPacket.error) {
let msg = "Error getting event listeners: " + aPacket.message;
threadClient.eventListeners(packet => {
if (packet.error) {
const msg = "Error getting event listeners: " + packet.message;
ok(false, msg);
deferred.reject(msg);
return;
@ -69,13 +80,13 @@ function testEventListeners(aThreadClient) {
// There are 2 event listeners in the page: button.onclick, window.onload.
// The video element controls listeners are skipped — they cannot be
// unwrapped but they shouldn't cause us to throw either.
is(aPacket.listeners.length, 2, "Found all event listeners.");
aThreadClient.resume(deferred.resolve);
is(packet.listeners.length, 2, "Found all event listeners.");
threadClient.resume(deferred.resolve);
});
return deferred.promise;
}
registerCleanupFunction(function () {
registerCleanupFunction(function() {
gClient = null;
});

Просмотреть файл

@ -5,16 +5,14 @@
"use strict";
/* import-globals-from helper_addons.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_addons.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
const chromeRegistry =
Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
const DEBUGGER_CHROME_URL = "chrome://mochitests/content/browser/devtools/client/shared/test/";
const DEBUGGER_CHROME_URI = Services.io.newURI(DEBUGGER_CHROME_URL);
var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
/**
* Make sure the listAddons request works as specified.
*/
@ -118,48 +116,3 @@ registerCleanupFunction(function() {
gAddon2 = null;
gClient = null;
});
function getAddonURIFromPath(path) {
const chromeURI = Services.io.newURI(path, null, DEBUGGER_CHROME_URI);
return chromeRegistry.convertChromeURL(chromeURI).QueryInterface(Ci.nsIFileURL);
}
function addTemporaryAddon(path) {
const addonFile = getAddonURIFromPath(path).file;
info("Installing addon: " + addonFile.path);
return AddonManager.installTemporaryAddon(addonFile);
}
function getAddonActorForId(client, addonId) {
info("Get addon actor for ID: " + addonId);
const deferred = promise.defer();
client.listAddons().then(response => {
const addonTargetActor = response.addons.filter(grip => grip.id == addonId).pop();
info("got addon actor for ID: " + addonId);
deferred.resolve(addonTargetActor);
});
return deferred.promise;
}
function removeAddon(addon) {
info("Removing addon.");
const deferred = promise.defer();
const listener = {
onUninstalled: function(uninstalledAddon) {
if (uninstalledAddon != addon) {
return;
}
AddonManager.removeAddonListener(listener);
deferred.resolve();
},
};
AddonManager.addAddonListener(listener);
addon.uninstall();
return deferred.promise;
}

Просмотреть файл

@ -0,0 +1,73 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
var TAB_URL = EXAMPLE_URL + "doc_listworkers-tab.html";
var WORKER1_URL = "code_listworkers-worker1.js";
var WORKER2_URL = "code_listworkers-worker2.js";
add_task(async function test() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
const client = new DebuggerClient(DebuggerServer.connectPipe());
await connect(client);
const tab = await addTab(TAB_URL);
const { tabs } = await listTabs(client);
const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
let { workers } = await listWorkers(targetFront);
is(workers.length, 0);
executeSoon(() => {
evalInTab(tab, "var worker1 = new Worker('" + WORKER1_URL + "');");
});
await waitForWorkerListChanged(targetFront);
({ workers } = await listWorkers(targetFront));
is(workers.length, 1);
is(workers[0].url, WORKER1_URL);
executeSoon(() => {
evalInTab(tab, "var worker2 = new Worker('" + WORKER2_URL + "');");
});
await waitForWorkerListChanged(targetFront);
({ workers } = await listWorkers(targetFront));
is(workers.length, 2);
is(workers[0].url, WORKER1_URL);
is(workers[1].url, WORKER2_URL);
executeSoon(() => {
evalInTab(tab, "worker1.terminate()");
});
await waitForWorkerListChanged(targetFront);
({ workers } = await listWorkers(targetFront));
is(workers.length, 1);
is(workers[0].url, WORKER2_URL);
executeSoon(() => {
evalInTab(tab, "worker2.terminate()");
});
await waitForWorkerListChanged(targetFront);
({ workers } = await listWorkers(targetFront));
is(workers.length, 0);
await close(client);
finish();
});

Просмотреть файл

@ -3,13 +3,19 @@
"use strict";
// Import helpers for the workers
/* import-globals-from helper_workers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
this);
// The following "connectionClosed" rejection should not be left uncaught. This
// test has been whitelisted until the issue is fixed.
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.expectUncaughtRejection(/[object Object]/);
var TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
var WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
const TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
const WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
add_task(async function() {
await pushPrefs(["devtools.scratchpad.enabled", true]);
@ -17,21 +23,21 @@ add_task(async function() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let client = new DebuggerClient(DebuggerServer.connectPipe());
const client = new DebuggerClient(DebuggerServer.connectPipe());
await connect(client);
let tab = await addTab(TAB_URL);
let { tabs } = await listTabs(client);
let [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
const tab = await addTab(TAB_URL);
const { tabs } = await listTabs(client);
const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
await listWorkers(targetFront);
await createWorkerInTab(tab, WORKER_URL);
let { workers } = await listWorkers(targetFront);
let [, workerTargetFront] = await attachWorker(targetFront,
const { workers } = await listWorkers(targetFront);
const [, workerTargetFront] = await attachWorker(targetFront,
findWorker(workers, WORKER_URL));
let toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
const toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
"jsdebugger",
Toolbox.HostType.WINDOW);
@ -48,8 +54,8 @@ add_task(async function() {
ok(toolbox.win.parent.document.title.includes(WORKER_URL),
"worker URL in host title");
let toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
let activeTools = [...toolTabs].map(tab=>tab.getAttribute("data-id"));
const toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
const activeTools = [...toolTabs].map(toolTab => toolTab.getAttribute("data-id"));
is(activeTools.join(","), "webconsole,jsdebugger,scratchpad",
"Correct set of tools supported by worker");

Просмотреть файл

@ -0,0 +1,3 @@
"use strict";
self.onmessage = function() {};

Просмотреть файл

@ -0,0 +1,3 @@
"use strict";
self.onmessage = function() {};

Просмотреть файл

@ -12,10 +12,12 @@
<input type="text" onchange="changeHandler()">
<script type="text/javascript">
window.addEventListener("load", function () {
"use strict";
window.addEventListener("load", function() {
function initialSetup(event) {
debugger;
var button = document.querySelector("button");
const button = document.querySelector("button");
button.onclick = clickHandler;
}
function clickHandler(event) {
@ -28,10 +30,10 @@
window.foobar = "keyupHandler";
}
var button = document.querySelector("button");
const button = document.querySelector("button");
button.onclick = initialSetup;
var input = document.querySelector("input");
const input = document.querySelector("input");
input.addEventListener("keyup", keyupHandler, true);
window.changeHandler = changeHandler;

Просмотреть файл

@ -14,9 +14,11 @@
<button id="boundHandleEventClick">boundHandleEventClick</button>
<script type="text/javascript">
window.addEventListener("load", function () {
"use strict";
window.addEventListener("load", function() {
function initialSetup(event) {
var button = document.getElementById("initialSetup");
const button = document.getElementById("initialSetup");
button.removeEventListener("click", initialSetup);
debugger;
}
@ -26,7 +28,7 @@
}
function handleEventClick() {
var button = document.getElementById("handleEventClick");
const button = document.getElementById("handleEventClick");
// Create a long prototype chain to test for weird edge cases.
button.addEventListener("click", Object.create(Object.create(this)));
}
@ -36,7 +38,7 @@
};
function boundHandleEventClick() {
var button = document.getElementById("boundHandleEventClick");
const button = document.getElementById("boundHandleEventClick");
this.handleEvent = this.handleEvent.bind(this);
button.addEventListener("click", this);
}
@ -45,15 +47,15 @@
window.foobar = "boundHandleEventClick";
};
var button = document.getElementById("clicker");
const button = document.getElementById("clicker");
// Bind more than once to test for weird edge cases.
var boundClicker = clicker.bind(this).bind(this).bind(this);
const boundClicker = clicker.bind(this).bind(this).bind(this);
button.addEventListener("click", boundClicker);
new handleEventClick();
new boundHandleEventClick();
var initButton = document.getElementById("initialSetup");
const initButton = document.getElementById("initialSetup");
initButton.addEventListener("click", initialSetup);
}, {once: true});
</script>

Просмотреть файл

@ -12,6 +12,7 @@
<button>Click me!</button>
<script type="text/javascript">
"use strict";
function runDebuggerStatement() {
debugger;
}

Просмотреть файл

@ -6,6 +6,8 @@
<meta charset="utf-8">
<title>A video element with native event handlers</title>
<script type="text/javascript">
"use strict";
function initialSetup(event) {
debugger;
}

Просмотреть файл

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */
"use strict";
const chromeRegistry =
Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
const DEBUGGER_CHROME_URL = "chrome://mochitests/content/browser/devtools/client/shared/test/";
const DEBUGGER_CHROME_URI = Services.io.newURI(DEBUGGER_CHROME_URL);
const EventEmitter = require("devtools/shared/event-emitter");
var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
/**
* Returns a thenable promise
* @return {Promise}
*/
function getDeferredPromise() {
// Override promise with deprecated-sync-thenables
const promise = require("devtools/shared/deprecated-sync-thenables");
return promise;
}
function getAddonURIFromPath(path) {
const chromeURI = Services.io.newURI(path, null, DEBUGGER_CHROME_URI);
return chromeRegistry.convertChromeURL(chromeURI).QueryInterface(Ci.nsIFileURL);
}
function addTemporaryAddon(path) {
const addonFile = getAddonURIFromPath(path).file;
info("Installing addon: " + addonFile.path);
return AddonManager.installTemporaryAddon(addonFile);
}
function getAddonActorForId(client, addonId) {
info("Get addon actor for ID: " + addonId);
const deferred = getDeferredPromise().defer();
client.listAddons().then(response => {
const addonTargetActor = response.addons.filter(grip => grip.id == addonId).pop();
info("got addon actor for ID: " + addonId);
deferred.resolve(addonTargetActor);
});
return deferred.promise;
}
function removeAddon(addon) {
info("Removing addon.");
const deferred = getDeferredPromise().defer();
const listener = {
onUninstalled: function(uninstalledAddon) {
if (uninstalledAddon != addon) {
return;
}
AddonManager.removeAddonListener(listener);
deferred.resolve();
},
};
AddonManager.addAddonListener(listener);
addon.uninstall();
return deferred.promise;
}

Просмотреть файл

@ -12,13 +12,16 @@ Services.scriptloader.loadSubScript(
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
var { Toolbox } = require("devtools/client/framework/toolbox");
const FRAME_SCRIPT_URL = getRootDirectory(gTestPath) + "code_frame-script.js";
var nextId = 0;
/**
* Returns a thenable promise
* @return {Promise}
*/
function getDeferredPromise() {
// Override promise with deprecated-sync-thenables
const promise = require("devtools/shared/deprecated-sync-thenables");
@ -68,6 +71,24 @@ function postMessageToWorkerInTab(tab, url, message) {
return jsonrpc(tab, "postMessageToWorker", [url, message]);
}
function generateMouseClickInTab(tab, path) {
info("Generating mouse click in tab.");
return jsonrpc(tab, "generateMouseClick", [path]);
}
function evalInTab(tab, string) {
info("Evalling string in tab.");
return jsonrpc(tab, "_eval", [string]);
}
function callInTab(tab, name) {
info("Calling function with name '" + name + "' in tab.");
return jsonrpc(tab, "call", [name, Array.prototype.slice.call(arguments, 2)]);
}
function connect(client) {
info("Connecting client.");
return client.connect();
@ -118,6 +139,11 @@ function attachWorker(targetFront, worker) {
return targetFront.attachWorker(worker.actor);
}
function waitForWorkerListChanged(targetFront) {
info("Waiting for worker list to change.");
return targetFront.once("workerListChanged");
}
function attachThread(workerTargetFront, options) {
info("Attaching to thread.");
return workerTargetFront.attachThread(options);
@ -221,3 +247,39 @@ this.removeTab = function removeTab(tab, win) {
targetBrowser.removeTab(tab);
return deferred.promise;
};
async function attachTargetActorForUrl(client, url) {
const grip = await getTargetActorForUrl(client, url);
const [ response, front ] = await client.attachTarget(grip.actor);
return [grip, response, front];
}
async function attachThreadActorForUrl(client, url) {
const [, response] = await attachTargetActorForUrl(client, url);
const [, threadClient] = await client.attachThread(response.threadActor);
await threadClient.resume();
return threadClient;
}
function getTargetActorForUrl(client, url) {
const deferred = getDeferredPromise().defer();
client.listTabs().then(response => {
const targetActor = response.tabs.filter(grip => grip.url == url).pop();
deferred.resolve(targetActor);
});
return deferred.promise;
}
function pushPrefs(...aPrefs) {
const deferred = getDeferredPromise().defer();
SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
return deferred.promise;
}
function popPrefs() {
const deferred = getDeferredPromise().defer();
SpecialPowers.popPrefEnv(deferred.resolve);
return deferred.promise;
}

Просмотреть файл

@ -9,7 +9,6 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/MessageManagerGlobal.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "nsContentUtils.h"
#include "xpcpublic.h"

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/MessageManagerBinding.h"
#include "mozilla/dom/ParentProcessMessageManager.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ipc/SharedMap.h"

Просмотреть файл

@ -47,7 +47,6 @@
#include "mozilla/dom/ParentProcessMessageManager.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/ProcessMessageManager.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/SameProcessMessageQueue.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ToJSValue.h"

Просмотреть файл

@ -56,7 +56,6 @@
#include "mozilla/dom/XULPopupElementBinding.h"
#include "mozilla/dom/XULTextElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
@ -3512,29 +3511,6 @@ UnwrapWindowProxyImpl(JSContext* cx,
return NS_OK;
}
bool
SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, bool* resolvedp)
{
if (!ResolveGlobal(cx, obj, id, resolvedp)) {
return false;
}
if (*resolvedp) {
return true;
}
return ResolveSystemBinding(cx, obj, id, resolvedp);
}
bool
SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
{
bool ignored = false;
return JS_EnumerateStandardClasses(cx, obj) &&
ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
}
template<decltype(JS::NewMapObject) Method>
bool
GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,

Просмотреть файл

@ -13576,121 +13576,6 @@ class CGRegisterWorkletBindings(CGAbstractMethod):
return CGList(lines, "\n").define()
class CGSystemBindingInitIds(CGAbstractMethod):
def __init__(self):
CGAbstractMethod.__init__(self, None, 'SystemBindingInitIds', 'bool',
[Argument('JSContext*', 'aCx')])
def definition_body(self):
return dedent("""
MOZ_ASSERT(NS_IsMainThread());
if (!idsInited) {
// We can't use range-based for because we need the index to call IdString.
for (uint32_t i = 0; i < ArrayLength(properties); ++i) {
if (!properties[i].id.init(aCx, IdString(i))) {
return false;
}
}
idsInited = true;
}
return true;
""")
class CGResolveSystemBinding(CGAbstractMethod):
def __init__(self):
CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool',
[Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aObj'),
Argument('JS::Handle<jsid>', 'aId'),
Argument('bool*', 'aResolvedp')])
def definition_body(self):
return dedent("""
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(idsInited);
if (JSID_IS_VOID(aId)) {
for (const auto& property : properties) {
if (!property.enabled || property.enabled(aCx, aObj)) {
if (!property.define(aCx)) {
return false;
}
*aResolvedp = true;
}
}
return true;
}
for (const auto& property : properties) {
if (property.id == aId) {
if (!property.enabled || property.enabled(aCx, aObj)) {
if (!property.define(aCx)) {
return false;
}
*aResolvedp = true;
break;
}
}
}
return true;
""")
class CGMayResolveAsSystemBindingName(CGAbstractMethod):
def __init__(self):
CGAbstractMethod.__init__(self, None, 'MayResolveAsSystemBindingName', 'bool',
[Argument('jsid', 'aId')])
def definition_body(self):
return dedent("""
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(idsInited);
for (const auto& property : properties) {
if (aId == property.id) {
return true;
}
}
return false;
""")
class CGGetSystemBindingNames(CGAbstractMethod):
def __init__(self):
CGAbstractMethod.__init__(self, None, 'GetSystemBindingNames', 'void',
[Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aObj'),
Argument('JS::AutoIdVector&', 'aNames'),
Argument('bool', 'aEnumerableOnly'),
Argument('mozilla::ErrorResult&', 'aRv')])
def definition_body(self):
return dedent("""
MOZ_ASSERT(NS_IsMainThread());
if (aEnumerableOnly) {
return;
}
if (!SystemBindingInitIds(aCx)) {
aRv.NoteJSContextException(aCx);
return;
}
for (const auto& property : properties) {
if (!property.enabled || property.enabled(aCx, aObj)) {
if (!aNames.append(property.id)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
}
""")
def getGlobalNames(config):
names = []
for desc in config.getDescriptors(registersGlobalNamesOnWindow=True):
@ -17259,70 +17144,6 @@ class GlobalGenRoots():
# Done.
return curr
@staticmethod
def ResolveSystemBinding(config):
curr = CGList([], "\n")
descriptors = config.getDescriptors(hasInterfaceObject=True,
isExposedInWindow=True,
register=True)
properties = [desc.name for desc in descriptors]
curr.append(CGStringTable("IdString", properties, static=True))
initValues = []
for desc in descriptors:
bindingNS = toBindingNamespace(desc.name)
if desc.isExposedConditionally():
enabled = "%s::ConstructorEnabled" % bindingNS
else:
enabled = "nullptr"
define = "%s::GetConstructorObject" % bindingNS
initValues.append("{ %s, %s },\n" % (enabled, define))
curr.append(CGGeneric(fill("""
struct SystemProperty
{
WebIDLGlobalNameHash::ConstructorEnabled enabled;
ProtoGetter define;
PinnedStringId id;
};
static SystemProperty properties[] = {
$*{init}
};
static bool idsInited = false;
""",
init="".join(initValues))))
curr.append(CGSystemBindingInitIds())
curr.append(CGResolveSystemBinding())
curr.append(CGMayResolveAsSystemBindingName())
curr.append(CGGetSystemBindingNames())
# Wrap all of that in our namespaces.
curr = CGNamespace.build(['mozilla', 'dom'],
CGWrapper(curr, post='\n'))
curr = CGWrapper(curr, post='\n')
# Add the includes
defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
for desc in config.getDescriptors(hasInterfaceObject=True,
register=True,
isExposedInWindow=True)]
defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread
defineIncludes.append("js/Id.h") # For jsid
defineIncludes.append("mozilla/dom/WebIDLGlobalNameHash.h")
curr = CGHeaders([], [], [], [], [], defineIncludes,
'ResolveSystemBinding', curr)
# Add include guards.
curr = CGIncludeGuard('ResolveSystemBinding', curr)
# Done.
return curr
@staticmethod
def UnionTypes(config):
unionTypes = UnionsForFile(config, None)

Просмотреть файл

@ -206,5 +206,79 @@ WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
return true;
}
/* static */
bool
WebIDLGlobalNameHash::ResolveForSystemGlobal(JSContext* aCx,
JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
bool* aResolvedp)
{
MOZ_ASSERT(JS_IsGlobalObject(aObj));
// First we try to resolve standard classes.
if (!JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp)) {
return false;
}
if (*aResolvedp) {
return true;
}
// We don't resolve any non-string entries.
if (!JSID_IS_STRING(aId)) {
return true;
}
// XXX(nika): In the Window case, we unwrap our global object here to handle
// XRays. I don't think we ever create xrays to system globals, so I believe
// we can skip this step.
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(aObj), "Xrays not supported!");
// Look up the corresponding entry in the name table, and resolve if enabled.
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_FLAT_STRING(aId));
if (entry && (!entry->mEnabled || entry->mEnabled(aCx, aObj))) {
if (NS_WARN_IF(!GetPerInterfaceObjectHandle(aCx, entry->mConstructorId,
entry->mCreate,
/* aDefineOnGlobal = */ true))) {
return Throw(aCx, NS_ERROR_FAILURE);
}
*aResolvedp = true;
}
return true;
}
/* static */
bool
WebIDLGlobalNameHash::NewEnumerateSystemGlobal(JSContext* aCx,
JS::Handle<JSObject*> aObj,
JS::AutoIdVector& aProperties,
bool aEnumerableOnly)
{
MOZ_ASSERT(JS_IsGlobalObject(aObj));
if (!JS_NewEnumerateStandardClasses(aCx, aObj, aProperties, aEnumerableOnly)) {
return false;
}
// All properties defined on our global are non-enumerable, so we can skip
// remaining properties.
if (aEnumerableOnly) {
return true;
}
// Enumerate all entries & add enabled ones.
for (size_t i = 0; i < sCount; ++i) {
const WebIDLNameTableEntry& entry = sEntries[i];
if (!entry.mEnabled || entry.mEnabled(aCx, aObj)) {
JSString* str = JS_AtomizeStringN(aCx, sNames + entry.mNameOffset,
entry.mNameLength);
if (!str || !aProperties.append(NON_INTEGER_ATOM_TO_JSID(str))) {
return false;
}
}
}
return true;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -64,6 +64,17 @@ public:
NameType aNameType,
JS::AutoIdVector& aNames);
// Helpers for resolving & enumerating names on the system global.
// NOTE: These are distinct as it currently lacks a ProtoAndIfaceCache, and is
// an XPCOM global.
static bool ResolveForSystemGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId, bool* aResolvedp);
static bool NewEnumerateSystemGlobal(JSContext* aCx,
JS::Handle<JSObject*> aObj,
JS::AutoIdVector& aProperties,
bool aEnumerableOnly);
private:
friend struct WebIDLNameTableEntry;

Просмотреть файл

@ -134,7 +134,6 @@ class WebIDLCodegenManager(LoggingMixin):
'RegisterWorkerBindings.h',
'RegisterWorkerDebuggerBindings.h',
'RegisterWorkletBindings.h',
'ResolveSystemBinding.h',
'UnionConversions.h',
'UnionTypes.h',
}
@ -145,7 +144,6 @@ class WebIDLCodegenManager(LoggingMixin):
'RegisterWorkerBindings.cpp',
'RegisterWorkerDebuggerBindings.cpp',
'RegisterWorkletBindings.cpp',
'ResolveSystemBinding.cpp',
'UnionTypes.cpp',
'PrototypeList.cpp',
}

Просмотреть файл

@ -36,17 +36,17 @@ FeaturePolicy::InheritPolicy(FeaturePolicy* aParentPolicy)
RefPtr<FeaturePolicy> dest = this;
RefPtr<FeaturePolicy> src = aParentPolicy;
nsCOMPtr<nsIPrincipal> origin = mDefaultOrigin;
FeaturePolicyUtils::ForEachFeature([dest, src, origin](const char* aFeatureName) {
FeaturePolicyUtils::ForEachFeature([dest, src](const char* aFeatureName) {
nsString featureName;
featureName.AppendASCII(aFeatureName);
// If the destination has a declared feature (via the HTTP header or 'allow'
// attribute) we allow the feature only if both parent FeaturePolicy and this
// one allow the current origin.
if (dest->HasDeclaredFeature(featureName)) {
if (!dest->AllowsFeatureInternal(featureName, origin) ||
!src->AllowsFeatureInternal(featureName, origin)) {
// attribute) we allow the feature if the destination allows it and the
// parent allows its origin or the destinations' one.
if (dest->HasDeclaredFeature(featureName) &&
dest->AllowsFeatureInternal(featureName, dest->mDefaultOrigin)) {
if (!src->AllowsFeatureInternal(featureName, src->mDefaultOrigin) &&
!src->AllowsFeatureInternal(featureName, dest->mDefaultOrigin)) {
dest->SetInheritedDeniedFeature(featureName);
}
return;
@ -54,7 +54,7 @@ FeaturePolicy::InheritPolicy(FeaturePolicy* aParentPolicy)
// If there was not a declared feature, we allow the feature if the parent
// FeaturePolicy allows the current origin.
if (!src->AllowsFeatureInternal(featureName, origin)) {
if (!src->AllowsFeatureInternal(featureName, dest->mDefaultOrigin)) {
dest->SetInheritedDeniedFeature(featureName);
}
});

Просмотреть файл

@ -446,10 +446,12 @@ APZUpdater::RunOnControllerThread(LayersId aLayersId, already_AddRefed<Runnable>
{
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
RefPtr<Runnable> task = aTask;
RunOnUpdaterThread(aLayersId, NewRunnableFunction(
"APZUpdater::RunOnControllerThread",
&APZThreadUtils::RunOnControllerThread,
std::move(aTask)));
std::move(task)));
}
bool

Просмотреть файл

@ -41,9 +41,9 @@ APZThreadUtils::AssertOnControllerThread() {
}
/*static*/ void
APZThreadUtils::RunOnControllerThread(already_AddRefed<Runnable> aTask)
APZThreadUtils::RunOnControllerThread(RefPtr<Runnable>&& aTask)
{
RefPtr<Runnable> task = aTask;
RefPtr<Runnable> task = std::move(aTask);
if (!sControllerThread) {
// Could happen on startup

Просмотреть файл

@ -45,7 +45,7 @@ public:
* this function is called from the controller thread itself then the task is
* run immediately without getting queued.
*/
static void RunOnControllerThread(already_AddRefed<Runnable> aTask);
static void RunOnControllerThread(RefPtr<Runnable>&& aTask);
/**
* Returns true if currently on APZ "controller thread".

Просмотреть файл

@ -292,9 +292,12 @@ ClipManager::DefineScrollLayers(const ActiveScrolledRoot* aASR,
Maybe<ScrollMetadata> metadata = aASR->mScrollableFrame->ComputeScrollMetadata(
mManager, aItem->ReferenceFrame(), Nothing(), nullptr);
MOZ_ASSERT(metadata);
FrameMetrics& metrics = metadata->GetMetrics();
if (!metadata) {
MOZ_ASSERT_UNREACHABLE("Expected scroll metadata to be available!");
return ancestorScrollId;
}
FrameMetrics& metrics = metadata->GetMetrics();
if (!metrics.IsScrollable()) {
// This item is a scrolling no-op, skip over it in the ASR chain.
return ancestorScrollId;

Просмотреть файл

@ -79,7 +79,8 @@ interface nsIXPCScriptable : nsISupports
boolean newEnumerate(in nsIXPConnectWrappedNative wrapper,
in JSContextPtr cx, in JSObjectPtr obj,
in JSAutoIdVector properties);
in JSAutoIdVector properties,
in boolean enumerableOnly);
boolean resolve(in nsIXPConnectWrappedNative wrapper,
in JSContextPtr cx, in JSObjectPtr obj, in jsid id,

Просмотреть файл

@ -65,7 +65,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreate(nsISupports* nativeObj, JSContext * c
#endif
#if !((XPC_MAP_FLAGS) & XPC_SCRIPTABLE_WANT_NEWENUMERATE)
NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, JS::AutoIdVector& properties, bool* _retval)
NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, JS::AutoIdVector& properties, bool enumerableOnly, bool* _retval)
{NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
#endif

Просмотреть файл

@ -207,6 +207,7 @@ NS_IMETHODIMP
nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj,
JS::AutoIdVector& properties,
bool enumerableOnly,
bool* _retval)
{
@ -394,6 +395,7 @@ NS_IMETHODIMP
nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj,
JS::AutoIdVector& properties,
bool enumerableOnly,
bool* _retval)
{
@ -589,6 +591,7 @@ NS_IMETHODIMP
nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj,
JS::AutoIdVector& properties,
bool enumerableOnly,
bool* _retval)
{
nsCOMPtr<nsIComponentRegistrar> compMgr;
@ -784,6 +787,7 @@ NS_IMETHODIMP
nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj,
JS::AutoIdVector& properties,
bool enumerableOnly,
bool* _retval)
{
@ -993,6 +997,7 @@ NS_IMETHODIMP
nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj,
JS::AutoIdVector& properties,
bool enumerableOnly,
bool* _retval)
{
const char* name;

Просмотреть файл

@ -10,6 +10,9 @@
#include "BackstagePass.h"
#include "nsIPrincipal.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(BackstagePass,
nsIXPCScriptable,
@ -18,11 +21,15 @@ NS_IMPL_ISUPPORTS(BackstagePass,
nsIScriptObjectPrincipal,
nsISupportsWeakReference)
// XXX(nika): It appears we don't have support for mayresolve hooks in
// nsIXPCScriptable, and I don't really want to add it because I'd rather just
// kill nsIXPCScriptable alltogether, so we don't use it here.
// The nsIXPCScriptable map declaration that will generate stubs for us...
#define XPC_MAP_CLASSNAME BackstagePass
#define XPC_MAP_QUOTED_CLASSNAME "BackstagePass"
#define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_RESOLVE | \
XPC_SCRIPTABLE_WANT_ENUMERATE | \
XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
XPC_SCRIPTABLE_WANT_FINALIZE | \
XPC_SCRIPTABLE_WANT_PRECREATE | \
XPC_SCRIPTABLE_USE_JSSTUB_FOR_ADDPROPERTY | \
@ -58,17 +65,21 @@ BackstagePass::Resolve(nsIXPConnectWrappedNative* wrapper,
{
JS::RootedObject obj(cx, objArg);
JS::RootedId id(cx, idArg);
*_retval = mozilla::dom::SystemGlobalResolve(cx, obj, id, resolvedp);
*_retval =
WebIDLGlobalNameHash::ResolveForSystemGlobal(cx, obj, id, resolvedp);
return *_retval ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
BackstagePass::Enumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* objArg, bool* _retval)
BackstagePass::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* objArg, JS::AutoIdVector& properties,
bool enumerableOnly, bool* _retval)
{
JS::RootedObject obj(cx, objArg);
*_retval = mozilla::dom::SystemGlobalEnumerate(cx, obj);
return *_retval ? NS_OK : NS_ERROR_FAILURE;
*_retval =
WebIDLGlobalNameHash::NewEnumerateSystemGlobal(cx, obj, properties,
enumerableOnly);
return *_retval ? NS_OK : NS_ERROR_FAILURE;
}
/***************************************************************************/

Просмотреть файл

@ -941,7 +941,8 @@ XPC_WN_NewEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
}
bool retval = true;
nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties, &retval);
nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties,
enumerableOnly, &retval);
if (NS_FAILED(rv)) {
return Throw(rv, cx);
}

Просмотреть файл

@ -27,7 +27,6 @@
#include "mozilla/dom/DOMPrefs.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "nsDOMMutationObserver.h"
#include "nsICycleCollectorListener.h"
@ -580,10 +579,6 @@ InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
// we need to have a principal.
MOZ_ASSERT(aPrincipal);
if (!SystemBindingInitIds(aJSContext)) {
return NS_ERROR_FAILURE;
}
InitGlobalObjectOptions(aOptions, aPrincipal);
// Call into XPCWrappedNative to make a new global object, scope, and global

Просмотреть файл

@ -634,6 +634,11 @@ nsFileControlFrame::UpdateDisplayedValue(const nsAString& aValue, bool aNotify)
if (auto* textFrame = static_cast<nsTextFrame*>(text->GetPrimaryFrame())) {
textFrame->NotifyNativeAnonymousTextnodeChange(oldLength);
}
nsBlockFrame* label = do_QueryFrame(mTextContent->GetPrimaryFrame());
if (label && label->LinesBegin() != label->LinesEnd()) {
label->AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
label->LinesBegin()->MarkDirty();
}
}
}

Просмотреть файл

@ -219,17 +219,10 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
// property amounts to anything.
if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowInput->mFrame)) {
const nsStyleCoord &textIndent = mStyleText->mTextIndent;
nscoord pctBasis = 0;
if (textIndent.HasPercent()) {
pctBasis =
mBlockReflowInput->GetContainingBlockContentISize(aWritingMode);
}
nscoord indent = textIndent.ComputeCoordPercentCalc(pctBasis);
mTextIndent = indent;
psd->mICoord += indent;
nscoord pctBasis = mBlockReflowInput->ComputedISize();
mTextIndent = nsLayoutUtils::ResolveToLength<false>(mStyleText->mTextIndent,
pctBasis);
psd->mICoord += mTextIndent;
}
PerFrameData* pfd = NewPerFrameData(mBlockReflowInput->mFrame);

Просмотреть файл

@ -2045,7 +2045,7 @@ skip-if(isDebugBuild&&winWidget) == 1330051.svg 1330051-ref.svg
== 1375674.html 1375674-ref.html
== 1372041.html 1372041-ref.html
== 1376092.html 1376092-ref.html
fuzzy-if(Android&&debug,1-1,1-1) needs-focus == 1377447-1.html 1377447-1-ref.html
fuzzy-if(Android,0-3,0-3) needs-focus == 1377447-1.html 1377447-1-ref.html
needs-focus != 1377447-1.html 1377447-2.html
== 1379041.html 1379041-ref.html
== 1379696.html 1379696-ref.html

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1500530</title>
<style type="text/css">
html,body {
color:black; background-color:black; font:48pt/1 Arial; padding:0; margin:0;
}
div { width: 100px; height: 20px; margin-top: -2px; background: lime; }
</style>
</head>
<body>
<div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Testcase for bug 1500530</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:48pt/1 Arial; padding:0; margin:0;
}
input {
font-family: Arial;
font-size: 48pt;
vertical-align: top;
background: lime;
}
div { text-indent: -24ch; margin-top: -2px; }
mask {
position: absolute;
left: 100px; right: 0; top: 0; bottom: 0;
background: black;
}
mask2 {
position: absolute;
left: 0; right: 0; top: 18px; bottom: 0;
background: black;
}
</style>
</head>
<body>
<mask></mask>
<mask2></mask2>
<div><input type="file"></div>
</body>
</html>

Просмотреть файл

@ -5,4 +5,5 @@ fuzzy-if(gtkWidget||webrender,0-1,0-10) fails-if(Android) == background.html bac
fuzzy-if(gtkWidget,0-1,0-10) fails-if(Android) == style.html style-ref.xul
!= width-clip.html width-clip-ref.html
fails-if(Android) == color-inherit.html color-inherit-ref.html
fuzzy-if(Android,1-2,2-2) fails-if(webrender) == dynamic-max-width.html dynamic-max-width-ref.html # bug 1496542 for webrender.
fuzzy-if(Android,1-2,2-2) fails-if(webrender&&!cocoaWidget) == dynamic-max-width.html dynamic-max-width-ref.html # bug 1496542 for webrender.
== label-min-inline-size.html label-min-inline-size-ref.html

Просмотреть файл

@ -3,7 +3,7 @@
<body>
<div id="x" style="background: lightgreen; height: 3em; width: 500px; padding: 4px;">
<div style="text-indent: 200px; width: 200px; background: yellow;">X</div>
<div style="text-indent: 80px; width: 200px; background: yellow;">X</div>
</div>
</body>

Просмотреть файл

@ -3,7 +3,7 @@
<title>text-indent test</title>
<style type="text/css">
div { width: 500px; }
p { width: 300px; text-indent: 50px; }
p { width: 300px; text-indent: 30px; }
</style>
</head>
<body>

Просмотреть файл

@ -486,6 +486,7 @@ input[type="file"] {
}
input[type="file"] > label {
display: inline-block;
min-inline-size: 12em;
padding-inline-start: 5px;
text-align: match-parent;

Просмотреть файл

@ -1,3 +0,0 @@
[text-indent-percentage-001.xht]
expected:
if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[text-indent-percentage-002.html]
expected: FAIL

Просмотреть файл

@ -1,6 +0,0 @@
[text-indent-percentage-003.html]
expected:
if debug and not webrender and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
if not debug and not webrender and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
if debug and not webrender and e10s and (os == "win") and (version == "10.0.15063") and (processor == "x86_64") and (bits == 64): FAIL
if not debug and not webrender and e10s and (os == "win") and (version == "10.0.15063") and (processor == "x86_64") and (bits == 64): FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[text-indent-percentage-004.html]
expected: FAIL

Просмотреть файл

@ -1,33 +1,12 @@
[feature-policy-frame-policy-allowed-for-self.https.sub.html]
[Test frame policy on sandboxed iframe with allow="fullscreen https://www.web-platform.test:8443".]
expected: FAIL
[Test frame policy on sandboxed iframe with no allow attribute.]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "*".]
[Test frame policy on data: URL origin iframe with allow = "*".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen *;".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'self';".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'none';".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and header policy = "Feature-Policy: fullscreen *;".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and header policy = "Feature-Policy: fullscreen 'self';".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and header policy = "Feature-Policy: fullscreen 'none';".]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "*" and allowfullscreen.]
expected: FAIL
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and allowfullscreen.]
[Test frame policy on data: URL origin iframe with allow = "*" and allowfullscreen.]
expected: FAIL

Просмотреть файл

@ -1,28 +1,6 @@
[feature-policy-frame-policy-allowed-for-some.https.sub.html]
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen *;".]
[Test frame policy on data: URL cross origin iframe with allow = "*".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'self';".]
[Test frame policy on data: URL cross origin iframe with allow = "*" and allowfullscreen.]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'none';".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and allowfullscreen.]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen *;".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'self';".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and header policy = "Feature-Policy: fullscreen 'none';".]
expected: FAIL
[Test frame policy on another cross origin iframe with allow = "*" and allowfullscreen.]
expected: FAIL

Просмотреть файл

@ -32,13 +32,7 @@
margin-top: 0em;
}
div#X
{
float: left;
margin-left: 50%;
}
div#after-X
div
{
background-color: aqua;
width: 25%;
@ -58,9 +52,7 @@
the others should all be<br />
<em>aligned on the left</em> of the window.</p>
<div id="X">X</div>
<div id="after-X"><br />The X on the previous line should be centered across the window.</div>
<div><span style="padding-left:50%">X The first X in this sentence should be indented to the center of this block.</span></div>
</body>
</html>

Просмотреть файл

@ -27,7 +27,7 @@
<em>aligned on the left</em> of the window.
</p>
<div>
X The X on the previous line should be centered across the window.
X The first X in this sentence should be indented to the center of this block.
</div>
</body>
</html>

Просмотреть файл

@ -2,7 +2,7 @@
<title>text-indent test</title>
<style type="text/css">
div { width: 500px; }
p { width: 300px; text-indent: 50px; }
p { width: 300px; text-indent: 30px; }
</style>
</head>
<body>

Просмотреть файл

@ -19,7 +19,7 @@
<body>
<p>Test passes if there is no red visible on the page.</p>
<div id="parent">
<div>X</div>
<div style="padding-left: 100px">X</div>
</div>
<p>Test passes if the following two text blocks look same in terms of margin-left and text-indent respectively.</p>
<div>

Просмотреть файл

@ -4,8 +4,8 @@
<title>CSS Text Test reference</title>
<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
<style>
body { background: white; }
div { padding-left: 50px; }
</style>
<p>Test passes if there is a single black X below and no red.
<div>X</div>

Просмотреть файл

@ -18,7 +18,7 @@
#reference1
{
color: red;
left: 0;
left: 100px; /* see comments for #test1 below */
position: absolute;
top: 0;
z-index: -1;
@ -29,8 +29,8 @@
}
#test1
{
text-indent: 50%;
margin-left: -50%;
margin-left: -50%; /* -50% * 400px = -200px which makes the inline-size of this block 600px */
text-indent: 50%; /* 50% * 600px = 300px (which is 100px from the start of #parent due to the negative margin) */
}
#test2
{

Просмотреть файл

@ -8,7 +8,7 @@
<link rel="match" href="reference/text-indent-percentage-002-ref.html">
<meta name="assert" content="Percentages in text-indent refer to width of the element's content box">
<style>
section { position: absolute; }
body { background: white; }
section, div {
border-right: 10px solid white;
margin-right: 10px;
@ -18,10 +18,7 @@ div {
box-sizing: border-box;
width: 120px;
}
.test div { text-indent: 50%; color: red; }
.ref div { text-indent: 50px; }
.test div { text-indent: 50%; }
</style>
<p>Test passes if there is a single black X below and no red.
<section class=test><div>X</div></section>
<section class=ref><div>X</div></section>

Просмотреть файл

@ -8,7 +8,7 @@
<link rel="match" href="reference/text-indent-percentage-002-ref.html">
<meta name="assert" content="Percentages in text-indent refer to width of the element's content box">
<style>
section { position: absolute; }
body { background: white; }
section, div {
border-right: 10px solid white;
margin-right: 10px;
@ -18,10 +18,7 @@ div {
box-sizing: border-box;
width: 120px;
}
.test div { text-indent: 50%; color: red; overflow: hidden; } /* overflow:hidden should not make any difference, but it does in some browsers */
.ref div { text-indent: 50px; }
.test div { text-indent: 50%; overflow: hidden; } /* overflow:hidden should not make any difference, but it does in some browsers */
</style>
<p>Test passes if there is a single black X below and no red.
<section class=test><div>X</div></section>
<section class=ref><div>X</div></section>

Просмотреть файл

@ -8,7 +8,7 @@
<link rel="match" href="reference/text-indent-percentage-002-ref.html">
<meta name="assert" content="Percentages in text-indent refer to width of the element's content box, when used in a calc expression">
<style>
section { position: absolute; }
body { background: white; }
section, div {
border-right: 10px solid white;
margin-right: 10px;
@ -18,10 +18,7 @@ div {
box-sizing: border-box;
width: 120px;
}
.test div { text-indent: calc(25px + 25%); color: red; }
.ref div { text-indent: 50px; }
.test div { text-indent: calc(25px + 25%); }
</style>
<p>Test passes if there is a single black X below and no red.
<section class=test><div>X</div></section>
<section class=ref><div>X</div></section>

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/Unused.h"
#include "nsASCIIMask.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h"
#include "nsIClearDataService.h"
#include "nsIHttpChannel.h"
@ -20,6 +21,7 @@
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
#include "nsNetUtil.h"
using namespace mozilla;
@ -194,6 +196,26 @@ ClearSiteData::ClearDataFromChannel(nsIHttpChannel* aChannel)
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (NS_WARN_IF(!ssm)) {
return;
}
nsCOMPtr<nsIPrincipal> principal;
rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsCOMPtr<nsIContentSecurityManager> csm =
do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
bool secure;
rv = csm->IsOriginPotentiallyTrustworthy(principal, &secure);
if (NS_WARN_IF(NS_FAILED(rv)) || !secure) {
return;
}
// We want to use the final URI to check if Clear-Site-Data should be allowed
// or not.
rv = aChannel->GetURI(getter_AddRefs(uri));
@ -201,27 +223,12 @@ ClearSiteData::ClearDataFromChannel(nsIHttpChannel* aChannel)
return;
}
if (!IsSecureURI(uri)) {
return;
}
uint32_t flags = ParseHeader(aChannel, uri);
if (flags == 0) {
// Nothing to do.
return;
}
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (NS_WARN_IF(!ssm)) {
return;
}
nsCOMPtr<nsIPrincipal> principal;
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv)) || !principal) {
return;
}
int32_t cleanFlags = 0;
RefPtr<PendingCleanupHolder> holder = new PendingCleanupHolder(aChannel);
@ -264,21 +271,6 @@ ClearSiteData::ClearDataFromChannel(nsIHttpChannel* aChannel)
}
}
bool
ClearSiteData::IsSecureURI(nsIURI* aURI) const
{
MOZ_ASSERT(aURI);
bool prioriAuthenticated = false;
if (NS_WARN_IF(NS_FAILED(NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
&prioriAuthenticated)))) {
return false;
}
return prioriAuthenticated;
}
uint32_t
ClearSiteData::ParseHeader(nsIHttpChannel* aChannel, nsIURI* aURI) const
{

Просмотреть файл

@ -39,11 +39,6 @@ private:
void
ClearDataFromChannel(nsIHttpChannel* aChannel);
// This method checks if the protocol handler of the URI has the
// URI_IS_POTENTIALLY_TRUSTWORTHY flag.
bool
IsSecureURI(nsIURI* aURI) const;
// From the Clear-Site-Data header, it returns a bitmap with Type values.
uint32_t
ParseHeader(nsIHttpChannel* aChannel, nsIURI* aURI) const;

Просмотреть файл

@ -668,6 +668,10 @@ class MozFindbar extends XULElement {
this.setAttribute("noanim", true);
this.hidden = true;
let event = document.createEvent("Events");
event.initEvent("findbarclose", true, false);
this.dispatchEvent(event);
// 'focusContent()' iterates over all listeners in the chrome
// process, so we need to call it from here.
this.browser.finder.focusContent();

Просмотреть файл

@ -14,18 +14,7 @@
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="tree-base" extends="chrome://global/content/bindings/general.xml#basecontrol">
<implementation>
<method name="_isAccelPressed">
<parameter name="aEvent"/>
<body><![CDATA[
return aEvent.getModifierState("Accel");
]]></body>
</method>
</implementation>
</binding>
<binding id="tree" extends="chrome://global/content/bindings/tree.xml#tree-base">
<binding id="tree" extends="chrome://global/content/bindings/general.xml#basecontrol">
<content hidevscroll="true" hidehscroll="true" clickthrough="never">
<children includes="treecols"/>
<xul:stack class="tree-stack" flex="1">
@ -416,7 +405,7 @@
if (this.view.rowCount == 0)
return;
if (this._isAccelPressed(event) && this.view.selection.single) {
if (event.getModifierState("Accel") && this.view.selection.single) {
this.treeBoxObject.scrollByLines(offset);
return;
}
@ -428,7 +417,7 @@
c = edge;
}
if (!this._isAccelPressed(event))
if (!event.getModifierState("Accel"))
this.view.selection.timedSelect(c, this._selectDelay);
else // Ctrl+Up/Down moves the anchor without selecting
this.currentIndex = c;
@ -469,7 +458,7 @@
// Extend the selection from the existing pivot, if any
this.view.selection.rangedSelect(-1, c + offset,
this._isAccelPressed(event));
event.getModifierState("Accel"));
this.treeBoxObject.ensureRowIsVisible(c + offset);
]]>
@ -487,7 +476,7 @@
if (this.view.rowCount == 0)
return;
if (this.pageUpOrDownMovesSelection == this._isAccelPressed(event)) {
if (this.pageUpOrDownMovesSelection == event.getModifierState("Accel")) {
this.treeBoxObject.scrollByPages(offset);
return;
}
@ -537,7 +526,7 @@
return;
if (this.view.rowCount == 1 && !this.view.selection.isSelected(0) &&
!(this.pageUpOrDownMovesSelection == this._isAccelPressed(event))) {
!(this.pageUpOrDownMovesSelection == event.getModifierState("Accel"))) {
this.view.selection.timedSelect(0, this._selectDelay);
return;
}
@ -562,7 +551,7 @@
this.treeBoxObject.ensureRowIsVisible(i > edge ? edge : i);
}
// Extend the selection from the existing pivot, if any
this.view.selection.rangedSelect(-1, i > edge ? edge : i, this._isAccelPressed(event));
this.view.selection.rangedSelect(-1, i > edge ? edge : i, event.getModifierState("Accel"));
} else {
@ -571,7 +560,7 @@
this.treeBoxObject.ensureRowIsVisible(i);
}
// Extend the selection from the existing pivot, if any
this.view.selection.rangedSelect(-1, i, this._isAccelPressed(event));
this.view.selection.rangedSelect(-1, i, event.getModifierState("Accel"));
}
]]>
@ -594,7 +583,7 @@
}
// Normal behaviour is to select the first/last row
if (!this._isAccelPressed(event))
if (!event.getModifierState("Accel"))
this.view.selection.timedSelect(edge, this._selectDelay);
// In a multiselect tree Ctrl+Home/End moves the anchor
@ -627,7 +616,7 @@
// Extend the selection from the existing pivot, if any.
// -1 doesn't work here, so using currentIndex instead
this.view.selection.rangedSelect(this.currentIndex, edge, this._isAccelPressed(event));
this.view.selection.rangedSelect(this.currentIndex, edge, event.getModifierState("Accel"));
this.treeBoxObject.ensureRowIsVisible(edge);
]]>
@ -906,12 +895,12 @@
if (event.charCode == " ".charCodeAt(0)) {
var c = this.currentIndex;
if (!this.view.selection.isSelected(c) ||
(!this.view.selection.single && this._isAccelPressed(event))) {
(!this.view.selection.single && event.getModifierState("Accel"))) {
this.view.selection.toggleSelect(c);
event.preventDefault();
}
} else if (!this.disableKeyNavigation && event.charCode > 0 &&
!event.altKey && !this._isAccelPressed(event) &&
!event.altKey && !event.getModifierState("Accel") &&
!event.metaKey && !event.ctrlKey) {
var l = this._keyNavigate(event);
if (l >= 0) {
@ -944,7 +933,7 @@
</implementation>
</binding>
<binding id="treerows" extends="chrome://global/content/bindings/tree.xml#tree-base">
<binding id="treerows" extends="chrome://global/content/bindings/general.xml#basecontrol">
<content>
<xul:hbox flex="1" class="tree-bodybox">
<children/>
@ -983,7 +972,7 @@
</handlers>
</binding>
<binding id="treebody" extends="chrome://global/content/bindings/tree.xml#tree-base">
<binding id="treebody" extends="chrome://global/content/bindings/general.xml#basecontrol">
<implementation>
<constructor>
if ("_ensureColumnOrder" in this.parentNode)
@ -1001,7 +990,7 @@
<![CDATA[
if (this.parentNode.disabled)
return;
if (((!this._isAccelPressed(event) ||
if (((!event.getModifierState("Accel") ||
!this.parentNode.pageUpOrDownMovesSelection) &&
!event.shiftKey && !event.metaKey) ||
this.parentNode.view.selection.single) {
@ -1071,7 +1060,7 @@
}
if (!view.selection.single) {
var augment = this._isAccelPressed(event);
var augment = event.getModifierState("Accel");
if (event.shiftKey) {
view.selection.rangedSelect(-1, cell.row, augment);
b.ensureRowIsVisible(cell.row);
@ -1135,7 +1124,7 @@
</binding>
<binding id="treecol-base"
extends="chrome://global/content/bindings/tree.xml#tree-base">
extends="chrome://global/content/bindings/general.xml#basecontrol">
<implementation>
<constructor>
this.parentNode.parentNode._columnsDirty = true;
@ -1353,7 +1342,7 @@
</binding>
<binding id="columnpicker" display="xul:button"
extends="chrome://global/content/bindings/tree.xml#tree-base">
extends="chrome://global/content/bindings/general.xml#basecontrol">
<content>
<xul:image class="tree-columnpicker-icon"/>
<xul:menupopup anonid="popup">

Просмотреть файл

@ -87,7 +87,7 @@ class StableHashTableInfo
// Get an existing key in the table.
KeyInfo* FindKeyInfo(HashNumber aOriginalHash, const void* aKey, HashInfo** aHashInfo = nullptr) {
HashToKeyMap::iterator iter = mHashToKey.find(aOriginalHash);
MOZ_ASSERT(iter != mHashToKey.end());
MOZ_RELEASE_ASSERT(iter != mHashToKey.end());
HashInfo* hashInfo = iter->second.get();
for (KeyInfo& keyInfo : hashInfo->mKeys) {
@ -114,7 +114,7 @@ public:
}
~StableHashTableInfo() {
MOZ_ASSERT(mHashToKey.empty());
MOZ_RELEASE_ASSERT(mHashToKey.empty());
DeallocateMemory(mCallbackStorage, CallbackStorageCapacity, MemoryKind::Tracked);
}
@ -175,7 +175,7 @@ public:
HashNumber GetOriginalHashNumber(const void* aKey) {
KeyToHashMap::iterator iter = mKeyToHash.find(aKey);
MOZ_ASSERT(iter != mKeyToHash.end());
MOZ_RELEASE_ASSERT(iter != mKeyToHash.end());
return iter->second;
}
@ -212,7 +212,7 @@ public:
}
HashNumber GetLastNewHash(const void* aKey) {
MOZ_ASSERT(aKey == mLastKey);
MOZ_RELEASE_ASSERT(aKey == mLastKey);
return mLastNewHash;
}
@ -302,7 +302,7 @@ WrapPLHashAllocEntry(void* aAllocPrivate, const void* aKey)
// the hashes are supplied directly to the table and we don't have a chance
// to modify them. Fortunately, none of these tables are iterated in a way
// that can cause the replay to diverge, so just punt in these cases.
MOZ_ASSERT(info->IsEmpty());
MOZ_RELEASE_ASSERT(info->IsEmpty());
}
return info->mAllocOps

Просмотреть файл

@ -135,10 +135,21 @@ Lock::Find(void* aNativeLock)
// should be generated right now. Doing things in this order avoids
// reentrancy issues when initializing the thread-local state used by
// these calls.
if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
Lock* lock = iter->second;
if (AreThreadEventsPassedThrough()) {
return nullptr;
}
return iter->second;
if (HasDivergedFromRecording()) {
// When diverged from the recording, don't allow uses of locks that are
// held by idling threads that have not diverged from the recording.
// This will cause the process to deadlock, so rewind instead.
if (lock->mOwner && Thread::GetById(lock->mOwner)->IsIdle()) {
EnsureNotDivergedFromRecording();
Unreachable();
}
return nullptr;
}
return lock;
}
}
@ -171,6 +182,9 @@ Lock::Enter()
while (thread->Id() != acquires->mNextOwner && !thread->MaybeDivergeFromRecording()) {
Thread::Wait();
}
if (!thread->HasDivergedFromRecording()) {
mOwner = thread->Id();
}
}
}
@ -179,6 +193,8 @@ Lock::Exit()
{
Thread* thread = Thread::Current();
if (IsReplaying() && !thread->HasDivergedFromRecording()) {
mOwner = 0;
// Notify the next owner before releasing the lock.
LockAcquires* acquires = gLockAcquires.Get(mId);
acquires->ReadAndNotifyNextOwner(thread);

Просмотреть файл

@ -30,9 +30,12 @@ class Lock
// Unique ID for this lock.
size_t mId;
// When replaying, any thread owning this lock as part of the recording.
Atomic<size_t, SequentiallyConsistent, Behavior::DontPreserve> mOwner;
public:
explicit Lock(size_t aId)
: mId(aId)
: mId(aId), mOwner(0)
{
MOZ_ASSERT(aId);
}

Просмотреть файл

@ -662,6 +662,17 @@ HandleDirtyMemoryFault(uint8_t* aAddress)
return true;
}
bool
MemoryRangeIsTracked(void* aAddress, size_t aSize)
{
for (uint8_t* ptr = PageBase(aAddress); ptr < (uint8_t*) aAddress + aSize; ptr += PageSize) {
if (!IsTrackedAddress(ptr, nullptr)) {
return false;
}
}
return true;
}
void
UnrecoverableSnapshotFailure()
{

Просмотреть файл

@ -50,6 +50,11 @@ void RegisterAllocatedMemory(void* aBaseAddress, size_t aSize, MemoryKind aKind)
// been reached.
void AddInitialUntrackedMemoryRegion(uint8_t* aBase, size_t aSize);
// Return whether a range of memory is in a tracked region. This excludes
// memory that was allocated after the last checkpoint and is not write
// protected.
bool MemoryRangeIsTracked(void* aAddress, size_t aSize);
// Initialize the memory snapshots system.
void InitializeMemorySnapshots();

Просмотреть файл

@ -163,7 +163,7 @@ ProcessMiddlemanCall(const char* aInputData, size_t aInputSize,
call->DecodeInput(inputStream);
const Redirection& redirection = gRedirections[call->mCallId];
MOZ_RELEASE_ASSERT(gRedirections[call->mCallId].mMiddlemanCall);
MOZ_RELEASE_ASSERT(redirection.mMiddlemanCall);
CallArguments arguments;
call->mArguments.CopyTo(&arguments);
@ -323,6 +323,9 @@ void
Middleman_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating)
{
if (!*aOutput) {
if (aCx.mPhase == MiddlemanCallPhase::MiddlemanOutput) {
aCx.mCall->SetMiddlemanValue(*aOutput);
}
return;
}

Просмотреть файл

@ -354,7 +354,7 @@ void ResetMiddlemanCalls();
///////////////////////////////////////////////////////////////////////////////
// Capture the contents of an input buffer at BufferArg with element count at CountArg.
template <size_t BufferArg, size_t CountArg, typename ElemType>
template <size_t BufferArg, size_t CountArg, typename ElemType = char>
static inline void
Middleman_Buffer(MiddlemanCallContext& aCx)
{

Просмотреть файл

@ -8,6 +8,7 @@
#include "InfallibleVector.h"
#include "MiddlemanCall.h"
#include "ipc/ParentInternal.h"
#include "mozilla/Sprintf.h"
#include <dlfcn.h>
@ -99,6 +100,11 @@ RecordReplayInterceptCall(int aCallId, CallArguments* aArguments)
}
}
if (parent::InRepaintStressMode()) {
// We're about to crash, so print out the name of the call that failed.
Print("Could not perform middleman call: %s\n", redirection.mName);
}
// Calling any redirection which performs the standard steps will cause
// debugger operations that have diverged from the recording to fail.
EnsureNotDivergedFromRecording();

Просмотреть файл

@ -152,7 +152,7 @@ namespace recordreplay {
MACRO(pthread_cond_wait, nullptr, Preamble_pthread_cond_wait) \
MACRO(pthread_cond_timedwait, nullptr, Preamble_pthread_cond_timedwait) \
MACRO(pthread_cond_timedwait_relative_np, nullptr, Preamble_pthread_cond_timedwait_relative_np) \
MACRO(pthread_create, nullptr, Preamble_pthread_create, nullptr, Preamble_SetError) \
MACRO(pthread_create, nullptr, Preamble_pthread_create) \
MACRO(pthread_join, nullptr, Preamble_pthread_join) \
MACRO(pthread_mutex_init, nullptr, Preamble_pthread_mutex_init) \
MACRO(pthread_mutex_destroy, nullptr, Preamble_pthread_mutex_destroy) \
@ -291,6 +291,7 @@ namespace recordreplay {
MACRO(CFRunLoopGetCurrent, RR_ScalarRval) \
MACRO(CFRunLoopRemoveSource) \
MACRO(CFRunLoopSourceCreate, RR_ScalarRval, Preamble_CFRunLoopSourceCreate) \
MACRO(CFRunLoopSourceInvalidate) \
MACRO(CFRunLoopSourceSignal) \
MACRO(CFRunLoopWakeUp) \
MACRO(CFStringAppendCharacters) \
@ -328,9 +329,9 @@ namespace recordreplay {
MACRO(CFURLCreateWithString, RR_ScalarRval) \
MACRO(CFURLGetFileSystemRepresentation, RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3>>) \
MACRO(CFURLGetFSRef, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(FSRef)>>) \
MACRO(CFUUIDCreate, RR_ScalarRval) \
MACRO(CFUUIDCreate, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
MACRO(CFUUIDCreateString, RR_ScalarRval) \
MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval) \
MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval, nullptr, Middleman_CFTypeArg<0>) \
MACRO(CGAffineTransformConcat, RR_OversizeRval<sizeof(CGAffineTransform)>) \
MACRO(CGBitmapContextCreateImage, RR_ScalarRval) \
MACRO(CGBitmapContextCreateWithData, \
@ -386,8 +387,9 @@ namespace recordreplay {
Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
MACRO(CGContextScaleCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
MACRO(CGContextTranslateCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
MACRO(CGDataProviderCreateWithData, RR_Compose<RR_ScalarRval, RR_CGDataProviderCreateWithData>) \
MACRO(CGDataProviderRelease) \
MACRO(CGDataProviderCreateWithData, RR_Compose<RR_ScalarRval, RR_CGDataProviderCreateWithData>, \
nullptr, Middleman_CGDataProviderCreateWithData) \
MACRO(CGDataProviderRelease, nullptr, nullptr, nullptr, Preamble_Veto<0>) \
MACRO(CGDisplayCopyColorSpace, RR_ScalarRval) \
MACRO(CGDisplayIOServicePort, RR_ScalarRval) \
MACRO(CGEventSourceCounterForEventType, RR_ScalarRval) \
@ -398,7 +400,8 @@ namespace recordreplay {
MACRO(CGFontCopyVariations, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CGFontCreateCopyWithVariations, RR_ScalarRval) \
MACRO(CGFontCreateWithDataProvider, RR_ScalarRval) \
MACRO(CGFontCreateWithDataProvider, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CGFontCreateWithFontName, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CGFontCreateWithPlatformFont, RR_ScalarRval) \
@ -442,10 +445,14 @@ namespace recordreplay {
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CTFontCopyTable, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CTFontCopyVariationAxes, RR_ScalarRval) \
MACRO(CTFontCopyVariationAxes, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
MACRO(CTFontCreateForString, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
MACRO(CTFontCreatePathForGlyph, RR_ScalarRval) \
MACRO(CTFontCreatePathForGlyph, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, \
Middleman_BufferFixedSize<2, sizeof(CGAffineTransform)>, \
Middleman_CreateCFTypeRval>) \
MACRO(CTFontCreateWithFontDescriptor, RR_ScalarRval, nullptr, \
Middleman_Compose<Middleman_CFTypeArg<0>, \
Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
@ -589,6 +596,11 @@ namespace recordreplay {
MACRO(ReleaseEvent, RR_ScalarRval) \
MACRO(RemoveEventFromQueue, RR_ScalarRval) \
MACRO(RetainEvent, RR_ScalarRval) \
MACRO(SCDynamicStoreCopyProxies, RR_ScalarRval) \
MACRO(SCDynamicStoreCreate, RR_ScalarRval) \
MACRO(SCDynamicStoreCreateRunLoopSource, RR_ScalarRval) \
MACRO(SCDynamicStoreKeyCreateProxies, RR_ScalarRval) \
MACRO(SCDynamicStoreSetNotificationKeys, RR_ScalarRval) \
MACRO(SendEventToEventTarget, RR_ScalarRval) \
/* These are not public APIs, but other redirected functions may be aliases for */ \
/* these which are dynamically installed on the first call in a way that our */ \
@ -689,20 +701,6 @@ ReplayInvokeCallback(size_t aCallbackId)
// Middleman Call Helpers
///////////////////////////////////////////////////////////////////////////////
static bool
TestObjCObjectClass(id aObj, const char* aName)
{
Class cls = object_getClass(aObj);
while (cls) {
const char* className = class_getName(cls);
if (!strcmp(className, aName)) {
return true;
}
cls = class_getSuperclass(cls);
}
return false;
}
// Inputs that originate from static data in the replaying process itself
// rather than from previous middleman calls.
enum class ObjCInputKind {
@ -710,6 +708,14 @@ enum class ObjCInputKind {
ConstantString,
};
// Internal layout of a constant compile time CFStringRef.
struct CFConstantString {
Class mClass;
size_t mStuff;
char* mData;
size_t mLength;
};
// Capture an Objective C or CoreFoundation input to a call, which may come
// either from another middleman call, or from static data in the replaying
// process.
@ -753,22 +759,23 @@ Middleman_ObjCInput(MiddlemanCallContext& aCx, id* aThingPtr)
}
// Watch for constant compile time strings baked into the generated code or
// stored in system libraries. We can crash here if the object came from
// e.g. a replayed pointer from the recording, as can happen if not enough
// redirections have middleman call hooks. We could do better here to make
// sure the pointer looks like it could be a constant string, but it seems
// better and simpler to crash more reliably here than mask problems due to
// missing middleman call hooks.
if (TestObjCObjectClass(*aThingPtr, "NSString")) {
AutoPassThroughThreadEvents pt;
CFIndex len = CFStringGetLength((CFStringRef)*aThingPtr);
InfallibleVector<UniChar> buffer;
buffer.appendN(0, len);
CFStringGetCharacters((CFStringRef)*aThingPtr, { 0, len }, buffer.begin());
aCx.WriteInputScalar((size_t) ObjCInputKind::ConstantString);
aCx.WriteInputScalar(len);
aCx.WriteInputBytes(buffer.begin(), len * sizeof(UniChar));
return;
// stored in system libraries. Be careful when accessing the pointer as in
// the case where a middleman call hook for a function is missing the
// pointer could have originated from the recording and its address may not
// be mapped. In this case we would rather gracefully recover and fail to
// paint, instead of crashing.
if (MemoryRangeIsTracked(*aThingPtr, sizeof(CFConstantString))) {
CFConstantString* str = (CFConstantString*) *aThingPtr;
if (str->mClass == objc_lookUpClass("__NSCFConstantString") &&
str->mLength <= 4096 && // Sanity check.
MemoryRangeIsTracked(str->mData, str->mLength)) {
InfallibleVector<UniChar> buffer;
NS_ConvertUTF8toUTF16 converted(str->mData, str->mLength);
aCx.WriteInputScalar((size_t) ObjCInputKind::ConstantString);
aCx.WriteInputScalar(str->mLength);
aCx.WriteInputBytes(converted.get(), str->mLength * sizeof(UniChar));
return;
}
}
aCx.MarkAsFailed();
@ -1212,6 +1219,12 @@ Preamble_pthread_create(CallArguments* aArguments)
*token = Thread::StartThread((Thread::Callback) start, startArg,
detachState == PTHREAD_CREATE_JOINABLE);
if (!*token) {
// Don't create new threads after diverging from the recording.
MOZ_RELEASE_ASSERT(HasDivergedFromRecording());
return Preamble_SetError(aArguments);
}
aArguments->Rval<ssize_t>() = 0;
return PreambleResult::Veto;
}
@ -1752,6 +1765,7 @@ Middleman_CFArrayGetValueAtIndex(MiddlemanCallContext& aCx)
if (call) {
switch (call->mCallId) {
case CallEvent_CTLineGetGlyphRuns:
case CallEvent_CTFontCopyVariationAxes:
case CallEvent_CTFontDescriptorCreateMatchingFontDescriptors:
isCFTypeRval = true;
break;
@ -2048,6 +2062,39 @@ RR_CGDataProviderCreateWithData(Stream& aEvents, CallArguments* aArguments, Erro
}
}
static void
ReleaseDataCallback(void*, const void* aData, size_t)
{
free((void*) aData);
}
static void
Middleman_CGDataProviderCreateWithData(MiddlemanCallContext& aCx)
{
Middleman_Buffer<1, 2>(aCx);
Middleman_CreateCFTypeRval(aCx);
auto& info = aCx.mArguments->Arg<0, void*>();
auto& data = aCx.mArguments->Arg<1, const void*>();
auto& size = aCx.mArguments->Arg<2, size_t>();
auto& releaseData = aCx.mArguments->Arg<3, CGDataProviderReleaseDataCallback>();
// Make a copy of the data that won't be released the next time middleman
// calls are reset, in case CoreGraphics decides to hang onto the data
// provider after that point.
if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
void* newData = malloc(size);
memcpy(newData, data, size);
data = newData;
releaseData = ReleaseDataCallback;
}
// Immediately release the data in the replaying process.
if (aCx.mPhase == MiddlemanCallPhase::ReplayInput) {
releaseData(info, data, size);
}
}
static PreambleResult
Preamble_CGPathApply(CallArguments* aArguments)
{

Просмотреть файл

@ -199,6 +199,11 @@ DivergeFromRecording()
// Reset middleman call state whenever we first diverge from the recording.
child::SendResetMiddlemanCalls();
// Make sure all non-main threads are idle before we begin diverging. This
// thread's new behavior can change values used by other threads and induce
// recording mismatches.
Thread::WaitForIdleThreads();
thread->DivergeFromRecording();
}

Просмотреть файл

@ -237,8 +237,7 @@ Thread::StartThread(Callback aStart, void* aArgument, bool aNeedsJoin)
Thread* thread = Thread::Current();
RecordingEventSection res(thread);
if (!res.CanAccessEvents()) {
EnsureNotDivergedFromRecording();
Unreachable();
return 0;
}
MonitorAutoLock lock(*gMonitor);
@ -364,24 +363,16 @@ RecordReplayInterface_InternalAreThreadEventsDisallowed()
// Thread Coordination
///////////////////////////////////////////////////////////////////////////////
// Whether all threads should attempt to idle.
static Atomic<bool, SequentiallyConsistent, Behavior::DontPreserve> gThreadsShouldIdle;
// Whether all threads are considered to be idle.
static Atomic<bool, SequentiallyConsistent, Behavior::DontPreserve> gThreadsAreIdle;
/* static */ void
Thread::WaitForIdleThreads()
{
MOZ_RELEASE_ASSERT(CurrentIsMainThread());
MOZ_RELEASE_ASSERT(!gThreadsShouldIdle);
MOZ_RELEASE_ASSERT(!gThreadsAreIdle);
gThreadsShouldIdle = true;
MonitorAutoLock lock(*gMonitor);
for (size_t i = MainThreadId + 1; i <= MaxRecordedThreadId; i++) {
GetById(i)->mUnrecordedWaitNotified = false;
Thread* thread = GetById(i);
thread->mShouldIdle = true;
thread->mUnrecordedWaitNotified = false;
}
while (true) {
bool done = true;
@ -426,23 +417,21 @@ Thread::WaitForIdleThreads()
MonitorAutoUnlock unlock(*gMonitor);
WaitNoIdle();
}
}
gThreadsAreIdle = true;
/* static */ void
Thread::ResumeSingleIdleThread(size_t aId)
{
GetById(aId)->mShouldIdle = false;
Notify(aId);
}
/* static */ void
Thread::ResumeIdleThreads()
{
MOZ_RELEASE_ASSERT(CurrentIsMainThread());
MOZ_RELEASE_ASSERT(gThreadsAreIdle);
gThreadsAreIdle = false;
MOZ_RELEASE_ASSERT(gThreadsShouldIdle);
gThreadsShouldIdle = false;
for (size_t i = MainThreadId + 1; i <= MaxRecordedThreadId; i++) {
Notify(i);
ResumeSingleIdleThread(i);
}
}
@ -464,7 +453,7 @@ Thread::NotifyUnrecordedWait(const std::function<void()>& aCallback, bool aOnlyW
// The main thread might be able to make progress now by calling the routine
// if it is waiting for idle replay threads.
if (gThreadsShouldIdle) {
if (mShouldIdle) {
Notify(MainThreadId);
}
}
@ -473,7 +462,8 @@ Thread::NotifyUnrecordedWait(const std::function<void()>& aCallback, bool aOnlyW
Thread::MaybeWaitForCheckpointSave()
{
MonitorAutoLock lock(*gMonitor);
while (gThreadsShouldIdle) {
Thread* thread = Thread::Current();
while (thread->mShouldIdle) {
MonitorAutoUnlock unlock(*gMonitor);
Wait();
}
@ -531,7 +521,7 @@ Thread::Wait()
}
thread->mIdle = true;
if (gThreadsShouldIdle) {
if (thread->mShouldIdle) {
// Notify the main thread that we just became idle.
Notify(MainThreadId);
}
@ -546,7 +536,7 @@ Thread::Wait()
RestoreThreadStack(thread->Id());
Unreachable();
}
} while (gThreadsShouldIdle);
} while (thread->mShouldIdle);
thread->mIdle = false;
thread->SetPassThrough(false);

Просмотреть файл

@ -127,6 +127,9 @@ private:
// File descriptor to notify to wake the thread up, fixed at creation.
FileHandle mNotifyfd;
// Whether the thread should attempt to idle.
Atomic<bool, SequentiallyConsistent, Behavior::DontPreserve> mShouldIdle;
// Whether the thread is waiting on idlefd.
Atomic<bool, SequentiallyConsistent, Behavior::DontPreserve> mIdle;
@ -289,6 +292,13 @@ public:
// After WaitForIdleThreads(), the main thread will call this to allow
// other threads to resume execution.
static void ResumeIdleThreads();
// Allow a single thread to resume execution.
static void ResumeSingleIdleThread(size_t aId);
// Return whether this thread is in the idle state entered after
// WaitForIdleThreads.
bool IsIdle() { return mIdle; }
};
// This uses a stack pointer instead of TLS to make sure events are passed

Просмотреть файл

@ -545,7 +545,7 @@ PaintFromMainThread()
void
NotifyPaintComplete()
{
MOZ_RELEASE_ASSERT(Thread::Current()->Id() == gCompositorThreadId);
MOZ_RELEASE_ASSERT(!gCompositorThreadId || Thread::Current()->Id() == gCompositorThreadId);
// Notify the main thread in case it is waiting for this paint to complete.
{
@ -577,22 +577,21 @@ Repaint(size_t* aWidth, size_t* aHeight)
// and the last graphics we sent will still be correct.
Thread* compositorThread = Thread::GetById(gCompositorThreadId);
if (!compositorThread->WillDivergeFromRecordingSoon()) {
// Allow the compositor to diverge from the recording so it can perform
// any paint we are about to trigger, or finish any in flight paint that
// that existed at the point we are paused at.
Thread::GetById(gCompositorThreadId)->SetShouldDivergeFromRecording();
Thread::ResumeSingleIdleThread(gCompositorThreadId);
// Create an artifical vsync to see if graphics have changed since the last
// paint and a new paint is needed.
NotifyVsyncObserver();
if (gNumPendingPaints) {
// Allow the compositor to diverge from the recording so it can perform
// any paint we just triggered, or finish any in flight paint that that
// existed at the point we are paused at.
Thread::GetById(gCompositorThreadId)->SetShouldDivergeFromRecording();
// Wait for the compositor to finish all in flight paints, including any
// one we just triggered.
MonitorAutoLock lock(*gMonitor);
while (gNumPendingPaints) {
gMonitor->Wait();
}
// Wait for the compositor to finish all in flight paints, including any
// one we just triggered.
MonitorAutoLock lock(*gMonitor);
while (gNumPendingPaints) {
gMonitor->Wait();
}
}

Просмотреть файл

@ -23,8 +23,8 @@ module.exports = {
"Ci": false,
"Cr": false,
"Cu": false,
// These globals are made available via WebIDL files, see ResolveSystemBinding in:
// https://searchfox.org/mozilla-central/source/__GENERATED__/dom/bindings/ResolveSystemBinding.cpp
// These globals are made available via WebIDL files, see WebIDLGlobalNameHash.
// XXX(nika): We should also explicitly include window-defined globals here now.
"AbortController": false,
"AbortSignal": false,
"AddonManagerPermissions": false,