mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 17:25:36 +00:00
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
3d78756bdb
@ -0,0 +1,419 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/* This test records I/O syscalls done on the main thread during startup.
|
||||||
|
*
|
||||||
|
* To run this test similar to try server, you need to run:
|
||||||
|
* ./mach package
|
||||||
|
* ./mach test --appname=dist <path to test>
|
||||||
|
*
|
||||||
|
* If you made changes that cause this test to fail, it's likely because you
|
||||||
|
* are touching more files or directories during startup.
|
||||||
|
* Most code has no reason to use main thread I/O.
|
||||||
|
* If for some reason accessing the file system on the main thread is currently
|
||||||
|
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||||
|
* the end of startup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||||
|
const kDumpAllStacks = false;
|
||||||
|
|
||||||
|
// Shortcuts for conditions.
|
||||||
|
const LINUX = AppConstants.platform == "linux";
|
||||||
|
const WIN = AppConstants.platform == "win";
|
||||||
|
const MAC = AppConstants.platform == "macosx";
|
||||||
|
|
||||||
|
/* Paths in the whitelist can:
|
||||||
|
* - be a full path, eg. "/etc/mime.types"
|
||||||
|
* - have a prefix which will be resolved using Services.dirsvc
|
||||||
|
* eg. "GreD:omni.ja"
|
||||||
|
* It's possible to have only a prefix, in thise case the directory will
|
||||||
|
* still be resolved, eg. "UAppData:"
|
||||||
|
* - use * at the begining and/or end as a wildcard
|
||||||
|
* The folder separator is '/' even for Windows paths, where it'll be
|
||||||
|
* automatically converted to '\'.
|
||||||
|
*
|
||||||
|
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||||
|
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||||
|
*
|
||||||
|
* Each entry specifies the maximum number of times an operation is expected to
|
||||||
|
* occur.
|
||||||
|
* The operations currently reported by the I/O interposer are:
|
||||||
|
* create/open: only supported on Windows currently. The test currently
|
||||||
|
* ignores these markers to have a shorter initial whitelist.
|
||||||
|
* Adding Unix support is bug 1533779.
|
||||||
|
* stat: supported on all platforms when checking the last modified date or
|
||||||
|
* file size. Supported only on Windows when checking if a file exists;
|
||||||
|
* fixing this inconsistency is bug 1536109.
|
||||||
|
* read: supported on all platforms, but unix platforms will only report read
|
||||||
|
* calls going through NSPR.
|
||||||
|
* write: supported on all platforms, but Linux will only report write calls
|
||||||
|
* going through NSPR.
|
||||||
|
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||||
|
* Adding Windows support is bug 1524574.
|
||||||
|
* fsync: supported only on Windows.
|
||||||
|
*
|
||||||
|
* If an entry specifies more than one operation, if at least one of them is
|
||||||
|
* encountered, the test won't report a failure for the entry. This helps when
|
||||||
|
* whitelisting cases where the reported operations aren't the same on all
|
||||||
|
* platforms due to the I/O interposer inconsistencies across platforms
|
||||||
|
* documented above.
|
||||||
|
*/
|
||||||
|
const processes = {
|
||||||
|
"Web Content": [
|
||||||
|
{
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543761
|
||||||
|
path: "GreD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994, bug 1543761
|
||||||
|
path: "XCurProcD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||||
|
path: "XCurProcD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"Privileged Content": [
|
||||||
|
{
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543761
|
||||||
|
path: "GreD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994, bug 1543761
|
||||||
|
path: "XCurProcD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||||
|
path: "XCurProcD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"WebExtensions": [
|
||||||
|
{
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543761
|
||||||
|
path: "GreD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994, bug 1543761
|
||||||
|
path: "XCurProcD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||||
|
path: "XCurProcD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1357205
|
||||||
|
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function expandWhitelistPath(path) {
|
||||||
|
if (path.includes(":")) {
|
||||||
|
let [prefix, suffix] = path.split(":");
|
||||||
|
let [key, property] = prefix.split(".");
|
||||||
|
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||||
|
if (property) {
|
||||||
|
dir = dir[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve symLinks.
|
||||||
|
let dirPath = dir.path;
|
||||||
|
while (dir && !dir.isSymlink()) {
|
||||||
|
dir = dir.parent;
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
dirPath = dirPath.replace(dir.path, dir.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = dirPath;
|
||||||
|
|
||||||
|
if (suffix) {
|
||||||
|
path += "/" + suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (AppConstants.platform == "win") {
|
||||||
|
path = path.replace(/\//g, "\\");
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStackFromProfile(profile, stack) {
|
||||||
|
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||||
|
const stackFrameCol = profile.stackTable.schema.frame;
|
||||||
|
const frameLocationCol = profile.frameTable.schema.location;
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
while (stack) {
|
||||||
|
let sp = profile.stackTable.data[stack];
|
||||||
|
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||||
|
stack = sp[stackPrefixCol];
|
||||||
|
frame = profile.stringTable[frame[frameLocationCol]];
|
||||||
|
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||||
|
result.push(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIOMarkersFromProfile(profile) {
|
||||||
|
const nameCol = profile.markers.schema.name;
|
||||||
|
const dataCol = profile.markers.schema.data;
|
||||||
|
|
||||||
|
let markers = [];
|
||||||
|
for (let m of profile.markers.data) {
|
||||||
|
let markerName = profile.stringTable[m[nameCol]];
|
||||||
|
|
||||||
|
if (markerName != "FileIO")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let markerData = m[dataCol];
|
||||||
|
if (markerData.source == "sqlite-mainthread") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let samples = markerData.stack.samples;
|
||||||
|
let stack = samples.data[0][samples.schema.stack];
|
||||||
|
markers.push({operation: markerData.operation,
|
||||||
|
filename: markerData.filename,
|
||||||
|
source: markerData.source,
|
||||||
|
stackId: stack});
|
||||||
|
}
|
||||||
|
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathMatches(path, filename) {
|
||||||
|
path = path.toLowerCase();
|
||||||
|
return path == filename || // Full match
|
||||||
|
// Wildcard on both sides of the path
|
||||||
|
(path.startsWith("*") && path.endsWith("*") &&
|
||||||
|
filename.includes(path.slice(1, -1))) ||
|
||||||
|
// Wildcard suffix
|
||||||
|
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||||
|
// Wildcard prefix
|
||||||
|
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||||
|
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||||
|
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||||
|
"non-debug build.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||||
|
omniJa.append("omni.ja");
|
||||||
|
if (!omniJa.exists()) {
|
||||||
|
ok(false, "This test requires a packaged build, " +
|
||||||
|
"run 'mach package' and then use --appname=dist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||||
|
await startupRecorder.done;
|
||||||
|
|
||||||
|
for (let process in processes) {
|
||||||
|
processes[process] =
|
||||||
|
processes[process].filter(entry => !("condition" in entry) || entry.condition);
|
||||||
|
processes[process].forEach(entry => {
|
||||||
|
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||||
|
let shouldPass = true;
|
||||||
|
for (let procName in processes) {
|
||||||
|
let whitelist = processes[procName];
|
||||||
|
info(`whitelisted paths for ${procName} process:\n` +
|
||||||
|
whitelist.map(e => {
|
||||||
|
let operations = Object.keys(e).filter(k => !["path", "condition"].includes(k))
|
||||||
|
.map(k => `${k}: ${e[k]}`);
|
||||||
|
return ` ${e.path} - ${operations.join(", ")}`;
|
||||||
|
}).join("\n"));
|
||||||
|
|
||||||
|
let profile;
|
||||||
|
for (let process of startupRecorder.data.profile.processes) {
|
||||||
|
if (process.threads[0].processName == procName) {
|
||||||
|
profile = process.threads[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (procName == "Privileged Content" && !profile) {
|
||||||
|
// The Privileged Content is started from an idle task that may not have
|
||||||
|
// been executed yet at the time we captured the startup profile in
|
||||||
|
// startupRecorder.
|
||||||
|
todo(false, `profile for ${procName} process not found`);
|
||||||
|
} else {
|
||||||
|
ok(profile, `Found profile for ${procName} process`);
|
||||||
|
}
|
||||||
|
if (!profile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let markers = getIOMarkersFromProfile(profile);
|
||||||
|
for (let marker of markers) {
|
||||||
|
if (marker.operation == "create/open") {
|
||||||
|
// TODO: handle these I/O markers once they are supported on
|
||||||
|
// non-Windows platforms.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to lower case before comparing because the OS X test slaves
|
||||||
|
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||||
|
// as 'firefox' for some reason.
|
||||||
|
let filename = marker.filename.toLowerCase();
|
||||||
|
|
||||||
|
if (!filename) {
|
||||||
|
// We are still missing the filename on some mainthreadio markers,
|
||||||
|
// these markers are currently useless for the purpose of this test.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIN) {
|
||||||
|
if (filename == "/dev/urandom") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||||
|
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected = false;
|
||||||
|
for (let entry of whitelist) {
|
||||||
|
if (pathMatches(entry.path, filename)) {
|
||||||
|
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||||
|
entry._used = true;
|
||||||
|
expected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!expected) {
|
||||||
|
record(false,
|
||||||
|
`unexpected ${marker.operation} on ${marker.filename} in ${procName} process`,
|
||||||
|
undefined,
|
||||||
|
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||||
|
shouldPass = false;
|
||||||
|
}
|
||||||
|
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||||
|
if (kDumpAllStacks) {
|
||||||
|
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||||
|
.join("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let entry of whitelist) {
|
||||||
|
for (let op in entry) {
|
||||||
|
if (["path", "condition", "ignoreIfUnused", "_used"].includes(op)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let message = `${op} on ${entry.path} `;
|
||||||
|
if (entry[op] == 0) {
|
||||||
|
message += "as many times as expected";
|
||||||
|
} else if (entry[op] > 0) {
|
||||||
|
message += `allowed ${entry[op]} more times`;
|
||||||
|
} else {
|
||||||
|
message += `${entry[op] * -1} more times than expected`;
|
||||||
|
}
|
||||||
|
ok(entry[op] >= 0, `${message} in ${procName} process`);
|
||||||
|
}
|
||||||
|
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||||
|
ok(false, `unused whitelist entry ${procName}: ${entry.path}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldPass) {
|
||||||
|
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||||
|
} else {
|
||||||
|
const filename = "child-startup-mainthreadio-profile.json";
|
||||||
|
let path = Cc["@mozilla.org/process/environment;1"]
|
||||||
|
.getService(Ci.nsIEnvironment)
|
||||||
|
.get("MOZ_UPLOAD_DIR");
|
||||||
|
let encoder = new TextEncoder();
|
||||||
|
let profilePath = OS.Path.join(path, filename);
|
||||||
|
await OS.File.writeAtomic(profilePath,
|
||||||
|
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||||
|
ok(false,
|
||||||
|
"Found some unexpected main thread I/O during child process startup; " +
|
||||||
|
"profile uploaded in " + filename);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,933 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/* This test records I/O syscalls done on the main thread during startup.
|
||||||
|
*
|
||||||
|
* To run this test similar to try server, you need to run:
|
||||||
|
* ./mach package
|
||||||
|
* ./mach test --appname=dist <path to test>
|
||||||
|
*
|
||||||
|
* If you made changes that cause this test to fail, it's likely because you
|
||||||
|
* are touching more files or directories during startup.
|
||||||
|
* Most code has no reason to use main thread I/O.
|
||||||
|
* If for some reason accessing the file system on the main thread is currently
|
||||||
|
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||||
|
* the end of startup.
|
||||||
|
* If your code isn't strictly required to show the first browser window,
|
||||||
|
* it shouldn't be loaded before we are done with first paint.
|
||||||
|
* Finally, if your code isn't really needed during startup, it should not be
|
||||||
|
* loaded before we have started handling user events.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
|
||||||
|
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||||
|
const kDumpAllStacks = false;
|
||||||
|
|
||||||
|
// Shortcuts for conditions.
|
||||||
|
const LINUX = AppConstants.platform == "linux";
|
||||||
|
const WIN = AppConstants.platform == "win";
|
||||||
|
const MAC = AppConstants.platform == "macosx";
|
||||||
|
|
||||||
|
/* Paths in the whitelist can:
|
||||||
|
* - be a full path, eg. "/etc/mime.types"
|
||||||
|
* - have a prefix which will be resolved using Services.dirsvc
|
||||||
|
* eg. "GreD:omni.ja"
|
||||||
|
* It's possible to have only a prefix, in thise case the directory will
|
||||||
|
* still be resolved, eg. "UAppData:"
|
||||||
|
* - use * at the begining and/or end as a wildcard
|
||||||
|
* - For Windows specific entries that require resolving the path to its
|
||||||
|
* canonical form, ie. the old DOS 8.3 format, use canonicalize: true.
|
||||||
|
* This is needed for stat calls to non-existent files.
|
||||||
|
* The folder separator is '/' even for Windows paths, where it'll be
|
||||||
|
* automatically converted to '\'.
|
||||||
|
*
|
||||||
|
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||||
|
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||||
|
*
|
||||||
|
* Each entry specifies the maximum number of times an operation is expected to
|
||||||
|
* occur.
|
||||||
|
* The operations currently reported by the I/O interposer are:
|
||||||
|
* create/open: only supported on Windows currently. The test currently
|
||||||
|
* ignores these markers to have a shorter initial whitelist.
|
||||||
|
* Adding Unix support is bug 1533779.
|
||||||
|
* stat: supported on all platforms when checking the last modified date or
|
||||||
|
* file size. Supported only on Windows when checking if a file exists;
|
||||||
|
* fixing this inconsistency is bug 1536109.
|
||||||
|
* read: supported on all platforms, but unix platforms will only report read
|
||||||
|
* calls going through NSPR.
|
||||||
|
* write: supported on all platforms, but Linux will only report write calls
|
||||||
|
* going through NSPR.
|
||||||
|
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||||
|
* Adding Windows support is bug 1524574.
|
||||||
|
* fsync: supported only on Windows.
|
||||||
|
*
|
||||||
|
* If an entry specifies more than one operation, if at least one of them is
|
||||||
|
* encountered, the test won't report a failure for the entry. This helps when
|
||||||
|
* whitelisting cases where the reported operations aren't the same on all
|
||||||
|
* platforms due to the I/O interposer inconsistencies across platforms
|
||||||
|
* documented above.
|
||||||
|
*/
|
||||||
|
const startupPhases = {
|
||||||
|
// Anything done before or during app-startup must have a compelling reason
|
||||||
|
// to run before we have even selected the user profile.
|
||||||
|
"before profile selection": [
|
||||||
|
{ // bug 1541226
|
||||||
|
path: "UAppData:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 3,
|
||||||
|
},
|
||||||
|
{ // bug 1541200
|
||||||
|
path: "UAppData:Crash Reports/InstallTime20*",
|
||||||
|
condition: AppConstants.MOZ_CRASHREPORTER,
|
||||||
|
stat: 1, // only caught on Windows.
|
||||||
|
read: 1,
|
||||||
|
write: 2,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541200
|
||||||
|
path: "UAppData:Crash Reports/LastCrash",
|
||||||
|
condition: WIN && AppConstants.MOZ_CRASHREPORTER,
|
||||||
|
stat: 1, // only caught on Windows.
|
||||||
|
read: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541200
|
||||||
|
path: "UAppData:Crash Reports/LastCrash",
|
||||||
|
condition: !WIN && AppConstants.MOZ_CRASHREPORTER,
|
||||||
|
ignoreIfUnused: true, // only if we ever crashed on this machine
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541226
|
||||||
|
path: "DefProfLRt.parent:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // At least the read seems unavoidable for a regular startup.
|
||||||
|
path: "UAppData:profiles.ini",
|
||||||
|
condition: MAC,
|
||||||
|
stat: 1,
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1546931
|
||||||
|
path: "UAppData:installs.ini",
|
||||||
|
condition: WIN || MAC,
|
||||||
|
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||||
|
read: 1,
|
||||||
|
stat: 2,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // At least the read seems unavoidable for a regular startup.
|
||||||
|
path: "UAppData:profiles.ini",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||||
|
read: 1,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541226, bug 1363586, bug 1541593
|
||||||
|
path: "ProfD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ProfLD:.startup-incomplete",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541491 to stop using this file, bug 1541494 to write correctly.
|
||||||
|
path: "ProfLD:compatibility.ini",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
write: 18,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ProfD:parent.lock",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541603
|
||||||
|
path: "ProfD:minidumps",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543746
|
||||||
|
path: "XCurProcD:defaults/preferences",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1544034
|
||||||
|
path: "ProfLDS:startupCache/scriptCache-child-current.bin",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1544034
|
||||||
|
path: "ProfLDS:startupCache/scriptCache-child.bin",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1544034
|
||||||
|
path: "ProfLDS:startupCache/scriptCache-current.bin",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1544034
|
||||||
|
path: "ProfLDS:startupCache/scriptCache.bin",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1544037
|
||||||
|
path: "ProfLDS:startupCache/startupCache." +
|
||||||
|
(Services.appinfo.is64Bit ? 8 : 4) + ".little",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541601
|
||||||
|
path: "PrfDef:channel-prefs.js",
|
||||||
|
stat: 1,
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543761
|
||||||
|
path: "GreD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1376994, bug 1543761
|
||||||
|
path: "XCurProcD:chrome.manifest",
|
||||||
|
condition: !WIN, // Visible on Windows with an open marker
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // At least the read seems unavoidable
|
||||||
|
path: "PrefD:prefs.js",
|
||||||
|
stat: 1,
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543752
|
||||||
|
path: "PrefD:user.js",
|
||||||
|
stat: 1,
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "*ld.so.conf*",
|
||||||
|
condition: LINUX,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
read: 22,
|
||||||
|
close: 11,
|
||||||
|
},
|
||||||
|
{ // bug 1546838
|
||||||
|
path: "ProfD:xulstore/data.mdb",
|
||||||
|
condition: WIN,
|
||||||
|
write: 1,
|
||||||
|
fsync: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"before opening first browser window": [
|
||||||
|
{ // bug 1541226
|
||||||
|
path: "ProfD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "XCurProcD:blocklist.xml",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1534745
|
||||||
|
path: "ProfD:cookies.sqlite-journal",
|
||||||
|
condition: !LINUX,
|
||||||
|
stat: 3,
|
||||||
|
write: 4,
|
||||||
|
},
|
||||||
|
{ // bug 1534745
|
||||||
|
path: "ProfD:cookies.sqlite",
|
||||||
|
condition: !LINUX,
|
||||||
|
stat: 2,
|
||||||
|
read: 2,
|
||||||
|
write: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1534745
|
||||||
|
path: "ProfD:cookies.sqlite-wal",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 975996
|
||||||
|
path: "ProfD:permissions.sqlite",
|
||||||
|
condition: WIN || MAC,
|
||||||
|
fsync: 7,
|
||||||
|
read: 2,
|
||||||
|
stat: 1,
|
||||||
|
write: 10,
|
||||||
|
},
|
||||||
|
{ // bug 975996
|
||||||
|
path: "ProfD:permissions.sqlite-journal",
|
||||||
|
condition: WIN || MAC,
|
||||||
|
fsync: 7,
|
||||||
|
stat: 26,
|
||||||
|
write: 38,
|
||||||
|
},
|
||||||
|
{ // bug 975996
|
||||||
|
path: "ProfD:permissions.sqlite-wal",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 20,
|
||||||
|
},
|
||||||
|
{ // Seems done by OS X and outside of our control.
|
||||||
|
path: "*.savedState/restorecount.plist",
|
||||||
|
condition: MAC,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
write: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "*ld.so.conf*",
|
||||||
|
condition: LINUX,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
read: 22,
|
||||||
|
close: 11,
|
||||||
|
},
|
||||||
|
{ // bug 1545167
|
||||||
|
path: "/etc/mime.types",
|
||||||
|
condition: LINUX,
|
||||||
|
read: 3,
|
||||||
|
close: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "UChrm:userChrome.css",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541233
|
||||||
|
path: "UChrm:userContent.css",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "XREUSysExt:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "XRESysExtDev:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "ProfD:extensions",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "XCurProcD:extensions",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "UAppData:",
|
||||||
|
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||||
|
// sometimes before first paint
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1546838
|
||||||
|
path: "ProfD:xulstore/data.mdb",
|
||||||
|
condition: WIN,
|
||||||
|
read: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// We reach this phase right after showing the first browser window.
|
||||||
|
// This means that any I/O at this point delayed first paint.
|
||||||
|
"before first paint": [
|
||||||
|
{ // bug 1541226
|
||||||
|
path: "ProfD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545119
|
||||||
|
path: "OldUpdRootD:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1446012
|
||||||
|
path: "UpdRootD:updates/0/update.status",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:pluginreg.dat",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:pluginreg.dat.tmp",
|
||||||
|
stat: 1,
|
||||||
|
write: 64,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:plugins",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "APlugns:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "UserPlugins.parent:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "UserPlugins:",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:plugins/nptest.dll",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:plugins/npsecondtest.dll",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:plugins/npthirdtest.dll",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545123
|
||||||
|
path: "ProfD:plugins/npswftest.dll",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1545167
|
||||||
|
path: "/etc/mime.types",
|
||||||
|
condition: LINUX,
|
||||||
|
read: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // We only hit this for new profiles.
|
||||||
|
path: "XREAppDist:distribution.ini",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "*WindowsApps/microsoft.windowscommunicationsapps*",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 3,
|
||||||
|
},
|
||||||
|
{ // bug 1545139
|
||||||
|
path: "*Fonts/StaticCache.dat",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true, // Only on Win7
|
||||||
|
read: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1541246
|
||||||
|
path: "UAppData:",
|
||||||
|
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||||
|
// sometimes before first paint
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // Not in packaged builds; useful for artifact builds.
|
||||||
|
path: "GreD:ScalarArtifactDefinitions.json",
|
||||||
|
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // Not in packaged builds; useful for artifact builds.
|
||||||
|
path: "GreD:EventArtifactDefinitions.json",
|
||||||
|
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1546838
|
||||||
|
path: "ProfD:xulstore/data.mdb",
|
||||||
|
condition: MAC,
|
||||||
|
write: 3,
|
||||||
|
},
|
||||||
|
{ // bug 1543090
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543090
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// We are at this phase once we are ready to handle user events.
|
||||||
|
// Any IO at this phase or before gets in the way of the user
|
||||||
|
// interacting with the first browser window.
|
||||||
|
"before handling user events": [
|
||||||
|
{
|
||||||
|
path: "GreD:update.test",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
condition: LINUX,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:cert9.db",
|
||||||
|
condition: WIN,
|
||||||
|
read: 2,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:cert9.db",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:cert9.db-journal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:cert9.db-wal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:pkcs11.txt",
|
||||||
|
condition: WIN,
|
||||||
|
read: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:key4.db",
|
||||||
|
condition: WIN,
|
||||||
|
read: 2,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:key4.db",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:key4.db-journal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 5,
|
||||||
|
},
|
||||||
|
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||||
|
path: "ProfD:key4.db-wal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||||
|
condition: !WIN,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1003968
|
||||||
|
path: "XREAppDist:searchplugins",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "XCurProcD:extensions",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543090
|
||||||
|
path: "GreD:omni.ja",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1543090
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// Things that are expected to be completely out of the startup path
|
||||||
|
// and loaded lazily when used for the first time by the user should
|
||||||
|
// be blacklisted here.
|
||||||
|
"before becoming idle": [
|
||||||
|
{
|
||||||
|
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 1,
|
||||||
|
close: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:places.sqlite-journal",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
fsync: 1,
|
||||||
|
stat: 4,
|
||||||
|
write: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:places.sqlite-wal",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 4,
|
||||||
|
fsync: 3,
|
||||||
|
write: 148,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:places.sqlite-shm",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 1,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:places.sqlite",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
fsync: 2,
|
||||||
|
read: 1,
|
||||||
|
stat: 3,
|
||||||
|
write: 1310,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:favicons.sqlite-journal",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
fsync: 2,
|
||||||
|
stat: 7,
|
||||||
|
write: 7,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:favicons.sqlite-wal",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
fsync: 2,
|
||||||
|
stat: 7,
|
||||||
|
write: 15,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:favicons.sqlite-shm",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{ // bug 1391590
|
||||||
|
path: "ProfD:favicons.sqlite",
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
fsync: 3,
|
||||||
|
read: 4,
|
||||||
|
stat: 4,
|
||||||
|
write: 1300,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ProfD:key4.db-journal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ProfD:key4.db-wal",
|
||||||
|
condition: WIN,
|
||||||
|
canonicalize: true,
|
||||||
|
stat: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ProfD:",
|
||||||
|
condition: WIN,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 3,
|
||||||
|
},
|
||||||
|
{ // bug 1543090
|
||||||
|
path: "XCurProcD:omni.ja",
|
||||||
|
condition: WIN,
|
||||||
|
stat: 7,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let name of ["d3d11layers", "d3d9video", "glcontext", "d3d11video", "wmfvpxvideo"]) {
|
||||||
|
startupPhases["before first paint"].push({
|
||||||
|
path: `ProfD:${name}.guard`,
|
||||||
|
ignoreIfUnused: true,
|
||||||
|
stat: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandWhitelistPath(path, canonicalize = false) {
|
||||||
|
if (path.includes(":")) {
|
||||||
|
let [prefix, suffix] = path.split(":");
|
||||||
|
let [key, property] = prefix.split(".");
|
||||||
|
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||||
|
if (property) {
|
||||||
|
dir = dir[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canonicalize) {
|
||||||
|
path = dir.QueryInterface(Ci.nsILocalFileWin).canonicalPath;
|
||||||
|
} else {
|
||||||
|
// Resolve symLinks.
|
||||||
|
let dirPath = dir.path;
|
||||||
|
while (dir && !dir.isSymlink()) {
|
||||||
|
dir = dir.parent;
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
dirPath = dirPath.replace(dir.path, dir.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = dirPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix) {
|
||||||
|
path += "/" + suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (AppConstants.platform == "win") {
|
||||||
|
path = path.replace(/\//g, "\\");
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStackFromProfile(profile, stack) {
|
||||||
|
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||||
|
const stackFrameCol = profile.stackTable.schema.frame;
|
||||||
|
const frameLocationCol = profile.frameTable.schema.location;
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
while (stack) {
|
||||||
|
let sp = profile.stackTable.data[stack];
|
||||||
|
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||||
|
stack = sp[stackPrefixCol];
|
||||||
|
frame = profile.stringTable[frame[frameLocationCol]];
|
||||||
|
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||||
|
result.push(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathMatches(path, filename) {
|
||||||
|
path = path.toLowerCase();
|
||||||
|
return path == filename || // Full match
|
||||||
|
// Wildcard on both sides of the path
|
||||||
|
(path.startsWith("*") && path.endsWith("*") &&
|
||||||
|
filename.includes(path.slice(1, -1))) ||
|
||||||
|
// Wildcard suffix
|
||||||
|
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||||
|
// Wildcard prefix
|
||||||
|
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||||
|
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||||
|
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||||
|
"non-debug build.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||||
|
omniJa.append("omni.ja");
|
||||||
|
if (!omniJa.exists()) {
|
||||||
|
ok(false, "This test requires a packaged build, " +
|
||||||
|
"run 'mach package' and then use --appname=dist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||||
|
await startupRecorder.done;
|
||||||
|
|
||||||
|
// Add system add-ons to the whitelist dynamically.
|
||||||
|
// They should go in the omni.ja file (bug 1357205).
|
||||||
|
{
|
||||||
|
let addons = await AddonManager.getAddonsByTypes(["extension"]);
|
||||||
|
for (let addon of addons) {
|
||||||
|
if (addon.isSystem) {
|
||||||
|
startupPhases["before opening first browser window"].push({
|
||||||
|
path: `XREAppFeat:${addon.id}.xpi`,
|
||||||
|
stat: 3,
|
||||||
|
close: 2,
|
||||||
|
});
|
||||||
|
startupPhases["before handling user events"].push({
|
||||||
|
path: `XREAppFeat:${addon.id}.xpi`,
|
||||||
|
condition: WIN,
|
||||||
|
stat: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for main thread I/O markers in the startup profile.
|
||||||
|
let profile = startupRecorder.data.profile.threads[0];
|
||||||
|
|
||||||
|
let phases = {};
|
||||||
|
{
|
||||||
|
const nameCol = profile.markers.schema.name;
|
||||||
|
const dataCol = profile.markers.schema.data;
|
||||||
|
|
||||||
|
let markersForCurrentPhase = [];
|
||||||
|
|
||||||
|
for (let m of profile.markers.data) {
|
||||||
|
let markerName = profile.stringTable[m[nameCol]];
|
||||||
|
if (markerName.startsWith("startupRecorder:")) {
|
||||||
|
phases[markerName.split("startupRecorder:")[1]] = markersForCurrentPhase;
|
||||||
|
markersForCurrentPhase = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (markerName != "FileIO")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let markerData = m[dataCol];
|
||||||
|
if (markerData.source == "sqlite-mainthread") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let samples = markerData.stack.samples;
|
||||||
|
let stack = samples.data[0][samples.schema.stack];
|
||||||
|
markersForCurrentPhase.push({operation: markerData.operation,
|
||||||
|
filename: markerData.filename,
|
||||||
|
source: markerData.source,
|
||||||
|
stackId: stack});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let phase in startupPhases) {
|
||||||
|
startupPhases[phase] =
|
||||||
|
startupPhases[phase].filter(entry => !("condition" in entry) || entry.condition);
|
||||||
|
startupPhases[phase].forEach(entry => {
|
||||||
|
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||||
|
let shouldPass = true;
|
||||||
|
for (let phase in phases) {
|
||||||
|
let whitelist = startupPhases[phase];
|
||||||
|
info(`whitelisted paths ${phase}:\n` +
|
||||||
|
whitelist.map(e => {
|
||||||
|
let operations = Object.keys(e).filter(k => k != "path")
|
||||||
|
.map(k => `${k}: ${e[k]}`);
|
||||||
|
return ` ${e.path} - ${operations.join(", ")}`;
|
||||||
|
}).join("\n"));
|
||||||
|
|
||||||
|
let markers = phases[phase];
|
||||||
|
for (let marker of markers) {
|
||||||
|
if (marker.operation == "create/open") {
|
||||||
|
// TODO: handle these I/O markers once they are supported on
|
||||||
|
// non-Windows platforms.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to lower case before comparing because the OS X test slaves
|
||||||
|
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||||
|
// as 'firefox' for some reason.
|
||||||
|
let filename = marker.filename.toLowerCase();
|
||||||
|
|
||||||
|
if (!filename) {
|
||||||
|
// We are still missing the filename on some mainthreadio markers,
|
||||||
|
// these markers are currently useless for the purpose of this test.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIN) {
|
||||||
|
if (filename == "/dev/urandom") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||||
|
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected = false;
|
||||||
|
for (let entry of whitelist) {
|
||||||
|
if (pathMatches(entry.path, filename)) {
|
||||||
|
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||||
|
entry._used = true;
|
||||||
|
expected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!expected) {
|
||||||
|
record(false,
|
||||||
|
`unexpected ${marker.operation} on ${marker.filename} ${phase}`,
|
||||||
|
undefined,
|
||||||
|
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||||
|
shouldPass = false;
|
||||||
|
}
|
||||||
|
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||||
|
if (kDumpAllStacks) {
|
||||||
|
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||||
|
.join("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let entry of whitelist) {
|
||||||
|
for (let op in entry) {
|
||||||
|
if (["path", "condition", "canonicalize", "ignoreIfUnused", "_used"].includes(op)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let message = `${op} on ${entry.path} `;
|
||||||
|
if (entry[op] == 0) {
|
||||||
|
message += "as many times as expected";
|
||||||
|
} else if (entry[op] > 0) {
|
||||||
|
message += `allowed ${entry[op]} more times`;
|
||||||
|
} else {
|
||||||
|
message += `${entry[op] * -1} more times than expected`;
|
||||||
|
}
|
||||||
|
ok(entry[op] >= 0, `${message} ${phase}`);
|
||||||
|
}
|
||||||
|
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||||
|
ok(false, `unused whitelist entry ${phase}: ${entry.path}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldPass) {
|
||||||
|
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||||
|
} else {
|
||||||
|
const filename = "startup-mainthreadio-profile.json";
|
||||||
|
let path = Cc["@mozilla.org/process/environment;1"]
|
||||||
|
.getService(Ci.nsIEnvironment)
|
||||||
|
.get("MOZ_UPLOAD_DIR");
|
||||||
|
let encoder = new TextEncoder();
|
||||||
|
let profilePath = OS.Path.join(path, filename);
|
||||||
|
await OS.File.writeAtomic(profilePath,
|
||||||
|
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||||
|
ok(false,
|
||||||
|
"Found some unexpected main thread I/O during startup; profile uploaded in " +
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
});
|
20
browser/base/content/test/performance/io/browser.ini
Normal file
20
browser/base/content/test/performance/io/browser.ini
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
# Currently disabled on debug due to debug-only failures, see bug 1549723.
|
||||||
|
skip-if = debug || (os == "linux" && asan) # bug 1549729
|
||||||
|
# to avoid overhead when running the browser normally, startupRecorder.js will
|
||||||
|
# do almost nothing unless browser.startup.record is true.
|
||||||
|
# gfx.canvas.willReadFrequently.enable is just an optimization, but needs to be
|
||||||
|
# set during early startup to have an impact as a canvas will be used by
|
||||||
|
# startupRecorder.js
|
||||||
|
prefs =
|
||||||
|
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
||||||
|
# representative of common startup, and triggers Places I/O.
|
||||||
|
browser.migration.version=9999999
|
||||||
|
browser.startup.record=true
|
||||||
|
gfx.canvas.willReadFrequently.enable=true
|
||||||
|
environment =
|
||||||
|
MOZ_PROFILER_STARTUP=1
|
||||||
|
MOZ_PROFILER_STARTUP_FEATURES=js,mainthreadio
|
||||||
|
MOZ_PROFILER_STARTUP_ENTRIES=10000000
|
||||||
|
[../browser_startup_mainthreadio.js]
|
||||||
|
[../browser_startup_content_mainthreadio.js]
|
@ -34,6 +34,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||||||
'content/test/pageinfo/browser.ini',
|
'content/test/pageinfo/browser.ini',
|
||||||
'content/test/performance/browser.ini',
|
'content/test/performance/browser.ini',
|
||||||
'content/test/performance/hidpi/browser.ini',
|
'content/test/performance/hidpi/browser.ini',
|
||||||
|
'content/test/performance/io/browser.ini',
|
||||||
'content/test/performance/legacyurlbar/browser.ini',
|
'content/test/performance/legacyurlbar/browser.ini',
|
||||||
'content/test/performance/lowdpi/browser.ini',
|
'content/test/performance/lowdpi/browser.ini',
|
||||||
'content/test/permissions/browser.ini',
|
'content/test/permissions/browser.ini',
|
||||||
|
@ -24,7 +24,6 @@ body.config-warning {
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
background-image: url("chrome://global/skin/icons/warning.svg");
|
background-image: url("chrome://global/skin/icons/warning.svg");
|
||||||
-moz-context-properties: fill;
|
|
||||||
fill: #fcd100;
|
fill: #fcd100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +96,8 @@ body.config-warning {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 9px center;
|
background-position: 9px center;
|
||||||
background-size: 16px 16px;
|
background-size: 16px 16px;
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#prefs > tr.locked:dir(rtl) {
|
#prefs > tr.locked:dir(rtl) {
|
||||||
|
@ -37,7 +37,11 @@ NOTE: The collection and messages can also be created manually using the [admin
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
Services.prefs.setStringPref("services.settings.server", "https://kinto.dev.mozaws.net/v1");
|
Services.prefs.setStringPref("services.settings.server", "https://kinto.dev.mozaws.net/v1");
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
// Disable signature verification
|
||||||
|
const { RemoteSettings } = ChromeUtils.import("resource://services-settings/remote-settings.js", {});
|
||||||
|
|
||||||
|
RemoteSettings("cfr").verifySignature = false;
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. Set ASRouter CFR pref to use Remote Settings provider and enable asrouter devtools.**
|
**3. Set ASRouter CFR pref to use Remote Settings provider and enable asrouter devtools.**
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extensionName": {
|
|
||||||
"message": "Amazon.com.br"
|
|
||||||
},
|
|
||||||
"extensionDescription": {
|
|
||||||
"message": "Amazon.com.br Search"
|
|
||||||
},
|
|
||||||
"searchUrl": {
|
|
||||||
"message": "https://www.amazon.com.br/exec/obidos/external-search/"
|
|
||||||
},
|
|
||||||
"searchForm": {
|
|
||||||
"message": "https://www.amazon.com.br/exec/obidos/external-search/?field-keywords={searchTerms}&ie={inputEncoding}&mode=blended"
|
|
||||||
},
|
|
||||||
"searchUrlGetParams": {
|
|
||||||
"message": "field-keywords={searchTerms}&ie={inputEncoding}&mode=blended"
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
"name": "__MSG_extensionName__",
|
"name": "__MSG_extensionName__",
|
||||||
"description": "__MSG_extensionDescription__",
|
"description": "__MSG_extensionDescription__",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"version": "1.0",
|
"version": "1.1",
|
||||||
"applications": {
|
"applications": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "amazon@search.mozilla.org"
|
"id": "amazon@search.mozilla.org"
|
||||||
@ -24,4 +24,4 @@
|
|||||||
"search_url_get_params": "__MSG_searchUrlGetParams__"
|
"search_url_get_params": "__MSG_searchUrlGetParams__"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "__MSG_extensionName__",
|
"name": "__MSG_extensionName__",
|
||||||
"description": "__MSG_extensionDescription__",
|
"description": "__MSG_extensionDescription__",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"version": "1.0",
|
"version": "1.1",
|
||||||
"applications": {
|
"applications": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "amazondotcom@search.mozilla.org"
|
"id": "amazondotcom@search.mozilla.org"
|
||||||
@ -25,4 +25,4 @@
|
|||||||
"search_url_get_params": "__MSG_searchUrlGetParams__"
|
"search_url_get_params": "__MSG_searchUrlGetParams__"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,14 +214,14 @@
|
|||||||
"de": {
|
"de": {
|
||||||
"default": {
|
"default": {
|
||||||
"visibleDefaultEngines": [
|
"visibleDefaultEngines": [
|
||||||
"google-b-d", "amazondotcom-de", "bing", "ddg", "ebay-de", "ecosia", "leo_ende_de", "wikipedia-de"
|
"google-b-d", "amazon-de", "bing", "ddg", "ebay-de", "ecosia", "leo_ende_de", "wikipedia-de"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dsb": {
|
"dsb": {
|
||||||
"default": {
|
"default": {
|
||||||
"visibleDefaultEngines": [
|
"visibleDefaultEngines": [
|
||||||
"google-b-d", "bing", "amazondotcom-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-dsb"
|
"google-b-d", "bing", "amazon-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-dsb"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -396,7 +396,7 @@
|
|||||||
"hsb": {
|
"hsb": {
|
||||||
"default": {
|
"default": {
|
||||||
"visibleDefaultEngines": [
|
"visibleDefaultEngines": [
|
||||||
"google-b-d", "bing", "amazondotcom-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-hsb"
|
"google-b-d", "bing", "amazon-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-hsb"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -26,18 +26,21 @@ var gSetBackground = {
|
|||||||
// regular screens seem to be 32:9 (3.56) according to Wikipedia.
|
// regular screens seem to be 32:9 (3.56) according to Wikipedia.
|
||||||
let screenRatio = Math.min(this._screenWidth / this._screenHeight, 4);
|
let screenRatio = Math.min(this._screenWidth / this._screenHeight, 4);
|
||||||
this._canvas.width = this._canvas.height * screenRatio;
|
this._canvas.width = this._canvas.height * screenRatio;
|
||||||
|
document.getElementById("preview-unavailable").style.width =
|
||||||
|
this._canvas.width + "px";
|
||||||
|
|
||||||
if (AppConstants.platform == "macosx") {
|
if (AppConstants.platform == "macosx") {
|
||||||
document.documentElement.getButton("accept").hidden = true;
|
document.documentElement.getButton("accept").hidden = true;
|
||||||
} else {
|
} else {
|
||||||
let multiMonitors = false;
|
let multiMonitors = false;
|
||||||
try {
|
if (AppConstants.platform == "linux") {
|
||||||
|
// getMonitors only ever returns the primary monitor on Linux, so just
|
||||||
|
// always show the option
|
||||||
|
multiMonitors = true;
|
||||||
|
} else {
|
||||||
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
|
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
|
||||||
const monitors = gfxInfo.getMonitors();
|
const monitors = gfxInfo.getMonitors();
|
||||||
multiMonitors = monitors.length > 1;
|
multiMonitors = monitors.length > 1;
|
||||||
} catch (e) {
|
|
||||||
// getMonitors() isn't implemented on Linux
|
|
||||||
multiMonitors = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!multiMonitors || AppConstants.isPlatformAndVersionAtMost("win", 6.1)) {
|
if (!multiMonitors || AppConstants.isPlatformAndVersionAtMost("win", 6.1)) {
|
||||||
@ -101,6 +104,7 @@ var gSetBackground = {
|
|||||||
updatePosition() {
|
updatePosition() {
|
||||||
var ctx = this._canvas.getContext("2d");
|
var ctx = this._canvas.getContext("2d");
|
||||||
ctx.clearRect(0, 0, this._screenWidth, this._screenHeight);
|
ctx.clearRect(0, 0, this._screenWidth, this._screenHeight);
|
||||||
|
document.getElementById("preview-unavailable").hidden = true;
|
||||||
|
|
||||||
if (AppConstants.platform != "macosx") {
|
if (AppConstants.platform != "macosx") {
|
||||||
this._position = document.getElementById("menuPosition").value;
|
this._position = document.getElementById("menuPosition").value;
|
||||||
@ -157,18 +161,9 @@ var gSetBackground = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "SPAN": {
|
case "SPAN": {
|
||||||
ctx.fillStyle = "black";
|
document.getElementById("preview-unavailable").hidden = false;
|
||||||
|
ctx.fillStyle = "#222";
|
||||||
ctx.fillRect(0, 0, this._screenWidth, this._screenHeight);
|
ctx.fillRect(0, 0, this._screenWidth, this._screenHeight);
|
||||||
let x = this._screenWidth / 2;
|
|
||||||
let y = this._screenHeight / 2;
|
|
||||||
let radius = this._screenHeight * .4;
|
|
||||||
let delta = Math.sin(.25 * Math.PI) * radius; // opp = sin * hyp
|
|
||||||
ctx.lineWidth = radius / 4.5;
|
|
||||||
ctx.strokeStyle = "#9B2423";
|
|
||||||
ctx.arc(x, y, radius, -.75 * Math.PI, 1.25 * Math.PI);
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.lineWidth *= .8;
|
|
||||||
ctx.lineTo(x + delta, y + delta);
|
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,12 @@
|
|||||||
|
|
||||||
<vbox align="center">
|
<vbox align="center">
|
||||||
<!-- default to 16:9, will be adjusted to match user's actual screen -->
|
<!-- default to 16:9, will be adjusted to match user's actual screen -->
|
||||||
<html:canvas id="screen" width="202" height="114" role="presentation"/>
|
<stack>
|
||||||
|
<html:canvas id="screen" width="202" height="114" role="presentation"/>
|
||||||
|
<vbox pack="center">
|
||||||
|
<html:p id="preview-unavailable" hidden="">&previewUnavailable;</html:p>
|
||||||
|
</vbox>
|
||||||
|
</stack>
|
||||||
<image id="monitor-base"/>
|
<image id="monitor-base"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ startupRecorder.prototype = {
|
|||||||
if (!Services.prefs.getBoolPref("browser.startup.record", false))
|
if (!Services.prefs.getBoolPref("browser.startup.record", false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Services.profiler.AddMarker("startupRecorder:" + name);
|
||||||
this.data.code[name] = {
|
this.data.code[name] = {
|
||||||
components: Cu.loadedComponents,
|
components: Cu.loadedComponents,
|
||||||
modules: Cu.loadedModules,
|
modules: Cu.loadedModules,
|
||||||
@ -163,8 +164,24 @@ startupRecorder.prototype = {
|
|||||||
Services.prefs.readStats((key, value) => this.data.prefStats[key] = value);
|
Services.prefs.readStats((key, value) => this.data.prefStats[key] = value);
|
||||||
}
|
}
|
||||||
paints = null;
|
paints = null;
|
||||||
this._resolve();
|
|
||||||
this._resolve = null;
|
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||||
|
if (!env.exists("MOZ_PROFILER_STARTUP")) {
|
||||||
|
this._resolve();
|
||||||
|
this._resolve = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.profiler.getProfileDataAsync().then(profileData => {
|
||||||
|
this.data.profile = profileData;
|
||||||
|
// There's no equivalent StartProfiler call in this file because the
|
||||||
|
// profiler is started using the MOZ_PROFILER_STARTUP environment
|
||||||
|
// variable in browser/base/content/test/performance/browser.ini
|
||||||
|
Services.profiler.StopProfiler();
|
||||||
|
|
||||||
|
this._resolve();
|
||||||
|
this._resolve = null;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const topicsToNames = {
|
const topicsToNames = {
|
||||||
|
@ -18,3 +18,4 @@
|
|||||||
<!ENTITY setDesktopBackground.title "Set Desktop Background">
|
<!ENTITY setDesktopBackground.title "Set Desktop Background">
|
||||||
<!ENTITY openDesktopPrefs.label "Open Desktop Preferences">
|
<!ENTITY openDesktopPrefs.label "Open Desktop Preferences">
|
||||||
<!ENTITY closeWindow.key "w">
|
<!ENTITY closeWindow.key "w">
|
||||||
|
<!ENTITY previewUnavailable "Preview unavailable">
|
||||||
|
@ -14,8 +14,6 @@ body {
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
background-image: url("chrome://global/skin/icons/blocked.svg");
|
background-image: url("chrome://global/skin/icons/blocked.svg");
|
||||||
fill: currentColor;
|
|
||||||
-moz-context-properties: fill;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-text {
|
.title-text {
|
||||||
|
@ -14,3 +14,10 @@ html|canvas#screen {
|
|||||||
#monitor-base {
|
#monitor-base {
|
||||||
list-style-image: url("chrome://browser/skin/monitor-base.png");
|
list-style-image: url("chrome://browser/skin/monitor-base.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html|p#preview-unavailable {
|
||||||
|
margin: 12px 11px;
|
||||||
|
text-align: center;
|
||||||
|
color: #9B2423;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
@ -11,6 +11,8 @@ const Services = require("Services");
|
|||||||
|
|
||||||
const { l10n } = require("../modules/l10n");
|
const { l10n } = require("../modules/l10n");
|
||||||
|
|
||||||
|
const { isSupportedDebugTargetPane } = require("../modules/debug-target-support");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
openTemporaryExtension,
|
openTemporaryExtension,
|
||||||
uninstallAddon,
|
uninstallAddon,
|
||||||
@ -23,6 +25,7 @@ const {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
DEBUG_TARGETS,
|
DEBUG_TARGETS,
|
||||||
|
DEBUG_TARGET_PANE,
|
||||||
REQUEST_EXTENSIONS_FAILURE,
|
REQUEST_EXTENSIONS_FAILURE,
|
||||||
REQUEST_EXTENSIONS_START,
|
REQUEST_EXTENSIONS_START,
|
||||||
REQUEST_EXTENSIONS_SUCCESS,
|
REQUEST_EXTENSIONS_SUCCESS,
|
||||||
@ -162,10 +165,13 @@ function requestTabs() {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
dispatch({ type: REQUEST_TABS_START });
|
dispatch({ type: REQUEST_TABS_START });
|
||||||
|
|
||||||
|
const runtime = getCurrentRuntime(getState().runtimes);
|
||||||
const clientWrapper = getCurrentClient(getState().runtimes);
|
const clientWrapper = getCurrentClient(getState().runtimes);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tabs = await clientWrapper.listTabs({ favicons: true });
|
const isSupported = isSupportedDebugTargetPane(runtime.runtimeDetails.info.type,
|
||||||
|
DEBUG_TARGET_PANE.TAB);
|
||||||
|
const tabs = isSupported ? (await clientWrapper.listTabs({ favicons: true })) : [];
|
||||||
|
|
||||||
dispatch({ type: REQUEST_TABS_SUCCESS, tabs });
|
dispatch({ type: REQUEST_TABS_SUCCESS, tabs });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -41,6 +41,24 @@ add_task(async function testThisFirefoxWithoutLocalTab() {
|
|||||||
await removeTab(tab);
|
await removeTab(tab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the tab which is discarded keeps the state after open the aboutdebugging.
|
||||||
|
*/
|
||||||
|
add_task(async function testThisFirefoxKeepDiscardedTab() {
|
||||||
|
const targetTab = await addTab("https://example.com/");
|
||||||
|
const blankTab = await addTab("about:blank");
|
||||||
|
targetTab.ownerGlobal.gBrowser.discardBrowser(targetTab);
|
||||||
|
|
||||||
|
const { document, tab, window } = await openAboutDebugging({ enableLocalTabs: false });
|
||||||
|
await selectThisFirefoxPage(document, window.AboutDebugging.store);
|
||||||
|
|
||||||
|
ok(!targetTab.linkedPanel, "The target tab is still discarded");
|
||||||
|
|
||||||
|
await removeTab(blankTab);
|
||||||
|
await removeTab(targetTab);
|
||||||
|
await removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the Temporary Extensions is hidden if "xpinstall.enabled" is set to false.
|
* Check that the Temporary Extensions is hidden if "xpinstall.enabled" is set to false.
|
||||||
*/
|
*/
|
||||||
@ -81,4 +99,3 @@ async function checkThisFirefoxTargetPanes(doc, expectedTargetPanes) {
|
|||||||
`Expected debug target category found: ${ expectedPaneTitle }`);
|
`Expected debug target category found: ${ expectedPaneTitle }`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,17 +267,20 @@ void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
|
|||||||
|
|
||||||
const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
|
const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
|
||||||
currentSlots.RemoveElement(*aSlot);
|
currentSlots.RemoveElement(*aSlot);
|
||||||
|
|
||||||
// Move assigned nodes from removed slot to the next slot in
|
|
||||||
// tree order with the same name.
|
|
||||||
if (!wasFirstSlot) {
|
if (!wasFirstSlot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move assigned nodes from removed slot to the next slot in
|
||||||
|
// tree order with the same name.
|
||||||
InvalidateStyleAndLayoutOnSubtree(aSlot);
|
InvalidateStyleAndLayoutOnSubtree(aSlot);
|
||||||
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
||||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
||||||
bool slottedNodesChanged = !assignedNodes.IsEmpty();
|
if (assignedNodes.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidateStyleAndLayoutOnSubtree(replacementSlot);
|
||||||
while (!assignedNodes.IsEmpty()) {
|
while (!assignedNodes.IsEmpty()) {
|
||||||
nsINode* assignedNode = assignedNodes[0];
|
nsINode* assignedNode = assignedNodes[0];
|
||||||
|
|
||||||
@ -285,10 +288,8 @@ void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
|
|||||||
replacementSlot->AppendAssignedNode(assignedNode);
|
replacementSlot->AppendAssignedNode(assignedNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slottedNodesChanged) {
|
aSlot->EnqueueSlotChangeEvent();
|
||||||
aSlot->EnqueueSlotChangeEvent();
|
replacementSlot->EnqueueSlotChangeEvent();
|
||||||
replacementSlot->EnqueueSlotChangeEvent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): There's a bit of code duplication between this and the
|
// FIXME(emilio): There's a bit of code duplication between this and the
|
||||||
|
@ -62,13 +62,13 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
|||||||
virtual ~nsDocumentEncoder();
|
virtual ~nsDocumentEncoder();
|
||||||
|
|
||||||
void Initialize(bool aClearCachedSerializer = true);
|
void Initialize(bool aClearCachedSerializer = true);
|
||||||
nsresult SerializeNodeStart(nsINode* aNode, int32_t aStartOffset,
|
nsresult SerializeNodeStart(nsINode& aOriginalNode, int32_t aStartOffset,
|
||||||
int32_t aEndOffset, nsAString& aStr,
|
int32_t aEndOffset, nsAString& aStr,
|
||||||
nsINode* aOriginalNode = nullptr);
|
nsINode* aFixupNode = nullptr);
|
||||||
nsresult SerializeToStringRecursive(nsINode* aNode, nsAString& aStr,
|
nsresult SerializeToStringRecursive(nsINode* aNode, nsAString& aStr,
|
||||||
bool aDontSerializeRoot,
|
bool aDontSerializeRoot,
|
||||||
uint32_t aMaxLength = 0);
|
uint32_t aMaxLength = 0);
|
||||||
nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr);
|
nsresult SerializeNodeEnd(nsINode& aNode, nsAString& aStr);
|
||||||
// This serializes the content of aNode.
|
// This serializes the content of aNode.
|
||||||
nsresult SerializeToStringIterative(nsINode* aNode, nsAString& aStr);
|
nsresult SerializeToStringIterative(nsINode* aNode, nsAString& aStr);
|
||||||
nsresult SerializeRangeToString(nsRange* aRange, nsAString& aOutputString);
|
nsresult SerializeRangeToString(nsRange* aRange, nsAString& aOutputString);
|
||||||
@ -296,34 +296,59 @@ nsDocumentEncoder::GetMimeType(nsAString& aMimeType) {
|
|||||||
|
|
||||||
bool nsDocumentEncoder::IncludeInContext(nsINode* aNode) { return false; }
|
bool nsDocumentEncoder::IncludeInContext(nsINode* aNode) { return false; }
|
||||||
|
|
||||||
nsresult nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
|
class FixupNodeDeterminer {
|
||||||
int32_t aStartOffset,
|
public:
|
||||||
int32_t aEndOffset,
|
FixupNodeDeterminer(nsIDocumentEncoderNodeFixup* aNodeFixup,
|
||||||
nsAString& aStr,
|
nsINode* aFixupNode, nsINode& aOriginalNode)
|
||||||
nsINode* aOriginalNode) {
|
: mIsSerializationOfFixupChildrenNeeded{false},
|
||||||
if (mNeedsPreformatScanning && aNode->IsElement()) {
|
mNodeFixup(aNodeFixup),
|
||||||
mSerializer->ScanElementForPreformat(aNode->AsElement());
|
mOriginalNode(aOriginalNode) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsVisibleNode(aNode)) return NS_OK;
|
|
||||||
|
|
||||||
nsINode* node = nullptr;
|
|
||||||
nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
|
|
||||||
|
|
||||||
// Caller didn't do fixup, so we'll do it ourselves
|
|
||||||
if (!aOriginalNode) {
|
|
||||||
aOriginalNode = aNode;
|
|
||||||
if (mNodeFixup) {
|
if (mNodeFixup) {
|
||||||
bool dummy;
|
if (aFixupNode) {
|
||||||
mNodeFixup->FixupNode(aNode, &dummy,
|
mFixupNode = aFixupNode;
|
||||||
getter_AddRefs(fixedNodeKungfuDeathGrip));
|
} else {
|
||||||
node = fixedNodeKungfuDeathGrip;
|
mNodeFixup->FixupNode(&mOriginalNode,
|
||||||
|
&mIsSerializationOfFixupChildrenNeeded,
|
||||||
|
getter_AddRefs(mFixupNode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Either there was no fixed-up node,
|
bool IsSerializationOfFixupChildrenNeeded() const {
|
||||||
// or the caller did fixup themselves and aNode is already fixed
|
return mIsSerializationOfFixupChildrenNeeded;
|
||||||
if (!node) node = aNode;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The fixup node, if available, otherwise the original node. The
|
||||||
|
* former is kept alive by this object.
|
||||||
|
*/
|
||||||
|
nsINode& GetFixupNodeFallBackToOriginalNode() const {
|
||||||
|
return mFixupNode ? *mFixupNode : mOriginalNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mIsSerializationOfFixupChildrenNeeded;
|
||||||
|
nsIDocumentEncoderNodeFixup* mNodeFixup;
|
||||||
|
nsCOMPtr<nsINode> mFixupNode;
|
||||||
|
nsINode& mOriginalNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsresult nsDocumentEncoder::SerializeNodeStart(nsINode& aOriginalNode,
|
||||||
|
int32_t aStartOffset,
|
||||||
|
int32_t aEndOffset,
|
||||||
|
nsAString& aStr,
|
||||||
|
nsINode* aFixupNode) {
|
||||||
|
if (mNeedsPreformatScanning && aOriginalNode.IsElement()) {
|
||||||
|
mSerializer->ScanElementForPreformat(aOriginalNode.AsElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsVisibleNode(&aOriginalNode)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixupNodeDeterminer fixupNodeDeterminer{mNodeFixup, aFixupNode,
|
||||||
|
aOriginalNode};
|
||||||
|
nsINode* node = &fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
|
||||||
|
|
||||||
if (node->IsElement()) {
|
if (node->IsElement()) {
|
||||||
if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
|
if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
|
||||||
@ -331,7 +356,7 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
|
|||||||
nsLayoutUtils::IsInvisibleBreak(node)) {
|
nsLayoutUtils::IsInvisibleBreak(node)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
Element* originalElement = Element::FromNodeOrNull(aOriginalNode);
|
Element* originalElement = aOriginalNode.AsElement();
|
||||||
mSerializer->AppendElementStart(node->AsElement(), originalElement, aStr);
|
mSerializer->AppendElementStart(node->AsElement(), originalElement, aStr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -367,15 +392,17 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode, nsAString& aStr) {
|
nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode& aNode, nsAString& aStr) {
|
||||||
if (mNeedsPreformatScanning && aNode->IsElement()) {
|
if (mNeedsPreformatScanning && aNode.IsElement()) {
|
||||||
mSerializer->ForgetElementForPreformat(aNode->AsElement());
|
mSerializer->ForgetElementForPreformat(aNode.AsElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsVisibleNode(aNode)) return NS_OK;
|
if (!IsVisibleNode(&aNode)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (aNode->IsElement()) {
|
if (aNode.IsElement()) {
|
||||||
mSerializer->AppendElementEnd(aNode->AsElement(), aStr);
|
mSerializer->AppendElementEnd(aNode.AsElement(), aStr);
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -391,18 +418,11 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
|||||||
if (!IsVisibleNode(aNode)) return NS_OK;
|
if (!IsVisibleNode(aNode)) return NS_OK;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
bool serializeClonedChildren = false;
|
|
||||||
nsINode* maybeFixedNode = nullptr;
|
|
||||||
|
|
||||||
// Keep the node from FixupNode alive.
|
MOZ_ASSERT(aNode, "aNode shouldn't be nullptr.");
|
||||||
nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
|
FixupNodeDeterminer fixupNodeDeterminer{mNodeFixup, nullptr, *aNode};
|
||||||
if (mNodeFixup) {
|
nsINode* maybeFixedNode =
|
||||||
mNodeFixup->FixupNode(aNode, &serializeClonedChildren,
|
&fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
|
||||||
getter_AddRefs(fixedNodeKungfuDeathGrip));
|
|
||||||
maybeFixedNode = fixedNodeKungfuDeathGrip;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!maybeFixedNode) maybeFixedNode = aNode;
|
|
||||||
|
|
||||||
if ((mFlags & SkipInvisibleContent) &&
|
if ((mFlags & SkipInvisibleContent) &&
|
||||||
!(mFlags & OutputNonTextContentAsPlaceholder)) {
|
!(mFlags & OutputNonTextContentAsPlaceholder)) {
|
||||||
@ -421,11 +441,13 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
|||||||
MOZ_ASSERT(aMaxLength >= aStr.Length());
|
MOZ_ASSERT(aMaxLength >= aStr.Length());
|
||||||
endOffset = aMaxLength - aStr.Length();
|
endOffset = aMaxLength - aStr.Length();
|
||||||
}
|
}
|
||||||
rv = SerializeNodeStart(maybeFixedNode, 0, endOffset, aStr, aNode);
|
rv = SerializeNodeStart(*aNode, 0, endOffset, aStr, maybeFixedNode);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* node = serializeClonedChildren ? maybeFixedNode : aNode;
|
nsINode* node = fixupNodeDeterminer.IsSerializationOfFixupChildrenNeeded()
|
||||||
|
? maybeFixedNode
|
||||||
|
: aNode;
|
||||||
|
|
||||||
for (nsINode* child = nsNodeUtils::GetFirstChildOfTemplateOrNode(node); child;
|
for (nsINode* child = nsNodeUtils::GetFirstChildOfTemplateOrNode(node); child;
|
||||||
child = child->GetNextSibling()) {
|
child = child->GetNextSibling()) {
|
||||||
@ -434,7 +456,7 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!aDontSerializeRoot) {
|
if (!aDontSerializeRoot) {
|
||||||
rv = SerializeNodeEnd(maybeFixedNode, aStr);
|
rv = SerializeNodeEnd(*maybeFixedNode, aStr);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,11 +470,11 @@ nsresult nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode,
|
|||||||
nsINode* node = nsNodeUtils::GetFirstChildOfTemplateOrNode(aNode);
|
nsINode* node = nsNodeUtils::GetFirstChildOfTemplateOrNode(aNode);
|
||||||
while (node) {
|
while (node) {
|
||||||
nsINode* current = node;
|
nsINode* current = node;
|
||||||
rv = SerializeNodeStart(current, 0, -1, aStr, current);
|
rv = SerializeNodeStart(*current, 0, -1, aStr, current);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
node = nsNodeUtils::GetFirstChildOfTemplateOrNode(current);
|
node = nsNodeUtils::GetFirstChildOfTemplateOrNode(current);
|
||||||
while (!node && current && current != aNode) {
|
while (!node && current && current != aNode) {
|
||||||
rv = SerializeNodeEnd(current, aStr);
|
rv = SerializeNodeEnd(*current, aStr);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
// Check if we have siblings.
|
// Check if we have siblings.
|
||||||
node = current->GetNextSibling();
|
node = current->GetNextSibling();
|
||||||
@ -577,14 +599,14 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
|||||||
if (IsTextNode(aNode)) {
|
if (IsTextNode(aNode)) {
|
||||||
if (startNode == content) {
|
if (startNode == content) {
|
||||||
int32_t startOffset = aRange->StartOffset();
|
int32_t startOffset = aRange->StartOffset();
|
||||||
rv = SerializeNodeStart(aNode, startOffset, -1, aString);
|
rv = SerializeNodeStart(*aNode, startOffset, -1, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
int32_t endOffset = aRange->EndOffset();
|
int32_t endOffset = aRange->EndOffset();
|
||||||
rv = SerializeNodeStart(aNode, 0, endOffset, aString);
|
rv = SerializeNodeStart(*aNode, 0, endOffset, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
rv = SerializeNodeEnd(aNode, aString);
|
rv = SerializeNodeEnd(*aNode, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
if (aNode != mCommonParent) {
|
if (aNode != mCommonParent) {
|
||||||
@ -597,7 +619,7 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
|||||||
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
||||||
|
|
||||||
// serialize the start of this node
|
// serialize the start of this node
|
||||||
rv = SerializeNodeStart(aNode, 0, -1, aString);
|
rv = SerializeNodeStart(*aNode, 0, -1, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,7 +675,7 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
|||||||
|
|
||||||
// serialize the end of this node
|
// serialize the end of this node
|
||||||
if (aNode != mCommonParent) {
|
if (aNode != mCommonParent) {
|
||||||
rv = SerializeNodeEnd(aNode, aString);
|
rv = SerializeNodeEnd(*aNode, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,7 +704,7 @@ nsresult nsDocumentEncoder::SerializeRangeContextStart(
|
|||||||
|
|
||||||
// Either a general inclusion or as immediate context
|
// Either a general inclusion or as immediate context
|
||||||
if (IncludeInContext(node) || i < j) {
|
if (IncludeInContext(node) || i < j) {
|
||||||
rv = SerializeNodeStart(node, 0, -1, aString);
|
rv = SerializeNodeStart(*node, 0, -1, aString);
|
||||||
serializedContext->AppendElement(node);
|
serializedContext->AppendElement(node);
|
||||||
if (NS_FAILED(rv)) break;
|
if (NS_FAILED(rv)) break;
|
||||||
}
|
}
|
||||||
@ -702,7 +724,7 @@ nsresult nsDocumentEncoder::SerializeRangeContextEnd(nsAString& aString) {
|
|||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
for (nsINode* node : Reversed(serializedContext)) {
|
for (nsINode* node : Reversed(serializedContext)) {
|
||||||
rv = SerializeNodeEnd(node, aString);
|
rv = SerializeNodeEnd(*node, aString);
|
||||||
|
|
||||||
if (NS_FAILED(rv)) break;
|
if (NS_FAILED(rv)) break;
|
||||||
}
|
}
|
||||||
@ -759,10 +781,10 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange,
|
|||||||
if (!parent || !IsVisibleNode(parent)) return NS_OK;
|
if (!parent || !IsVisibleNode(parent)) return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = SerializeNodeStart(startContainer, startOffset, endOffset,
|
rv = SerializeNodeStart(*startContainer, startOffset, endOffset,
|
||||||
aOutputString);
|
aOutputString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = SerializeNodeEnd(startContainer, aOutputString);
|
rv = SerializeNodeEnd(*startContainer, aOutputString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
|
rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
|
||||||
@ -861,7 +883,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||||||
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
||||||
if (node != prevNode) {
|
if (node != prevNode) {
|
||||||
if (prevNode) {
|
if (prevNode) {
|
||||||
rv = SerializeNodeEnd(prevNode, output);
|
rv = SerializeNodeEnd(*prevNode, output);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||||
@ -878,7 +900,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||||||
mDisableContextSerialize = true;
|
mDisableContextSerialize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = SerializeNodeStart(node, 0, -1, output);
|
rv = SerializeNodeStart(*node, 0, -1, output);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
prevNode = node;
|
prevNode = node;
|
||||||
} else if (prevNode) {
|
} else if (prevNode) {
|
||||||
@ -899,7 +921,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||||||
mStartDepth = firstRangeStartDepth;
|
mStartDepth = firstRangeStartDepth;
|
||||||
|
|
||||||
if (prevNode) {
|
if (prevNode) {
|
||||||
rv = SerializeNodeEnd(prevNode, output);
|
rv = SerializeNodeEnd(*prevNode, output);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
mDisableContextSerialize = false;
|
mDisableContextSerialize = false;
|
||||||
rv = SerializeRangeContextEnd(output);
|
rv = SerializeRangeContextEnd(output);
|
||||||
@ -1266,12 +1288,12 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
|||||||
i = count;
|
i = count;
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
node = mCommonAncestors.ElementAt(--i);
|
node = mCommonAncestors.ElementAt(--i);
|
||||||
SerializeNodeStart(node, 0, -1, aContextString);
|
SerializeNodeStart(*node, 0, -1, aContextString);
|
||||||
}
|
}
|
||||||
// i = 0; guaranteed by above
|
// i = 0; guaranteed by above
|
||||||
while (i < count) {
|
while (i < count) {
|
||||||
node = mCommonAncestors.ElementAt(i++);
|
node = mCommonAncestors.ElementAt(i++);
|
||||||
SerializeNodeEnd(node, aContextString);
|
SerializeNodeEnd(*node, aContextString);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode range info : the start and end depth of the selection, where the
|
// encode range info : the start and end depth of the selection, where the
|
||||||
|
@ -96,12 +96,7 @@ function check_mp4(v, enabled) {
|
|||||||
check(codec, "probably");
|
check(codec, "probably");
|
||||||
ok(MediaSource.isTypeSupported(codec), "VP9 in MP4 should be supported in MSE");
|
ok(MediaSource.isTypeSupported(codec), "VP9 in MP4 should be supported in MSE");
|
||||||
});
|
});
|
||||||
|
check("video/mp4; codecs=\"av1\"", "probably");
|
||||||
if (IsAndroid()) {
|
|
||||||
check("video/mp4; codecs=\"av1\"", "");
|
|
||||||
} else {
|
|
||||||
check("video/mp4; codecs=\"av1\"", "probably");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_mp3(v, enabled) {
|
function check_mp3(v, enabled) {
|
||||||
@ -143,10 +138,6 @@ function getPref(name) {
|
|||||||
return pref;
|
return pref;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IsAndroid() {
|
|
||||||
return getAndroidVersion() >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function IsSupportedAndroid() {
|
function IsSupportedAndroid() {
|
||||||
return getAndroidVersion() >= 14;
|
return getAndroidVersion() >= 14;
|
||||||
}
|
}
|
||||||
|
@ -123,30 +123,6 @@ using namespace widget;
|
|||||||
* mozilla::EditorBase
|
* mozilla::EditorBase
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
template already_AddRefed<Element> EditorBase::CreateNodeWithTransaction(
|
|
||||||
nsAtom& aTag, const EditorDOMPoint& aPointToInsert);
|
|
||||||
template already_AddRefed<Element> EditorBase::CreateNodeWithTransaction(
|
|
||||||
nsAtom& aTag, const EditorRawDOMPoint& aPointToInsert);
|
|
||||||
template nsresult EditorBase::InsertNodeWithTransaction(
|
|
||||||
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
|
||||||
template nsresult EditorBase::InsertNodeWithTransaction(
|
|
||||||
nsIContent& aContentToInsert, const EditorRawDOMPoint& aPointToInsert);
|
|
||||||
template already_AddRefed<nsIContent> EditorBase::SplitNodeWithTransaction(
|
|
||||||
const EditorDOMPoint& aStartOfRightNode, ErrorResult& aError);
|
|
||||||
template already_AddRefed<nsIContent> EditorBase::SplitNodeWithTransaction(
|
|
||||||
const EditorRawDOMPoint& aStartOfRightNode, ErrorResult& aError);
|
|
||||||
template SplitNodeResult EditorBase::SplitNodeDeepWithTransaction(
|
|
||||||
nsIContent& aMostAncestorToSplit,
|
|
||||||
const EditorDOMPoint& aStartOfDeepestRightNode, SplitAtEdges aSplitAtEdges);
|
|
||||||
template SplitNodeResult EditorBase::SplitNodeDeepWithTransaction(
|
|
||||||
nsIContent& aMostAncestorToSplit,
|
|
||||||
const EditorRawDOMPoint& aStartOfDeepestRightNode,
|
|
||||||
SplitAtEdges aSplitAtEdges);
|
|
||||||
template nsresult EditorBase::MoveNodeWithTransaction(
|
|
||||||
nsIContent& aContent, const EditorDOMPoint& aPointToInsert);
|
|
||||||
template nsresult EditorBase::MoveNodeWithTransaction(
|
|
||||||
nsIContent& aContent, const EditorRawDOMPoint& aPointToInsert);
|
|
||||||
|
|
||||||
EditorBase::EditorBase()
|
EditorBase::EditorBase()
|
||||||
: mEditActionData(nullptr),
|
: mEditActionData(nullptr),
|
||||||
mPlaceholderName(nullptr),
|
mPlaceholderName(nullptr),
|
||||||
@ -1342,9 +1318,8 @@ EditorBase::SetSpellcheckUserOverride(bool enable) {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
already_AddRefed<Element> EditorBase::CreateNodeWithTransaction(
|
already_AddRefed<Element> EditorBase::CreateNodeWithTransaction(
|
||||||
nsAtom& aTagName, const EditorDOMPointBase<PT, CT>& aPointToInsert) {
|
nsAtom& aTagName, const EditorDOMPoint& aPointToInsert) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
||||||
@ -1414,18 +1389,16 @@ EditorBase::InsertNode(nsINode* aNodeToInsert, nsINode* aContainer,
|
|||||||
aOffset < 0
|
aOffset < 0
|
||||||
? static_cast<int32_t>(aContainer->Length())
|
? static_cast<int32_t>(aContainer->Length())
|
||||||
: std::min(aOffset, static_cast<int32_t>(aContainer->Length()));
|
: std::min(aOffset, static_cast<int32_t>(aContainer->Length()));
|
||||||
nsresult rv = InsertNodeWithTransaction(
|
nsresult rv = InsertNodeWithTransaction(*contentToInsert,
|
||||||
*contentToInsert, EditorRawDOMPoint(aContainer, offset));
|
EditorDOMPoint(aContainer, offset));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return EditorBase::ToGenericNSResult(rv);
|
return EditorBase::ToGenericNSResult(rv);
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
nsresult EditorBase::InsertNodeWithTransaction(
|
nsresult EditorBase::InsertNodeWithTransaction(
|
||||||
nsIContent& aContentToInsert,
|
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert) {
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert) {
|
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||||
@ -1472,7 +1445,7 @@ EditorBase::SplitNode(nsINode* aNode, int32_t aOffset, nsINode** aNewLeftNode) {
|
|||||||
std::min(std::max(aOffset, 0), static_cast<int32_t>(aNode->Length()));
|
std::min(std::max(aOffset, 0), static_cast<int32_t>(aNode->Length()));
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
nsCOMPtr<nsIContent> newNode =
|
nsCOMPtr<nsIContent> newNode =
|
||||||
SplitNodeWithTransaction(EditorRawDOMPoint(aNode, offset), error);
|
SplitNodeWithTransaction(EditorDOMPoint(aNode, offset), error);
|
||||||
newNode.forget(aNewLeftNode);
|
newNode.forget(aNewLeftNode);
|
||||||
if (NS_WARN_IF(error.Failed())) {
|
if (NS_WARN_IF(error.Failed())) {
|
||||||
return EditorBase::ToGenericNSResult(error.StealNSResult());
|
return EditorBase::ToGenericNSResult(error.StealNSResult());
|
||||||
@ -1480,9 +1453,8 @@ EditorBase::SplitNode(nsINode* aNode, int32_t aOffset, nsINode** aNewLeftNode) {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
already_AddRefed<nsIContent> EditorBase::SplitNodeWithTransaction(
|
already_AddRefed<nsIContent> EditorBase::SplitNodeWithTransaction(
|
||||||
const EditorDOMPointBase<PT, CT>& aStartOfRightNode, ErrorResult& aError) {
|
const EditorDOMPoint& aStartOfRightNode, ErrorResult& aError) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
if (NS_WARN_IF(!aStartOfRightNode.IsSet()) ||
|
if (NS_WARN_IF(!aStartOfRightNode.IsSet()) ||
|
||||||
@ -1712,7 +1684,7 @@ already_AddRefed<Element> EditorBase::ReplaceContainerWithTransactionInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
rv = InsertNodeWithTransaction(
|
rv = InsertNodeWithTransaction(
|
||||||
*child, EditorRawDOMPoint(newContainer, newContainer->Length()));
|
*child, EditorDOMPoint(newContainer, newContainer->Length()));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1764,8 +1736,8 @@ nsresult EditorBase::RemoveContainerWithTransaction(Element& aElement) {
|
|||||||
// use offset here because previous child might have been moved to
|
// use offset here because previous child might have been moved to
|
||||||
// container.
|
// container.
|
||||||
rv = InsertNodeWithTransaction(
|
rv = InsertNodeWithTransaction(
|
||||||
*child, EditorRawDOMPoint(pointToInsertChildren.GetContainer(),
|
*child, EditorDOMPoint(pointToInsertChildren.GetContainer(),
|
||||||
pointToInsertChildren.Offset()));
|
pointToInsertChildren.Offset()));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1820,8 +1792,7 @@ already_AddRefed<Element> EditorBase::InsertContainerWithTransactionInternal(
|
|||||||
|
|
||||||
{
|
{
|
||||||
AutoTransactionsConserveSelection conserveSelection(*this);
|
AutoTransactionsConserveSelection conserveSelection(*this);
|
||||||
rv =
|
rv = InsertNodeWithTransaction(aContent, EditorDOMPoint(newContainer, 0));
|
||||||
InsertNodeWithTransaction(aContent, EditorRawDOMPoint(newContainer, 0));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1836,9 +1807,8 @@ already_AddRefed<Element> EditorBase::InsertContainerWithTransactionInternal(
|
|||||||
return newContainer.forget();
|
return newContainer.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
nsresult EditorBase::MoveNodeWithTransaction(
|
nsresult EditorBase::MoveNodeWithTransaction(
|
||||||
nsIContent& aContent, const EditorDOMPointBase<PT, CT>& aPointToInsert) {
|
nsIContent& aContent, const EditorDOMPoint& aPointToInsert) {
|
||||||
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
||||||
|
|
||||||
EditorDOMPoint oldPoint(&aContent);
|
EditorDOMPoint oldPoint(&aContent);
|
||||||
@ -1852,8 +1822,7 @@ nsresult EditorBase::MoveNodeWithTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify our internal selection state listener
|
// Notify our internal selection state listener
|
||||||
EditorDOMPoint newPoint(aPointToInsert);
|
AutoMoveNodeSelNotify selNotify(RangeUpdaterRef(), oldPoint, aPointToInsert);
|
||||||
AutoMoveNodeSelNotify selNotify(RangeUpdaterRef(), oldPoint, newPoint);
|
|
||||||
|
|
||||||
// Hold a reference so aNode doesn't go away when we remove it (bug 772282)
|
// Hold a reference so aNode doesn't go away when we remove it (bug 772282)
|
||||||
nsresult rv = DeleteNodeWithTransaction(aContent);
|
nsresult rv = DeleteNodeWithTransaction(aContent);
|
||||||
@ -1862,7 +1831,7 @@ nsresult EditorBase::MoveNodeWithTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mutation event listener could break insertion point. Let's check it.
|
// Mutation event listener could break insertion point. Let's check it.
|
||||||
EditorRawDOMPoint pointToInsert(selNotify.ComputeInsertionPoint());
|
EditorDOMPoint pointToInsert(selNotify.ComputeInsertionPoint());
|
||||||
if (NS_WARN_IF(!pointToInsert.IsSet())) {
|
if (NS_WARN_IF(!pointToInsert.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -3728,10 +3697,9 @@ bool EditorBase::IsPreformatted(nsINode* aNode) {
|
|||||||
return styleText->WhiteSpaceIsSignificant();
|
return styleText->WhiteSpaceIsSignificant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
SplitNodeResult EditorBase::SplitNodeDeepWithTransaction(
|
SplitNodeResult EditorBase::SplitNodeDeepWithTransaction(
|
||||||
nsIContent& aMostAncestorToSplit,
|
nsIContent& aMostAncestorToSplit,
|
||||||
const EditorDOMPointBase<PT, CT>& aStartOfDeepestRightNode,
|
const EditorDOMPoint& aStartOfDeepestRightNode,
|
||||||
SplitAtEdges aSplitAtEdges) {
|
SplitAtEdges aSplitAtEdges) {
|
||||||
MOZ_ASSERT(aStartOfDeepestRightNode.IsSetAndValid());
|
MOZ_ASSERT(aStartOfDeepestRightNode.IsSetAndValid());
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(
|
||||||
|
@ -936,10 +936,8 @@ class EditorBase : public nsIEditor,
|
|||||||
* container. Otherwise, will insert the node
|
* container. Otherwise, will insert the node
|
||||||
* before child node referred by this.
|
* before child node referred by this.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
MOZ_CAN_RUN_SCRIPT nsresult InsertNodeWithTransaction(
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult
|
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
||||||
InsertNodeWithTransaction(nsIContent& aContentToInsert,
|
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ReplaceContainerWithTransaction() creates new element whose name is
|
* ReplaceContainerWithTransaction() creates new element whose name is
|
||||||
@ -1071,10 +1069,8 @@ class EditorBase : public nsIEditor,
|
|||||||
* @param aError If succeed, returns no error. Otherwise, an
|
* @param aError If succeed, returns no error. Otherwise, an
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIContent> SplitNodeWithTransaction(
|
MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIContent> SplitNodeWithTransaction(
|
||||||
const EditorDOMPointBase<PT, CT>& aStartOfRightNode,
|
const EditorDOMPoint& aStartOfRightNode, ErrorResult& aResult);
|
||||||
ErrorResult& aResult);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JoinNodesWithTransaction() joins aLeftNode and aRightNode. Content of
|
* JoinNodesWithTransaction() joins aLeftNode and aRightNode. Content of
|
||||||
@ -1093,9 +1089,8 @@ class EditorBase : public nsIEditor,
|
|||||||
*
|
*
|
||||||
* @param aContent The node to be moved.
|
* @param aContent The node to be moved.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult MoveNodeWithTransaction(
|
MOZ_CAN_RUN_SCRIPT nsresult MoveNodeWithTransaction(
|
||||||
nsIContent& aContent, const EditorDOMPointBase<PT, CT>& aPointToInsert);
|
nsIContent& aContent, const EditorDOMPoint& aPointToInsert);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MoveNodeToEndWithTransaction() moves aContent to end of aNewContainer.
|
* MoveNodeToEndWithTransaction() moves aContent to end of aNewContainer.
|
||||||
@ -1107,7 +1102,7 @@ class EditorBase : public nsIEditor,
|
|||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult MoveNodeToEndWithTransaction(nsIContent& aContent,
|
nsresult MoveNodeToEndWithTransaction(nsIContent& aContent,
|
||||||
nsINode& aNewContainer) {
|
nsINode& aNewContainer) {
|
||||||
EditorRawDOMPoint pointToInsert;
|
EditorDOMPoint pointToInsert;
|
||||||
pointToInsert.SetToEndOf(&aNewContainer);
|
pointToInsert.SetToEndOf(&aNewContainer);
|
||||||
return MoveNodeWithTransaction(aContent, pointToInsert);
|
return MoveNodeWithTransaction(aContent, pointToInsert);
|
||||||
}
|
}
|
||||||
@ -1243,9 +1238,8 @@ class EditorBase : public nsIEditor,
|
|||||||
* child node referred by this.
|
* child node referred by this.
|
||||||
* @return The created new element node.
|
* @return The created new element node.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> CreateNodeWithTransaction(
|
||||||
already_AddRefed<Element> CreateNodeWithTransaction(
|
nsAtom& aTag, const EditorDOMPoint& aPointToInsert);
|
||||||
nsAtom& aTag, const EditorDOMPointBase<PT, CT>& aPointToInsert);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an aggregate transaction for delete selection. The result may
|
* Create an aggregate transaction for delete selection. The result may
|
||||||
@ -1287,6 +1281,7 @@ class EditorBase : public nsIEditor,
|
|||||||
* @param aOffset Start offset of removing text in aCharData.
|
* @param aOffset Start offset of removing text in aCharData.
|
||||||
* @param aLength Length of removing text.
|
* @param aLength Length of removing text.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult DeleteTextWithTransaction(dom::CharacterData& aCharacterData,
|
nsresult DeleteTextWithTransaction(dom::CharacterData& aCharacterData,
|
||||||
uint32_t aOffset, uint32_t aLength);
|
uint32_t aOffset, uint32_t aLength);
|
||||||
|
|
||||||
@ -1389,11 +1384,10 @@ class EditorBase : public nsIEditor,
|
|||||||
* be good to insert something if the
|
* be good to insert something if the
|
||||||
* caller want to do it.
|
* caller want to do it.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
MOZ_CAN_RUN_SCRIPT SplitNodeResult
|
||||||
MOZ_CAN_RUN_SCRIPT SplitNodeResult SplitNodeDeepWithTransaction(
|
SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
|
||||||
nsIContent& aMostAncestorToSplit,
|
const EditorDOMPoint& aDeepestStartOfRightNode,
|
||||||
const EditorDOMPointBase<PT, CT>& aDeepestStartOfRightNode,
|
SplitAtEdges aSplitAtEdges);
|
||||||
SplitAtEdges aSplitAtEdges);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
|
* JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
|
||||||
|
@ -240,17 +240,17 @@ class MOZ_STACK_CLASS SplitNodeResult final {
|
|||||||
* by this instance. Therefore, the life time of both container node
|
* by this instance. Therefore, the life time of both container node
|
||||||
* and child node are guaranteed while using the result temporarily.
|
* and child node are guaranteed while using the result temporarily.
|
||||||
*/
|
*/
|
||||||
EditorRawDOMPoint SplitPoint() const {
|
EditorDOMPoint SplitPoint() const {
|
||||||
if (Failed()) {
|
if (Failed()) {
|
||||||
return EditorRawDOMPoint();
|
return EditorDOMPoint();
|
||||||
}
|
}
|
||||||
if (mGivenSplitPoint.IsSet()) {
|
if (mGivenSplitPoint.IsSet()) {
|
||||||
return EditorRawDOMPoint(mGivenSplitPoint);
|
return EditorDOMPoint(mGivenSplitPoint);
|
||||||
}
|
}
|
||||||
if (!mPreviousNode) {
|
if (!mPreviousNode) {
|
||||||
return EditorRawDOMPoint(mNextNode);
|
return EditorDOMPoint(mNextNode);
|
||||||
}
|
}
|
||||||
EditorRawDOMPoint point(mPreviousNode);
|
EditorDOMPoint point(mPreviousNode);
|
||||||
DebugOnly<bool> advanced = point.AdvanceOffset();
|
DebugOnly<bool> advanced = point.AdvanceOffset();
|
||||||
NS_WARNING_ASSERTION(advanced,
|
NS_WARNING_ASSERTION(advanced,
|
||||||
"Failed to advance offset to after previous node");
|
"Failed to advance offset to after previous node");
|
||||||
|
@ -519,7 +519,7 @@ nsresult HTMLEditor::SetPositionToAbsolute(Element& aElement) {
|
|||||||
nsINode* parentNode = aElement.GetParentNode();
|
nsINode* parentNode = aElement.GetParentNode();
|
||||||
if (parentNode->GetChildCount() == 1) {
|
if (parentNode->GetChildCount() == 1) {
|
||||||
RefPtr<Element> newBrElement =
|
RefPtr<Element> newBrElement =
|
||||||
InsertBrElementWithTransaction(EditorRawDOMPoint(parentNode, 0));
|
InsertBrElementWithTransaction(EditorDOMPoint(parentNode, 0));
|
||||||
if (NS_WARN_IF(!newBrElement)) {
|
if (NS_WARN_IF(!newBrElement)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1833,7 @@ EditActionResult HTMLEditRules::WillInsertParagraphSeparator() {
|
|||||||
// make block have a line. Then code further below will put in a second br.)
|
// make block have a line. Then code further below will put in a second br.)
|
||||||
if (IsEmptyBlockElement(*blockParent, IgnoreSingleBR::eNo)) {
|
if (IsEmptyBlockElement(*blockParent, IgnoreSingleBR::eNo)) {
|
||||||
AutoEditorDOMPointChildInvalidator lockOffset(atStartOfSelection);
|
AutoEditorDOMPointChildInvalidator lockOffset(atStartOfSelection);
|
||||||
EditorRawDOMPoint endOfBlockParent;
|
EditorDOMPoint endOfBlockParent;
|
||||||
endOfBlockParent.SetToEndOf(blockParent);
|
endOfBlockParent.SetToEndOf(blockParent);
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
@ -2060,7 +2060,7 @@ nsresult HTMLEditRules::InsertBRElement(const EditorDOMPoint& aPointToBreak) {
|
|||||||
EditActionResult HTMLEditRules::SplitMailCites() {
|
EditActionResult HTMLEditRules::SplitMailCites() {
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
|
||||||
EditorRawDOMPoint pointToSplit(EditorBase::GetStartPoint(*SelectionRefPtr()));
|
EditorDOMPoint pointToSplit(EditorBase::GetStartPoint(*SelectionRefPtr()));
|
||||||
if (NS_WARN_IF(!pointToSplit.IsSet())) {
|
if (NS_WARN_IF(!pointToSplit.IsSet())) {
|
||||||
return EditActionIgnored(NS_ERROR_FAILURE);
|
return EditActionIgnored(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
@ -2128,7 +2128,7 @@ EditActionResult HTMLEditRules::SplitMailCites() {
|
|||||||
nsCOMPtr<nsINode> lastChild = previousNodeOfSplitPoint->GetLastChild();
|
nsCOMPtr<nsINode> lastChild = previousNodeOfSplitPoint->GetLastChild();
|
||||||
if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
// We ignore the result here.
|
// We ignore the result here.
|
||||||
EditorRawDOMPoint endOfPreviousNodeOfSplitPoint;
|
EditorDOMPoint endOfPreviousNodeOfSplitPoint;
|
||||||
endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
|
endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
|
||||||
RefPtr<Element> invisibleBrElement =
|
RefPtr<Element> invisibleBrElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
@ -2144,7 +2144,7 @@ EditActionResult HTMLEditRules::SplitMailCites() {
|
|||||||
// In most cases, <br> should be inserted after current cite. However, if
|
// In most cases, <br> should be inserted after current cite. However, if
|
||||||
// left cite hasn't been created because the split point was start of the
|
// left cite hasn't been created because the split point was start of the
|
||||||
// cite node, <br> should be inserted before the current cite.
|
// cite node, <br> should be inserted before the current cite.
|
||||||
EditorRawDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
|
EditorDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.InsertBrElementWithTransaction(pointToInsertBrNode);
|
.InsertBrElementWithTransaction(pointToInsertBrNode);
|
||||||
@ -2179,8 +2179,8 @@ EditActionResult HTMLEditRules::SplitMailCites() {
|
|||||||
// then we will need a 2nd br added to achieve blank line that user expects.
|
// then we will need a 2nd br added to achieve blank line that user expects.
|
||||||
if (IsInlineNode(*citeNode)) {
|
if (IsInlineNode(*citeNode)) {
|
||||||
// Use DOM point which we tried to collapse to.
|
// Use DOM point which we tried to collapse to.
|
||||||
EditorRawDOMPoint pointToCreateNewBrNode(atBrNode.GetContainer(),
|
EditorDOMPoint pointToCreateNewBrNode(atBrNode.GetContainer(),
|
||||||
atBrNode.Offset());
|
atBrNode.Offset());
|
||||||
|
|
||||||
WSRunObject wsObj(&HTMLEditorRef(), pointToCreateNewBrNode);
|
WSRunObject wsObj(&HTMLEditorRef(), pointToCreateNewBrNode);
|
||||||
WSType wsType;
|
WSType wsType;
|
||||||
@ -2457,8 +2457,9 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
*aHandled = true;
|
*aHandled = true;
|
||||||
rv = HTMLEditorRef().DeleteTextWithTransaction(
|
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
nodeAsText, std::min(so, eo), DeprecatedAbs(eo - so));
|
.DeleteTextWithTransaction(nodeAsText, std::min(so, eo),
|
||||||
|
DeprecatedAbs(eo - so));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -3053,8 +3054,10 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||||||
// Delete to last character
|
// Delete to last character
|
||||||
OwningNonNull<CharacterData> dataNode =
|
OwningNonNull<CharacterData> dataNode =
|
||||||
*static_cast<CharacterData*>(startNode.get());
|
*static_cast<CharacterData*>(startNode.get());
|
||||||
rv = HTMLEditorRef().DeleteTextWithTransaction(
|
rv =
|
||||||
dataNode, startOffset, startNode->Length() - startOffset);
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.DeleteTextWithTransaction(dataNode, startOffset,
|
||||||
|
startNode->Length() - startOffset);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -3066,8 +3069,8 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||||||
// Delete to first character
|
// Delete to first character
|
||||||
OwningNonNull<CharacterData> dataNode =
|
OwningNonNull<CharacterData> dataNode =
|
||||||
*static_cast<CharacterData*>(endNode.get());
|
*static_cast<CharacterData*>(endNode.get());
|
||||||
rv =
|
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
HTMLEditorRef().DeleteTextWithTransaction(dataNode, 0, endOffset);
|
.DeleteTextWithTransaction(dataNode, 0, endOffset);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -3165,7 +3168,7 @@ nsresult HTMLEditRules::DeleteNodeIfCollapsedText(nsINode& aNode) {
|
|||||||
nsresult HTMLEditRules::InsertBRIfNeeded() {
|
nsresult HTMLEditRules::InsertBRIfNeeded() {
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
|
||||||
EditorRawDOMPoint atStartOfSelection(
|
EditorDOMPoint atStartOfSelection(
|
||||||
EditorBase::GetStartPoint(*SelectionRefPtr()));
|
EditorBase::GetStartPoint(*SelectionRefPtr()));
|
||||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -3684,7 +3687,7 @@ EditActionResult HTMLEditRules::MoveNodeSmart(nsIContent& aNode,
|
|||||||
return EditActionIgnored(rv);
|
return EditActionIgnored(rv);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EditorRawDOMPoint pointToInsert(&aDestElement, *aInOutDestOffset);
|
EditorDOMPoint pointToInsert(&aDestElement, *aInOutDestOffset);
|
||||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(aNode, pointToInsert);
|
.MoveNodeWithTransaction(aNode, pointToInsert);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
@ -3958,8 +3961,10 @@ nsresult HTMLEditRules::MakeList(nsAtom& aListType, bool aEntireList,
|
|||||||
if (NS_WARN_IF(splitAtSelectionStartResult.Failed())) {
|
if (NS_WARN_IF(splitAtSelectionStartResult.Failed())) {
|
||||||
return splitAtSelectionStartResult.Rv();
|
return splitAtSelectionStartResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> theList = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> theList =
|
||||||
aListType, splitAtSelectionStartResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(
|
||||||
|
aListType, splitAtSelectionStartResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -3967,9 +3972,9 @@ nsresult HTMLEditRules::MakeList(nsAtom& aListType, bool aEntireList,
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atFirstListItemToInsertBefore(theList, 0);
|
RefPtr<Element> theListItem =
|
||||||
RefPtr<Element> theListItem = HTMLEditorRef().CreateNodeWithTransaction(
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
aItemType, atFirstListItemToInsertBefore);
|
.CreateNodeWithTransaction(aItemType, EditorDOMPoint(theList, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4079,7 +4084,7 @@ nsresult HTMLEditRules::MakeList(nsAtom& aListType, bool aEntireList,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atCurNode(curNode);
|
EditorDOMPoint atCurNode(curNode);
|
||||||
if (NS_WARN_IF(!atCurNode.IsSet())) {
|
if (NS_WARN_IF(!atCurNode.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -4104,9 +4109,10 @@ nsresult HTMLEditRules::MakeList(nsAtom& aListType, bool aEntireList,
|
|||||||
return error.StealNSResult();
|
return error.StealNSResult();
|
||||||
}
|
}
|
||||||
newBlock = newLeftNode ? newLeftNode->AsElement() : nullptr;
|
newBlock = newLeftNode ? newLeftNode->AsElement() : nullptr;
|
||||||
EditorRawDOMPoint atParentOfCurNode(atCurNode.GetContainer());
|
curList =
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
aListType, atParentOfCurNode);
|
.CreateNodeWithTransaction(
|
||||||
|
aListType, EditorDOMPoint(atCurNode.GetContainer()));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4216,8 +4222,9 @@ nsresult HTMLEditRules::MakeList(nsAtom& aListType, bool aEntireList,
|
|||||||
if (NS_WARN_IF(splitCurNodeResult.Failed())) {
|
if (NS_WARN_IF(splitCurNodeResult.Failed())) {
|
||||||
return splitCurNodeResult.Rv();
|
return splitCurNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
aListType, splitCurNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(aListType,
|
||||||
|
splitCurNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4467,7 +4474,7 @@ nsresult HTMLEditRules::MakeBasicBlock(nsAtom& blockType) {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
EditorRawDOMPoint pointToInsertBrNode(splitNodeResult.SplitPoint());
|
EditorDOMPoint pointToInsertBrNode(splitNodeResult.SplitPoint());
|
||||||
// Put a <br> element at the split point
|
// Put a <br> element at the split point
|
||||||
brContent = MOZ_KnownLive(HTMLEditorRef())
|
brContent = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.InsertBrElementWithTransaction(pointToInsertBrNode);
|
.InsertBrElementWithTransaction(pointToInsertBrNode);
|
||||||
@ -4515,8 +4522,9 @@ nsresult HTMLEditRules::MakeBasicBlock(nsAtom& blockType) {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> block = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> block =
|
||||||
blockType, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(blockType, splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4706,8 +4714,10 @@ nsresult HTMLEditRules::IndentAroundSelectionWithCSS() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> theBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> theBlock =
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4779,7 +4789,7 @@ nsresult HTMLEditRules::IndentAroundSelectionWithCSS() {
|
|||||||
nsresult rv =
|
nsresult rv =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
|
.MoveNodeWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
|
||||||
EditorRawDOMPoint(sibling, 0));
|
EditorDOMPoint(sibling, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4827,8 +4837,9 @@ nsresult HTMLEditRules::IndentAroundSelectionWithCSS() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*containerName, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4878,8 +4889,9 @@ nsresult HTMLEditRules::IndentAroundSelectionWithCSS() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curQuote = HTMLEditorRef().CreateNodeWithTransaction(
|
curQuote = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -4985,8 +4997,10 @@ nsresult HTMLEditRules::IndentAroundSelectionWithHTML() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> theBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> theBlock =
|
||||||
*nsGkAtoms::blockquote, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(*nsGkAtoms::blockquote,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -5051,7 +5065,7 @@ nsresult HTMLEditRules::IndentAroundSelectionWithHTML() {
|
|||||||
sibling->NodeInfo()->NamespaceID()) {
|
sibling->NodeInfo()->NamespaceID()) {
|
||||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
|
.MoveNodeWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
|
||||||
EditorRawDOMPoint(sibling, 0));
|
EditorDOMPoint(sibling, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -5099,8 +5113,9 @@ nsresult HTMLEditRules::IndentAroundSelectionWithHTML() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*containerName, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -5161,8 +5176,9 @@ nsresult HTMLEditRules::IndentAroundSelectionWithHTML() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*containerName, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -5207,8 +5223,9 @@ nsresult HTMLEditRules::IndentAroundSelectionWithHTML() {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curQuote = HTMLEditorRef().CreateNodeWithTransaction(
|
curQuote = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*nsGkAtoms::blockquote, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(*nsGkAtoms::blockquote,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -5547,7 +5564,7 @@ SplitRangeOffFromNodeResult HTMLEditRules::OutdentAroundSelection() {
|
|||||||
// We have an embedded list, so move it out from under the parent
|
// We have an embedded list, so move it out from under the parent
|
||||||
// list. Be sure to put it after the parent list because this
|
// list. Be sure to put it after the parent list because this
|
||||||
// loop iterates backwards through the parent's list of children.
|
// loop iterates backwards through the parent's list of children.
|
||||||
EditorRawDOMPoint afterCurrentList(curParent, offset + 1);
|
EditorDOMPoint afterCurrentList(curParent, offset + 1);
|
||||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(*child, afterCurrentList);
|
.MoveNodeWithTransaction(*child, afterCurrentList);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
@ -5656,7 +5673,7 @@ SplitRangeOffFromNodeResult HTMLEditRules::SplitRangeOffFromBlock(
|
|||||||
SplitNodeResult splitAtStartResult =
|
SplitNodeResult splitAtStartResult =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
aBlockElement, EditorRawDOMPoint(&aStartOfMiddleElement),
|
aBlockElement, EditorDOMPoint(&aStartOfMiddleElement),
|
||||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
|
return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
|
||||||
@ -5665,7 +5682,7 @@ SplitRangeOffFromNodeResult HTMLEditRules::SplitRangeOffFromBlock(
|
|||||||
"Failed to split aBlockElement at start");
|
"Failed to split aBlockElement at start");
|
||||||
|
|
||||||
// Split at after the end
|
// Split at after the end
|
||||||
EditorRawDOMPoint atAfterEnd(&aEndOfMiddleElement);
|
EditorDOMPoint atAfterEnd(&aEndOfMiddleElement);
|
||||||
DebugOnly<bool> advanced = atAfterEnd.AdvanceOffset();
|
DebugOnly<bool> advanced = atAfterEnd.AdvanceOffset();
|
||||||
NS_WARNING_ASSERTION(advanced, "Failed to advance offset after the end node");
|
NS_WARNING_ASSERTION(advanced, "Failed to advance offset after the end node");
|
||||||
SplitNodeResult splitAtEndResult =
|
SplitNodeResult splitAtEndResult =
|
||||||
@ -5826,7 +5843,7 @@ nsresult HTMLEditRules::CreateStyleForInsertText(Document& aDocument) {
|
|||||||
SplitNodeResult splitTextNodeResult =
|
SplitNodeResult splitTextNodeResult =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
*text, EditorRawDOMPoint(text, offset),
|
*text, EditorDOMPoint(text, offset),
|
||||||
SplitAtEdges::eAllowToCreateEmptyContainer);
|
SplitAtEdges::eAllowToCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -5843,9 +5860,9 @@ nsresult HTMLEditRules::CreateStyleForInsertText(Document& aDocument) {
|
|||||||
}
|
}
|
||||||
OwningNonNull<Text> newNode =
|
OwningNonNull<Text> newNode =
|
||||||
EditorBase::CreateTextNode(aDocument, EmptyString());
|
EditorBase::CreateTextNode(aDocument, EmptyString());
|
||||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
nsresult rv =
|
||||||
.InsertNodeWithTransaction(
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
*newNode, EditorRawDOMPoint(node, offset));
|
.InsertNodeWithTransaction(*newNode, EditorDOMPoint(node, offset));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -6054,8 +6071,9 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefPtr<Element> div = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> div =
|
||||||
*nsGkAtoms::div, pointToInsertDiv);
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -6070,8 +6088,7 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
// Put in a moz-br so that it won't get deleted
|
// Put in a moz-br so that it won't get deleted
|
||||||
CreateElementResult createMozBrResult =
|
CreateElementResult createMozBrResult = CreateMozBR(EditorDOMPoint(div, 0));
|
||||||
CreateMozBR(EditorRawDOMPoint(div, 0));
|
|
||||||
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
||||||
return createMozBrResult.Rv();
|
return createMozBrResult.Rv();
|
||||||
}
|
}
|
||||||
@ -6193,8 +6210,9 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curDiv = HTMLEditorRef().CreateNodeWithTransaction(
|
curDiv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -6277,9 +6295,9 @@ nsresult HTMLEditRules::AlignBlockContents(nsINode& aNode,
|
|||||||
|
|
||||||
// else we need to put in a div, set the alignment, and toss in all the
|
// else we need to put in a div, set the alignment, and toss in all the
|
||||||
// children
|
// children
|
||||||
EditorRawDOMPoint atStartOfNode(&aNode, 0);
|
RefPtr<Element> divElem = MOZ_KnownLive(HTMLEditorRef())
|
||||||
RefPtr<Element> divElem =
|
.CreateNodeWithTransaction(
|
||||||
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div, atStartOfNode);
|
*nsGkAtoms::div, EditorDOMPoint(&aNode, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -6300,7 +6318,7 @@ nsresult HTMLEditRules::AlignBlockContents(nsINode& aNode,
|
|||||||
while (lastChild && (lastChild != divElem)) {
|
while (lastChild && (lastChild != divElem)) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(*lastChild, EditorRawDOMPoint(divElem, 0));
|
.MoveNodeWithTransaction(*lastChild, EditorDOMPoint(divElem, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -7471,8 +7489,7 @@ nsresult HTMLEditRules::BustUpInlinesAtRangeEndpoints(RangeItem& aRangeItem) {
|
|||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
*endInline,
|
*endInline,
|
||||||
EditorRawDOMPoint(aRangeItem.mEndContainer,
|
EditorDOMPoint(aRangeItem.mEndContainer, aRangeItem.mEndOffset),
|
||||||
aRangeItem.mEndOffset),
|
|
||||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -7496,8 +7513,8 @@ nsresult HTMLEditRules::BustUpInlinesAtRangeEndpoints(RangeItem& aRangeItem) {
|
|||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
*startInline,
|
*startInline,
|
||||||
EditorRawDOMPoint(aRangeItem.mStartContainer,
|
EditorDOMPoint(aRangeItem.mStartContainer,
|
||||||
aRangeItem.mStartOffset),
|
aRangeItem.mStartOffset),
|
||||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -7538,7 +7555,7 @@ nsresult HTMLEditRules::BustUpInlinesAtBRs(
|
|||||||
// Else we need to bust up aNode along all the breaks
|
// Else we need to bust up aNode along all the breaks
|
||||||
nsCOMPtr<nsIContent> nextNode = &aNode;
|
nsCOMPtr<nsIContent> nextNode = &aNode;
|
||||||
for (OwningNonNull<nsINode>& brNode : arrayOfBreaks) {
|
for (OwningNonNull<nsINode>& brNode : arrayOfBreaks) {
|
||||||
EditorRawDOMPoint atBrNode(brNode);
|
EditorDOMPoint atBrNode(brNode);
|
||||||
if (NS_WARN_IF(!atBrNode.IsSet())) {
|
if (NS_WARN_IF(!atBrNode.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -7563,7 +7580,7 @@ nsresult HTMLEditRules::BustUpInlinesAtBRs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move break outside of container and also put in node list
|
// Move break outside of container and also put in node list
|
||||||
EditorRawDOMPoint atNextNode(splitNodeResult.GetNextNode());
|
EditorDOMPoint atNextNode(splitNodeResult.GetNextNode());
|
||||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(
|
.MoveNodeWithTransaction(
|
||||||
MOZ_KnownLive(*brNode->AsContent()), atNextNode);
|
MOZ_KnownLive(*brNode->AsContent()), atNextNode);
|
||||||
@ -7741,7 +7758,7 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
|
|||||||
SplitNodeResult splitHeaderResult =
|
SplitNodeResult splitHeaderResult =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
aHeader, EditorRawDOMPoint(node, aOffset),
|
aHeader, EditorDOMPoint(node, aOffset),
|
||||||
SplitAtEdges::eAllowToCreateEmptyContainer);
|
SplitAtEdges::eAllowToCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -7760,7 +7777,7 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
|
|||||||
}
|
}
|
||||||
if (isEmptyNode) {
|
if (isEmptyNode) {
|
||||||
CreateElementResult createMozBrResult =
|
CreateElementResult createMozBrResult =
|
||||||
CreateMozBR(EditorRawDOMPoint(prevItem, 0));
|
CreateMozBR(EditorDOMPoint(prevItem, 0));
|
||||||
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
||||||
return createMozBrResult.Rv();
|
return createMozBrResult.Rv();
|
||||||
}
|
}
|
||||||
@ -7789,9 +7806,13 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
|
|||||||
// Create a paragraph
|
// Create a paragraph
|
||||||
nsAtom& paraAtom = DefaultParagraphSeparator();
|
nsAtom& paraAtom = DefaultParagraphSeparator();
|
||||||
// We want a wrapper element even if we separate with <br>
|
// We want a wrapper element even if we separate with <br>
|
||||||
EditorRawDOMPoint nextToHeader(headerParent, offset + 1);
|
EditorDOMPoint nextToHeader(headerParent, offset + 1);
|
||||||
RefPtr<Element> pNode = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> pNode =
|
||||||
¶Atom == nsGkAtoms::br ? *nsGkAtoms::p : paraAtom, nextToHeader);
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(¶Atom == nsGkAtoms::br
|
||||||
|
? *nsGkAtoms::p
|
||||||
|
: MOZ_KnownLive(paraAtom),
|
||||||
|
nextToHeader);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -7802,7 +7823,7 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
|
|||||||
// Append a <br> to it
|
// Append a <br> to it
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.InsertBrElementWithTransaction(EditorRawDOMPoint(pNode, 0));
|
.InsertBrElementWithTransaction(EditorDOMPoint(pNode, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -7938,7 +7959,7 @@ EditActionResult HTMLEditRules::ReturnInParagraph(Element& aParentDivOrP) {
|
|||||||
|
|
||||||
EditorDOMPoint pointToSplitParentDivOrP(atStartOfSelection);
|
EditorDOMPoint pointToSplitParentDivOrP(atStartOfSelection);
|
||||||
|
|
||||||
EditorRawDOMPoint pointToInsertBR;
|
EditorDOMPoint pointToInsertBR;
|
||||||
if (doesCRCreateNewP && atStartOfSelection.GetContainer() == &aParentDivOrP) {
|
if (doesCRCreateNewP && atStartOfSelection.GetContainer() == &aParentDivOrP) {
|
||||||
// We are at the edges of the block, so, we don't need to create new <br>.
|
// We are at the edges of the block, so, we don't need to create new <br>.
|
||||||
brContent = nullptr;
|
brContent = nullptr;
|
||||||
@ -8065,7 +8086,7 @@ nsresult HTMLEditRules::SplitParagraph(
|
|||||||
SplitNodeResult splitDivOrPResult =
|
SplitNodeResult splitDivOrPResult =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
aParentDivOrP, EditorRawDOMPoint(selNode, selOffset),
|
aParentDivOrP, EditorDOMPoint(selNode, selOffset),
|
||||||
SplitAtEdges::eAllowToCreateEmptyContainer);
|
SplitAtEdges::eAllowToCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -8157,7 +8178,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
// Are we the last list item in the list?
|
// Are we the last list item in the list?
|
||||||
if (!HTMLEditorRef().IsLastEditableChild(&aListItem)) {
|
if (!HTMLEditorRef().IsLastEditableChild(&aListItem)) {
|
||||||
// We need to split the list!
|
// We need to split the list!
|
||||||
EditorRawDOMPoint atListItem(&aListItem);
|
EditorDOMPoint atListItem(&aListItem);
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
leftListNode = MOZ_KnownLive(HTMLEditorRef())
|
leftListNode = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeWithTransaction(atListItem, error);
|
.SplitNodeWithTransaction(atListItem, error);
|
||||||
@ -8171,7 +8192,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Are we in a sublist?
|
// Are we in a sublist?
|
||||||
EditorRawDOMPoint atNextSiblingOfLeftList(leftListNode);
|
EditorDOMPoint atNextSiblingOfLeftList(leftListNode);
|
||||||
DebugOnly<bool> advanced = atNextSiblingOfLeftList.AdvanceOffset();
|
DebugOnly<bool> advanced = atNextSiblingOfLeftList.AdvanceOffset();
|
||||||
NS_WARNING_ASSERTION(advanced,
|
NS_WARNING_ASSERTION(advanced,
|
||||||
"Failed to advance offset after the right list node");
|
"Failed to advance offset after the right list node");
|
||||||
@ -8209,9 +8230,12 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
// Time to insert a paragraph
|
// Time to insert a paragraph
|
||||||
nsAtom& paraAtom = DefaultParagraphSeparator();
|
nsAtom& paraAtom = DefaultParagraphSeparator();
|
||||||
// We want a wrapper even if we separate with <br>
|
// We want a wrapper even if we separate with <br>
|
||||||
RefPtr<Element> pNode = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> pNode =
|
||||||
¶Atom == nsGkAtoms::br ? *nsGkAtoms::p : paraAtom,
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
atNextSiblingOfLeftList);
|
.CreateNodeWithTransaction(¶Atom == nsGkAtoms::br
|
||||||
|
? *nsGkAtoms::p
|
||||||
|
: MOZ_KnownLive(paraAtom),
|
||||||
|
atNextSiblingOfLeftList);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8222,7 +8246,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
// Append a <br> to it
|
// Append a <br> to it
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.InsertBrElementWithTransaction(EditorRawDOMPoint(pNode, 0));
|
.InsertBrElementWithTransaction(EditorDOMPoint(pNode, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8263,7 +8287,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
SplitNodeResult splitListItemResult =
|
SplitNodeResult splitListItemResult =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.SplitNodeDeepWithTransaction(
|
.SplitNodeDeepWithTransaction(
|
||||||
aListItem, EditorRawDOMPoint(selNode, aOffset),
|
aListItem, EditorDOMPoint(selNode, aOffset),
|
||||||
SplitAtEdges::eAllowToCreateEmptyContainer);
|
SplitAtEdges::eAllowToCreateEmptyContainer);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
@ -8284,7 +8308,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
}
|
}
|
||||||
if (isEmptyNode) {
|
if (isEmptyNode) {
|
||||||
CreateElementResult createMozBrResult =
|
CreateElementResult createMozBrResult =
|
||||||
CreateMozBR(EditorRawDOMPoint(prevItem, 0));
|
CreateMozBR(EditorDOMPoint(prevItem, 0));
|
||||||
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
||||||
return createMozBrResult.Rv();
|
return createMozBrResult.Rv();
|
||||||
}
|
}
|
||||||
@ -8302,11 +8326,12 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||||||
nsAtom* listAtom =
|
nsAtom* listAtom =
|
||||||
nodeAtom == nsGkAtoms::dt ? nsGkAtoms::dd : nsGkAtoms::dt;
|
nodeAtom == nsGkAtoms::dt ? nsGkAtoms::dd : nsGkAtoms::dt;
|
||||||
MOZ_DIAGNOSTIC_ASSERT(itemOffset != -1);
|
MOZ_DIAGNOSTIC_ASSERT(itemOffset != -1);
|
||||||
EditorRawDOMPoint atNextListItem(list, aListItem.GetNextSibling(),
|
EditorDOMPoint atNextListItem(list, aListItem.GetNextSibling(),
|
||||||
itemOffset + 1);
|
itemOffset + 1);
|
||||||
RefPtr<Element> newListItem =
|
RefPtr<Element> newListItem =
|
||||||
HTMLEditorRef().CreateNodeWithTransaction(*listAtom,
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
atNextListItem);
|
.CreateNodeWithTransaction(MOZ_KnownLive(*listAtom),
|
||||||
|
atNextListItem);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8454,15 +8479,15 @@ nsresult HTMLEditRules::MakeBlockquote(
|
|||||||
|
|
||||||
// If no curBlock, make one
|
// If no curBlock, make one
|
||||||
if (!curBlock) {
|
if (!curBlock) {
|
||||||
EditorDOMPoint atCurNode(curNode);
|
|
||||||
SplitNodeResult splitNodeResult =
|
SplitNodeResult splitNodeResult =
|
||||||
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
|
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
|
||||||
atCurNode);
|
EditorDOMPoint(curNode));
|
||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
curBlock = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*nsGkAtoms::blockquote, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(*nsGkAtoms::blockquote,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8674,8 +8699,10 @@ nsresult HTMLEditRules::ApplyBlockStyle(
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> theBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> theBlock =
|
||||||
aBlockTag, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(aBlockTag,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8711,8 +8738,9 @@ nsresult HTMLEditRules::ApplyBlockStyle(
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
curBlock = MOZ_KnownLive(HTMLEditorRef())
|
||||||
aBlockTag, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(aBlockTag,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8757,8 +8785,9 @@ nsresult HTMLEditRules::ApplyBlockStyle(
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curBlock = HTMLEditorRef().CreateNodeWithTransaction(
|
curBlock = MOZ_KnownLive(HTMLEditorRef())
|
||||||
aBlockTag, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(aBlockTag,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -8793,9 +8822,8 @@ nsresult HTMLEditRules::ApplyBlockStyle(
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
SplitNodeResult HTMLEditRules::MaybeSplitAncestorsForInsertWithTransaction(
|
SplitNodeResult HTMLEditRules::MaybeSplitAncestorsForInsertWithTransaction(
|
||||||
nsAtom& aTag, const EditorDOMPointBase<PT, CT>& aStartOfDeepestRightNode) {
|
nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode) {
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
|
||||||
if (NS_WARN_IF(!aStartOfDeepestRightNode.IsSet())) {
|
if (NS_WARN_IF(!aStartOfDeepestRightNode.IsSet())) {
|
||||||
@ -8873,7 +8901,7 @@ nsresult HTMLEditRules::JoinNearestEditableNodesWithTransaction(
|
|||||||
int32_t parOffset = parent->ComputeIndexOf(&aNodeLeft);
|
int32_t parOffset = parent->ComputeIndexOf(&aNodeLeft);
|
||||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
.MoveNodeWithTransaction(
|
.MoveNodeWithTransaction(
|
||||||
aNodeRight, EditorRawDOMPoint(parent, parOffset));
|
aNodeRight, EditorDOMPoint(parent, parOffset));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -9110,7 +9138,7 @@ HTMLEditRules::InsertBRElementToEmptyListItemsAndTableCellsInChangedRange() {
|
|||||||
// still pass the "IsEmptyNode" test, and we want the br's to be after
|
// still pass the "IsEmptyNode" test, and we want the br's to be after
|
||||||
// them. Also, we want the br to be after the selection if the selection
|
// them. Also, we want the br to be after the selection if the selection
|
||||||
// is in this node.
|
// is in this node.
|
||||||
EditorRawDOMPoint endOfNode;
|
EditorDOMPoint endOfNode;
|
||||||
endOfNode.SetToEndOf(node);
|
endOfNode.SetToEndOf(node);
|
||||||
// XXX This method should return nsreuslt due to may be destroyed by this
|
// XXX This method should return nsreuslt due to may be destroyed by this
|
||||||
// CreateMozBr() call.
|
// CreateMozBr() call.
|
||||||
@ -9628,7 +9656,7 @@ nsresult HTMLEditRules::RemoveEmptyNodesInChangedRange() {
|
|||||||
// but preserve br.
|
// but preserve br.
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
MOZ_KnownLive(HTMLEditorRef())
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
.InsertBrElementWithTransaction(EditorRawDOMPoint(delNode));
|
.InsertBrElementWithTransaction(EditorDOMPoint(delNode));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10029,8 +10057,8 @@ nsresult HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CreateElementResult createBrResult =
|
CreateElementResult createBrResult =
|
||||||
!aInsertMozBR ? CreateBR(EditorRawDOMPoint(&aNode, 0))
|
!aInsertMozBR ? CreateBR(EditorDOMPoint(&aNode, 0))
|
||||||
: CreateMozBR(EditorRawDOMPoint(&aNode, 0));
|
: CreateMozBR(EditorDOMPoint(&aNode, 0));
|
||||||
if (NS_WARN_IF(createBrResult.Failed())) {
|
if (NS_WARN_IF(createBrResult.Failed())) {
|
||||||
return createBrResult.Rv();
|
return createBrResult.Rv();
|
||||||
}
|
}
|
||||||
@ -10345,7 +10373,7 @@ nsresult HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundCR) {
|
if (!foundCR) {
|
||||||
EditorRawDOMPoint pointToInsert;
|
EditorDOMPoint pointToInsert;
|
||||||
if (!aStarts) {
|
if (!aStarts) {
|
||||||
pointToInsert.SetToEndOf(&aNode);
|
pointToInsert.SetToEndOf(&aNode);
|
||||||
} else {
|
} else {
|
||||||
@ -10591,8 +10619,10 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
RefPtr<Element> positionedDiv = HTMLEditorRef().CreateNodeWithTransaction(
|
RefPtr<Element> positionedDiv =
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10665,8 +10695,10 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
if (!curPositionedDiv) {
|
if (!curPositionedDiv) {
|
||||||
curPositionedDiv = HTMLEditorRef().CreateNodeWithTransaction(
|
curPositionedDiv =
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
MOZ_KnownLive(HTMLEditorRef())
|
||||||
|
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||||
|
splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10675,10 +10707,11 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
"Failed to create current positioned div element");
|
"Failed to create current positioned div element");
|
||||||
*aTargetElement = curPositionedDiv;
|
*aTargetElement = curPositionedDiv;
|
||||||
}
|
}
|
||||||
EditorRawDOMPoint atEndOfCurPositionedDiv;
|
EditorDOMPoint atEndOfCurPositionedDiv;
|
||||||
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
|
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*containerName, atEndOfCurPositionedDiv);
|
.CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
|
||||||
|
atEndOfCurPositionedDiv);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10734,9 +10767,10 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
if (!curPositionedDiv) {
|
if (!curPositionedDiv) {
|
||||||
EditorRawDOMPoint atListItemParent(atListItem.GetContainer());
|
curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
curPositionedDiv = HTMLEditorRef().CreateNodeWithTransaction(
|
.CreateNodeWithTransaction(
|
||||||
*nsGkAtoms::div, atListItemParent);
|
*nsGkAtoms::div,
|
||||||
|
EditorDOMPoint(atListItem.GetContainer()));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10745,10 +10779,11 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
"Failed to create current positioned div element");
|
"Failed to create current positioned div element");
|
||||||
*aTargetElement = curPositionedDiv;
|
*aTargetElement = curPositionedDiv;
|
||||||
}
|
}
|
||||||
EditorRawDOMPoint atEndOfCurPositionedDiv;
|
EditorDOMPoint atEndOfCurPositionedDiv;
|
||||||
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
|
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
|
||||||
curList = HTMLEditorRef().CreateNodeWithTransaction(
|
curList = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*containerName, atEndOfCurPositionedDiv);
|
.CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
|
||||||
|
atEndOfCurPositionedDiv);
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -10783,8 +10818,9 @@ nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
|
|||||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||||
return splitNodeResult.Rv();
|
return splitNodeResult.Rv();
|
||||||
}
|
}
|
||||||
curPositionedDiv = HTMLEditorRef().CreateNodeWithTransaction(
|
curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
|
||||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
.CreateNodeWithTransaction(
|
||||||
|
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
|
@ -1087,10 +1087,9 @@ class HTMLEditRules : public TextEditRules {
|
|||||||
* @return When succeeded, SplitPoint() returns
|
* @return When succeeded, SplitPoint() returns
|
||||||
* the point to insert the element.
|
* the point to insert the element.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitNodeResult
|
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitNodeResult
|
||||||
MaybeSplitAncestorsForInsertWithTransaction(
|
MaybeSplitAncestorsForInsertWithTransaction(
|
||||||
nsAtom& aTag, const EditorDOMPointBase<PT, CT>& aStartOfDeepestRightNode);
|
nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JoinNearestEditableNodesWithTransaction() joins two editable nodes which
|
* JoinNearestEditableNodesWithTransaction() joins two editable nodes which
|
||||||
|
@ -133,13 +133,6 @@ bool HTMLEditorPrefs::sUserWantsToEnableResizingUIByDefault = false;
|
|||||||
bool HTMLEditorPrefs::sUserWantsToEnableInlineTableEditingUIByDefault = false;
|
bool HTMLEditorPrefs::sUserWantsToEnableInlineTableEditingUIByDefault = false;
|
||||||
bool HTMLEditorPrefs::sUserWantsToEnableAbsolutePositioningUIByDefault = false;
|
bool HTMLEditorPrefs::sUserWantsToEnableAbsolutePositioningUIByDefault = false;
|
||||||
|
|
||||||
template EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
|
||||||
nsIContent& aNode, const EditorDOMPoint& aPointToInsert,
|
|
||||||
SplitAtEdges aSplitAtEdges);
|
|
||||||
template EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
|
||||||
nsIContent& aNode, const EditorRawDOMPoint& aPointToInsert,
|
|
||||||
SplitAtEdges aSplitAtEdges);
|
|
||||||
|
|
||||||
HTMLEditor::HTMLEditor()
|
HTMLEditor::HTMLEditor()
|
||||||
: mCRInParagraphCreatesParagraph(false),
|
: mCRInParagraphCreatesParagraph(false),
|
||||||
mCSSAware(false),
|
mCSSAware(false),
|
||||||
@ -1184,7 +1177,7 @@ nsresult HTMLEditor::InsertBrElementAtSelectionWithTransaction() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atStartOfSelection(
|
EditorDOMPoint atStartOfSelection(
|
||||||
EditorBase::GetStartPoint(*SelectionRefPtr()));
|
EditorBase::GetStartPoint(*SelectionRefPtr()));
|
||||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -1298,7 +1291,7 @@ nsresult HTMLEditor::ReplaceHeadContentsWithSourceWithTransaction(
|
|||||||
// Loop over the contents of the fragment and move into the document
|
// Loop over the contents of the fragment and move into the document
|
||||||
while (nsCOMPtr<nsIContent> child = documentFragment->GetFirstChild()) {
|
while (nsCOMPtr<nsIContent> child = documentFragment->GetFirstChild()) {
|
||||||
nsresult rv = InsertNodeWithTransaction(
|
nsresult rv = InsertNodeWithTransaction(
|
||||||
*child, EditorRawDOMPoint(headNode, offsetOfNewNode++));
|
*child, EditorDOMPoint(headNode, offsetOfNewNode++));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1611,7 +1604,7 @@ HTMLEditor::InsertElementAtSelection(Element* aElement, bool aDeleteSelection) {
|
|||||||
if (SelectionRefPtr()->GetAnchorNode()) {
|
if (SelectionRefPtr()->GetAnchorNode()) {
|
||||||
EditorRawDOMPoint atAnchor(SelectionRefPtr()->AnchorRef());
|
EditorRawDOMPoint atAnchor(SelectionRefPtr()->AnchorRef());
|
||||||
// Adjust position based on the node we are going to insert.
|
// Adjust position based on the node we are going to insert.
|
||||||
EditorRawDOMPoint pointToInsert =
|
EditorDOMPoint pointToInsert =
|
||||||
GetBetterInsertionPointFor(*aElement, atAnchor);
|
GetBetterInsertionPointFor(*aElement, atAnchor);
|
||||||
if (NS_WARN_IF(!pointToInsert.IsSet())) {
|
if (NS_WARN_IF(!pointToInsert.IsSet())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -1654,9 +1647,8 @@ HTMLEditor::InsertElementAtSelection(Element* aElement, bool aDeleteSelection) {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
||||||
nsIContent& aNode, const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
nsIContent& aNode, const EditorDOMPoint& aPointToInsert,
|
||||||
SplitAtEdges aSplitAtEdges) {
|
SplitAtEdges aSplitAtEdges) {
|
||||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||||
return EditorDOMPoint();
|
return EditorDOMPoint();
|
||||||
@ -2120,7 +2112,7 @@ HTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList,
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
|
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
|
||||||
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
||||||
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -2160,9 +2152,8 @@ HTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList,
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
// make a list item
|
// make a list item
|
||||||
EditorRawDOMPoint atStartOfNewList(newList, 0);
|
|
||||||
RefPtr<Element> newItem =
|
RefPtr<Element> newItem =
|
||||||
CreateNodeWithTransaction(*nsGkAtoms::li, atStartOfNewList);
|
CreateNodeWithTransaction(*nsGkAtoms::li, EditorDOMPoint(newList, 0));
|
||||||
if (NS_WARN_IF(!newItem)) {
|
if (NS_WARN_IF(!newItem)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -2296,7 +2287,7 @@ nsresult HTMLEditor::InsertBasicBlockWithTransaction(nsAtom& aTagName) {
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
|
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
|
||||||
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
||||||
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -2436,7 +2427,7 @@ nsresult HTMLEditor::IndentOrOutdentAsSubAction(
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
|
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
|
||||||
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
|
||||||
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -3834,7 +3825,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
|
|||||||
!sibling->IsHTMLElement(nsGkAtoms::br) && !IsBlockNode(child)) {
|
!sibling->IsHTMLElement(nsGkAtoms::br) && !IsBlockNode(child)) {
|
||||||
// Insert br node
|
// Insert br node
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
InsertBrElementWithTransaction(EditorRawDOMPoint(&aElement, 0));
|
InsertBrElementWithTransaction(EditorDOMPoint(&aElement, 0));
|
||||||
if (NS_WARN_IF(!brElement)) {
|
if (NS_WARN_IF(!brElement)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -3852,7 +3843,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
|
|||||||
MOZ_ASSERT(child, "aNode has first editable child but not last?");
|
MOZ_ASSERT(child, "aNode has first editable child but not last?");
|
||||||
if (!IsBlockNode(child) && !child->IsHTMLElement(nsGkAtoms::br)) {
|
if (!IsBlockNode(child) && !child->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
// Insert br node
|
// Insert br node
|
||||||
EditorRawDOMPoint endOfNode;
|
EditorDOMPoint endOfNode;
|
||||||
endOfNode.SetToEndOf(&aElement);
|
endOfNode.SetToEndOf(&aElement);
|
||||||
RefPtr<Element> brElement = InsertBrElementWithTransaction(endOfNode);
|
RefPtr<Element> brElement = InsertBrElementWithTransaction(endOfNode);
|
||||||
if (NS_WARN_IF(!brElement)) {
|
if (NS_WARN_IF(!brElement)) {
|
||||||
@ -3875,7 +3866,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
|
|||||||
!sibling->IsHTMLElement(nsGkAtoms::br)) {
|
!sibling->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
// Insert br node
|
// Insert br node
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
InsertBrElementWithTransaction(EditorRawDOMPoint(&aElement, 0));
|
InsertBrElementWithTransaction(EditorDOMPoint(&aElement, 0));
|
||||||
if (NS_WARN_IF(!brElement)) {
|
if (NS_WARN_IF(!brElement)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -4562,9 +4553,8 @@ nsresult HTMLEditor::CopyLastEditableChildStylesWithTransaction(
|
|||||||
nsAtom* tagName = elementInPreviousBlock->NodeInfo()->NameAtom();
|
nsAtom* tagName = elementInPreviousBlock->NodeInfo()->NameAtom();
|
||||||
// At first time, just create the most descendant inline container element.
|
// At first time, just create the most descendant inline container element.
|
||||||
if (!firstClonsedElement) {
|
if (!firstClonsedElement) {
|
||||||
EditorRawDOMPoint atStartOfNewBlock(newBlock, 0);
|
firstClonsedElement = lastClonedElement = CreateNodeWithTransaction(
|
||||||
firstClonsedElement = lastClonedElement =
|
MOZ_KnownLive(*tagName), EditorDOMPoint(newBlock, 0));
|
||||||
CreateNodeWithTransaction(*tagName, atStartOfNewBlock);
|
|
||||||
if (NS_WARN_IF(!firstClonsedElement)) {
|
if (NS_WARN_IF(!firstClonsedElement)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -4591,7 +4581,7 @@ nsresult HTMLEditor::CopyLastEditableChildStylesWithTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Element> brElement =
|
RefPtr<Element> brElement =
|
||||||
InsertBrElementWithTransaction(EditorRawDOMPoint(firstClonsedElement, 0));
|
InsertBrElementWithTransaction(EditorDOMPoint(firstClonsedElement, 0));
|
||||||
if (NS_WARN_IF(!brElement)) {
|
if (NS_WARN_IF(!brElement)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -525,6 +525,7 @@ class HTMLEditor final : public TextEditor,
|
|||||||
* @param aOffset Start offset of removing text in aCharData.
|
* @param aOffset Start offset of removing text in aCharData.
|
||||||
* @param aLength Length of removing text.
|
* @param aLength Length of removing text.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult DeleteTextWithTransaction(dom::CharacterData& aTextNode,
|
nsresult DeleteTextWithTransaction(dom::CharacterData& aTextNode,
|
||||||
uint32_t aOffset, uint32_t aLength);
|
uint32_t aOffset, uint32_t aLength);
|
||||||
|
|
||||||
@ -1478,9 +1479,8 @@ class HTMLEditor final : public TextEditor,
|
|||||||
* @return Returns inserted point if succeeded.
|
* @return Returns inserted point if succeeded.
|
||||||
* Otherwise, the result is not set.
|
* Otherwise, the result is not set.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT EditorDOMPoint InsertNodeIntoProperAncestorWithTransaction(
|
MOZ_CAN_RUN_SCRIPT EditorDOMPoint InsertNodeIntoProperAncestorWithTransaction(
|
||||||
nsIContent& aNode, const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
nsIContent& aNode, const EditorDOMPoint& aPointToInsert,
|
||||||
SplitAtEdges aSplitAtEdges);
|
SplitAtEdges aSplitAtEdges);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -646,7 +646,7 @@ nsresult HTMLEditor::DoInsertHTMLWithContext(
|
|||||||
// in a BR that is not visible. If so, the code above just placed
|
// in a BR that is not visible. If so, the code above just placed
|
||||||
// selection inside that. So I split it instead.
|
// selection inside that. So I split it instead.
|
||||||
SplitNodeResult splitLinkResult = SplitNodeDeepWithTransaction(
|
SplitNodeResult splitLinkResult = SplitNodeDeepWithTransaction(
|
||||||
*linkContent, EditorRawDOMPoint(selNode, selOffset),
|
*linkContent, EditorDOMPoint(selNode, selOffset),
|
||||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||||
NS_WARNING_ASSERTION(splitLinkResult.Succeeded(),
|
NS_WARNING_ASSERTION(splitLinkResult.Succeeded(),
|
||||||
"Failed to split the link");
|
"Failed to split the link");
|
||||||
|
@ -364,7 +364,7 @@ nsresult HTMLEditor::SetInlinePropertyOnTextNode(
|
|||||||
nsCOMPtr<nsIContent> textNodeForTheRange = &aText;
|
nsCOMPtr<nsIContent> textNodeForTheRange = &aText;
|
||||||
|
|
||||||
// Split at the end of the range.
|
// Split at the end of the range.
|
||||||
EditorRawDOMPoint atEnd(textNodeForTheRange, aEndOffset);
|
EditorDOMPoint atEnd(textNodeForTheRange, aEndOffset);
|
||||||
if (!atEnd.IsEndOfContainer()) {
|
if (!atEnd.IsEndOfContainer()) {
|
||||||
// We need to split off back of text node
|
// We need to split off back of text node
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
@ -375,7 +375,7 @@ nsresult HTMLEditor::SetInlinePropertyOnTextNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Split at the start of the range.
|
// Split at the start of the range.
|
||||||
EditorRawDOMPoint atStart(textNodeForTheRange, aStartOffset);
|
EditorDOMPoint atStart(textNodeForTheRange, aStartOffset);
|
||||||
if (!atStart.IsStartOfContainer()) {
|
if (!atStart.IsStartOfContainer()) {
|
||||||
// We need to split off front of text node
|
// We need to split off front of text node
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
@ -397,7 +397,7 @@ nsresult HTMLEditor::SetInlinePropertyOnTextNode(
|
|||||||
if (IsSimpleModifiableNode(sibling, &aProperty, aAttribute, &aValue)) {
|
if (IsSimpleModifiableNode(sibling, &aProperty, aAttribute, &aValue)) {
|
||||||
// Following sib is already right kind of inline node; slide this over
|
// Following sib is already right kind of inline node; slide this over
|
||||||
return MoveNodeWithTransaction(*textNodeForTheRange,
|
return MoveNodeWithTransaction(*textNodeForTheRange,
|
||||||
EditorRawDOMPoint(sibling, 0));
|
EditorDOMPoint(sibling, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +453,7 @@ nsresult HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
|
|||||||
}
|
}
|
||||||
if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
|
if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
MoveNodeWithTransaction(aNode, EditorRawDOMPoint(nextSibling, 0));
|
MoveNodeWithTransaction(aNode, EditorDOMPoint(nextSibling, 0));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -641,7 +641,7 @@ nsresult HTMLEditor::SplitStyleAbovePoint(
|
|||||||
isSet) {
|
isSet) {
|
||||||
// Found a style node we need to split
|
// Found a style node we need to split
|
||||||
SplitNodeResult splitNodeResult = SplitNodeDeepWithTransaction(
|
SplitNodeResult splitNodeResult = SplitNodeDeepWithTransaction(
|
||||||
*node, EditorRawDOMPoint(*aNode, *aOffset),
|
*node, EditorDOMPoint(*aNode, *aOffset),
|
||||||
SplitAtEdges::eAllowToCreateEmptyContainer);
|
SplitAtEdges::eAllowToCreateEmptyContainer);
|
||||||
NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
|
NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
|
||||||
"Failed to split the node");
|
"Failed to split the node");
|
||||||
@ -732,8 +732,7 @@ nsresult HTMLEditor::ClearStyle(nsCOMPtr<nsINode>* aNode, int32_t* aOffset,
|
|||||||
// leftNode. This is so we you don't revert back to the previous style
|
// leftNode. This is so we you don't revert back to the previous style
|
||||||
// if you happen to click at the end of a line.
|
// if you happen to click at the end of a line.
|
||||||
if (savedBR) {
|
if (savedBR) {
|
||||||
rv =
|
rv = MoveNodeWithTransaction(*savedBR, EditorDOMPoint(newSelParent, 0));
|
||||||
MoveNodeWithTransaction(*savedBR, EditorRawDOMPoint(newSelParent, 0));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1641,7 +1640,7 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
|
|||||||
nsCOMPtr<nsIContent> textNodeForTheRange = &aTextNode;
|
nsCOMPtr<nsIContent> textNodeForTheRange = &aTextNode;
|
||||||
|
|
||||||
// Split at the end of the range.
|
// Split at the end of the range.
|
||||||
EditorRawDOMPoint atEnd(textNodeForTheRange, aEndOffset);
|
EditorDOMPoint atEnd(textNodeForTheRange, aEndOffset);
|
||||||
if (!atEnd.IsEndOfContainer()) {
|
if (!atEnd.IsEndOfContainer()) {
|
||||||
// We need to split off back of text node
|
// We need to split off back of text node
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
@ -1652,7 +1651,7 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Split at the start of the range.
|
// Split at the start of the range.
|
||||||
EditorRawDOMPoint atStart(textNodeForTheRange, aStartOffset);
|
EditorDOMPoint atStart(textNodeForTheRange, aStartOffset);
|
||||||
if (!atStart.IsStartOfContainer()) {
|
if (!atStart.IsStartOfContainer()) {
|
||||||
// We need to split off front of text node
|
// We need to split off front of text node
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
@ -1678,7 +1677,7 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
|
|||||||
if (sibling && sibling->IsHTMLElement(nodeType)) {
|
if (sibling && sibling->IsHTMLElement(nodeType)) {
|
||||||
// Following sib is already right kind of inline node; slide this over
|
// Following sib is already right kind of inline node; slide this over
|
||||||
nsresult rv = MoveNodeWithTransaction(*textNodeForTheRange,
|
nsresult rv = MoveNodeWithTransaction(*textNodeForTheRange,
|
||||||
EditorRawDOMPoint(sibling, 0));
|
EditorDOMPoint(sibling, 0));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1789,7 +1788,7 @@ nsresult HTMLEditor::RelativeFontChangeOnNode(int32_t aSizeChange,
|
|||||||
if (sibling && sibling->IsHTMLElement(atom)) {
|
if (sibling && sibling->IsHTMLElement(atom)) {
|
||||||
// following sib is already right kind of inline node; slide this over
|
// following sib is already right kind of inline node; slide this over
|
||||||
// into it
|
// into it
|
||||||
return MoveNodeWithTransaction(*aNode, EditorRawDOMPoint(sibling, 0));
|
return MoveNodeWithTransaction(*aNode, EditorDOMPoint(sibling, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// else insert it above aNode
|
// else insert it above aNode
|
||||||
|
@ -2799,8 +2799,8 @@ nsresult HTMLEditor::MergeCells(RefPtr<Element> aTargetCell,
|
|||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
rv = InsertNodeWithTransaction(
|
rv = InsertNodeWithTransaction(*cellChild,
|
||||||
*cellChild, EditorRawDOMPoint(aTargetCell, insertIndex));
|
EditorDOMPoint(aTargetCell, insertIndex));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -44,11 +44,6 @@ namespace mozilla {
|
|||||||
|
|
||||||
using namespace dom;
|
using namespace dom;
|
||||||
|
|
||||||
template CreateElementResult TextEditRules::CreateBRInternal(
|
|
||||||
const EditorDOMPoint& aPointToInsert, bool aCreateMozBR);
|
|
||||||
template CreateElementResult TextEditRules::CreateBRInternal(
|
|
||||||
const EditorRawDOMPoint& aPointToInsert, bool aCreateMozBR);
|
|
||||||
|
|
||||||
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
|
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
|
||||||
if (IsReadonly() || IsDisabled()) { \
|
if (IsReadonly() || IsDisabled()) { \
|
||||||
*aCancel = true; \
|
*aCancel = true; \
|
||||||
@ -982,7 +977,7 @@ nsresult TextEditRules::WillSetText(bool* aCancel, bool* aHandled,
|
|||||||
}
|
}
|
||||||
nsresult rv = MOZ_KnownLive(TextEditorRef())
|
nsresult rv = MOZ_KnownLive(TextEditorRef())
|
||||||
.InsertNodeWithTransaction(
|
.InsertNodeWithTransaction(
|
||||||
*newNode, EditorRawDOMPoint(rootElement, 0));
|
*newNode, EditorDOMPoint(rootElement, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -1473,7 +1468,7 @@ nsresult TextEditRules::CreateTrailingBRIfNeeded() {
|
|||||||
|
|
||||||
if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
|
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
|
||||||
EditorRawDOMPoint endOfRoot;
|
EditorDOMPoint endOfRoot;
|
||||||
endOfRoot.SetToEndOf(rootElement);
|
endOfRoot.SetToEndOf(rootElement);
|
||||||
CreateElementResult createMozBrResult = CreateMozBR(endOfRoot);
|
CreateElementResult createMozBrResult = CreateMozBR(endOfRoot);
|
||||||
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
if (NS_WARN_IF(createMozBrResult.Failed())) {
|
||||||
@ -1558,8 +1553,8 @@ nsresult TextEditRules::CreateBogusNodeIfNeeded() {
|
|||||||
|
|
||||||
// Put the node in the document.
|
// Put the node in the document.
|
||||||
nsresult rv = MOZ_KnownLive(TextEditorRef())
|
nsresult rv = MOZ_KnownLive(TextEditorRef())
|
||||||
.InsertNodeWithTransaction(
|
.InsertNodeWithTransaction(*newBrElement,
|
||||||
*newBrElement, EditorRawDOMPoint(rootElement, 0));
|
EditorDOMPoint(rootElement, 0));
|
||||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
@ -1770,9 +1765,8 @@ void TextEditRules::FillBufWithPWChars(nsAString* aOutString, int32_t aLength) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
CreateElementResult TextEditRules::CreateBRInternal(
|
CreateElementResult TextEditRules::CreateBRInternal(
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert, bool aCreateMozBR) {
|
const EditorDOMPoint& aPointToInsert, bool aCreateMozBR) {
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
|
||||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||||
|
@ -312,9 +312,8 @@ class TextEditRules : public nsITimerCallback, public nsINamed {
|
|||||||
* @return Returns created <br> element or an error code
|
* @return Returns created <br> element or an error code
|
||||||
* if couldn't create new <br> element.
|
* if couldn't create new <br> element.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT CreateElementResult
|
MOZ_CAN_RUN_SCRIPT CreateElementResult
|
||||||
CreateBR(const EditorDOMPointBase<PT, CT>& aPointToInsert) {
|
CreateBR(const EditorDOMPoint& aPointToInsert) {
|
||||||
CreateElementResult ret = CreateBRInternal(aPointToInsert, false);
|
CreateElementResult ret = CreateBRInternal(aPointToInsert, false);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
|
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
|
||||||
@ -333,9 +332,8 @@ class TextEditRules : public nsITimerCallback, public nsINamed {
|
|||||||
* @return Returns created <br> element or an error code
|
* @return Returns created <br> element or an error code
|
||||||
* if couldn't create new <br> element.
|
* if couldn't create new <br> element.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT CreateElementResult
|
MOZ_CAN_RUN_SCRIPT CreateElementResult
|
||||||
CreateMozBR(const EditorDOMPointBase<PT, CT>& aPointToInsert) {
|
CreateMozBR(const EditorDOMPoint& aPointToInsert) {
|
||||||
CreateElementResult ret = CreateBRInternal(aPointToInsert, true);
|
CreateElementResult ret = CreateBRInternal(aPointToInsert, true);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
|
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
|
||||||
@ -391,9 +389,8 @@ class TextEditRules : public nsITimerCallback, public nsINamed {
|
|||||||
* @return Returns created <br> element and error code.
|
* @return Returns created <br> element and error code.
|
||||||
* If it succeeded, never returns nullptr.
|
* If it succeeded, never returns nullptr.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
MOZ_CAN_RUN_SCRIPT CreateElementResult
|
||||||
MOZ_CAN_RUN_SCRIPT CreateElementResult CreateBRInternal(
|
CreateBRInternal(const EditorDOMPoint& aPointToInsert, bool aCreateMozBR);
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert, bool aCreateMozBR);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -64,11 +64,6 @@ namespace mozilla {
|
|||||||
|
|
||||||
using namespace dom;
|
using namespace dom;
|
||||||
|
|
||||||
template already_AddRefed<Element> TextEditor::InsertBrElementWithTransaction(
|
|
||||||
const EditorDOMPoint& aPointToInsert, EDirection aSelect);
|
|
||||||
template already_AddRefed<Element> TextEditor::InsertBrElementWithTransaction(
|
|
||||||
const EditorRawDOMPoint& aPointToInsert, EDirection aSelect);
|
|
||||||
|
|
||||||
TextEditor::TextEditor()
|
TextEditor::TextEditor()
|
||||||
: mWrapColumn(0),
|
: mWrapColumn(0),
|
||||||
mMaxTextLength(-1),
|
mMaxTextLength(-1),
|
||||||
@ -242,9 +237,8 @@ TextEditor::SetDocumentCharacterSet(const nsACString& characterSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new meta charset tag
|
// Create a new meta charset tag
|
||||||
EditorRawDOMPoint atStartOfHeadNode(headNode, 0);
|
|
||||||
RefPtr<Element> metaElement =
|
RefPtr<Element> metaElement =
|
||||||
CreateNodeWithTransaction(*nsGkAtoms::meta, atStartOfHeadNode);
|
CreateNodeWithTransaction(*nsGkAtoms::meta, EditorDOMPoint(headNode, 0));
|
||||||
if (NS_WARN_IF(!metaElement)) {
|
if (NS_WARN_IF(!metaElement)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -436,10 +430,8 @@ nsresult TextEditor::InsertLineBreakAsAction() {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
already_AddRefed<Element> TextEditor::InsertBrElementWithTransaction(
|
already_AddRefed<Element> TextEditor::InsertBrElementWithTransaction(
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
const EditorDOMPoint& aPointToInsert, EDirection aSelect /* = eNone */) {
|
||||||
EDirection aSelect /* = eNone */) {
|
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||||
@ -869,7 +861,7 @@ already_AddRefed<Element> TextEditor::DeleteSelectionAndCreateElement(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRawDOMPoint pointToInsert(SelectionRefPtr()->AnchorRef());
|
EditorDOMPoint pointToInsert(SelectionRefPtr()->AnchorRef());
|
||||||
if (!pointToInsert.IsSet()) {
|
if (!pointToInsert.IsSet()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -354,10 +354,8 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
|
|||||||
* @return The new <br> node. If failed to create new
|
* @return The new <br> node. If failed to create new
|
||||||
* <br> node, returns nullptr.
|
* <br> node, returns nullptr.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertBrElementWithTransaction(
|
MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertBrElementWithTransaction(
|
||||||
const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);
|
||||||
EDirection aSelect = eNone);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends the selection for given deletion operation
|
* Extends the selection for given deletion operation
|
||||||
|
@ -55,12 +55,6 @@ template void WSRunObject::NextVisibleNode(const EditorRawDOMPoint& aPoint,
|
|||||||
nsCOMPtr<nsINode>* outVisNode,
|
nsCOMPtr<nsINode>* outVisNode,
|
||||||
int32_t* outVisOffset,
|
int32_t* outVisOffset,
|
||||||
WSType* outType) const;
|
WSType* outType) const;
|
||||||
template already_AddRefed<Element> WSRunObject::InsertBreak(
|
|
||||||
Selection& aSelection, const EditorDOMPoint& aPointToInsert,
|
|
||||||
nsIEditor::EDirection aSelect);
|
|
||||||
template already_AddRefed<Element> WSRunObject::InsertBreak(
|
|
||||||
Selection& aSelection, const EditorRawDOMPoint& aPointToInsert,
|
|
||||||
nsIEditor::EDirection aSelect);
|
|
||||||
template void WSRunObject::GetASCIIWhitespacesBounds(
|
template void WSRunObject::GetASCIIWhitespacesBounds(
|
||||||
int16_t aDir, const EditorDOMPoint& aPoint, dom::Text** outStartNode,
|
int16_t aDir, const EditorDOMPoint& aPoint, dom::Text** outStartNode,
|
||||||
int32_t* outStartOffset, dom::Text** outEndNode, int32_t* outEndOffset);
|
int32_t* outStartOffset, dom::Text** outEndNode, int32_t* outEndOffset);
|
||||||
@ -171,9 +165,8 @@ nsresult WSRunObject::PrepareToSplitAcrossBlocks(HTMLEditor* aHTMLEditor,
|
|||||||
return wsObj.PrepareToSplitAcrossBlocksPriv();
|
return wsObj.PrepareToSplitAcrossBlocksPriv();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
already_AddRefed<Element> WSRunObject::InsertBreak(
|
already_AddRefed<Element> WSRunObject::InsertBreak(
|
||||||
Selection& aSelection, const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
Selection& aSelection, const EditorDOMPoint& aPointToInsert,
|
||||||
nsIEditor::EDirection aSelect) {
|
nsIEditor::EDirection aSelect) {
|
||||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -393,8 +386,8 @@ nsresult WSRunObject::DeleteWSBackward() {
|
|||||||
// Easy case, preformatted ws.
|
// Easy case, preformatted ws.
|
||||||
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP)) {
|
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP)) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
DeleteRange(EditorRawDOMPoint(point.mTextNode, point.mOffset),
|
DeleteRange(EditorDOMPoint(point.mTextNode, point.mOffset),
|
||||||
EditorRawDOMPoint(point.mTextNode, point.mOffset + 1));
|
EditorDOMPoint(point.mTextNode, point.mOffset + 1));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -420,8 +413,8 @@ nsresult WSRunObject::DeleteWSBackward() {
|
|||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// finally, delete that ws
|
// finally, delete that ws
|
||||||
rv = DeleteRange(EditorRawDOMPoint(startNode, startOffset),
|
rv = DeleteRange(EditorDOMPoint(startNode, startOffset),
|
||||||
EditorRawDOMPoint(endNode, endOffset));
|
EditorDOMPoint(endNode, endOffset));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -439,8 +432,8 @@ nsresult WSRunObject::DeleteWSBackward() {
|
|||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// finally, delete that ws
|
// finally, delete that ws
|
||||||
rv = DeleteRange(EditorRawDOMPoint(node, startOffset),
|
rv = DeleteRange(EditorDOMPoint(node, startOffset),
|
||||||
EditorRawDOMPoint(node, endOffset));
|
EditorDOMPoint(node, endOffset));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -457,8 +450,8 @@ nsresult WSRunObject::DeleteWSForward() {
|
|||||||
// Easy case, preformatted ws.
|
// Easy case, preformatted ws.
|
||||||
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP)) {
|
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP)) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
DeleteRange(EditorRawDOMPoint(point.mTextNode, point.mOffset),
|
DeleteRange(EditorDOMPoint(point.mTextNode, point.mOffset),
|
||||||
EditorRawDOMPoint(point.mTextNode, point.mOffset + 1));
|
EditorDOMPoint(point.mTextNode, point.mOffset + 1));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -483,8 +476,8 @@ nsresult WSRunObject::DeleteWSForward() {
|
|||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Finally, delete that ws
|
// Finally, delete that ws
|
||||||
rv = DeleteRange(EditorRawDOMPoint(startNode, startOffset),
|
rv = DeleteRange(EditorDOMPoint(startNode, startOffset),
|
||||||
EditorRawDOMPoint(endNode, endOffset));
|
EditorDOMPoint(endNode, endOffset));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -502,8 +495,8 @@ nsresult WSRunObject::DeleteWSForward() {
|
|||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Finally, delete that ws
|
// Finally, delete that ws
|
||||||
rv = DeleteRange(EditorRawDOMPoint(node, startOffset),
|
rv = DeleteRange(EditorDOMPoint(node, startOffset),
|
||||||
EditorRawDOMPoint(node, endOffset));
|
EditorDOMPoint(node, endOffset));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1302,10 +1295,8 @@ nsresult WSRunObject::PrepareToSplitAcrossBlocksPriv() {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT1, typename CT1, typename PT2, typename CT2>
|
nsresult WSRunObject::DeleteRange(const EditorDOMPoint& aStartPoint,
|
||||||
nsresult WSRunObject::DeleteRange(
|
const EditorDOMPoint& aEndPoint) {
|
||||||
const EditorDOMPointBase<PT1, CT1>& aStartPoint,
|
|
||||||
const EditorDOMPointBase<PT2, CT2>& aEndPoint) {
|
|
||||||
if (NS_WARN_IF(!aStartPoint.IsSet()) || NS_WARN_IF(!aEndPoint.IsSet())) {
|
if (NS_WARN_IF(!aStartPoint.IsSet()) || NS_WARN_IF(!aEndPoint.IsSet())) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -1325,8 +1316,9 @@ nsresult WSRunObject::DeleteRange(
|
|||||||
|
|
||||||
if (aStartPoint.GetContainer() == aEndPoint.GetContainer() &&
|
if (aStartPoint.GetContainer() == aEndPoint.GetContainer() &&
|
||||||
aStartPoint.IsInTextNode()) {
|
aStartPoint.IsInTextNode()) {
|
||||||
|
RefPtr<Text> textNode = aStartPoint.GetContainerAsText();
|
||||||
return htmlEditor->DeleteTextWithTransaction(
|
return htmlEditor->DeleteTextWithTransaction(
|
||||||
*aStartPoint.GetContainerAsText(), aStartPoint.Offset(),
|
*textNode, aStartPoint.Offset(),
|
||||||
aEndPoint.Offset() - aStartPoint.Offset());
|
aEndPoint.Offset() - aStartPoint.Offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1883,9 +1875,8 @@ nsresult WSRunObject::CheckTrailingNBSPOfRun(WSFragment* aRun) {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PT, typename CT>
|
|
||||||
nsresult WSRunObject::ReplacePreviousNBSPIfUnncessary(
|
nsresult WSRunObject::ReplacePreviousNBSPIfUnncessary(
|
||||||
WSFragment* aRun, const EditorDOMPointBase<PT, CT>& aPoint) {
|
WSFragment* aRun, const EditorDOMPoint& aPoint) {
|
||||||
if (NS_WARN_IF(!aRun) || NS_WARN_IF(!aPoint.IsSet())) {
|
if (NS_WARN_IF(!aRun) || NS_WARN_IF(!aPoint.IsSet())) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
@ -240,9 +240,8 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||||||
* @return The new <br> node. If failed to create new <br>
|
* @return The new <br> node. If failed to create new <br>
|
||||||
* node, returns nullptr.
|
* node, returns nullptr.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT already_AddRefed<dom::Element> InsertBreak(
|
MOZ_CAN_RUN_SCRIPT already_AddRefed<dom::Element> InsertBreak(
|
||||||
Selection& aSelection, const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
Selection& aSelection, const EditorDOMPoint& aPointToInsert,
|
||||||
nsIEditor::EDirection aSelect);
|
nsIEditor::EDirection aSelect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -387,10 +386,8 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||||||
* When aEndPoint is in a text node, removes the text data before the point.
|
* When aEndPoint is in a text node, removes the text data before the point.
|
||||||
* Removes any nodes between them.
|
* Removes any nodes between them.
|
||||||
*/
|
*/
|
||||||
template <typename PT1, typename CT1, typename PT2, typename CT2>
|
MOZ_CAN_RUN_SCRIPT nsresult DeleteRange(const EditorDOMPoint& aStartPoint,
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult
|
const EditorDOMPoint& aEndPoint);
|
||||||
DeleteRange(const EditorDOMPointBase<PT1, CT1>& aStartPoint,
|
|
||||||
const EditorDOMPointBase<PT2, CT2>& aEndPoint);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetNextCharPoint() returns next character's point of aPoint. If there is
|
* GetNextCharPoint() returns next character's point of aPoint. If there is
|
||||||
@ -492,9 +489,8 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||||||
* @param aPoint Current insertion point. Its previous character is
|
* @param aPoint Current insertion point. Its previous character is
|
||||||
* unnecessary NBSP will be checked.
|
* unnecessary NBSP will be checked.
|
||||||
*/
|
*/
|
||||||
template <typename PT, typename CT>
|
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult ReplacePreviousNBSPIfUnncessary(
|
MOZ_CAN_RUN_SCRIPT nsresult ReplacePreviousNBSPIfUnncessary(
|
||||||
WSFragment* aRun, const EditorDOMPointBase<PT, CT>& aPoint);
|
WSFragment* aRun, const EditorDOMPoint& aPoint);
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode, int32_t aOffset);
|
nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode, int32_t aOffset);
|
||||||
@ -502,11 +498,11 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||||||
MOZ_CAN_RUN_SCRIPT nsresult Scrub();
|
MOZ_CAN_RUN_SCRIPT nsresult Scrub();
|
||||||
bool IsBlockNode(nsINode* aNode);
|
bool IsBlockNode(nsINode* aNode);
|
||||||
|
|
||||||
EditorRawDOMPoint StartPoint() const {
|
EditorDOMPoint StartPoint() const {
|
||||||
return EditorRawDOMPoint(mStartNode, mStartOffset);
|
return EditorDOMPoint(mStartNode, mStartOffset);
|
||||||
}
|
}
|
||||||
EditorRawDOMPoint EndPoint() const {
|
EditorDOMPoint EndPoint() const {
|
||||||
return EditorRawDOMPoint(mEndNode, mEndOffset);
|
return EditorDOMPoint(mEndNode, mEndOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The node passed to our constructor.
|
// The node passed to our constructor.
|
||||||
|
@ -12,6 +12,7 @@ support-files =
|
|||||||
en-AU/en_AU.aff
|
en-AU/en_AU.aff
|
||||||
de-DE/de_DE.dic
|
de-DE/de_DE.dic
|
||||||
de-DE/de_DE.aff
|
de-DE/de_DE.aff
|
||||||
|
!/editor/libeditor/tests/spellcheck.js
|
||||||
|
|
||||||
[test_async_UpdateCurrentDictionary.html]
|
[test_async_UpdateCurrentDictionary.html]
|
||||||
[test_bug678842.html]
|
[test_bug678842.html]
|
||||||
@ -24,3 +25,4 @@ support-files =
|
|||||||
[test_bug1219928.html]
|
[test_bug1219928.html]
|
||||||
skip-if = e10s
|
skip-if = e10s
|
||||||
[test_bug1365383.html]
|
[test_bug1365383.html]
|
||||||
|
[test_bug1418629.html]
|
||||||
|
96
editor/spellchecker/tests/test_bug1418629.html
Normal file
96
editor/spellchecker/tests/test_bug1418629.html
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Mozilla bug 1418629</title>
|
||||||
|
<link rel=stylesheet href="/tests/SimpleTest/test.css">
|
||||||
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script src="/tests/SimpleTest/AddTask.js"></script>
|
||||||
|
<script src="/tests/editor/libeditor/tests/spellcheck.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1418629">Mozilla Bug 1418629</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input id="input1" autofocus spellcheck="true">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const {onSpellCheck} = SpecialPowers.Cu.import("resource://testing-common/AsyncSpellCheckTestHelper.jsm", {});
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
SimpleTest.waitForFocus(() => {
|
||||||
|
SimpleTest.executeSoon(resolve);
|
||||||
|
}, window);
|
||||||
|
});
|
||||||
|
|
||||||
|
let misspeltWords = [];
|
||||||
|
let input = document.getElementById("input1");
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
input.value = "";
|
||||||
|
synthesizeKey("d");
|
||||||
|
synthesizeKey("o");
|
||||||
|
synthesizeKey("e");
|
||||||
|
synthesizeKey("s");
|
||||||
|
|
||||||
|
await new Promise((resolve) => { onSpellCheck(input, resolve); });
|
||||||
|
// isSpellingCheckOk is defined in spellcheck.js
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
|
||||||
|
"no misspelt words");
|
||||||
|
|
||||||
|
synthesizeKey("n");
|
||||||
|
synthesizeKey("\'");
|
||||||
|
is(input.value, "doesn\'", "");
|
||||||
|
|
||||||
|
await new Promise((resolve) => { onSpellCheck(input, resolve); });
|
||||||
|
// isSpellingCheckOk is defined in spellcheck.js
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
|
||||||
|
"don't run spellchecker during inputting word");
|
||||||
|
|
||||||
|
synthesizeKey(" ");
|
||||||
|
is(input.value, "doesn\' ", "");
|
||||||
|
|
||||||
|
await new Promise((resolve) => { onSpellCheck(input, resolve); });
|
||||||
|
misspeltWords.push("doesn\'");
|
||||||
|
// isSpellingCheckOk is defined in spellcheck.js
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
|
||||||
|
"should run spellchecker");
|
||||||
|
});
|
||||||
|
|
||||||
|
async function test_with_twice_characters(ch) {
|
||||||
|
let misspeltWords = [];
|
||||||
|
let input = document.getElementById("input1");
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
input.value = "";
|
||||||
|
synthesizeKey("d");
|
||||||
|
synthesizeKey("o");
|
||||||
|
synthesizeKey("e");
|
||||||
|
synthesizeKey("s");
|
||||||
|
synthesizeKey("n");
|
||||||
|
synthesizeKey(ch);
|
||||||
|
synthesizeKey(ch);
|
||||||
|
is(input.value, "doesn" + ch + ch, "");
|
||||||
|
|
||||||
|
await new Promise((resolve) => { onSpellCheck(input, resolve); });
|
||||||
|
misspeltWords.push("doesn");
|
||||||
|
// isSpellingCheckOk is defined in spellcheck.js
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
|
||||||
|
"should run spellchecker");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(test_with_twice_characters.bind(null, "\'"));
|
||||||
|
add_task(test_with_twice_characters.bind(null, String.fromCharCode(0x2019)));
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -418,8 +418,19 @@ CharClass WordSplitState::ClassifyCharacter(int32_t aIndex,
|
|||||||
if (mDOMWordText[aIndex - 1] == '.') return CHAR_CLASS_SEPARATOR;
|
if (mDOMWordText[aIndex - 1] == '.') return CHAR_CLASS_SEPARATOR;
|
||||||
|
|
||||||
// now we know left char is a word-char, check the right-hand character
|
// now we know left char is a word-char, check the right-hand character
|
||||||
if (aIndex == int32_t(mDOMWordText.Length()) - 1)
|
if (aIndex == int32_t(mDOMWordText.Length() - 1)) {
|
||||||
|
if (mDOMWordText[aIndex] == '\'' || mDOMWordText[aIndex] == 0x2019) {
|
||||||
|
nsUGenCategory prevCategory =
|
||||||
|
mozilla::unicode::GetGenCategory(mDOMWordText[aIndex - 1]);
|
||||||
|
if (prevCategory == nsUGenCategory::kLetter ||
|
||||||
|
prevCategory == nsUGenCategory::kNumber) {
|
||||||
|
// If single quotation mark is last, we don't return separator yet.
|
||||||
|
return CHAR_CLASS_WORD;
|
||||||
|
}
|
||||||
|
}
|
||||||
return CHAR_CLASS_SEPARATOR;
|
return CHAR_CLASS_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ClassifyCharacter(aIndex + 1, false) != CHAR_CLASS_WORD)
|
if (ClassifyCharacter(aIndex + 1, false) != CHAR_CLASS_WORD)
|
||||||
return CHAR_CLASS_SEPARATOR;
|
return CHAR_CLASS_SEPARATOR;
|
||||||
// If the next charatcer is a word-char, make sure that it's not a
|
// If the next charatcer is a word-char, make sure that it's not a
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
#include "mozilla/ReverseIterator.h"
|
|
||||||
#include "mozilla/Sprintf.h"
|
#include "mozilla/Sprintf.h"
|
||||||
#include "mozilla/Variant.h"
|
#include "mozilla/Variant.h"
|
||||||
|
|
||||||
@ -91,24 +90,6 @@ static bool ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) {
|
|||||||
kind == ParseNodeKind::Function;
|
kind == ParseNodeKind::Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
BytecodeEmitter::BytecodeSection::BytecodeSection(JSContext* cx,
|
|
||||||
uint32_t lineNum)
|
|
||||||
: code_(cx),
|
|
||||||
notes_(cx),
|
|
||||||
tryNoteList_(cx),
|
|
||||||
scopeNoteList_(cx),
|
|
||||||
resumeOffsetList_(cx),
|
|
||||||
currentLine_(lineNum) {}
|
|
||||||
|
|
||||||
BytecodeEmitter::PerScriptData::PerScriptData(JSContext* cx)
|
|
||||||
: scopeList_(cx),
|
|
||||||
numberList_(cx),
|
|
||||||
atomIndices_(cx->frontendCollectionPool()) {}
|
|
||||||
|
|
||||||
bool BytecodeEmitter::PerScriptData::init(JSContext* cx) {
|
|
||||||
return atomIndices_.acquire(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
BytecodeEmitter::BytecodeEmitter(
|
BytecodeEmitter::BytecodeEmitter(
|
||||||
BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
|
BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
|
||||||
Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode,
|
Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode,
|
||||||
@ -260,21 +241,6 @@ bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeEmitter::BytecodeSection::updateDepth(ptrdiff_t target) {
|
|
||||||
jsbytecode* pc = code(target);
|
|
||||||
|
|
||||||
int nuses = StackUses(pc);
|
|
||||||
int ndefs = StackDefs(pc);
|
|
||||||
|
|
||||||
stackDepth_ -= nuses;
|
|
||||||
MOZ_ASSERT(stackDepth_ >= 0);
|
|
||||||
stackDepth_ += ndefs;
|
|
||||||
|
|
||||||
if ((uint32_t)stackDepth_ > maxStackDepth_) {
|
|
||||||
maxStackDepth_ = stackDepth_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
|
bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
|
||||||
if (IsCheckStrictOp(op) && !sc->strict()) {
|
if (IsCheckStrictOp(op) && !sc->strict()) {
|
||||||
@ -9562,127 +9528,6 @@ void BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes) {
|
|||||||
SN_MAKE_TERMINATOR(&destination[count]);
|
SN_MAKE_TERMINATOR(&destination[count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGNumberList::finish(mozilla::Span<GCPtrValue> array) {
|
|
||||||
MOZ_ASSERT(length() == array.size());
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < length(); i++) {
|
|
||||||
array[i].init(vector[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find the index of the given object for code generator.
|
|
||||||
*
|
|
||||||
* Since the emitter refers to each parsed object only once, for the index we
|
|
||||||
* use the number of already indexed objects. We also add the object to a list
|
|
||||||
* to convert the list to a fixed-size array when we complete code generation,
|
|
||||||
* see js::CGObjectList::finish below.
|
|
||||||
*/
|
|
||||||
unsigned CGObjectList::add(ObjectBox* objbox) {
|
|
||||||
MOZ_ASSERT(objbox->isObjectBox());
|
|
||||||
MOZ_ASSERT(!objbox->emitLink);
|
|
||||||
objbox->emitLink = lastbox;
|
|
||||||
lastbox = objbox;
|
|
||||||
return length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGObjectList::finish(mozilla::Span<GCPtrObject> array) {
|
|
||||||
MOZ_ASSERT(length <= INDEX_LIMIT);
|
|
||||||
MOZ_ASSERT(length == array.size());
|
|
||||||
|
|
||||||
ObjectBox* objbox = lastbox;
|
|
||||||
for (GCPtrObject& obj : mozilla::Reversed(array)) {
|
|
||||||
MOZ_ASSERT(obj == nullptr);
|
|
||||||
MOZ_ASSERT(objbox->object()->isTenured());
|
|
||||||
obj.init(objbox->object());
|
|
||||||
objbox = objbox->emitLink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGObjectList::finishInnerFunctions() {
|
|
||||||
ObjectBox* objbox = lastbox;
|
|
||||||
while (objbox) {
|
|
||||||
if (objbox->isFunctionBox()) {
|
|
||||||
objbox->asFunctionBox()->finish();
|
|
||||||
}
|
|
||||||
objbox = objbox->emitLink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGScopeList::finish(mozilla::Span<GCPtrScope> array) {
|
|
||||||
MOZ_ASSERT(length() <= INDEX_LIMIT);
|
|
||||||
MOZ_ASSERT(length() == array.size());
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < length(); i++) {
|
|
||||||
array[i].init(vector[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth,
|
|
||||||
size_t start, size_t end) {
|
|
||||||
MOZ_ASSERT(start <= end);
|
|
||||||
MOZ_ASSERT(size_t(uint32_t(start)) == start);
|
|
||||||
MOZ_ASSERT(size_t(uint32_t(end)) == end);
|
|
||||||
|
|
||||||
// Offsets are given relative to sections, but we only expect main-section
|
|
||||||
// to have TryNotes. In finish() we will fixup base offset.
|
|
||||||
|
|
||||||
JSTryNote note;
|
|
||||||
note.kind = kind;
|
|
||||||
note.stackDepth = stackDepth;
|
|
||||||
note.start = uint32_t(start);
|
|
||||||
note.length = uint32_t(end - start);
|
|
||||||
|
|
||||||
return list.append(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGTryNoteList::finish(mozilla::Span<JSTryNote> array) {
|
|
||||||
MOZ_ASSERT(length() == array.size());
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < length(); i++) {
|
|
||||||
array[i] = list[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset,
|
|
||||||
uint32_t parent) {
|
|
||||||
CGScopeNote note;
|
|
||||||
mozilla::PodZero(¬e);
|
|
||||||
|
|
||||||
// Offsets are given relative to sections. In finish() we will fixup base
|
|
||||||
// offset if needed.
|
|
||||||
|
|
||||||
note.index = scopeIndex;
|
|
||||||
note.start = offset;
|
|
||||||
note.parent = parent;
|
|
||||||
|
|
||||||
return list.append(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGScopeNoteList::recordEnd(uint32_t index, uint32_t offset) {
|
|
||||||
MOZ_ASSERT(index < length());
|
|
||||||
MOZ_ASSERT(list[index].length == 0);
|
|
||||||
list[index].end = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGScopeNoteList::finish(mozilla::Span<ScopeNote> array) {
|
|
||||||
MOZ_ASSERT(length() == array.size());
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < length(); i++) {
|
|
||||||
MOZ_ASSERT(list[i].end >= list[i].start);
|
|
||||||
list[i].length = list[i].end - list[i].start;
|
|
||||||
array[i] = list[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGResumeOffsetList::finish(mozilla::Span<uint32_t> array) {
|
|
||||||
MOZ_ASSERT(length() == array.size());
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < length(); i++) {
|
|
||||||
array[i] = list[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSSrcNoteSpec js_SrcNoteSpec[] = {
|
const JSSrcNoteSpec js_SrcNoteSpec[] = {
|
||||||
#define DEFINE_SRC_NOTE_SPEC(sym, name, arity) {name, arity},
|
#define DEFINE_SRC_NOTE_SPEC(sym, name, arity) {name, arity},
|
||||||
FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
|
FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "ds/InlineTable.h"
|
#include "ds/InlineTable.h"
|
||||||
#include "frontend/BCEParserHandle.h"
|
#include "frontend/BCEParserHandle.h"
|
||||||
|
#include "frontend/BytecodeSection.h" // BytecodeSection, PerScriptData
|
||||||
#include "frontend/DestructuringFlavor.h"
|
#include "frontend/DestructuringFlavor.h"
|
||||||
#include "frontend/EitherParser.h"
|
#include "frontend/EitherParser.h"
|
||||||
#include "frontend/JumpList.h"
|
#include "frontend/JumpList.h"
|
||||||
@ -29,80 +30,6 @@
|
|||||||
namespace js {
|
namespace js {
|
||||||
namespace frontend {
|
namespace frontend {
|
||||||
|
|
||||||
class CGNumberList {
|
|
||||||
Rooted<ValueVector> vector;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CGNumberList(JSContext* cx) : vector(cx, ValueVector(cx)) {}
|
|
||||||
MOZ_MUST_USE bool append(const Value& v) { return vector.append(v); }
|
|
||||||
size_t length() const { return vector.length(); }
|
|
||||||
void finish(mozilla::Span<GCPtrValue> array);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CGObjectList {
|
|
||||||
uint32_t length; /* number of emitted so far objects */
|
|
||||||
ObjectBox* lastbox; /* last emitted object */
|
|
||||||
|
|
||||||
CGObjectList() : length(0), lastbox(nullptr) {}
|
|
||||||
|
|
||||||
unsigned add(ObjectBox* objbox);
|
|
||||||
void finish(mozilla::Span<GCPtrObject> array);
|
|
||||||
void finishInnerFunctions();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MOZ_STACK_CLASS CGScopeList {
|
|
||||||
Rooted<GCVector<Scope*>> vector;
|
|
||||||
|
|
||||||
explicit CGScopeList(JSContext* cx) : vector(cx, GCVector<Scope*>(cx)) {}
|
|
||||||
|
|
||||||
bool append(Scope* scope) { return vector.append(scope); }
|
|
||||||
uint32_t length() const { return vector.length(); }
|
|
||||||
void finish(mozilla::Span<GCPtrScope> array);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CGTryNoteList {
|
|
||||||
Vector<JSTryNote> list;
|
|
||||||
explicit CGTryNoteList(JSContext* cx) : list(cx) {}
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool append(JSTryNoteKind kind, uint32_t stackDepth,
|
|
||||||
size_t start, size_t end);
|
|
||||||
size_t length() const { return list.length(); }
|
|
||||||
void finish(mozilla::Span<JSTryNote> array);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CGScopeNote : public ScopeNote {
|
|
||||||
// The end offset. Used to compute the length.
|
|
||||||
uint32_t end;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CGScopeNoteList {
|
|
||||||
Vector<CGScopeNote> list;
|
|
||||||
explicit CGScopeNoteList(JSContext* cx) : list(cx) {}
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset,
|
|
||||||
uint32_t parent);
|
|
||||||
void recordEnd(uint32_t index, uint32_t offse);
|
|
||||||
size_t length() const { return list.length(); }
|
|
||||||
void finish(mozilla::Span<ScopeNote> array);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CGResumeOffsetList {
|
|
||||||
Vector<uint32_t> list;
|
|
||||||
explicit CGResumeOffsetList(JSContext* cx) : list(cx) {}
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
|
|
||||||
size_t length() const { return list.length(); }
|
|
||||||
void finish(mozilla::Span<uint32_t> array);
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr size_t MaxBytecodeLength = INT32_MAX;
|
|
||||||
static constexpr size_t MaxSrcNotesLength = INT32_MAX;
|
|
||||||
|
|
||||||
// Have a few inline elements, so as to avoid heap allocation for tiny
|
|
||||||
// sequences. See bug 1390526.
|
|
||||||
typedef Vector<jsbytecode, 64> BytecodeVector;
|
|
||||||
typedef Vector<jssrcnote, 64> SrcNotesVector;
|
|
||||||
|
|
||||||
class CallOrNewEmitter;
|
class CallOrNewEmitter;
|
||||||
class ElemOpEmitter;
|
class ElemOpEmitter;
|
||||||
class EmitterScope;
|
class EmitterScope;
|
||||||
@ -127,198 +54,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
|
|||||||
Rooted<LazyScript*> lazyScript;
|
Rooted<LazyScript*> lazyScript;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Bytecode and all data directly associated with specific opcode/index inside
|
|
||||||
// bytecode is stored in this class.
|
|
||||||
class BytecodeSection {
|
|
||||||
public:
|
|
||||||
BytecodeSection(JSContext* cx, uint32_t lineNum);
|
|
||||||
|
|
||||||
// ---- Bytecode ----
|
|
||||||
|
|
||||||
BytecodeVector& code() { return code_; }
|
|
||||||
const BytecodeVector& code() const { return code_; }
|
|
||||||
|
|
||||||
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
|
|
||||||
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
|
|
||||||
|
|
||||||
// ---- Source notes ----
|
|
||||||
|
|
||||||
SrcNotesVector& notes() { return notes_; }
|
|
||||||
const SrcNotesVector& notes() const { return notes_; }
|
|
||||||
|
|
||||||
ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
|
|
||||||
void setLastNoteOffset(ptrdiff_t offset) { lastNoteOffset_ = offset; }
|
|
||||||
|
|
||||||
// ---- Jump ----
|
|
||||||
|
|
||||||
ptrdiff_t lastTargetOffset() const { return lastTarget_.offset; }
|
|
||||||
void setLastTargetOffset(ptrdiff_t offset) { lastTarget_.offset = offset; }
|
|
||||||
|
|
||||||
// Check if the last emitted opcode is a jump target.
|
|
||||||
bool lastOpcodeIsJumpTarget() const {
|
|
||||||
return offset() - lastTarget_.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// JumpTarget should not be part of the emitted statement, as they can be
|
|
||||||
// aliased by multiple statements. If we included the jump target as part of
|
|
||||||
// the statement we might have issues where the enclosing statement might
|
|
||||||
// not contain all the opcodes of the enclosed statements.
|
|
||||||
ptrdiff_t lastNonJumpTargetOffset() const {
|
|
||||||
return lastOpcodeIsJumpTarget() ? lastTarget_.offset : offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Stack ----
|
|
||||||
|
|
||||||
int32_t stackDepth() const { return stackDepth_; }
|
|
||||||
void setStackDepth(int32_t depth) { stackDepth_ = depth; }
|
|
||||||
|
|
||||||
uint32_t maxStackDepth() const { return maxStackDepth_; }
|
|
||||||
|
|
||||||
void updateDepth(ptrdiff_t target);
|
|
||||||
|
|
||||||
// ---- Try notes ----
|
|
||||||
|
|
||||||
CGTryNoteList& tryNoteList() { return tryNoteList_; };
|
|
||||||
const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
|
|
||||||
|
|
||||||
// ---- Scope ----
|
|
||||||
|
|
||||||
CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
|
|
||||||
const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
|
|
||||||
|
|
||||||
// ---- Generator ----
|
|
||||||
|
|
||||||
CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
|
|
||||||
const CGResumeOffsetList& resumeOffsetList() const {
|
|
||||||
return resumeOffsetList_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t numYields() const { return numYields_; }
|
|
||||||
void addNumYields() { numYields_++; }
|
|
||||||
|
|
||||||
// ---- Line and column ----
|
|
||||||
|
|
||||||
uint32_t currentLine() const { return currentLine_; }
|
|
||||||
uint32_t lastColumn() const { return lastColumn_; }
|
|
||||||
void setCurrentLine(uint32_t line) {
|
|
||||||
currentLine_ = line;
|
|
||||||
lastColumn_ = 0;
|
|
||||||
}
|
|
||||||
void setLastColumn(uint32_t column) { lastColumn_ = column; }
|
|
||||||
|
|
||||||
void updateSeparatorPosition() {
|
|
||||||
lastSeparatorOffet_ = code().length();
|
|
||||||
lastSeparatorLine_ = currentLine_;
|
|
||||||
lastSeparatorColumn_ = lastColumn_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateSeparatorPositionIfPresent() {
|
|
||||||
if (lastSeparatorOffet_ == code().length()) {
|
|
||||||
lastSeparatorLine_ = currentLine_;
|
|
||||||
lastSeparatorColumn_ = lastColumn_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDuplicateLocation() const {
|
|
||||||
return lastSeparatorLine_ == currentLine_ &&
|
|
||||||
lastSeparatorColumn_ == lastColumn_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- JIT ----
|
|
||||||
|
|
||||||
uint32_t numICEntries() const { return numICEntries_; }
|
|
||||||
void incrementNumICEntries() {
|
|
||||||
MOZ_ASSERT(numICEntries_ != UINT32_MAX, "Shouldn't overflow");
|
|
||||||
numICEntries_++;
|
|
||||||
}
|
|
||||||
void setNumICEntries(uint32_t entries) { numICEntries_ = entries; }
|
|
||||||
|
|
||||||
uint32_t numTypeSets() const { return numTypeSets_; }
|
|
||||||
void incrementNumTypeSets() {
|
|
||||||
MOZ_ASSERT(numTypeSets_ != UINT32_MAX, "Shouldn't overflow");
|
|
||||||
numTypeSets_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// ---- Bytecode ----
|
|
||||||
|
|
||||||
// Bytecode.
|
|
||||||
BytecodeVector code_;
|
|
||||||
|
|
||||||
// ---- Source notes ----
|
|
||||||
|
|
||||||
// Source notes
|
|
||||||
SrcNotesVector notes_;
|
|
||||||
|
|
||||||
// Code offset for last source note
|
|
||||||
ptrdiff_t lastNoteOffset_ = 0;
|
|
||||||
|
|
||||||
// ---- Jump ----
|
|
||||||
|
|
||||||
// Last jump target emitted.
|
|
||||||
JumpTarget lastTarget_ = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
|
|
||||||
|
|
||||||
// ---- Stack ----
|
|
||||||
|
|
||||||
// Maximum number of expression stack slots so far.
|
|
||||||
uint32_t maxStackDepth_ = 0;
|
|
||||||
|
|
||||||
// Current stack depth in script frame.
|
|
||||||
int32_t stackDepth_ = 0;
|
|
||||||
|
|
||||||
// ---- Try notes ----
|
|
||||||
|
|
||||||
// List of emitted try notes.
|
|
||||||
CGTryNoteList tryNoteList_;
|
|
||||||
|
|
||||||
// ---- Scope ----
|
|
||||||
|
|
||||||
// List of emitted block scope notes.
|
|
||||||
CGScopeNoteList scopeNoteList_;
|
|
||||||
|
|
||||||
// ---- Generator ----
|
|
||||||
|
|
||||||
// Certain ops (yield, await, gosub) have an entry in the script's
|
|
||||||
// resumeOffsets list. This can be used to map from the op's resumeIndex to
|
|
||||||
// the bytecode offset of the next pc. This indirection makes it easy to
|
|
||||||
// resume in the JIT (because BaselineScript stores a resumeIndex => native
|
|
||||||
// code array).
|
|
||||||
CGResumeOffsetList resumeOffsetList_;
|
|
||||||
|
|
||||||
// Number of yield instructions emitted. Does not include JSOP_AWAIT.
|
|
||||||
uint32_t numYields_ = 0;
|
|
||||||
|
|
||||||
// ---- Line and column ----
|
|
||||||
|
|
||||||
// Line number for srcnotes.
|
|
||||||
//
|
|
||||||
// WARNING: If this becomes out of sync with already-emitted srcnotes,
|
|
||||||
// we can get undefined behavior.
|
|
||||||
uint32_t currentLine_;
|
|
||||||
|
|
||||||
// Zero-based column index on currentLine_ of last SRC_COLSPAN-annotated
|
|
||||||
// opcode.
|
|
||||||
//
|
|
||||||
// WARNING: If this becomes out of sync with already-emitted srcnotes,
|
|
||||||
// we can get undefined behavior.
|
|
||||||
uint32_t lastColumn_ = 0;
|
|
||||||
|
|
||||||
// The offset, line and column numbers of the last opcode for the
|
|
||||||
// breakpoint for step execution.
|
|
||||||
uint32_t lastSeparatorOffet_ = 0;
|
|
||||||
uint32_t lastSeparatorLine_ = 0;
|
|
||||||
uint32_t lastSeparatorColumn_ = 0;
|
|
||||||
|
|
||||||
// ---- JIT ----
|
|
||||||
|
|
||||||
// Number of ICEntries in the script. There's one ICEntry for each JOF_IC op
|
|
||||||
// and, if the script is a function, for |this| and each formal argument.
|
|
||||||
uint32_t numICEntries_ = 0;
|
|
||||||
|
|
||||||
// Number of JOF_TYPESET opcodes generated.
|
|
||||||
uint32_t numTypeSets_ = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
BytecodeSection bytecodeSection_;
|
BytecodeSection bytecodeSection_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -326,50 +61,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
|
|||||||
const BytecodeSection& bytecodeSection() const { return bytecodeSection_; }
|
const BytecodeSection& bytecodeSection() const { return bytecodeSection_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Data that is not directly associated with specific opcode/index inside
|
|
||||||
// bytecode, but referred from bytecode is stored in this class.
|
|
||||||
class PerScriptData {
|
|
||||||
public:
|
|
||||||
explicit PerScriptData(JSContext* cx);
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool init(JSContext* cx);
|
|
||||||
|
|
||||||
// ---- Scope ----
|
|
||||||
|
|
||||||
CGScopeList& scopeList() { return scopeList_; }
|
|
||||||
const CGScopeList& scopeList() const { return scopeList_; }
|
|
||||||
|
|
||||||
// ---- Literals ----
|
|
||||||
|
|
||||||
CGNumberList& numberList() { return numberList_; }
|
|
||||||
const CGNumberList& numberList() const { return numberList_; }
|
|
||||||
|
|
||||||
CGObjectList& objectList() { return objectList_; }
|
|
||||||
const CGObjectList& objectList() const { return objectList_; }
|
|
||||||
|
|
||||||
PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
|
|
||||||
const PooledMapPtr<AtomIndexMap>& atomIndices() const {
|
|
||||||
return atomIndices_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// ---- Scope ----
|
|
||||||
|
|
||||||
// List of emitted scopes.
|
|
||||||
CGScopeList scopeList_;
|
|
||||||
|
|
||||||
// ---- Literals ----
|
|
||||||
|
|
||||||
// List of double and bigint values used by script.
|
|
||||||
CGNumberList numberList_;
|
|
||||||
|
|
||||||
// List of emitted objects.
|
|
||||||
CGObjectList objectList_;
|
|
||||||
|
|
||||||
// Map from atom to index.
|
|
||||||
PooledMapPtr<AtomIndexMap> atomIndices_;
|
|
||||||
};
|
|
||||||
|
|
||||||
PerScriptData perScriptData_;
|
PerScriptData perScriptData_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
170
js/src/frontend/BytecodeSection.cpp
Normal file
170
js/src/frontend/BytecodeSection.cpp
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "frontend/BytecodeSection.h"
|
||||||
|
|
||||||
|
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||||
|
#include "mozilla/PodOperations.h" // PodZero
|
||||||
|
#include "mozilla/ReverseIterator.h" // mozilla::Reversed
|
||||||
|
|
||||||
|
#include "frontend/ParseNode.h" // ObjectBox
|
||||||
|
#include "frontend/SharedContext.h" // FunctionBox
|
||||||
|
#include "vm/BytecodeUtil.h" // INDEX_LIMIT, StackUses, StackDefs
|
||||||
|
#include "vm/JSContext.h" // JSContext
|
||||||
|
|
||||||
|
using namespace js;
|
||||||
|
using namespace js::frontend;
|
||||||
|
|
||||||
|
void CGNumberList::finish(mozilla::Span<GCPtrValue> array) {
|
||||||
|
MOZ_ASSERT(length() == array.size());
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < length(); i++) {
|
||||||
|
array[i].init(vector[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the index of the given object for code generator.
|
||||||
|
*
|
||||||
|
* Since the emitter refers to each parsed object only once, for the index we
|
||||||
|
* use the number of already indexed objects. We also add the object to a list
|
||||||
|
* to convert the list to a fixed-size array when we complete code generation,
|
||||||
|
* see js::CGObjectList::finish below.
|
||||||
|
*/
|
||||||
|
unsigned CGObjectList::add(ObjectBox* objbox) {
|
||||||
|
MOZ_ASSERT(objbox->isObjectBox());
|
||||||
|
MOZ_ASSERT(!objbox->emitLink);
|
||||||
|
objbox->emitLink = lastbox;
|
||||||
|
lastbox = objbox;
|
||||||
|
return length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGObjectList::finish(mozilla::Span<GCPtrObject> array) {
|
||||||
|
MOZ_ASSERT(length <= INDEX_LIMIT);
|
||||||
|
MOZ_ASSERT(length == array.size());
|
||||||
|
|
||||||
|
ObjectBox* objbox = lastbox;
|
||||||
|
for (GCPtrObject& obj : mozilla::Reversed(array)) {
|
||||||
|
MOZ_ASSERT(obj == nullptr);
|
||||||
|
MOZ_ASSERT(objbox->object()->isTenured());
|
||||||
|
obj.init(objbox->object());
|
||||||
|
objbox = objbox->emitLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGObjectList::finishInnerFunctions() {
|
||||||
|
ObjectBox* objbox = lastbox;
|
||||||
|
while (objbox) {
|
||||||
|
if (objbox->isFunctionBox()) {
|
||||||
|
objbox->asFunctionBox()->finish();
|
||||||
|
}
|
||||||
|
objbox = objbox->emitLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGScopeList::finish(mozilla::Span<GCPtrScope> array) {
|
||||||
|
MOZ_ASSERT(length() <= INDEX_LIMIT);
|
||||||
|
MOZ_ASSERT(length() == array.size());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < length(); i++) {
|
||||||
|
array[i].init(vector[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth,
|
||||||
|
size_t start, size_t end) {
|
||||||
|
MOZ_ASSERT(start <= end);
|
||||||
|
MOZ_ASSERT(size_t(uint32_t(start)) == start);
|
||||||
|
MOZ_ASSERT(size_t(uint32_t(end)) == end);
|
||||||
|
|
||||||
|
// Offsets are given relative to sections, but we only expect main-section
|
||||||
|
// to have TryNotes. In finish() we will fixup base offset.
|
||||||
|
|
||||||
|
JSTryNote note;
|
||||||
|
note.kind = kind;
|
||||||
|
note.stackDepth = stackDepth;
|
||||||
|
note.start = uint32_t(start);
|
||||||
|
note.length = uint32_t(end - start);
|
||||||
|
|
||||||
|
return list.append(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGTryNoteList::finish(mozilla::Span<JSTryNote> array) {
|
||||||
|
MOZ_ASSERT(length() == array.size());
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < length(); i++) {
|
||||||
|
array[i] = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset,
|
||||||
|
uint32_t parent) {
|
||||||
|
CGScopeNote note;
|
||||||
|
mozilla::PodZero(¬e);
|
||||||
|
|
||||||
|
// Offsets are given relative to sections. In finish() we will fixup base
|
||||||
|
// offset if needed.
|
||||||
|
|
||||||
|
note.index = scopeIndex;
|
||||||
|
note.start = offset;
|
||||||
|
note.parent = parent;
|
||||||
|
|
||||||
|
return list.append(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGScopeNoteList::recordEnd(uint32_t index, uint32_t offset) {
|
||||||
|
MOZ_ASSERT(index < length());
|
||||||
|
MOZ_ASSERT(list[index].length == 0);
|
||||||
|
list[index].end = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGScopeNoteList::finish(mozilla::Span<ScopeNote> array) {
|
||||||
|
MOZ_ASSERT(length() == array.size());
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < length(); i++) {
|
||||||
|
MOZ_ASSERT(list[i].end >= list[i].start);
|
||||||
|
list[i].length = list[i].end - list[i].start;
|
||||||
|
array[i] = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGResumeOffsetList::finish(mozilla::Span<uint32_t> array) {
|
||||||
|
MOZ_ASSERT(length() == array.size());
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < length(); i++) {
|
||||||
|
array[i] = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BytecodeSection::BytecodeSection(JSContext* cx, uint32_t lineNum)
|
||||||
|
: code_(cx),
|
||||||
|
notes_(cx),
|
||||||
|
tryNoteList_(cx),
|
||||||
|
scopeNoteList_(cx),
|
||||||
|
resumeOffsetList_(cx),
|
||||||
|
currentLine_(lineNum) {}
|
||||||
|
|
||||||
|
void BytecodeSection::updateDepth(ptrdiff_t target) {
|
||||||
|
jsbytecode* pc = code(target);
|
||||||
|
|
||||||
|
int nuses = StackUses(pc);
|
||||||
|
int ndefs = StackDefs(pc);
|
||||||
|
|
||||||
|
stackDepth_ -= nuses;
|
||||||
|
MOZ_ASSERT(stackDepth_ >= 0);
|
||||||
|
stackDepth_ += ndefs;
|
||||||
|
|
||||||
|
if (uint32_t(stackDepth_) > maxStackDepth_) {
|
||||||
|
maxStackDepth_ = stackDepth_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PerScriptData::PerScriptData(JSContext* cx)
|
||||||
|
: scopeList_(cx),
|
||||||
|
numberList_(cx),
|
||||||
|
atomIndices_(cx->frontendCollectionPool()) {}
|
||||||
|
|
||||||
|
bool PerScriptData::init(JSContext* cx) { return atomIndices_.acquire(cx); }
|
353
js/src/frontend/BytecodeSection.h
Normal file
353
js/src/frontend/BytecodeSection.h
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef frontend_BytecodeSection_h
|
||||||
|
#define frontend_BytecodeSection_h
|
||||||
|
|
||||||
|
#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS
|
||||||
|
#include "mozilla/Span.h" // mozilla::Span
|
||||||
|
|
||||||
|
#include <stddef.h> // ptrdiff_t, size_t
|
||||||
|
#include <stdint.h> // uint16_t, int32_t, uint32_t
|
||||||
|
|
||||||
|
#include "NamespaceImports.h" // ValueVector
|
||||||
|
#include "frontend/JumpList.h" // JumpTarget
|
||||||
|
#include "frontend/NameCollections.h" // AtomIndexMap, PooledMapPtr
|
||||||
|
#include "frontend/SourceNotes.h" // jssrcnote
|
||||||
|
#include "gc/Barrier.h" // GCPtrObject, GCPtrScope, GCPtrValue
|
||||||
|
#include "gc/Rooting.h" // JS::Rooted
|
||||||
|
#include "js/GCVector.h" // GCVector
|
||||||
|
#include "js/TypeDecls.h" // jsbytecode
|
||||||
|
#include "js/Value.h" // JS::Vector
|
||||||
|
#include "js/Vector.h" // Vector
|
||||||
|
#include "vm/JSScript.h" // JSTryNote, JSTryNoteKind, ScopeNote
|
||||||
|
#include "vm/Opcodes.h" // JSOP_*
|
||||||
|
|
||||||
|
struct JSContext;
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
class Scope;
|
||||||
|
|
||||||
|
namespace frontend {
|
||||||
|
|
||||||
|
class ObjectBox;
|
||||||
|
|
||||||
|
class CGNumberList {
|
||||||
|
JS::Rooted<ValueVector> vector;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CGNumberList(JSContext* cx) : vector(cx, ValueVector(cx)) {}
|
||||||
|
MOZ_MUST_USE bool append(const JS::Value& v) { return vector.append(v); }
|
||||||
|
size_t length() const { return vector.length(); }
|
||||||
|
void finish(mozilla::Span<GCPtrValue> array);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CGObjectList {
|
||||||
|
// Number of emitted so far objects.
|
||||||
|
uint32_t length;
|
||||||
|
// Last emitted object.
|
||||||
|
ObjectBox* lastbox;
|
||||||
|
|
||||||
|
CGObjectList() : length(0), lastbox(nullptr) {}
|
||||||
|
|
||||||
|
unsigned add(ObjectBox* objbox);
|
||||||
|
void finish(mozilla::Span<GCPtrObject> array);
|
||||||
|
void finishInnerFunctions();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MOZ_STACK_CLASS CGScopeList {
|
||||||
|
JS::Rooted<GCVector<Scope*>> vector;
|
||||||
|
|
||||||
|
explicit CGScopeList(JSContext* cx) : vector(cx, GCVector<Scope*>(cx)) {}
|
||||||
|
|
||||||
|
bool append(Scope* scope) { return vector.append(scope); }
|
||||||
|
uint32_t length() const { return vector.length(); }
|
||||||
|
void finish(mozilla::Span<GCPtrScope> array);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CGTryNoteList {
|
||||||
|
Vector<JSTryNote> list;
|
||||||
|
explicit CGTryNoteList(JSContext* cx) : list(cx) {}
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool append(JSTryNoteKind kind, uint32_t stackDepth,
|
||||||
|
size_t start, size_t end);
|
||||||
|
size_t length() const { return list.length(); }
|
||||||
|
void finish(mozilla::Span<JSTryNote> array);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CGScopeNote : public ScopeNote {
|
||||||
|
// The end offset. Used to compute the length.
|
||||||
|
uint32_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CGScopeNoteList {
|
||||||
|
Vector<CGScopeNote> list;
|
||||||
|
explicit CGScopeNoteList(JSContext* cx) : list(cx) {}
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset,
|
||||||
|
uint32_t parent);
|
||||||
|
void recordEnd(uint32_t index, uint32_t offse);
|
||||||
|
size_t length() const { return list.length(); }
|
||||||
|
void finish(mozilla::Span<ScopeNote> array);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CGResumeOffsetList {
|
||||||
|
Vector<uint32_t> list;
|
||||||
|
explicit CGResumeOffsetList(JSContext* cx) : list(cx) {}
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
|
||||||
|
size_t length() const { return list.length(); }
|
||||||
|
void finish(mozilla::Span<uint32_t> array);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr size_t MaxBytecodeLength = INT32_MAX;
|
||||||
|
static constexpr size_t MaxSrcNotesLength = INT32_MAX;
|
||||||
|
|
||||||
|
// Have a few inline elements, so as to avoid heap allocation for tiny
|
||||||
|
// sequences. See bug 1390526.
|
||||||
|
typedef Vector<jsbytecode, 64> BytecodeVector;
|
||||||
|
typedef Vector<jssrcnote, 64> SrcNotesVector;
|
||||||
|
|
||||||
|
// Bytecode and all data directly associated with specific opcode/index inside
|
||||||
|
// bytecode is stored in this class.
|
||||||
|
class BytecodeSection {
|
||||||
|
public:
|
||||||
|
BytecodeSection(JSContext* cx, uint32_t lineNum);
|
||||||
|
|
||||||
|
// ---- Bytecode ----
|
||||||
|
|
||||||
|
BytecodeVector& code() { return code_; }
|
||||||
|
const BytecodeVector& code() const { return code_; }
|
||||||
|
|
||||||
|
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
|
||||||
|
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
|
||||||
|
|
||||||
|
// ---- Source notes ----
|
||||||
|
|
||||||
|
SrcNotesVector& notes() { return notes_; }
|
||||||
|
const SrcNotesVector& notes() const { return notes_; }
|
||||||
|
|
||||||
|
ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
|
||||||
|
void setLastNoteOffset(ptrdiff_t offset) { lastNoteOffset_ = offset; }
|
||||||
|
|
||||||
|
// ---- Jump ----
|
||||||
|
|
||||||
|
ptrdiff_t lastTargetOffset() const { return lastTarget_.offset; }
|
||||||
|
void setLastTargetOffset(ptrdiff_t offset) { lastTarget_.offset = offset; }
|
||||||
|
|
||||||
|
// Check if the last emitted opcode is a jump target.
|
||||||
|
bool lastOpcodeIsJumpTarget() const {
|
||||||
|
return offset() - lastTarget_.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// JumpTarget should not be part of the emitted statement, as they can be
|
||||||
|
// aliased by multiple statements. If we included the jump target as part of
|
||||||
|
// the statement we might have issues where the enclosing statement might
|
||||||
|
// not contain all the opcodes of the enclosed statements.
|
||||||
|
ptrdiff_t lastNonJumpTargetOffset() const {
|
||||||
|
return lastOpcodeIsJumpTarget() ? lastTarget_.offset : offset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Stack ----
|
||||||
|
|
||||||
|
int32_t stackDepth() const { return stackDepth_; }
|
||||||
|
void setStackDepth(int32_t depth) { stackDepth_ = depth; }
|
||||||
|
|
||||||
|
uint32_t maxStackDepth() const { return maxStackDepth_; }
|
||||||
|
|
||||||
|
void updateDepth(ptrdiff_t target);
|
||||||
|
|
||||||
|
// ---- Try notes ----
|
||||||
|
|
||||||
|
CGTryNoteList& tryNoteList() { return tryNoteList_; };
|
||||||
|
const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
|
||||||
|
|
||||||
|
// ---- Scope ----
|
||||||
|
|
||||||
|
CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
|
||||||
|
const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
|
||||||
|
|
||||||
|
// ---- Generator ----
|
||||||
|
|
||||||
|
CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
|
||||||
|
const CGResumeOffsetList& resumeOffsetList() const {
|
||||||
|
return resumeOffsetList_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t numYields() const { return numYields_; }
|
||||||
|
void addNumYields() { numYields_++; }
|
||||||
|
|
||||||
|
// ---- Line and column ----
|
||||||
|
|
||||||
|
uint32_t currentLine() const { return currentLine_; }
|
||||||
|
uint32_t lastColumn() const { return lastColumn_; }
|
||||||
|
void setCurrentLine(uint32_t line) {
|
||||||
|
currentLine_ = line;
|
||||||
|
lastColumn_ = 0;
|
||||||
|
}
|
||||||
|
void setLastColumn(uint32_t column) { lastColumn_ = column; }
|
||||||
|
|
||||||
|
void updateSeparatorPosition() {
|
||||||
|
lastSeparatorOffet_ = code().length();
|
||||||
|
lastSeparatorLine_ = currentLine_;
|
||||||
|
lastSeparatorColumn_ = lastColumn_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSeparatorPositionIfPresent() {
|
||||||
|
if (lastSeparatorOffet_ == code().length()) {
|
||||||
|
lastSeparatorLine_ = currentLine_;
|
||||||
|
lastSeparatorColumn_ = lastColumn_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDuplicateLocation() const {
|
||||||
|
return lastSeparatorLine_ == currentLine_ &&
|
||||||
|
lastSeparatorColumn_ == lastColumn_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- JIT ----
|
||||||
|
|
||||||
|
uint32_t numICEntries() const { return numICEntries_; }
|
||||||
|
void incrementNumICEntries() {
|
||||||
|
MOZ_ASSERT(numICEntries_ != UINT32_MAX, "Shouldn't overflow");
|
||||||
|
numICEntries_++;
|
||||||
|
}
|
||||||
|
void setNumICEntries(uint32_t entries) { numICEntries_ = entries; }
|
||||||
|
|
||||||
|
uint32_t numTypeSets() const { return numTypeSets_; }
|
||||||
|
void incrementNumTypeSets() {
|
||||||
|
MOZ_ASSERT(numTypeSets_ != UINT32_MAX, "Shouldn't overflow");
|
||||||
|
numTypeSets_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ---- Bytecode ----
|
||||||
|
|
||||||
|
// Bytecode.
|
||||||
|
BytecodeVector code_;
|
||||||
|
|
||||||
|
// ---- Source notes ----
|
||||||
|
|
||||||
|
// Source notes
|
||||||
|
SrcNotesVector notes_;
|
||||||
|
|
||||||
|
// Code offset for last source note
|
||||||
|
ptrdiff_t lastNoteOffset_ = 0;
|
||||||
|
|
||||||
|
// ---- Jump ----
|
||||||
|
|
||||||
|
// Last jump target emitted.
|
||||||
|
JumpTarget lastTarget_ = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
|
||||||
|
|
||||||
|
// ---- Stack ----
|
||||||
|
|
||||||
|
// Maximum number of expression stack slots so far.
|
||||||
|
uint32_t maxStackDepth_ = 0;
|
||||||
|
|
||||||
|
// Current stack depth in script frame.
|
||||||
|
int32_t stackDepth_ = 0;
|
||||||
|
|
||||||
|
// ---- Try notes ----
|
||||||
|
|
||||||
|
// List of emitted try notes.
|
||||||
|
CGTryNoteList tryNoteList_;
|
||||||
|
|
||||||
|
// ---- Scope ----
|
||||||
|
|
||||||
|
// List of emitted block scope notes.
|
||||||
|
CGScopeNoteList scopeNoteList_;
|
||||||
|
|
||||||
|
// ---- Generator ----
|
||||||
|
|
||||||
|
// Certain ops (yield, await, gosub) have an entry in the script's
|
||||||
|
// resumeOffsets list. This can be used to map from the op's resumeIndex to
|
||||||
|
// the bytecode offset of the next pc. This indirection makes it easy to
|
||||||
|
// resume in the JIT (because BaselineScript stores a resumeIndex => native
|
||||||
|
// code array).
|
||||||
|
CGResumeOffsetList resumeOffsetList_;
|
||||||
|
|
||||||
|
// Number of yield instructions emitted. Does not include JSOP_AWAIT.
|
||||||
|
uint32_t numYields_ = 0;
|
||||||
|
|
||||||
|
// ---- Line and column ----
|
||||||
|
|
||||||
|
// Line number for srcnotes.
|
||||||
|
//
|
||||||
|
// WARNING: If this becomes out of sync with already-emitted srcnotes,
|
||||||
|
// we can get undefined behavior.
|
||||||
|
uint32_t currentLine_;
|
||||||
|
|
||||||
|
// Zero-based column index on currentLine_ of last SRC_COLSPAN-annotated
|
||||||
|
// opcode.
|
||||||
|
//
|
||||||
|
// WARNING: If this becomes out of sync with already-emitted srcnotes,
|
||||||
|
// we can get undefined behavior.
|
||||||
|
uint32_t lastColumn_ = 0;
|
||||||
|
|
||||||
|
// The offset, line and column numbers of the last opcode for the
|
||||||
|
// breakpoint for step execution.
|
||||||
|
uint32_t lastSeparatorOffet_ = 0;
|
||||||
|
uint32_t lastSeparatorLine_ = 0;
|
||||||
|
uint32_t lastSeparatorColumn_ = 0;
|
||||||
|
|
||||||
|
// ---- JIT ----
|
||||||
|
|
||||||
|
// Number of ICEntries in the script. There's one ICEntry for each JOF_IC op
|
||||||
|
// and, if the script is a function, for |this| and each formal argument.
|
||||||
|
uint32_t numICEntries_ = 0;
|
||||||
|
|
||||||
|
// Number of JOF_TYPESET opcodes generated.
|
||||||
|
uint32_t numTypeSets_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data that is not directly associated with specific opcode/index inside
|
||||||
|
// bytecode, but referred from bytecode is stored in this class.
|
||||||
|
class PerScriptData {
|
||||||
|
public:
|
||||||
|
explicit PerScriptData(JSContext* cx);
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool init(JSContext* cx);
|
||||||
|
|
||||||
|
// ---- Scope ----
|
||||||
|
|
||||||
|
CGScopeList& scopeList() { return scopeList_; }
|
||||||
|
const CGScopeList& scopeList() const { return scopeList_; }
|
||||||
|
|
||||||
|
// ---- Literals ----
|
||||||
|
|
||||||
|
CGNumberList& numberList() { return numberList_; }
|
||||||
|
const CGNumberList& numberList() const { return numberList_; }
|
||||||
|
|
||||||
|
CGObjectList& objectList() { return objectList_; }
|
||||||
|
const CGObjectList& objectList() const { return objectList_; }
|
||||||
|
|
||||||
|
PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
|
||||||
|
const PooledMapPtr<AtomIndexMap>& atomIndices() const { return atomIndices_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ---- Scope ----
|
||||||
|
|
||||||
|
// List of emitted scopes.
|
||||||
|
CGScopeList scopeList_;
|
||||||
|
|
||||||
|
// ---- Literals ----
|
||||||
|
|
||||||
|
// List of double and bigint values used by script.
|
||||||
|
CGNumberList numberList_;
|
||||||
|
|
||||||
|
// List of emitted objects.
|
||||||
|
CGObjectList objectList_;
|
||||||
|
|
||||||
|
// Map from atom to index.
|
||||||
|
PooledMapPtr<AtomIndexMap> atomIndices_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace frontend */
|
||||||
|
} /* namespace js */
|
||||||
|
|
||||||
|
#endif /* frontend_BytecodeSection_h */
|
@ -27,6 +27,7 @@ UNIFIED_SOURCES += [
|
|||||||
'BytecodeCompiler.cpp',
|
'BytecodeCompiler.cpp',
|
||||||
'BytecodeControlStructures.cpp',
|
'BytecodeControlStructures.cpp',
|
||||||
'BytecodeEmitter.cpp',
|
'BytecodeEmitter.cpp',
|
||||||
|
'BytecodeSection.cpp',
|
||||||
'CallOrNewEmitter.cpp',
|
'CallOrNewEmitter.cpp',
|
||||||
'CForEmitter.cpp',
|
'CForEmitter.cpp',
|
||||||
'DefaultEmitter.cpp',
|
'DefaultEmitter.cpp',
|
||||||
|
@ -241,7 +241,7 @@ void Zone::discardJitCode(FreeOp* fop,
|
|||||||
// Warm-up counter for scripts are reset on GC. After discarding code we
|
// Warm-up counter for scripts are reset on GC. After discarding code we
|
||||||
// need to let it warm back up to get information such as which
|
// need to let it warm back up to get information such as which
|
||||||
// opcodes are setting array holes or accessing getter properties.
|
// opcodes are setting array holes or accessing getter properties.
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterForGC();
|
||||||
|
|
||||||
// Clear the BaselineScript's control flow graph. The LifoAlloc is purged
|
// Clear the BaselineScript's control flow graph. The LifoAlloc is purged
|
||||||
// below.
|
// below.
|
||||||
|
@ -56,8 +56,8 @@ var Opts_IonEagerNoOffthreadCompilation =
|
|||||||
var Opts_Ion2NoOffthreadCompilation =
|
var Opts_Ion2NoOffthreadCompilation =
|
||||||
{
|
{
|
||||||
'ion.enable': 1,
|
'ion.enable': 1,
|
||||||
'ion.warmup.trigger': 2,
|
'ion.warmup.trigger': 3,
|
||||||
'ion.full.warmup.trigger': 2,
|
'ion.full.warmup.trigger': 3,
|
||||||
'baseline.enable': 1,
|
'baseline.enable': 1,
|
||||||
'baseline.warmup.trigger': 1,
|
'baseline.warmup.trigger': 1,
|
||||||
'offthread-compilation.enable': 0
|
'offthread-compilation.enable': 0
|
||||||
|
@ -518,3 +518,27 @@ wasmAssert(`(module
|
|||||||
|
|
||||||
// ADD NO MORE TESTS HERE!
|
// ADD NO MORE TESTS HERE!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard wat syntax: the parens around the initializer expression are
|
||||||
|
// optional.
|
||||||
|
{
|
||||||
|
let i1 = wasmEvalText(
|
||||||
|
`(module
|
||||||
|
(global $g i32 i32.const 37)
|
||||||
|
(func (export "f") (result i32) (global.get $g)))`);
|
||||||
|
assertEq(i1.exports.f(), 37);
|
||||||
|
|
||||||
|
let i2 = wasmEvalText(
|
||||||
|
`(module
|
||||||
|
(global $g (mut f64) f64.const 42.0)
|
||||||
|
(func (export "f") (result f64) (global.get $g)))`);
|
||||||
|
assertEq(i2.exports.f(), 42);
|
||||||
|
|
||||||
|
let i3 = wasmEvalText(
|
||||||
|
`(module
|
||||||
|
(global $x (import "m" "x") i32)
|
||||||
|
(global $g i32 global.get $x)
|
||||||
|
(func (export "f") (result i32) (global.get $g)))`,
|
||||||
|
{m:{x:86}});
|
||||||
|
assertEq(i3.exports.f(), 86);
|
||||||
|
}
|
||||||
|
@ -766,21 +766,35 @@ bool BaselineCodeGen<Handler>::emitStackCheck() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void EmitCallFrameIsDebuggeeCheck(MacroAssembler& masm) {
|
||||||
|
masm.Push(BaselineFrameReg);
|
||||||
|
masm.setupUnalignedABICall(R0.scratchReg());
|
||||||
|
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||||
|
masm.passABIArg(R0.scratchReg());
|
||||||
|
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::FrameIsDebuggeeCheck));
|
||||||
|
masm.Pop(BaselineFrameReg);
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void BaselineCompilerCodeGen::emitIsDebuggeeCheck() {
|
void BaselineCompilerCodeGen::emitIsDebuggeeCheck() {
|
||||||
if (handler.compileDebugInstrumentation()) {
|
if (handler.compileDebugInstrumentation()) {
|
||||||
masm.Push(BaselineFrameReg);
|
EmitCallFrameIsDebuggeeCheck(masm);
|
||||||
masm.setupUnalignedABICall(R0.scratchReg());
|
|
||||||
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
|
||||||
masm.passABIArg(R0.scratchReg());
|
|
||||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::FrameIsDebuggeeCheck));
|
|
||||||
masm.Pop(BaselineFrameReg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void BaselineInterpreterCodeGen::emitIsDebuggeeCheck() {
|
void BaselineInterpreterCodeGen::emitIsDebuggeeCheck() {
|
||||||
MOZ_CRASH("NYI: interpreter emitIsDebuggeeCheck");
|
// Use a toggled jump to call FrameIsDebuggeeCheck only if the debugger is
|
||||||
|
// enabled.
|
||||||
|
//
|
||||||
|
// TODO(bug 1522394): consider having a cx->realm->isDebuggee guard before the
|
||||||
|
// call. Consider moving the callWithABI out-of-line.
|
||||||
|
|
||||||
|
Label skipCheck;
|
||||||
|
CodeOffset toggleOffset = masm.toggledJump(&skipCheck);
|
||||||
|
EmitCallFrameIsDebuggeeCheck(masm);
|
||||||
|
masm.bind(&skipCheck);
|
||||||
|
handler.setDebuggeeCheckOffset(toggleOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -1050,7 +1064,44 @@ void BaselineCompilerCodeGen::emitInitFrameFields() {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
void BaselineInterpreterCodeGen::emitInitFrameFields() {
|
void BaselineInterpreterCodeGen::emitInitFrameFields() {
|
||||||
MOZ_CRASH("NYI: interpreter emitInitFrameFields");
|
Register scratch1 = R0.scratchReg();
|
||||||
|
Register scratch2 = R2.scratchReg();
|
||||||
|
|
||||||
|
masm.store32(Imm32(BaselineFrame::RUNNING_IN_INTERPRETER),
|
||||||
|
frame.addressOfFlags());
|
||||||
|
|
||||||
|
// Initialize interpreterScript.
|
||||||
|
Label notFunction, done;
|
||||||
|
masm.loadPtr(frame.addressOfCalleeToken(), scratch1);
|
||||||
|
masm.branchTestPtr(Assembler::NonZero, scratch1, Imm32(CalleeTokenScriptBit),
|
||||||
|
¬Function);
|
||||||
|
{
|
||||||
|
// CalleeToken_Function or CalleeToken_FunctionConstructing.
|
||||||
|
masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), scratch1);
|
||||||
|
masm.loadPtr(Address(scratch1, JSFunction::offsetOfScript()), scratch1);
|
||||||
|
masm.jump(&done);
|
||||||
|
}
|
||||||
|
masm.bind(¬Function);
|
||||||
|
{
|
||||||
|
// CalleeToken_Script.
|
||||||
|
masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), scratch1);
|
||||||
|
}
|
||||||
|
masm.bind(&done);
|
||||||
|
masm.storePtr(scratch1, frame.addressOfInterpreterScript());
|
||||||
|
|
||||||
|
// Initialize interpreterICEntry.
|
||||||
|
masm.loadPtr(Address(scratch1, JSScript::offsetOfTypes()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, TypeScript::offsetOfICScript()), scratch2);
|
||||||
|
masm.computeEffectiveAddress(Address(scratch2, ICScript::offsetOfICEntries()),
|
||||||
|
scratch2);
|
||||||
|
masm.storePtr(scratch2, frame.addressOfInterpreterICEntry());
|
||||||
|
|
||||||
|
// Initialize interpreterPC.
|
||||||
|
masm.loadPtr(Address(scratch1, JSScript::offsetOfScriptData()), scratch1);
|
||||||
|
masm.load32(Address(scratch1, SharedScriptData::offsetOfCodeOffset()),
|
||||||
|
scratch2);
|
||||||
|
masm.addPtr(scratch2, scratch1);
|
||||||
|
masm.storePtr(scratch1, frame.addressOfInterpreterPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -6071,7 +6122,27 @@ bool BaselineCompilerCodeGen::emit_JSOP_JUMPTARGET() {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool BaselineInterpreterCodeGen::emit_JSOP_JUMPTARGET() {
|
bool BaselineInterpreterCodeGen::emit_JSOP_JUMPTARGET() {
|
||||||
MOZ_CRASH("NYI: interpreter JSOP_JUMPTARGET");
|
Register scratch1 = R0.scratchReg();
|
||||||
|
Register scratch2 = R1.scratchReg();
|
||||||
|
|
||||||
|
// Load icIndex in scratch1.
|
||||||
|
LoadInt32Operand(masm, PCRegAtStart, scratch1);
|
||||||
|
|
||||||
|
// scratch1 := scratch1 * sizeof(ICEntry)
|
||||||
|
static_assert(sizeof(ICEntry) == 8 || sizeof(ICEntry) == 16,
|
||||||
|
"shift below depends on ICEntry size");
|
||||||
|
uint32_t shift = (sizeof(ICEntry) == 16) ? 4 : 3;
|
||||||
|
masm.lshiftPtr(Imm32(shift), scratch1);
|
||||||
|
|
||||||
|
// Compute ICEntry* and store to frame->interpreterICEntry.
|
||||||
|
loadScript(scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, JSScript::offsetOfTypes()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, TypeScript::offsetOfICScript()), scratch2);
|
||||||
|
masm.computeEffectiveAddress(
|
||||||
|
BaseIndex(scratch2, scratch1, TimesOne, ICScript::offsetOfICEntries()),
|
||||||
|
scratch2);
|
||||||
|
masm.storePtr(scratch2, frame.addressOfInterpreterICEntry());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
|
@ -655,6 +655,7 @@ class BaselineCompiler final : private BaselineCompilerCodeGen {
|
|||||||
class BaselineInterpreterHandler {
|
class BaselineInterpreterHandler {
|
||||||
InterpreterFrameInfo frame_;
|
InterpreterFrameInfo frame_;
|
||||||
Label interpretOp_;
|
Label interpretOp_;
|
||||||
|
CodeOffset debuggeeCheckOffset_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using FrameInfoT = InterpreterFrameInfo;
|
using FrameInfoT = InterpreterFrameInfo;
|
||||||
@ -671,6 +672,11 @@ class BaselineInterpreterHandler {
|
|||||||
JSScript* maybeScript() const { return nullptr; }
|
JSScript* maybeScript() const { return nullptr; }
|
||||||
JSFunction* maybeFunction() const { return nullptr; }
|
JSFunction* maybeFunction() const { return nullptr; }
|
||||||
|
|
||||||
|
void setDebuggeeCheckOffset(CodeOffset offset) {
|
||||||
|
debuggeeCheckOffset_ = offset;
|
||||||
|
}
|
||||||
|
CodeOffset debuggeeCheckOffset() const { return debuggeeCheckOffset_; }
|
||||||
|
|
||||||
// Interpreter doesn't need to keep track of RetAddrEntries, so these methods
|
// Interpreter doesn't need to keep track of RetAddrEntries, so these methods
|
||||||
// are no-ops.
|
// are no-ops.
|
||||||
MOZ_MUST_USE bool appendRetAddrEntry(JSContext* cx, RetAddrEntry::Kind kind,
|
MOZ_MUST_USE bool appendRetAddrEntry(JSContext* cx, RetAddrEntry::Kind kind,
|
||||||
|
@ -361,6 +361,8 @@ class ICScript {
|
|||||||
|
|
||||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
||||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
||||||
|
|
||||||
|
static constexpr size_t offsetOfICEntries() { return sizeof(ICScript); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICMonitoredStub;
|
class ICMonitoredStub;
|
||||||
|
@ -2252,7 +2252,7 @@ static MethodStatus Compile(JSContext* cx, HandleScript script,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!CanLikelyAllocateMoreExecutableMemory()) {
|
if (!CanLikelyAllocateMoreExecutableMemory()) {
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
return Method_Skipped;
|
return Method_Skipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2513,7 +2513,7 @@ bool jit::IonCompileScriptForBaseline(JSContext* cx, BaselineFrame* frame,
|
|||||||
// TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
|
// TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
|
||||||
// TODO: Clear all optimized stubs.
|
// TODO: Clear all optimized stubs.
|
||||||
// TODO: Add a ion-compilation-disabled checker IC stub
|
// TODO: Add a ion-compilation-disabled checker IC stub
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2576,7 +2576,7 @@ bool jit::IonCompileScriptForBaseline(JSContext* cx, BaselineFrame* frame,
|
|||||||
" Reset WarmUpCounter cantCompile=%s bailoutExpected=%s!",
|
" Reset WarmUpCounter cantCompile=%s bailoutExpected=%s!",
|
||||||
stat == Method_CantCompile ? "yes" : "no",
|
stat == Method_CantCompile ? "yes" : "no",
|
||||||
bailoutExpected ? "yes" : "no");
|
bailoutExpected ? "yes" : "no");
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2799,7 +2799,7 @@ static void ClearIonScriptAfterInvalidation(JSContext* cx, JSScript* script,
|
|||||||
// compile, unless we are recompiling *because* a script got hot
|
// compile, unless we are recompiling *because* a script got hot
|
||||||
// (resetUses is false).
|
// (resetUses is false).
|
||||||
if (resetUses) {
|
if (resetUses) {
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ static void HandleExceptionIon(JSContext* cx, const InlineFrameIterator& frame,
|
|||||||
// Ion can compile try-catch, but bailing out to catch
|
// Ion can compile try-catch, but bailing out to catch
|
||||||
// exceptions is slow. Reset the warm-up counter so that if we
|
// exceptions is slow. Reset the warm-up counter so that if we
|
||||||
// catch many exceptions we won't Ion-compile the script.
|
// catch many exceptions we won't Ion-compile the script.
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
|
|
||||||
if (*hitBailoutException) {
|
if (*hitBailoutException) {
|
||||||
break;
|
break;
|
||||||
@ -373,7 +373,7 @@ static bool ProcessTryNotesBaseline(JSContext* cx, const JSJitFrameIter& frame,
|
|||||||
// Ion can compile try-catch, but bailing out to catch
|
// Ion can compile try-catch, but bailing out to catch
|
||||||
// exceptions is slow. Reset the warm-up counter so that if we
|
// exceptions is slow. Reset the warm-up counter so that if we
|
||||||
// catch many exceptions we won't Ion-compile the script.
|
// catch many exceptions we won't Ion-compile the script.
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
|
|
||||||
// Resume at the start of the catch block.
|
// Resume at the start of the catch block.
|
||||||
rfe->kind = ResumeFromException::RESUME_CATCH;
|
rfe->kind = ResumeFromException::RESUME_CATCH;
|
||||||
|
@ -1636,11 +1636,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
|
|||||||
|
|
||||||
inline void cmp32Load32(Condition cond, Register lhs, const Address& rhs,
|
inline void cmp32Load32(Condition cond, Register lhs, const Address& rhs,
|
||||||
const Address& src, Register dest)
|
const Address& src, Register dest)
|
||||||
DEFINED_ON(arm, arm64, x86_shared);
|
DEFINED_ON(arm, arm64, mips_shared, x86_shared);
|
||||||
|
|
||||||
inline void cmp32Load32(Condition cond, Register lhs, Register rhs,
|
inline void cmp32Load32(Condition cond, Register lhs, Register rhs,
|
||||||
const Address& src, Register dest)
|
const Address& src, Register dest)
|
||||||
DEFINED_ON(arm, arm64, x86_shared);
|
DEFINED_ON(arm, arm64, mips_shared, x86_shared);
|
||||||
|
|
||||||
inline void cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs,
|
inline void cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs,
|
||||||
Register src, Register dest)
|
Register src, Register dest)
|
||||||
|
@ -435,23 +435,6 @@ void LIRGenerator::visitWasmStore(MWasmStore* ins) {
|
|||||||
add(lir, ins);
|
add(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
|
|
||||||
if (ins->type() == MIRType::Int64) {
|
|
||||||
auto* lir = new (alloc()) LWasmSelectI64(
|
|
||||||
useInt64RegisterAtStart(ins->trueExpr()), useInt64(ins->falseExpr()),
|
|
||||||
useRegister(ins->condExpr()));
|
|
||||||
|
|
||||||
defineInt64ReuseInput(lir, ins, LWasmSelectI64::TrueExprIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* lir = new (alloc())
|
|
||||||
LWasmSelect(useRegisterAtStart(ins->trueExpr()), use(ins->falseExpr()),
|
|
||||||
useRegister(ins->condExpr()));
|
|
||||||
|
|
||||||
defineReuseInput(lir, ins, LWasmSelect::TrueExprIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRGeneratorMIPSShared::lowerUDiv(MDiv* div) {
|
void LIRGeneratorMIPSShared::lowerUDiv(MDiv* div) {
|
||||||
MDefinition* lhs = div->getOperand(0);
|
MDefinition* lhs = div->getOperand(0);
|
||||||
MDefinition* rhs = div->getOperand(1);
|
MDefinition* rhs = div->getOperand(1);
|
||||||
|
@ -30,6 +30,10 @@ void MacroAssembler::move16SignExtend(Register src, Register dest) {
|
|||||||
ma_seh(dest, src);
|
ma_seh(dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroAssembler::loadAbiReturnAddress(Register dest) {
|
||||||
|
movePtr(ra, dest);
|
||||||
|
}
|
||||||
|
|
||||||
// ===============================================================
|
// ===============================================================
|
||||||
// Logical instructions
|
// Logical instructions
|
||||||
|
|
||||||
@ -797,6 +801,19 @@ void MacroAssembler::cmp32Move32(Condition cond, Register lhs,
|
|||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroAssembler::cmp32Load32(Condition cond, Register lhs,
|
||||||
|
const Address& rhs, const Address& src,
|
||||||
|
Register dest) {
|
||||||
|
// This is never used, but must be present to facilitate linking on mips(64).
|
||||||
|
MOZ_CRASH("No known use cases");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroAssembler::cmp32Load32(Condition cond, Register lhs, Register rhs,
|
||||||
|
const Address& src, Register dest) {
|
||||||
|
// This is never used, but must be present to facilitate linking on mips(64).
|
||||||
|
MOZ_CRASH("No known use cases");
|
||||||
|
}
|
||||||
|
|
||||||
void MacroAssembler::test32LoadPtr(Condition cond, const Address& addr,
|
void MacroAssembler::test32LoadPtr(Condition cond, const Address& addr,
|
||||||
Imm32 mask, const Address& src,
|
Imm32 mask, const Address& src,
|
||||||
Register dest) {
|
Register dest) {
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "jit/BaselineJIT.h"
|
#include "jit/BaselineJIT.h"
|
||||||
#include "jit/Ion.h"
|
#include "jit/Ion.h"
|
||||||
#include "jit/IonCode.h"
|
#include "jit/IonCode.h"
|
||||||
|
#include "jit/JitOptions.h"
|
||||||
#include "jit/JitRealm.h"
|
#include "jit/JitRealm.h"
|
||||||
#include "js/CompileOptions.h"
|
#include "js/CompileOptions.h"
|
||||||
#include "js/MemoryMetrics.h"
|
#include "js/MemoryMetrics.h"
|
||||||
@ -5465,6 +5466,18 @@ bool JSScript::mayReadFrameArgsDirectly() {
|
|||||||
return argumentsHasVarBinding() || hasRest();
|
return argumentsHasVarBinding() || hasRest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JSScript::resetWarmUpCounterToDelayIonCompilation() {
|
||||||
|
// Reset the warm-up count only if it's greater than the BaselineCompiler
|
||||||
|
// threshold. We do this to ensure this has no effect on Baseline compilation
|
||||||
|
// because we don't want scripts to get stuck in the (Baseline) interpreter in
|
||||||
|
// pathological cases.
|
||||||
|
|
||||||
|
if (warmUpCount > jit::JitOptions.baselineWarmUpThreshold) {
|
||||||
|
incWarmUpResetCounter();
|
||||||
|
warmUpCount = jit::JitOptions.baselineWarmUpThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JSScript::AutoDelazify::holdScript(JS::HandleFunction fun) {
|
void JSScript::AutoDelazify::holdScript(JS::HandleFunction fun) {
|
||||||
if (fun) {
|
if (fun) {
|
||||||
if (fun->realm()->isSelfHostingRealm()) {
|
if (fun->realm()->isSelfHostingRealm()) {
|
||||||
|
@ -2662,11 +2662,13 @@ class JSScript : public js::gc::TenuredCell {
|
|||||||
static size_t offsetOfWarmUpCounter() {
|
static size_t offsetOfWarmUpCounter() {
|
||||||
return offsetof(JSScript, warmUpCount);
|
return offsetof(JSScript, warmUpCount);
|
||||||
}
|
}
|
||||||
void resetWarmUpCounter() {
|
void resetWarmUpCounterForGC() {
|
||||||
incWarmUpResetCounter();
|
incWarmUpResetCounter();
|
||||||
warmUpCount = 0;
|
warmUpCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetWarmUpCounterToDelayIonCompilation();
|
||||||
|
|
||||||
unsigned getWarmUpResetCount() const {
|
unsigned getWarmUpResetCount() const {
|
||||||
constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
|
constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
|
||||||
return mutableFlags_ & MASK;
|
return mutableFlags_ & MASK;
|
||||||
|
@ -1569,7 +1569,7 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
script->resetWarmUpCounter();
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
*isValidOut = false;
|
*isValidOut = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2679,9 +2679,7 @@ void TypeZone::addPendingRecompile(JSContext* cx, JSScript* script) {
|
|||||||
CancelOffThreadIonCompile(script);
|
CancelOffThreadIonCompile(script);
|
||||||
|
|
||||||
// Let the script warm up again before attempting another compile.
|
// Let the script warm up again before attempting another compile.
|
||||||
if (jit::IsBaselineEnabled(cx)) {
|
script->resetWarmUpCounterToDelayIonCompilation();
|
||||||
script->resetWarmUpCounter();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (script->hasIonScript()) {
|
if (script->hasIonScript()) {
|
||||||
addPendingRecompile(
|
addPendingRecompile(
|
||||||
|
@ -4454,9 +4454,12 @@ static bool MaybeParseOwnerIndex(WasmParseContext& c) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstExpr* ParseInitializerExpression(WasmParseContext& c) {
|
static AstExpr* ParseInitializerConstExpression(WasmParseContext& c) {
|
||||||
if (!c.ts.match(WasmToken::OpenParen, c.error)) {
|
bool need_rparen = false;
|
||||||
return nullptr;
|
|
||||||
|
// For const initializer expressions, the parens are optional.
|
||||||
|
if (c.ts.getIf(WasmToken::OpenParen)) {
|
||||||
|
need_rparen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstExpr* initExpr = ParseExprInsideParens(c);
|
AstExpr* initExpr = ParseExprInsideParens(c);
|
||||||
@ -4464,7 +4467,7 @@ static AstExpr* ParseInitializerExpression(WasmParseContext& c) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c.ts.match(WasmToken::CloseParen, c.error)) {
|
if (need_rparen && !c.ts.match(WasmToken::CloseParen, c.error)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4480,11 +4483,19 @@ static bool ParseInitializerExpressionOrPassive(WasmParseContext& c,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AstExpr* initExpr = ParseInitializerExpression(c);
|
if (!c.ts.match(WasmToken::OpenParen, c.error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstExpr* initExpr = ParseExprInsideParens(c);
|
||||||
if (!initExpr) {
|
if (!initExpr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!c.ts.match(WasmToken::CloseParen, c.error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*maybeInitExpr = initExpr;
|
*maybeInitExpr = initExpr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -5119,7 +5130,7 @@ static bool ParseGlobal(WasmParseContext& c, AstModule* module) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstExpr* init = ParseInitializerExpression(c);
|
AstExpr* init = ParseInitializerConstExpression(c);
|
||||||
if (!init) {
|
if (!init) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -186,11 +186,10 @@ function load_cert(cert, trust) {
|
|||||||
|
|
||||||
function fetch_blocklist() {
|
function fetch_blocklist() {
|
||||||
Services.prefs.setBoolPref("services.settings.load_dump", false);
|
Services.prefs.setBoolPref("services.settings.load_dump", false);
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
Services.prefs.setCharPref("services.settings.server",
|
Services.prefs.setCharPref("services.settings.server",
|
||||||
`http://localhost:${port}/v1`);
|
`http://localhost:${port}/v1`);
|
||||||
|
|
||||||
BlocklistClients.initialize();
|
BlocklistClients.initialize({ verifySignature: false });
|
||||||
|
|
||||||
return RemoteSettings.pollChanges();
|
return RemoteSettings.pollChanges();
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ let remoteSecSetting;
|
|||||||
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
||||||
const {RemoteSecuritySettings} = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
const {RemoteSecuritySettings} = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
||||||
remoteSecSetting = new RemoteSecuritySettings();
|
remoteSecSetting = new RemoteSecuritySettings();
|
||||||
|
remoteSecSetting.client.verifySignature = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
@ -89,7 +90,6 @@ function setupKintoPreloadServer(certGenerator, options = {
|
|||||||
}) {
|
}) {
|
||||||
const dummyServerURL = `http://localhost:${server.identity.primaryPort}/v1`;
|
const dummyServerURL = `http://localhost:${server.identity.primaryPort}/v1`;
|
||||||
Services.prefs.setCharPref("services.settings.server", dummyServerURL);
|
Services.prefs.setCharPref("services.settings.server", dummyServerURL);
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
|
||||||
const configPath = "/v1/";
|
const configPath = "/v1/";
|
||||||
const recordsPath = "/v1/buckets/security-state/collections/intermediates/records";
|
const recordsPath = "/v1/buckets/security-state/collections/intermediates/records";
|
||||||
|
@ -110,6 +110,7 @@ skip-if = toolkit == 'android'
|
|||||||
[test_hmac.js]
|
[test_hmac.js]
|
||||||
[test_intermediate_basic_usage_constraints.js]
|
[test_intermediate_basic_usage_constraints.js]
|
||||||
[test_intermediate_preloads.js]
|
[test_intermediate_preloads.js]
|
||||||
|
tags = blocklist
|
||||||
# Bug 1520297 - do something to handle tighter resource constraints on Android
|
# Bug 1520297 - do something to handle tighter resource constraints on Android
|
||||||
skip-if = toolkit == 'android'
|
skip-if = toolkit == 'android'
|
||||||
[test_imminent_distrust.js]
|
[test_imminent_distrust.js]
|
||||||
|
@ -251,12 +251,15 @@ var OneCRLBlocklistClient;
|
|||||||
var PinningBlocklistClient;
|
var PinningBlocklistClient;
|
||||||
var RemoteSecuritySettingsClient;
|
var RemoteSecuritySettingsClient;
|
||||||
|
|
||||||
function initialize() {
|
function initialize(options = {}) {
|
||||||
|
const { verifySignature = true } = options;
|
||||||
|
|
||||||
OneCRLBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_SECURITY_SETTINGS_ONECRL_COLLECTION), {
|
OneCRLBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_SECURITY_SETTINGS_ONECRL_COLLECTION), {
|
||||||
bucketNamePref: PREF_SECURITY_SETTINGS_ONECRL_BUCKET,
|
bucketNamePref: PREF_SECURITY_SETTINGS_ONECRL_BUCKET,
|
||||||
lastCheckTimePref: PREF_SECURITY_SETTINGS_ONECRL_CHECKED,
|
lastCheckTimePref: PREF_SECURITY_SETTINGS_ONECRL_CHECKED,
|
||||||
signerName: Services.prefs.getCharPref(PREF_SECURITY_SETTINGS_ONECRL_SIGNER),
|
signerName: Services.prefs.getCharPref(PREF_SECURITY_SETTINGS_ONECRL_SIGNER),
|
||||||
});
|
});
|
||||||
|
OneCRLBlocklistClient.verifySignature = verifySignature;
|
||||||
OneCRLBlocklistClient.on("sync", updateCertBlocklist);
|
OneCRLBlocklistClient.on("sync", updateCertBlocklist);
|
||||||
|
|
||||||
PinningBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_COLLECTION), {
|
PinningBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_COLLECTION), {
|
||||||
@ -264,6 +267,7 @@ function initialize() {
|
|||||||
lastCheckTimePref: PREF_BLOCKLIST_PINNING_CHECKED_SECONDS,
|
lastCheckTimePref: PREF_BLOCKLIST_PINNING_CHECKED_SECONDS,
|
||||||
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_SIGNER),
|
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_SIGNER),
|
||||||
});
|
});
|
||||||
|
PinningBlocklistClient.verifySignature = verifySignature;
|
||||||
PinningBlocklistClient.on("sync", updatePinningList);
|
PinningBlocklistClient.on("sync", updatePinningList);
|
||||||
|
|
||||||
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
||||||
@ -272,6 +276,7 @@ function initialize() {
|
|||||||
// In Bug 1526018 this will move into its own service, as it's not quite like
|
// In Bug 1526018 this will move into its own service, as it's not quite like
|
||||||
// the others.
|
// the others.
|
||||||
RemoteSecuritySettingsClient = new RemoteSecuritySettings();
|
RemoteSecuritySettingsClient = new RemoteSecuritySettings();
|
||||||
|
RemoteSecuritySettingsClient.verifySignature = verifySignature;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
OneCRLBlocklistClient,
|
OneCRLBlocklistClient,
|
||||||
|
@ -19,7 +19,7 @@ add_task(async function test_something() {
|
|||||||
const dummyServerURL = `http://localhost:${server.identity.primaryPort}/v1`;
|
const dummyServerURL = `http://localhost:${server.identity.primaryPort}/v1`;
|
||||||
Services.prefs.setCharPref("services.settings.server", dummyServerURL);
|
Services.prefs.setCharPref("services.settings.server", dummyServerURL);
|
||||||
|
|
||||||
const {OneCRLBlocklistClient} = BlocklistClients.initialize();
|
const {OneCRLBlocklistClient} = BlocklistClients.initialize({verifySignature: false});
|
||||||
|
|
||||||
// register a handler
|
// register a handler
|
||||||
function handleResponse(request, response) {
|
function handleResponse(request, response) {
|
||||||
@ -104,10 +104,6 @@ add_task(async function test_something() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
// Ensure that signature verification is disabled to prevent interference
|
|
||||||
// with basic certificate sync tests
|
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
|
||||||
// Set up an HTTP Server
|
// Set up an HTTP Server
|
||||||
server = new HttpServer();
|
server = new HttpServer();
|
||||||
server.start(-1);
|
server.start(-1);
|
||||||
|
@ -27,7 +27,9 @@ let server;
|
|||||||
// Some simple tests to demonstrate that the core preload sync operations work
|
// Some simple tests to demonstrate that the core preload sync operations work
|
||||||
// correctly and that simple kinto operations are working as expected.
|
// correctly and that simple kinto operations are working as expected.
|
||||||
add_task(async function test_something() {
|
add_task(async function test_something() {
|
||||||
const PinningPreloadClient = BlocklistClients.initialize().PinningBlocklistClient;
|
const {
|
||||||
|
PinningBlocklistClient: PinningPreloadClient,
|
||||||
|
} = BlocklistClients.initialize({ verifySignature: false });
|
||||||
|
|
||||||
const configPath = "/v1/";
|
const configPath = "/v1/";
|
||||||
const recordsPath = "/v1/buckets/pinning/collections/pins/records";
|
const recordsPath = "/v1/buckets/pinning/collections/pins/records";
|
||||||
@ -138,10 +140,6 @@ add_task(async function test_something() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
// Ensure that signature verification is disabled to prevent interference
|
|
||||||
// with basic certificate sync tests
|
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
|
||||||
// Set up an HTTP Server
|
// Set up an HTTP Server
|
||||||
server = new HttpServer();
|
server = new HttpServer();
|
||||||
server.start(-1);
|
server.start(-1);
|
||||||
|
@ -8,7 +8,6 @@ const { UptakeTelemetry } = ChromeUtils.import("resource://services-common/uptak
|
|||||||
|
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
const PREF_SETTINGS_VERIFY_SIGNATURE = "services.settings.verify_signature";
|
|
||||||
const PREF_SETTINGS_SERVER = "services.settings.server";
|
const PREF_SETTINGS_SERVER = "services.settings.server";
|
||||||
const PREF_SIGNATURE_ROOT = "security.content.signature.root_hash";
|
const PREF_SIGNATURE_ROOT = "security.content.signature.root_hash";
|
||||||
|
|
||||||
@ -591,10 +590,8 @@ add_task(async function test_check_signatures() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
OneCRLBlocklistClient = BlocklistClients.initialize().OneCRLBlocklistClient;
|
// Signature verification is evabled by default.
|
||||||
|
({OneCRLBlocklistClient} = BlocklistClients.initialize());
|
||||||
// ensure signatures are enforced
|
|
||||||
Services.prefs.setBoolPref(PREF_SETTINGS_VERIFY_SIGNATURE, true);
|
|
||||||
|
|
||||||
// get a signature verifier to ensure nsNSSComponent is initialized
|
// get a signature verifier to ensure nsNSSComponent is initialized
|
||||||
Cc["@mozilla.org/security/contentsignatureverifier;1"]
|
Cc["@mozilla.org/security/contentsignatureverifier;1"]
|
||||||
|
@ -35,8 +35,6 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "gServerURL",
|
|||||||
"services.settings.server");
|
"services.settings.server");
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gChangesPath",
|
XPCOMUtils.defineLazyPreferenceGetter(this, "gChangesPath",
|
||||||
"services.settings.changes.path");
|
"services.settings.changes.path");
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gVerifySignature",
|
|
||||||
"services.settings.verify_signature", true);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cacheProxy returns an object Proxy that will memoize properties of the target.
|
* cacheProxy returns an object Proxy that will memoize properties of the target.
|
||||||
@ -189,6 +187,10 @@ class RemoteSettingsClient extends EventEmitter {
|
|||||||
this.localFields = localFields;
|
this.localFields = localFields;
|
||||||
this._lastCheckTimePref = lastCheckTimePref;
|
this._lastCheckTimePref = lastCheckTimePref;
|
||||||
|
|
||||||
|
// This attribute allows signature verification to be disabled, when running tests
|
||||||
|
// or when pulling data from a dev server.
|
||||||
|
this.verifySignature = true;
|
||||||
|
|
||||||
// The bucket preference value can be changed (eg. `main` to `main-preview`) in order
|
// The bucket preference value can be changed (eg. `main` to `main-preview`) in order
|
||||||
// to preview the changes to be approved in a real client.
|
// to preview the changes to be approved in a real client.
|
||||||
this.bucketNamePref = bucketNamePref;
|
this.bucketNamePref = bucketNamePref;
|
||||||
@ -328,7 +330,7 @@ class RemoteSettingsClient extends EventEmitter {
|
|||||||
|
|
||||||
// If signature verification is enabled, then add a synchronization hook
|
// If signature verification is enabled, then add a synchronization hook
|
||||||
// for incoming changes that validates the signature.
|
// for incoming changes that validates the signature.
|
||||||
if (this.signerName && gVerifySignature) {
|
if (this.verifySignature) {
|
||||||
kintoCollection.hooks["incoming-changes"] = [async (payload, collection) => {
|
kintoCollection.hooks["incoming-changes"] = [async (payload, collection) => {
|
||||||
await this._validateCollectionSignature(payload.changes,
|
await this._validateCollectionSignature(payload.changes,
|
||||||
payload.lastModified,
|
payload.lastModified,
|
||||||
|
@ -44,12 +44,12 @@ function run_test() {
|
|||||||
// Point the blocklist clients to use this local HTTP server.
|
// Point the blocklist clients to use this local HTTP server.
|
||||||
Services.prefs.setCharPref("services.settings.server",
|
Services.prefs.setCharPref("services.settings.server",
|
||||||
`http://localhost:${server.identity.primaryPort}/v1`);
|
`http://localhost:${server.identity.primaryPort}/v1`);
|
||||||
// Ensure that signature verification is disabled to prevent interference
|
|
||||||
// with basic certificate sync tests
|
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
|
||||||
client = RemoteSettings("password-fields");
|
client = RemoteSettings("password-fields");
|
||||||
|
client.verifySignature = false;
|
||||||
|
|
||||||
clientWithDump = RemoteSettings("language-dictionaries");
|
clientWithDump = RemoteSettings("language-dictionaries");
|
||||||
|
clientWithDump.verifySignature = false;
|
||||||
|
|
||||||
// Setup server fake responses.
|
// Setup server fake responses.
|
||||||
function handleResponse(request, response) {
|
function handleResponse(request, response) {
|
||||||
|
@ -769,6 +769,16 @@ def build_generic_worker_payload(config, task, task_def):
|
|||||||
'maxRunTime': worker['max-run-time'],
|
'maxRunTime': worker['max-run-time'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if worker['os'] == 'windows':
|
||||||
|
task_def['payload']['onExitStatus'] = {
|
||||||
|
'retry': [
|
||||||
|
# These codes (on windows) indicate a process interruption,
|
||||||
|
# rather than a task run failure. See bug 1544403.
|
||||||
|
1073807364, # process force-killed due to system shutdown
|
||||||
|
3221225786, # sigint (any interrupt)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
env = worker.get('env', {})
|
env = worker.get('env', {})
|
||||||
|
|
||||||
if task.get('needs-sccache'):
|
if task.get('needs-sccache'):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html]
|
[payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html]
|
||||||
disabled:
|
disabled:
|
||||||
if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
|
if (os == "android") and not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[Feature-Policy allow="payment" allows same-origin relocation.]
|
[Feature-Policy allow="payment" allows same-origin relocation.]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[payment-allowed-by-feature-policy-attribute.https.sub.html]
|
[payment-allowed-by-feature-policy-attribute.https.sub.html]
|
||||||
disabled:
|
disabled:
|
||||||
if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
|
if (os == "android") or not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[Feature policy "payment" can be enabled in same-origin iframe using allow="payment" attribute]
|
[Feature policy "payment" can be enabled in same-origin iframe using allow="payment" attribute]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[payment-allowed-by-feature-policy.https.sub.html]
|
[payment-allowed-by-feature-policy.https.sub.html]
|
||||||
disabled:
|
disabled:
|
||||||
if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
|
if (os == "android") or not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[Feature-Policy header {"payment" : ["*"\]} allows the top-level document.]
|
[Feature-Policy header {"payment" : ["*"\]} allows the top-level document.]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[payment-default-feature-policy.https.sub.html]
|
[payment-default-feature-policy.https.sub.html]
|
||||||
disabled:
|
disabled:
|
||||||
if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
|
if (os == "android") or not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[Default "payment" feature policy ["self"\] allows the top-level document.]
|
[Default "payment" feature policy ["self"\] allows the top-level document.]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[payment-disabled-by-feature-policy.https.sub.html]
|
[payment-disabled-by-feature-policy.https.sub.html]
|
||||||
disabled:
|
disabled:
|
||||||
if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
|
if (os == "android") or not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[Feature-Policy header {"payment" : [\]} disallows the top-level document.]
|
[Feature-Policy header {"payment" : [\]} disallows the top-level document.]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
[payment-supported-by-feature-policy.tentative.html]
|
[payment-supported-by-feature-policy.tentative.html]
|
||||||
|
disabled:
|
||||||
|
if (os == "android") or not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1549241
|
||||||
[document.featurePolicy.features should advertise payment.]
|
[document.featurePolicy.features should advertise payment.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Scoping: Dynamic reassignment of a slot.</title>
|
||||||
|
<link rel="author" title="Edgar Chen" href="mailto:echen@mozilla.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-scoping/#selectors-data-model">
|
||||||
|
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1548848">
|
||||||
|
<link rel="match" href="reference/green-box.html"/>
|
||||||
|
<div id="host">
|
||||||
|
<div id="green" style="background: green"></div>
|
||||||
|
<div>
|
||||||
|
<script>
|
||||||
|
let root = host.attachShadow({mode: 'open'});
|
||||||
|
root.innerHTML = `
|
||||||
|
<style>::slotted(div),div { width: 100px; height: 100px }</style>
|
||||||
|
<p>Test passes if you see a single 100px by 100px green box below.</p>
|
||||||
|
<slot id="slot"></slot>
|
||||||
|
<slot>
|
||||||
|
<div style="background: red"></div>
|
||||||
|
</slot>
|
||||||
|
`;
|
||||||
|
|
||||||
|
onload = function () {
|
||||||
|
root.offsetTop; // Update layout
|
||||||
|
root.getElementById('slot').remove();
|
||||||
|
};
|
||||||
|
</script>
|
@ -27,9 +27,6 @@ function run_test() {
|
|||||||
// Point the blocklist clients to use this local HTTP server.
|
// Point the blocklist clients to use this local HTTP server.
|
||||||
Services.prefs.setCharPref("services.settings.server",
|
Services.prefs.setCharPref("services.settings.server",
|
||||||
`http://localhost:${server.identity.primaryPort}/v1`);
|
`http://localhost:${server.identity.primaryPort}/v1`);
|
||||||
// Ensure that signature verification is disabled to prevent interference
|
|
||||||
// with basic certificate sync tests
|
|
||||||
Services.prefs.setBoolPref("services.settings.verify_signature", false);
|
|
||||||
|
|
||||||
// Unfortunately security settings are coupled with blocklists clients,
|
// Unfortunately security settings are coupled with blocklists clients,
|
||||||
// this will be fixed in Bug 1526018
|
// this will be fixed in Bug 1526018
|
||||||
@ -42,12 +39,15 @@ function run_test() {
|
|||||||
BlocklistGlobal.PluginBlocklistRS._ensureInitialized();
|
BlocklistGlobal.PluginBlocklistRS._ensureInitialized();
|
||||||
BlocklistGlobal.GfxBlocklistRS._ensureInitialized();
|
BlocklistGlobal.GfxBlocklistRS._ensureInitialized();
|
||||||
|
|
||||||
|
|
||||||
gBlocklistClients = [
|
gBlocklistClients = [
|
||||||
{client: BlocklistGlobal.ExtensionBlocklistRS._client, testData: ["i808", "i720", "i539"]},
|
{client: BlocklistGlobal.ExtensionBlocklistRS._client, testData: ["i808", "i720", "i539"]},
|
||||||
{client: BlocklistGlobal.PluginBlocklistRS._client, testData: ["p1044", "p32", "p28"]},
|
{client: BlocklistGlobal.PluginBlocklistRS._client, testData: ["p1044", "p32", "p28"]},
|
||||||
{client: BlocklistGlobal.GfxBlocklistRS._client, testData: ["g204", "g200", "g36"]},
|
{client: BlocklistGlobal.GfxBlocklistRS._client, testData: ["g204", "g200", "g36"]},
|
||||||
];
|
];
|
||||||
|
// Disable signature verification in these tests.
|
||||||
|
for (const c of gBlocklistClients) {
|
||||||
|
c.verifySignature = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Setup server fake responses.
|
// Setup server fake responses.
|
||||||
function handleResponse(request, response) {
|
function handleResponse(request, response) {
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
background-image: url("chrome://global/skin/icons/warning.svg");
|
background-image: url("chrome://global/skin/icons/warning.svg");
|
||||||
-moz-context-properties: fill;
|
|
||||||
fill: #fcd100;
|
fill: #fcd100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ body.wide-container {
|
|||||||
margin-inline-start: -2.3em;
|
margin-inline-start: -2.3em;
|
||||||
padding-inline-start: 2.3em;
|
padding-inline-start: 2.3em;
|
||||||
font-size: 2.2em;
|
font-size: 2.2em;
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title:-moz-locale-dir(rtl),
|
.title:-moz-locale-dir(rtl),
|
||||||
|
Loading…
Reference in New Issue
Block a user