Merge inbound to mozilla-central. a=merge

This commit is contained in:
Ciure Andrei 2018-02-08 00:05:57 +02:00
commit cda04ea11e
80 changed files with 1554 additions and 1440 deletions

View File

@ -1510,10 +1510,11 @@
<input />
</fieldset>
<figure id="figure">
<img src="../moz.png" alt="An awesome picture">
<figcaption id="figcaption">Caption for the awesome picture</figcaption>
</figure>
<!-- Depending on whether or not the image is cached, layout may be able to
optimize away spaces between the figure, img and figcaption tags. As
such, we should keep everything on one line to get consistent results.
-->
<figure id="figure"><img src="../moz.png" alt="An awesome picture"><figcaption id="figcaption">Caption for the awesome picture</figcaption></figure>
<footer id="footer">Some copyright info</footer>
<article>

View File

@ -234,6 +234,17 @@
title="no name from title"/>
</markup>
<!--
Disabled due to intermittent failures (bug 1436323) which became more
frequent due to the landing of bug 1383682. The latter bug made loading
of images from cache much more consistent, which appears to have impacted
the timing for this test case. If the image is switched to a unique
image (e.g. always decoding since there is no cache), the failure rate
increases, presumably because the test is dependent on a specific ordering
of events, and implicitly assumes the image is loaded immediately.
-->
<!--
<markup id="HTMLInputImageTest"
ref="html:input" ruleset="HTMLInputImage">
<html:span id="l1" textequiv="test2">test2</html:span>
@ -249,6 +260,7 @@
data="no name from data"
title="name from title"/>
</markup>
-->
<markup id="HTMLInputImageNoValidSrcTest"
ref="html:input" ruleset="HTMLInputImageNoValidSrc">

View File

@ -227,7 +227,9 @@
<div id="c6">This <abbr title="accessibility">a11y</abbr> test</div>
<div id="c7">This <acronym title="personal computer">PC</acronym> is broken</div>
<!-- only whitespace between images should be exposed -->
<div id="c8"> <img src="../moz.png"> <img src="../moz.png"> </div>
<!-- Whitespace between images should be exposed. Whitespace between the
div and img tags will be inconsistent depending on the image cache
state and what optimizations layout was able to apply. -->
<div id="c8"><img src="../moz.png"> <img src="../moz.png"></div>
</body>
</html>

View File

@ -170,8 +170,11 @@
<pre id="test">
</pre>
<div id="container1"> <img src="../moz.png"> <img id="img1" src="../moz.png"> <img src="../moz.png"> </div>
<div> <a id="container2"></a> <a><img src="../moz.png"></a> </div>
<!-- Whitespace between the div and img tags will be inconsistent depending
on the image cache state and what optimizations layout was able to
apply. -->
<div id="container1"><img src="../moz.png"> <img id="img1" src="../moz.png"> <img src="../moz.png"></div>
<div><a id="container2"></a> <a><img src="../moz.png"></a></div>
<div id="eventdump"></div>
</body>

View File

@ -1,9 +1,9 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Version 13.0
Comparison: https://github.com/devtools-html/debugger.html/compare/release-12...release-13
Commit: https://github.com/devtools-html/debugger.html/commit/3c10bd43b5
Version 14.0
Comparison: https://github.com/devtools-html/debugger.html/compare/release-13...release-14
Commit: https://github.com/devtools-html/debugger.html/commit/5805cf467
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.0

View File

@ -956,7 +956,7 @@ menuseparator {
.file,
.folder,
.domain {
background-color: var(--theme-splitter-color);
background-color: var(--theme-comment);
}
.worker,
@ -1022,7 +1022,7 @@ img.arrow {
width: 9px;
height: 9px;
padding-top: 9px;
background: var(--theme-splitter-color);
background: var(--disclosure-arrow);
mask-size: 100%;
display: inline-block;
margin-bottom: 1px;
@ -1067,7 +1067,8 @@ html .arrow.expanded svg {
fill: var(--theme-body-color);
}
.angular svg, .source-icon svg {
.angular svg,
.source-icon svg {
width: 15px;
height: 15px;
margin-right: 5px;
@ -1095,6 +1096,11 @@ html .arrow.expanded svg {
white-space: nowrap;
overflow: auto;
min-width: 100%;
display: grid;
grid-template-columns: 1fr;
align-content: start;
}
.managed-tree .tree button {
@ -1233,7 +1239,7 @@ html[dir="rtl"] .arrow svg,
.close-btn .close {
mask: url("chrome://devtools/skin/images/debugger/close.svg") no-repeat;
mask-size: 100%;
background-color: var(--theme-comment-alt);
background-color: var(--theme-comment);
width: 8px;
height: 8px;
transition: all 0.15s ease-in-out;
@ -1317,11 +1323,11 @@ html[dir="rtl"] .arrow svg,
.search-field .magnifying-glass path,
.search-field .magnifying-glass ellipse {
stroke: var(--theme-splitter-color);
stroke: var(--theme-comment);
}
.search-field input::placeholder {
color: var(--theme-body-color-inactive);
color: var(--theme-toolbar-color);
}
.search-field input:focus {
@ -1399,6 +1405,7 @@ html[dir="rtl"] .arrow svg,
padding: 4px 0 4px 30px;
line-height: 16px;
font-size: 10px;
width: 100%;
}
.project-text-search .matches-summary {
@ -1514,8 +1521,7 @@ html[dir="rtl"] .arrow svg,
}
.sources-list .managed-tree .tree .node {
padding: 0px 0px 0px 3px;
height: 21px;
padding: 0 10px 0 3px;
width: 100%;
}
@ -1531,10 +1537,6 @@ html[dir="rtl"] .arrow svg,
transform: rotate(0deg);
}
.theme-dark .sources-list .tree .node:not(.focused) img.arrow {
background: var(--theme-content-color3);
}
.theme-dark .source-list .tree .node.focused {
background-color: var(--theme-tab-toolbar-background);
}
@ -1669,7 +1671,7 @@ html[dir="rtl"] .arrow svg,
.outline-list {
list-style-type: none;
width: 100%;
flex: 1 0 100%;
padding: 10px 0px;
margin: 0;
}
@ -1688,19 +1690,18 @@ html[dir="rtl"] .arrow svg,
}
.outline-list__element {
padding-bottom: 0.5rem;
padding-right: 0.5rem;
padding-top: 0.2rem;
padding: 3px 10px 3px 10px;
cursor: default;
white-space: nowrap;
}
.outline-list__element:hover {
background: var(--theme-toolbar-background-hover);
.outline-list__element-icon {
padding-right: 0.4rem;
padding-left: 1rem;
}
.outline-list__element .function {
padding-left: 10px;
.outline-list__element:hover {
background: var(--theme-toolbar-background-hover);
}
/* 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
@ -1965,7 +1966,7 @@ html .toggle-button.end.vertical svg {
}
.search-bottom-bar .search-modifiers button svg {
fill: var(--theme-comment-alt);
fill: var(--theme-comment);
height: 16px;
width: 16px;
}
@ -1997,7 +1998,7 @@ html .toggle-button.end.vertical svg {
margin: 0 0 0 6px;
border: none;
background: transparent;
color: var(--theme-comment-alt);
color: var(--theme-comment);
}
.search-bottom-bar .search-type-toggles .search-type-btn:active {
@ -2989,8 +2990,7 @@ html .breakpoints-list .breakpoint.paused {
.input-expression::placeholder {
text-align: center;
font-style: italic;
color: var(--theme-comment-alt);
opacity: 1;
color: var(--theme-comment);
}
.input-expression:focus {
@ -3309,10 +3309,12 @@ html .breakpoints-list .breakpoint.paused {
:root {
--accordion-header-background: var(--theme-toolbar-background);
--disclosure-arrow: #b2b2b2;
}
:root.theme-dark {
--accordion-header-background: #222225;
--disclosure-arrow: #7f7f81;
}
.accordion {
@ -3383,6 +3385,10 @@ html .breakpoints-list .breakpoint.paused {
.accordion .header-buttons button::-moz-focus-inner {
border: none;
}
.accordion .arrow svg {
fill: var(--disclosure-arrow);
}
/* 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/>. */
@ -3408,7 +3414,11 @@ img.pause,
img.stepOver,
img.stepIn,
img.stepOut,
img.resume {
img.resume,
img.rewind,
img.reverseStepOver,
img.reverseStepIn,
img.reverseStepOut {
background-color: var(--theme-body-color);
}
@ -3432,6 +3442,26 @@ img.resume {
mask: url("chrome://devtools/skin/images/debugger/resume.svg") no-repeat;
}
.command-bar img.rewind {
mask: url("chrome://devtools/skin/images/debugger/resume.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepOver {
mask: url("chrome://devtools/skin/images/debugger/stepOver.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepIn {
mask: url("chrome://devtools/skin/images/debugger/stepIn.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepOut {
mask: url("chrome://devtools/skin/images/debugger/stepOut.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar > .pause-exceptions.uncaught.enabled > img.pause-exceptions {
background-color: var(--theme-highlight-purple);
}
@ -3697,10 +3727,6 @@ img.ignore-exceptions {
cursor: default;
}
.theme-dark .secondary-panes .accordion .arrow svg {
fill: var(--theme-content-color3);
}
.secondary-panes .breakpoints-buttons {
display: flex;
}
@ -3734,7 +3760,6 @@ img.ignore-exceptions {
padding: 50px 0 0 0;
text-align: center;
font-size: 1.25em;
color: var(--theme-comment-alt);
background-color: var(--theme-toolbar-background);
font-weight: lighter;
z-index: 10;
@ -3777,6 +3802,7 @@ img.ignore-exceptions {
text-align: left;
float: left;
margin-left: 25px;
color: var(--theme-comment);
}
html .welcomebox .toggle-button-end.collapsed {
@ -4033,15 +4059,16 @@ html .welcomebox .toggle-button-end.collapsed {
.theme-dark .result-list {
background-color: var(--theme-body-background);
}
.result-item .title .fuzzy-match {
.result-item .title .highlight {
font-weight: bold;
}
.result-item .subtitle .fuzzy-match {
.result-item .subtitle .highlight {
color: var(--grey-90);
font-weight: 500;
}
.theme-dark .result-item .title .fuzzy-match,
.theme-dark .result-item .subtitle .fuzzy-match {
.theme-dark .result-item .title .highlight,
.theme-dark .result-item .subtitle .highlight {
color: white;
}

File diff suppressed because one or more lines are too long

View File

@ -33263,7 +33263,24 @@ let symbolDeclarations = new Map();
function getFunctionParameterNames(path) {
if (path.node.params != null) {
return path.node.params.map(param => param.name);
return path.node.params.map(param => {
if (param.type !== "AssignmentPattern") {
return param.name;
}
// Parameter with default value
if (param.left.type === "Identifier" && param.right.type === "Identifier") {
return `${param.left.name} = ${param.right.name}`;
} else if (param.left.type === "Identifier" && param.right.type === "StringLiteral") {
return `${param.left.name} = ${param.right.value}`;
} else if (param.left.type === "Identifier" && param.right.type === "ObjectExpression") {
return `${param.left.name} = {}`;
} else if (param.left.type === "Identifier" && param.right.type === "ArrayExpression") {
return `${param.left.name} = []`;
} else if (param.left.type === "Identifier" && param.right.type === "NullLiteral") {
return `${param.left.name} = null`;
}
});
}
return [];
}
@ -33861,7 +33878,7 @@ self.onmessage = workerHandler({
getNextStep: _steps.getNextStep,
getEmptyLines: _getEmptyLines2.default,
hasSyntaxError: _validate.hasSyntaxError,
isReactComponent: _frameworks.isReactComponent
getFramework: _frameworks.getFramework
});
/***/ }),
@ -34598,7 +34615,7 @@ module.exports = findLastIndex;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isReactComponent = isReactComponent;
exports.getFramework = getFramework;
var _getSymbols = __webpack_require__(1457);
@ -34606,13 +34623,19 @@ var _getSymbols2 = _interopRequireDefault(_getSymbols);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function isReactComponent(sourceId) {
const { imports, classes, callExpressions } = (0, _getSymbols2.default)(sourceId);
return (importsReact(imports) || requiresReact(callExpressions)) && extendsComponent(classes);
function getFramework(sourceId) {
if (isReactComponent(sourceId)) {
return "React";
}
} /* 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/>. */
function isReactComponent(sourceId) {
const { imports, classes, callExpressions } = (0, _getSymbols2.default)(sourceId);
return (importsReact(imports) || requiresReact(callExpressions)) && extendsComponent(classes);
}
function importsReact(imports) {
return imports.some(importObj => importObj.source === "react" && importObj.specifiers.some(specifier => specifier === "React"));
}
@ -35266,6 +35289,20 @@ var _getFunctionName2 = _interopRequireDefault(_getFunctionName);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* "implicit"
* Variables added automaticly like "this" and "arguments"
*
* "var"
* Variables declared with "var" or non-block function declarations
*
* "let"
* Variables declared with "let".
*
* "const"
* Variables declared with "const", imported bindings, or added as const
* bindings like inner function expressions and inner class names.
*/
/* 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/. */
@ -35289,7 +35326,7 @@ function isNode(node, type) {
return node ? node.type === type : false;
}
function getFunctionScope(scope) {
function getVarScope(scope) {
let s = scope;
while (s.type !== "function" && s.type !== "module") {
if (!s.parent) {
@ -35361,29 +35398,22 @@ function toParsedScopes(children, sourceId) {
return undefined;
}
return children.map(scope => {
// Removing unneed information from TempScope such as parent reference and
// name types. We also need to convert BabelLocation to the Location type.
// Removing unneed information from TempScope such as parent reference.
// We also need to convert BabelLocation to the Location type.
const bindings = Object.keys(scope.names).reduce((_bindings, n) => {
const nameRefs = scope.names[n];
switch (nameRefs.type) {
case "var":
case "let":
case "const":
case "param":
case "fn":
case "import":
_bindings[n] = {
declarations: nameRefs.declarations.map(({ start, end }) => ({
start: fromBabelLocation(start, sourceId),
end: fromBabelLocation(end, sourceId)
})),
refs: nameRefs.refs.map(({ start, end }) => ({
start: fromBabelLocation(start, sourceId),
end: fromBabelLocation(end, sourceId)
}))
};
break;
}
_bindings[n] = {
type: nameRefs.type,
declarations: nameRefs.declarations.map(({ start, end }) => ({
start: fromBabelLocation(start, sourceId),
end: fromBabelLocation(end, sourceId)
})),
refs: nameRefs.refs.map(({ start, end }) => ({
start: fromBabelLocation(start, sourceId),
end: fromBabelLocation(end, sourceId)
}))
};
return _bindings;
}, Object.create(null));
return {
@ -35391,7 +35421,7 @@ function toParsedScopes(children, sourceId) {
end: fromBabelLocation(scope.loc.end, sourceId),
type: scope.type === "module" ? "block" : scope.type,
displayName: scope.displayName,
bindings,
bindings: bindings,
children: toParsedScopes(scope.children, sourceId)
};
});
@ -35449,6 +35479,11 @@ function createParseJSScopeVisitor(sourceId) {
parent = createTempScope("block", "Lexical Global", parent, location);
parent = createTempScope("module", "Module", parent, location);
parent.names.this = {
type: "implicit",
declarations: [],
refs: []
};
return;
}
if (path.isFunction()) {
@ -35470,18 +35505,53 @@ function createParseJSScopeVisitor(sourceId) {
end: location.end
});
if (path.isFunctionDeclaration() && isNode(tree.id, "Identifier")) {
const functionName = {
type: "fn",
// This ignores Annex B function declaration hoisting, which
// is probably a fine assumption.
const fnScope = getVarScope(parent);
scope.names[tree.id.name] = {
type: fnScope === scope ? "var" : "let",
declarations: [tree.id.loc],
refs: []
};
getFunctionScope(parent).names[tree.id.name] = functionName;
scope.names[tree.id.name] = functionName;
}
tree.params.forEach(param => parseDeclarator(param, scope, "param"));
tree.params.forEach(param => parseDeclarator(param, scope, "var"));
if (!path.isArrowFunctionExpression()) {
scope.names.this = {
type: "implicit",
declarations: [],
refs: []
};
scope.names.arguments = {
type: "implicit",
declarations: [],
refs: []
};
}
parent = scope;
return;
}
if (path.isClass()) {
if (path.isClassDeclaration() && path.get("id").isIdentifier()) {
parent.names[tree.id.name] = {
type: "let",
declarations: [tree.id.loc],
refs: []
};
}
if (path.get("id").isIdentifier()) {
savedParents.set(path, parent);
parent = createTempScope("block", "Class", parent, location);
parent.names[tree.id.name] = {
type: "const",
declarations: [tree.id.loc],
refs: []
};
}
}
if (path.isForXStatement() || path.isForStatement()) {
const init = tree.init || tree.left;
if (isNode(init, "VariableDeclaration") && isLetOrConst(init)) {
@ -35499,7 +35569,7 @@ function createParseJSScopeVisitor(sourceId) {
if (path.isCatchClause()) {
savedParents.set(path, parent);
parent = createTempScope("block", "Catch", parent, location);
parseDeclarator(tree.param, parent, "param");
parseDeclarator(tree.param, parent, "var");
return;
}
if (path.isBlockStatement()) {
@ -35510,9 +35580,11 @@ function createParseJSScopeVisitor(sourceId) {
}
return;
}
if (path.isVariableDeclaration()) {
if (path.isVariableDeclaration() && (path.node.kind === "var" ||
// Lexical declarations in for statements are handled above.
!path.parentPath.isForStatement({ init: tree }) || !path.parentPath.isXStatement({ left: tree }))) {
// Finds right lexical environment
const hoistAt = !isLetOrConst(tree) ? getFunctionScope(parent) : parent;
const hoistAt = !isLetOrConst(tree) ? getVarScope(parent) : parent;
tree.declarations.forEach(declarator => {
parseDeclarator(declarator.id, hoistAt, tree.kind);
});
@ -35523,7 +35595,7 @@ function createParseJSScopeVisitor(sourceId) {
path.get("specifiers").forEach(spec => {
parent.names[spec.node.local.name] = {
type: "import",
type: "const",
declarations: [spec.node.local.loc],
refs: []
};
@ -35542,10 +35614,26 @@ function createParseJSScopeVisitor(sourceId) {
}
return;
}
if (path.isThisExpression()) {
const scope = findIdentifierInScopes(parent, "this");
if (scope) {
scope.names.this.refs.push(tree.loc);
}
}
if (path.parentPath.isClassProperty({ value: tree })) {
savedParents.set(path, parent);
parent = createTempScope("block", "Class Field", parent, location);
parent.names.this = {
type: "implicit",
declarations: [],
refs: []
};
parent.names.arguments = {
type: "implicit",
declarations: [],
refs: []
};
return;
}

View File

@ -2,7 +2,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
async function waitForBreakpointCount(dbg, count) {
return waitForState(dbg, state => dbg.selectors.getBreakpoints(state).size === count)
return waitForState(
dbg,
state => dbg.selectors.getBreakpoints(state).size === count
);
}
add_task(async function() {

View File

@ -80,12 +80,12 @@ add_task(async function() {
await stepIn(dbg);
assertPausedLocation(dbg);
await dbg.actions.jumpToMappedSelectedLocation()
await dbg.actions.jumpToMappedSelectedLocation();
await stepOver(dbg);
assertPausedLocation(dbg);
assertDebugLine(dbg, 71);
await dbg.actions.jumpToMappedSelectedLocation()
await dbg.actions.jumpToMappedSelectedLocation();
await stepOut(dbg);
await stepOut(dbg);
assertPausedLocation(dbg);

View File

@ -29,13 +29,13 @@ add_task(async function() {
await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
// Expand nodes and make sure more sources appear.
assertSourceCount(dbg, 2);
await assertSourceCount(dbg, 2);
await clickElement(dbg, "sourceArrow", 2);
assertSourceCount(dbg, 7);
await assertSourceCount(dbg, 7);
await clickElement(dbg, "sourceArrow", 3);
assertSourceCount(dbg, 8);
await assertSourceCount(dbg, 8);
// Select a source.
ok(

View File

@ -285,9 +285,15 @@ function assertNotPaused(dbg) {
* @static
*/
function assertPausedLocation(dbg) {
const { selectors: { getSelectedSource, getVisibleSelectedFrame }, getState } = dbg;
const {
selectors: { getSelectedSource, getVisibleSelectedFrame },
getState
} = dbg;
ok(isSelectedFrameSelected(dbg, getState()), "top frame's source is selected");
ok(
isSelectedFrameSelected(dbg, getState()),
"top frame's source is selected"
);
// Check the pause location
const frame = getVisibleSelectedFrame(getState());
@ -447,7 +453,7 @@ async function waitForMappedScopes(dbg) {
await waitForState(
dbg,
state => {
const scopes = dbg.selectors.getScopes(state);
const scopes = dbg.selectors.getSelectedScope(state);
return scopes && scopes.sourceBindings;
},
"mapped scopes"
@ -949,14 +955,14 @@ const selectors = {
sourceMapLink: ".source-footer .mapped-source",
sourcesFooter: ".sources-panel .source-footer",
editorFooter: ".editor-pane .source-footer",
sourceNode: i => `.sources-list .tree-node:nth-child(${i})`,
sourceNode: i => `.sources-list .tree-node:nth-child(${i}) .node`,
sourceNodes: ".sources-list .tree-node",
sourceArrow: i => `.sources-list .tree-node:nth-child(${i}) .arrow`,
resultItems: ".result-list .result-item",
fileMatch: ".managed-tree .result",
popup: ".popover",
tooltip: ".tooltip",
outlineItem: i => `.outline-list__element:nth-child(${i})`,
outlineItem: i => `.outline-list__element:nth-child(${i}) .function-signature`,
outlineItems: ".outline-list__element"
};
@ -1082,3 +1088,17 @@ function getCM(dbg) {
const el = dbg.win.document.querySelector(".CodeMirror");
return el.CodeMirror;
}
// NOTE: still experimental, the screenshots might not be exactly correct
async function takeScreenshot(dbg) {
let canvas = dbg.win.document.createElementNS(
"http://www.w3.org/1999/xhtml",
"html:canvas"
);
let context = canvas.getContext("2d");
canvas.width = dbg.win.innerWidth;
canvas.height = dbg.win.innerHeight;
context.drawWindow(dbg.win, 0, 0, canvas.width, canvas.height, "white");
await waitForTime(1000);
dump(`[SCREENSHOT] ${canvas.toDataURL()}\n`);
}

View File

@ -164,26 +164,38 @@ blackboxCheckboxTooltip2=Toggle blackboxing
# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for
# searching all the source files the debugger has seen.
# Do not localize "CmdOrCtrl+P", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
sources.search.key2=CmdOrCtrl+P
# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the
# search for searching all the source files the debugger has seen.
# Do not localize "CmdOrCtrl+O", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
sources.search.alt.key=CmdOrCtrl+O
# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the
# full project text search for searching all the files the debugger has seen.
# Do not localize "CmdOrCtrl+Shift+F", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
projectTextSearch.key=CmdOrCtrl+Shift+F
# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the
# modal for searching functions in a file.
# Do not localize "CmdOrCtrl+Shift+O", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
functionSearch.key=CmdOrCtrl+Shift+O
# LOCALIZATION NOTE (toggleBreakpoint.key): A key shortcut to toggle
# breakpoints.
# Do not localize "CmdOrCtrl+B", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
toggleBreakpoint.key=CmdOrCtrl+B
# LOCALIZATION NOTE (toggleCondPanel.key): A key shortcut to toggle
# the conditional breakpoint panel.
# Do not localize "CmdOrCtrl+Shift+B", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
toggleCondPanel.key=CmdOrCtrl+Shift+B
# LOCALIZATION NOTE (stepOut.key): A key shortcut to
@ -216,6 +228,8 @@ sources.noSourcesAvailable=This page has no sources
# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search
# for searching within a the currently opened files in the editor
# Do not localize "CmdOrCtrl+F", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
sourceSearch.search.key2=CmdOrCtrl+F
# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in
@ -224,10 +238,14 @@ sourceSearch.search.placeholder=Search in file…
# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight
# the next occurrence of the last search triggered from a source search
# Do not localize "CmdOrCtrl+G", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
sourceSearch.search.again.key2=CmdOrCtrl+G
# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight
# the previous occurrence of the last search triggered from a source search
# Do not localize "CmdOrCtrl+Shift+G", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
sourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G
# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of
@ -550,16 +568,16 @@ watchExpressions.refreshButton=Refresh
# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's
# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on
# a mac we use the unicode character.
welcome.search=%S to search for sources
welcome.search=%S To search for sources
# LOCALIZATION NOTE (welcome.findInFiles): The center pane welcome panel's
# search prompt. e.g. cmd+f to search for files. On windows, it's ctrl+shift+f, on
# a mac we use the unicode character.
welcome.findInFiles=%S to find in files
welcome.findInFiles=%S To find in files
# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome
# panel. %S is replaced by the keyboard shortcut to search for functions.
welcome.searchFunction=%S to search for functions in file
welcome.searchFunction=%S To search for functions in file
# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search
# prompt for searching for files.
@ -687,8 +705,10 @@ functionSearchSeparatorLabel=←
# LOCALIZATION NOTE(gotoLineModal.placeholder): The placeholder
# text displayed when the user searches for specific lines in a file
# Do not localize "CmdOrCtrl+;", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
gotoLineModal.placeholder=Go to line…
gotoLineModal.key=CmdOrCtrl+Shift+;
gotoLineModal.key=CmdOrCtrl+;
gotoLineModal.title=Go to a line number in a file
# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder
@ -703,6 +723,8 @@ symbolSearch.search.variablesPlaceholder.title=Search for a variable in a file
# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for
# searching for a function or variable
# Do not localize "CmdOrCtrl+Shift+O", or change the format of the string. These are
# key identifiers, not messages displayed to the user.
symbolSearch.search.key2=CmdOrCtrl+Shift+O
# LOCALIZATION NOTE(symbolSearch.searchModifier.modifiersLabel): A label
@ -825,6 +847,10 @@ shortcuts.stepOut=Step Out
# keyboard shortcut action for source file search
shortcuts.fileSearch=Source File Search
# LOCALIZATION NOTE (shortcuts.gotoLine): text describing
# keyboard shortcut for jumping to a specific line
shortcuts.gotoLine=Go to line
# LOCALIZATION NOTE (shortcuts.searchAgain): text describing
# keyboard shortcut action for searching again
shortcuts.searchAgain=Search Again

View File

@ -45,7 +45,7 @@ pref("devtools.debugger.project-directory-root", "");
pref("devtools.debugger.features.wasm", true);
pref("devtools.debugger.features.shortcuts", true);
pref("devtools.debugger.features.root", false);
pref("devtools.debugger.features.root", true);
pref("devtools.debugger.features.column-breakpoints", false);
pref("devtools.debugger.features.chrome-scopes", false);
pref("devtools.debugger.features.map-scopes", false);

View File

@ -13823,6 +13823,11 @@ class CGDictionary(CGThing):
# they're not unrestricted float/double.
return not type.isFloat() or not type.isUnrestricted()
if type.isRecord():
# Records are okay, as long as the value type is.
# Per spec, only strings are allowed as keys.
return CGDictionary.typeSafeToJSONify(type.inner)
return False
@staticmethod

View File

@ -1,20 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
function boom()
{
document.getElementById("path").pathSegList.pathSegTypeAsLetter;
}
</script>
</head>
<body onload="boom()">
<svg xmlns="http://www.w3.org/2000/svg" height="400px" width="400px">
<path id="path" style="stroke: blue" d="M 200.50000,387.89713 L 201.19970,12.500000" />
</svg>
</body>
</html>

View File

@ -1,20 +0,0 @@
<svg width='100%' height='100%'
xmlns='http://www.w3.org/2000/svg'
xmlns:html="http://www.w3.org/1999/xhtml"
onload='boom()'>
<html:script>
function boom()
{
try {
document.getElementById("path").pathSegList.getItem(-10000000);
} catch(e) {
}
}
</html:script>
<path id='path' d='M300,25 C320,250 375,150 400,150 S400,340 330,350'/>
</svg>

Before

Width:  |  Height:  |  Size: 386 B

View File

@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" onload="setTimeout(boom, 30);" class="reftest-wait">
<script>
function boom()
{
try {
document.getElementById("path_1").pathSegList.insertItemBefore({}, 0);
} catch(e) {
}
document.documentElement.removeAttribute("class");
}
</script>
<path id='path_1' d='M300,25 C500,100 575,300 330,350'/>
</svg>

Before

Width:  |  Height:  |  Size: 371 B

View File

@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" onload="setTimeout(boom, 30);" class="reftest-wait">
<script>
function boom()
{
try {
document.getElementById("path_1").pathSegList.insertItemBefore({}, 0);
} catch(e) {
}
document.documentElement.removeAttribute("class");
}
</script>
<path id='path_1' d='M300,25 C500,100 575,300 330,350'/>
</svg>

Before

Width:  |  Height:  |  Size: 371 B

View File

@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg">
<path/>
<script xmlns="http://www.w3.org/1999/xhtml"><![CDATA[
var x=document.getElementsByTagName('path')[0];
var y = x.pathSegList;
var z = x.createSVGPathSegMovetoRel(0,0);
y.appendItem(z,0);
y.replaceItem(z, 0);
]]></script>
</svg>

Before

Width:  |  Height:  |  Size: 277 B

View File

@ -4,14 +4,10 @@ load 336994-1.html
load 344888-1.svg
load 345445-1.svg
load 360836-1.svg
load 367357-1.xhtml
load 369051-1.svg
load 369249-1.svg
load 369291-1.svg
load 369291-2.svg
load 369568-1.svg
load 372046-1.svg
load 372046-2.svg
load 374882-1.svg
load 380101-1.svg
load 381777-1.svg
@ -41,7 +37,6 @@ load 414188-1.svg
load 427325-1.svg
load 428228-1.svg
load 428841-1.svg
load 435209-1.svg
load 436418-mpathRoot-1.svg
load 448244-1.svg
load 466576-1.xhtml

View File

@ -55,8 +55,7 @@ skip-if = true # disabled-for-intermittent-failures--bug-701060
[test_object-delayed-intrinsic-size.html]
[test_onerror.xhtml]
[test_pathAnimInterpolation.xhtml]
[test_pathLength.html]
[test_pathSeg.xhtml]
skip-if = true # We need to polyfill the SVG DOM for path data
[test_pointAtLength.xhtml]
[test_pointer-events-1a.xhtml]
[test_pointer-events-1b.xhtml]
@ -77,7 +76,6 @@ skip-if = android_version == '18' # bug 1147994
[test_SVGMatrix.xhtml]
[test_SVG_namespace_ids.html]
[test_SVGNumberList.xhtml]
[test_SVGPathSegList.xhtml]
[test_SVGPointList.xhtml]
[test_SVGStringList.xhtml]
[test_SVGStyleElement.xhtml]

View File

@ -1,128 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=611138
-->
<head>
<title>Generic tests for SVG animated length lists</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="MutationEventChecker.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=611138">Mozilla Bug 611138</a>
<p id="display"></p>
<div id="content" style="display:none;">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<path id="path"/>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
/*
This file runs a series of SVGPathSegList specific tests. Generic SVGXxxList
tests can be found in test_SVGxxxList.xhtml. Anything that can be generalized
to other list types belongs there.
*/
function run_tests()
{
document.getElementById('svg').pauseAnimations();
var d;
var seg;
var path = document.getElementById("path");
var list = path.pathSegList;
// See https://bugzilla.mozilla.org/show_bug.cgi?id=611138
// Here we are doing a replace with a segment (arc) that has more arguments
// than the total number of arguments in the entire path + 2 (the +2
// refering to the encoding of the segment types for the two segments).
path.setAttribute('d', 'M0,0 L100,100');
var arc = path.createSVGPathSegArcAbs(400, 0, 200, 200, 0, 1, 1);
list.replaceItem(arc, 1);
is(list.numberOfItems, 2, 'The length of the list should be the same after a valid replaceItem() call');
is(list.getItem(1), arc, 'The inserted object should now be the object at the index being replaced');
// Test whether and when we normalize the 'd' attribute:
d = " \n M 10 , 10 \n L 20 10 \n ";
path.setAttribute('d', d);
is(path.getAttribute('d'), d, "Values passed to setAttribute for the 'd' attribute should not be normalised");
list.getItem(1).y = 20;
isnot(path.getAttribute('d'), d, "The 'd' attribute should change when its underlying DOM list changes");
// Test that path manipulations still work even when the path is invalid due
// to it not starting with a moveto segment:
path.setAttribute('d', 'M0,0 L1,1');
is(list.numberOfItems, 2, 'setAttribute should result in two items')
seg = list.getItem(1);
list.removeItem(0);
ok(list.numberOfItems == 1 && list.getItem(0) == seg,
'If removeItem removes the initial moveto leaving an invalid path, the other items should still be left in the list')
seg = path.createSVGPathSegLinetoAbs(1, 2);
list.appendItem(seg);
ok(list.numberOfItems == 2 && list.getItem(1) == seg,
'appendItem should be able to append to an invalid path');
seg = path.createSVGPathSegLinetoAbs(1, 2);
list.replaceItem(seg, 1);
ok(list.numberOfItems == 2 && list.getItem(1) == seg,
'replaceItem should be able to replace items in an invalid path');
seg = path.createSVGPathSegLinetoAbs(1, 2);
list.insertItemBefore(seg, 1);
ok(list.numberOfItems == 3 && list.getItem(1) == seg,
'insertItemBefore should be able insert items into an invalid path');
seg = path.createSVGPathSegLinetoAbs(1, 2);
list.initialize(seg);
ok(list.numberOfItems == 1 && list.getItem(0) == seg,
'initialize should be able initialize an invalid path with a non-moveto item');
// Test mutation events
eventChecker = new MutationEventChecker;
d = 'M0,0 L12,34'
path.setAttribute('d', d);
eventChecker.watchAttr(path, "d");
// -- Actual changes
eventChecker.expect("modify modify modify");
list[0].x = 10;
list[0].y = 5;
path.setAttribute("d", "M20,5 L12,34");
// -- Redundant changes
eventChecker.expect("");
list[0].x = 20;
list[1].y = 34;
path.setAttribute("d", "M20,5 L12,34");
// -- Attribute removal
eventChecker.expect("remove");
path.removeAttribute("d");
// -- Non-existent attribute removal
eventChecker.expect("");
path.removeAttribute("d");
path.removeAttributeNS(null, "d");
eventChecker.finish();
SimpleTest.finish();
}
window.addEventListener("load", run_tests);
]]>
</script>
</pre>
</body>
</html>

View File

@ -222,61 +222,6 @@ var tests = [
is(itemA.y, itemB.y, message);
}
},
{
// SVGPathSegList test:
target_element_id: 'path',
attr_name: 'd',
prop_name: null, // SVGAnimatedPathData is an inherited interface!
bv_name: 'pathSegList',
av_name: 'animatedPathSegList',
el_type: 'SVGPathElement',
prop_type: null,
list_type: 'SVGPathSegList',
item_type: 'SVGPathSeg',
attr_val_3a: 'M 10,10 L 50,50 L 90,10',
attr_val_3b: 'M 10,50 L 50,10 L 90,50',
attr_val_4 : 'M 10,10 L 50,50 L 90,10 M 200,100',
attr_val_5a: 'M 10,10 L 50,50 L 90,10 L 130,50 L 170,10',
attr_val_5b: 'M 50,10 L 50,10 L 90,50 L 130,10 L 170,50',
attr_val_5b_firstItem_x3_constructor: function(constructor) {
var expected = constructor();
is(expected.pathSegTypeAsLetter, "M",
"test error -- expected constructor to generate a segment of type M");
expected.x = 150;
expected.y = 30;
return expected;
},
item_constructor: function() {
// XXX return different values each time
return document.getElementById('path').createSVGPathSegMovetoAbs(1, 1);
},
item_is: function(itemA, itemB, message) {
ok(typeof(itemA.pathSegTypeAsLetter) != 'undefined' &&
typeof(itemB.pathSegTypeAsLetter) != 'undefined',
'expecting pathSegTypeAsLetter property');
// First: are we dealing with the same type of segment?
is(itemA.pathSegTypeAsLetter, itemB.pathSegTypeAsLetter, message);
if (itemA.pathSegTypeAsLetter != itemB.pathSegTypeAsLetter)
return; // The rest of this function is nonsense if types don't match.
// Make sure property-counts match (so we can iterate across itemA's
// properties and not worry about itemB having extra properties that
// we might be skipping over).
is(keys(itemA).length, keys(itemB).length,
'expecting same property-count when comparing path segs of same type.');
// Compare the properties, skipping the constant properties inherited
// from 'SVGPathSeg', and skipping the pathSegTypeAsLetter field since we
// already checked that above.
for (var prop in itemA) {
if (!SVGPathSeg.hasOwnProperty(prop) &&
prop != 'pathSegTypeAsLetter') {
is(itemA[prop], itemB[prop], message);
}
}
}
},
{
// SVGStringList test:
target_element_id: 'g',
@ -1170,14 +1115,12 @@ function run_animation_timeline_tests()
'in the '+t.list_type+' for '+t.bv_path+' to 5.');
// TODO
if (t.list_type != 'SVGPathSegList') {
ok(t.animVal.getItem(3) === t.old_animVal_items[3],
'When affected by SMIL animation, list items in the '+t.list_type+
' for '+t.bv_path+' that are at indexes that existed prior to the '+
'start of the animation should be the exact same objects as the '+
'objects that were at those indexes prior to the start of the '+
'animation.');
}
t.old_animVal_items = get_array_of_list_items(t.animVal);

View File

@ -48,13 +48,6 @@ var tests = [
subtests: [ { values: null, length: 3 },
{ values: "10", length: 1 },
{ values: "1 2 3 4 5", length: 5 } ] },
{ element: path,
attribute: "d",
listProperty: "pathSegList",
type: "SVGPathSegList",
subtests: [ { values: null, length: 2 },
{ values: "M50,50", length: 1 },
{ values: "M0,0 h10 v20 h30 v40", length: 5 } ] },
{ element: poly,
attribute: "points",
listProperty: "animatedPoints",

View File

@ -1,58 +0,0 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1024926
-->
<head>
<meta charset="utf-8">
<title>Test path length changes when manipulated</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1024926">Mozilla Bug 1024926</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg width="100%" height="1" id="svg">
<path id="path_lines" d="M50,100l0,0l0,-50l100,0l86.3325,122.665z"></path>
<path id="path_straight_curve" d="M0,0 C100,0 150,0 200,0" />
<path id="path_straight_arc" d="M0,0 A100,0 0 0 0 200, 0" />
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
// Test a closed path with a series of lines.
var path = document.getElementById("path_lines");
is(path.getTotalLength(), 500, "Unexpected path length");
// Test a path that's been shortened via the DOM.
for (var i = 0; i < 2; i++) {
path.pathSegList.removeItem(path.pathSegList.numberOfItems - 1);
}
is(path.getTotalLength(), 150, "Unexpected path length");
// Test a path that's been shortened to be empty, via the DOM.
while (path.pathSegList.numberOfItems > 0) {
path.pathSegList.removeItem(0);
}
is(path.getTotalLength(), 0, "Unexpected path length");
// Test a path with a curve command ("C") that is really a straight line.
path = document.getElementById("path_straight_curve");
is(path.getTotalLength(), 200, "Unexpected path length, for straight line " +
"generated by 'C' command");
// Test a path with an arc command ("A") that is really a straight line.
path = document.getElementById("path_straight_arc");
is(path.getTotalLength(), 200, "Unexpected path length, for straight line " +
"generated by 'A' command");
SimpleTest.finish();
</script>
</pre>
</body>
</html>

View File

@ -1,142 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=459953
-->
<head>
<title>Test for Bug 459953</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=459953">Mozilla Bug 459953</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
function runTest()
{
var svgns="http://www.w3.org/2000/svg";
var path1=document.createElementNS(svgns, "path");
var sseg;
var a=10,s=20,d=30,z=9; //Arbitrary numbers for arguments
var whatever=true; //This is often so, but here it does not matter
sseg=path1.createSVGPathSegMovetoAbs(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegMovetoRel(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoAbs(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoRel(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoVerticalAbs(a);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoVerticalRel(a);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoHorizontalAbs(a);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegLinetoHorizontalRel(a);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoCubicAbs(a, s, d, z, a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoCubicRel(a, s, d, z, a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoCubicSmoothAbs(a, s, d, z);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoCubicSmoothRel(a, s, d, z);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoQuadraticAbs(a, s, d, z);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoQuadraticRel(a, s, d, z);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoQuadraticSmoothAbs(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegCurvetoQuadraticSmoothRel(a, s);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegArcAbs(a, s, d, z, a, whatever, whatever);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegArcRel(a, s, d, z, a, whatever, whatever);
path1.pathSegList.appendItem(sseg);
sseg=path1.createSVGPathSegClosePath();
path1.pathSegList.appendItem(sseg);
for(var i=0;i<path1.pathSegList.numberOfItems;i++){
var seg=path1.pathSegList.getItem(i);
switch(seg.pathSegType){
case seg.PATHSEG_MOVETO_ABS:
is(seg.pathSegTypeAsLetter, "M", "wrong path segment letter");
break;
case seg.PATHSEG_MOVETO_REL:
is(seg.pathSegTypeAsLetter, "m", "wrong path segment letter");
break;
case seg.PATHSEG_CLOSEPATH:
is(seg.pathSegTypeAsLetter, "z", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_ABS:
is(seg.pathSegTypeAsLetter, "L", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_REL:
is(seg.pathSegTypeAsLetter, "l", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_VERTICAL_ABS:
is(seg.pathSegTypeAsLetter, "V", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_VERTICAL_REL:
is(seg.pathSegTypeAsLetter, "v", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_HORIZONTAL_ABS:
is(seg.pathSegTypeAsLetter, "H", "wrong path segment letter");
break;
case seg.PATHSEG_LINETO_HORIZONTAL_REL:
is(seg.pathSegTypeAsLetter, "h", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_CUBIC_ABS:
is(seg.pathSegTypeAsLetter, "C", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_CUBIC_REL:
is(seg.pathSegTypeAsLetter, "c", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
is(seg.pathSegTypeAsLetter, "S", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
is(seg.pathSegTypeAsLetter, "s", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_QUADRATIC_ABS:
is(seg.pathSegTypeAsLetter, "Q", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_QUADRATIC_REL:
is(seg.pathSegTypeAsLetter, "q", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
is(seg.pathSegTypeAsLetter, "T", "wrong path segment letter");
break;
case seg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
is(seg.pathSegTypeAsLetter, "t", "wrong path segment letter");
break;
case seg.PATHSEG_ARC_ABS:
is(seg.pathSegTypeAsLetter, "A", "wrong path segment letter");
break;
case seg.PATHSEG_ARC_REL:
is(seg.pathSegTypeAsLetter, "a", "wrong path segment letter");
break;
}
}
SimpleTest.finish();
}
window.addEventListener("load", runTest);
]]>
</script>
</pre>
</body>
</html>

View File

@ -1026,48 +1026,8 @@ var interfaceNamesInGlobalScope =
{name: "SVGNumberList", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathElement", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSeg", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegArcAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegArcRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegClosePath", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoCubicAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoCubicRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoCubicSmoothAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoCubicSmoothRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoQuadraticAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoQuadraticRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoQuadraticSmoothAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegCurvetoQuadraticSmoothRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoHorizontalAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoHorizontalRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoVerticalAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegLinetoVerticalRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegList", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegMovetoAbs", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPathSegMovetoRel", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SVGPatternElement", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -2113,10 +2113,10 @@ nsWebBrowserPersist::CalculateUniqueFilename(nsIURI *aURI, nsCOMPtr<nsIURI>& aOu
localFile->SetLeafName(filenameAsUnichar);
// Resync the URI with the file after the extension has been appended
return NS_MutateURI(aURI)
.Apply<nsIFileURLMutator>(&nsIFileURLMutator::SetFile,
localFile)
.Finalize(aOutURI);
nsresult rv;
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
fileURL->SetFile(localFile); // this should recalculate uri
}
else
{
@ -2292,10 +2292,9 @@ nsWebBrowserPersist::CalculateAndAppendFileExt(nsIURI *aURI,
localFile->SetLeafName(NS_ConvertUTF8toUTF16(newFileName));
// Resync the URI with the file after the extension has been appended
return NS_MutateURI(aURI)
.Apply<nsIFileURLMutator>(&nsIFileURLMutator::SetFile,
localFile)
.Finalize(aOutURI);
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
fileURL->SetFile(localFile); // this should recalculate uri
}
else
{

View File

@ -12,44 +12,6 @@
interface SVGPathElement : SVGGeometryElement {
unsigned long getPathSegAtLength(float distance);
[NewObject]
SVGPathSegClosePath createSVGPathSegClosePath();
[NewObject]
SVGPathSegMovetoAbs createSVGPathSegMovetoAbs(float x, float y);
[NewObject]
SVGPathSegMovetoRel createSVGPathSegMovetoRel(float x, float y);
[NewObject]
SVGPathSegLinetoAbs createSVGPathSegLinetoAbs(float x, float y);
[NewObject]
SVGPathSegLinetoRel createSVGPathSegLinetoRel(float x, float y);
[NewObject]
SVGPathSegCurvetoCubicAbs createSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1, float x2, float y2);
[NewObject]
SVGPathSegCurvetoCubicRel createSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1, float x2, float y2);
[NewObject]
SVGPathSegCurvetoQuadraticAbs createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1);
[NewObject]
SVGPathSegCurvetoQuadraticRel createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1);
[NewObject]
SVGPathSegArcAbs createSVGPathSegArcAbs(float x, float y, float r1, float r2, float angle, boolean largeArcFlag, boolean sweepFlag);
[NewObject]
SVGPathSegArcRel createSVGPathSegArcRel(float x, float y, float r1, float r2, float angle, boolean largeArcFlag, boolean sweepFlag);
[NewObject]
SVGPathSegLinetoHorizontalAbs createSVGPathSegLinetoHorizontalAbs(float x);
[NewObject]
SVGPathSegLinetoHorizontalRel createSVGPathSegLinetoHorizontalRel(float x);
[NewObject]
SVGPathSegLinetoVerticalAbs createSVGPathSegLinetoVerticalAbs(float y);
[NewObject]
SVGPathSegLinetoVerticalRel createSVGPathSegLinetoVerticalRel(float y);
[NewObject]
SVGPathSegCurvetoCubicSmoothAbs createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2);
[NewObject]
SVGPathSegCurvetoCubicSmoothRel createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2);
[NewObject]
SVGPathSegCurvetoQuadraticSmoothAbs createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y);
[NewObject]
SVGPathSegCurvetoQuadraticSmoothRel createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y);
};
SVGPathElement implements SVGAnimatedPathData;

View File

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[NoInterfaceObject]
interface SVGPathSeg {
// Path Segment Types
@ -40,9 +41,11 @@ interface SVGPathSeg {
readonly attribute DOMString pathSegTypeAsLetter;
};
[NoInterfaceObject]
interface SVGPathSegClosePath : SVGPathSeg {
};
[NoInterfaceObject]
interface SVGPathSegMovetoAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -50,6 +53,7 @@ interface SVGPathSegMovetoAbs : SVGPathSeg {
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegMovetoRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -57,6 +61,7 @@ interface SVGPathSegMovetoRel : SVGPathSeg {
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegLinetoAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -64,6 +69,7 @@ interface SVGPathSegLinetoAbs : SVGPathSeg {
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegLinetoRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -71,6 +77,7 @@ interface SVGPathSegLinetoRel : SVGPathSeg {
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoCubicAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -86,6 +93,7 @@ interface SVGPathSegCurvetoCubicAbs : SVGPathSeg {
attribute float y2;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoCubicRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -101,6 +109,7 @@ interface SVGPathSegCurvetoCubicRel : SVGPathSeg {
attribute float y2;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoQuadraticAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -112,6 +121,7 @@ interface SVGPathSegCurvetoQuadraticAbs : SVGPathSeg {
attribute float y1;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoQuadraticRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -123,6 +133,7 @@ interface SVGPathSegCurvetoQuadraticRel : SVGPathSeg {
attribute float y1;
};
[NoInterfaceObject]
interface SVGPathSegArcAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -140,6 +151,7 @@ interface SVGPathSegArcAbs : SVGPathSeg {
attribute boolean sweepFlag;
};
[NoInterfaceObject]
interface SVGPathSegArcRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -157,26 +169,31 @@ interface SVGPathSegArcRel : SVGPathSeg {
attribute boolean sweepFlag;
};
[NoInterfaceObject]
interface SVGPathSegLinetoHorizontalAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
};
[NoInterfaceObject]
interface SVGPathSegLinetoHorizontalRel : SVGPathSeg {
[SetterThrows]
attribute float x;
};
[NoInterfaceObject]
interface SVGPathSegLinetoVerticalAbs : SVGPathSeg {
[SetterThrows]
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegLinetoVerticalRel : SVGPathSeg {
[SetterThrows]
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoCubicSmoothAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -188,6 +205,7 @@ interface SVGPathSegCurvetoCubicSmoothAbs : SVGPathSeg {
attribute float y2;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoCubicSmoothRel : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -199,6 +217,7 @@ interface SVGPathSegCurvetoCubicSmoothRel : SVGPathSeg {
attribute float y2;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoQuadraticSmoothAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
@ -206,6 +225,7 @@ interface SVGPathSegCurvetoQuadraticSmoothAbs : SVGPathSeg {
attribute float y;
};
[NoInterfaceObject]
interface SVGPathSegCurvetoQuadraticSmoothRel : SVGPathSeg {
[SetterThrows]
attribute float x;

View File

@ -13,19 +13,7 @@
interface SVGPathSegList {
readonly attribute unsigned long numberOfItems;
[Throws]
void clear();
[Throws]
SVGPathSeg initialize(SVGPathSeg newItem);
[Throws]
getter SVGPathSeg getItem(unsigned long index);
[Throws]
SVGPathSeg insertItemBefore(SVGPathSeg newItem, unsigned long index);
[Throws]
SVGPathSeg replaceItem(SVGPathSeg newItem, unsigned long index);
[Throws]
SVGPathSeg removeItem(unsigned long index);
[Throws]
SVGPathSeg appendItem(SVGPathSeg newItem);
// Mozilla-specific stuff
readonly attribute unsigned long length; // synonym for numberOfItems

View File

@ -55,8 +55,7 @@ dictionary MakePublicKeyCredentialOptions {
sequence<PublicKeyCredentialDescriptor> excludeCredentials = [];
AuthenticatorSelectionCriteria authenticatorSelection;
AttestationConveyancePreference attestation = "none";
// Extensions are not supported yet.
// AuthenticationExtensions extensions; // Add in Bug 1406458
AuthenticationExtensionsClientInputs extensions;
};
dictionary PublicKeyCredentialEntity {
@ -102,11 +101,16 @@ dictionary PublicKeyCredentialRequestOptions {
USVString rpId;
sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
UserVerificationRequirement userVerification = "preferred";
// Extensions are not supported yet.
// AuthenticationExtensions extensions; // Add in Bug 1406458
AuthenticationExtensionsClientInputs extensions;
};
typedef record<DOMString, any> AuthenticationExtensions;
dictionary AuthenticationExtensionsClientInputs {
};
dictionary AuthenticationExtensionsClientOutputs {
};
typedef record<DOMString, DOMString> AuthenticationExtensionsAuthenticatorInputs;
dictionary CollectedClientData {
required DOMString type;
@ -114,9 +118,8 @@ dictionary CollectedClientData {
required DOMString origin;
required DOMString hashAlgorithm;
DOMString tokenBindingId;
// Extensions are not supported yet.
// AuthenticationExtensions clientExtensions; // Add in Bug 1406458
// AuthenticationExtensions authenticatorExtensions; // Add in Bug 1406458
AuthenticationExtensionsClientInputs clientExtensions;
AuthenticationExtensionsAuthenticatorInputs authenticatorExtensions;
};
enum PublicKeyCredentialType {

View File

@ -761,7 +761,7 @@ protected:
friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
friend already_AddRefed<TextureHost> CreateTextureHostWithBackend(
TextureClient*, LayersBackend&);
TextureClient*, ISurfaceAllocator*, LayersBackend&);
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
public:

View File

@ -116,15 +116,9 @@ TextureHost::CreateIPDLActor(HostIPCAllocator* aAllocator,
uint64_t aSerial,
const wr::MaybeExternalImageId& aExternalImageId)
{
if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
aSharedData.get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::Tuintptr_t &&
!aAllocator->IsSameProcess())
{
NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
return nullptr;
}
TextureParent* actor = new TextureParent(aAllocator, aSerial, aExternalImageId);
if (!actor->Init(aSharedData, aLayersBackend, aFlags)) {
actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
delete actor;
return nullptr;
}
@ -232,6 +226,11 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
#ifdef MOZ_X11
case SurfaceDescriptor::TSurfaceDescriptorX11: {
if (!aDeallocator->IsSameProcess()) {
NS_ERROR("A client process is trying to peek at our address space using a X11Texture!");
return nullptr;
}
const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
result = MakeAndAddRef<X11TextureHost>(aFlags, desc);
break;
@ -248,7 +247,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
MOZ_CRASH("GFX: Unsupported Surface type host");
}
if (WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
MOZ_ASSERT(aExternalImageId.isSome());
result = new WebRenderTextureHost(aDesc, aFlags, result, aExternalImageId.ref());
}
@ -269,13 +268,50 @@ CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
const MemoryOrShmem& data = bufferDesc.data();
switch (data.type()) {
case MemoryOrShmem::TShmem: {
result = new ShmemTextureHost(data.get_Shmem(),
bufferDesc.desc(),
aDeallocator,
aFlags);
const ipc::Shmem& shmem = data.get_Shmem();
const BufferDescriptor& desc = bufferDesc.desc();
if (!shmem.IsReadable()) {
// We failed to map the shmem so we can't verify its size. This
// should not be a fatal error, so just create the texture with
// nothing backing it.
result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
break;
}
size_t bufSize = shmem.Size<char>();
size_t reqSize = SIZE_MAX;
switch (desc.type()) {
case BufferDescriptor::TYCbCrDescriptor: {
const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor();
reqSize =
ImageDataSerializer::ComputeYCbCrBufferSize(ycbcr.ySize(), ycbcr.yStride(),
ycbcr.cbCrSize(), ycbcr.cbCrStride());
break;
}
case BufferDescriptor::TRGBDescriptor: {
const RGBDescriptor& rgb = desc.get_RGBDescriptor();
reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(), rgb.format());
break;
}
default:
gfxCriticalError() << "Bad buffer host descriptor " << (int)desc.type();
MOZ_CRASH("GFX: Bad descriptor");
}
if (bufSize < reqSize) {
NS_ERROR("A client process gave a shmem too small to fit for its descriptor!");
return nullptr;
}
result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
break;
}
case MemoryOrShmem::Tuintptr_t: {
if (!aDeallocator->IsSameProcess()) {
NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
return nullptr;
}
result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
bufferDesc.desc(),
aFlags);
@ -293,6 +329,11 @@ CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
}
#ifdef XP_WIN
case SurfaceDescriptor::TSurfaceDescriptorDIB: {
if (!aDeallocator->IsSameProcess()) {
NS_ERROR("A client process is trying to peek at our address space using a DIBTexture!");
return nullptr;
}
result = new DIBTextureHost(aFlags, aDesc);
break;
}

View File

@ -23,10 +23,9 @@ X11TextureHost::X11TextureHost(TextureFlags aFlags,
const SurfaceDescriptorX11& aDescriptor)
: TextureHost(aFlags)
{
RefPtr<gfxXlibSurface> surface = aDescriptor.OpenForeign();
mSurface = surface.get();
mSurface = aDescriptor.OpenForeign();
if (!(aFlags & TextureFlags::DEALLOCATE_CLIENT)) {
if (mSurface && !(aFlags & TextureFlags::DEALLOCATE_CLIENT)) {
mSurface->TakePixmap();
}
}
@ -34,7 +33,7 @@ X11TextureHost::X11TextureHost(TextureFlags aFlags,
bool
X11TextureHost::Lock()
{
if (!mCompositor) {
if (!mCompositor || !mSurface) {
return false;
}
@ -75,6 +74,9 @@ X11TextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
SurfaceFormat
X11TextureHost::GetFormat() const
{
if (!mSurface) {
return SurfaceFormat::UNKNOWN;
}
gfxContentType type = mSurface->GetContentType();
#ifdef GL_PROVIDER_GLX
if (mCompositor->GetBackendType() == LayersBackend::LAYERS_OPENGL) {
@ -87,6 +89,9 @@ X11TextureHost::GetFormat() const
IntSize
X11TextureHost::GetSize() const
{
if (!mSurface) {
return IntSize();
}
return mSurface->GetSize();
}

View File

@ -763,10 +763,6 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
{
RefPtr<TextureHost> result;
switch (aDesc.type()) {
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags);
break;
}
case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
result = new DXGITextureHostD3D11(aFlags,
aDesc.get_SurfaceDescriptorD3D10());
@ -778,7 +774,7 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
break;
}
default: {
NS_WARNING("Unsupported SurfaceDescriptor type");
MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
}
}
return result.forget();

View File

@ -32,6 +32,8 @@ MacIOSurfaceTextureHostOGL::~MacIOSurfaceTextureHostOGL()
GLTextureSource*
MacIOSurfaceTextureHostOGL::CreateTextureSourceForPlane(size_t aPlane)
{
MOZ_ASSERT(mSurface);
GLuint textureHandle;
gl::GLContext* gl = mProvider->GetGLContext();
gl->fGenTextures(1, &textureHandle);
@ -94,11 +96,17 @@ MacIOSurfaceTextureHostOGL::SetTextureSourceProvider(TextureSourceProvider* aPro
gfx::SurfaceFormat
MacIOSurfaceTextureHostOGL::GetFormat() const {
if (!mSurface) {
return gfx::SurfaceFormat::UNKNOWN;
}
return mSurface->GetFormat();
}
gfx::SurfaceFormat
MacIOSurfaceTextureHostOGL::GetReadFormat() const {
if (!mSurface) {
return gfx::SurfaceFormat::UNKNOWN;
}
return mSurface->GetReadFormat();
}

View File

@ -26,10 +26,6 @@
#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "mozilla/layers/X11TextureHost.h"
#endif
using namespace mozilla::gl;
using namespace mozilla::gfx;
@ -46,14 +42,6 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
{
RefPtr<TextureHost> result;
switch (aDesc.type()) {
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
result = CreateBackendIndependentTextureHost(aDesc,
aDeallocator,
aBackend,
aFlags);
break;
}
#ifdef MOZ_WIDGET_ANDROID
case SurfaceDescriptor::TSurfaceTextureDescriptor: {
const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
@ -88,14 +76,6 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
}
#endif
#ifdef GL_PROVIDER_GLX
case SurfaceDescriptor::TSurfaceDescriptorX11: {
const auto& desc = aDesc.get_SurfaceDescriptorX11();
result = new X11TextureHost(aFlags, desc);
break;
}
#endif
case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
result = new GLTextureHost(aFlags, desc.texture(),
@ -105,7 +85,10 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
desc.hasAlpha());
break;
}
default: return nullptr;
default: {
MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
break;
}
}
return result.forget();
}

View File

@ -8,6 +8,22 @@
#include "Layers.h"
#include "nsTArray.h"
#include "mozilla/layers/ISurfaceAllocator.h"
namespace mozilla {
namespace layers {
class TestSurfaceAllocator final : public ISurfaceAllocator
{
public:
TestSurfaceAllocator() {}
~TestSurfaceAllocator() override {}
bool IsSameProcess() const override { return true; }
};
} // layers
} // mozilla
/* Create layer tree from a simple layer tree description syntax.
* Each index is either the first letter of the layer type or

View File

@ -14,6 +14,7 @@
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/RefPtr.h"
#include "TestLayers.h"
#include "TextureHelper.h"
using mozilla::gfx::Feature;
@ -22,6 +23,7 @@ using mozilla::layers::BasicCompositor;
using mozilla::layers::Compositor;
using mozilla::layers::CompositorOptions;
using mozilla::layers::LayersBackend;
using mozilla::layers::TestSurfaceAllocator;
using mozilla::layers::TextureClient;
using mozilla::layers::TextureHost;
using mozilla::widget::CompositorWidget;
@ -31,8 +33,9 @@ using mozilla::widget::InProcessCompositorWidget;
* This function will create the possible TextureClient and TextureHost pairs
* according to the given backend.
*/
void
static void
CreateTextureWithBackend(LayersBackend& aLayersBackend,
ISurfaceAllocator* aDeallocator,
nsTArray<RefPtr<TextureClient>>& aTextureClients,
nsTArray<RefPtr<TextureHost>>& aTextureHosts)
{
@ -43,7 +46,8 @@ CreateTextureWithBackend(LayersBackend& aLayersBackend,
for (uint32_t i = 0; i < aTextureClients.Length(); i++) {
aTextureHosts.AppendElement(
CreateTextureHostWithBackend(aTextureClients[i], aLayersBackend));
CreateTextureHostWithBackend(aTextureClients[i], aDeallocator,
aLayersBackend));
}
}
@ -115,13 +119,15 @@ CheckCompatibilityWithBasicCompositor(LayersBackend aBackends,
TEST(Gfx, TestTextureCompatibility)
{
nsTArray<LayersBackend> backendHints;
RefPtr<TestSurfaceAllocator> deallocator = new TestSurfaceAllocator();
GetPlatformBackends(backendHints);
for (uint32_t i = 0; i < backendHints.Length(); i++) {
nsTArray<RefPtr<TextureClient>> textureClients;
nsTArray<RefPtr<TextureHost>> textureHosts;
CreateTextureWithBackend(backendHints[i], textureClients, textureHosts);
CreateTextureWithBackend(backendHints[i], deallocator,
textureClients, textureHosts);
CheckCompatibilityWithBasicCompositor(backendHints[i], textureHosts);
}
}

View File

@ -5,6 +5,7 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "TestLayers.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Tools.h"
@ -147,7 +148,8 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
// host deserialization
RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
RefPtr<TestSurfaceAllocator> deallocator = new TestSurfaceAllocator();
RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, deallocator,
LayersBackend::LAYERS_NONE,
texture->GetFlags());
@ -193,7 +195,8 @@ void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);
// host deserialization
RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
RefPtr<TestSurfaceAllocator> deallocator = new TestSurfaceAllocator();
RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, deallocator,
LayersBackend::LAYERS_NONE,
client->GetFlags());

View File

@ -140,6 +140,7 @@ CreateTextureClientWithBackend(LayersBackend aLayersBackend)
*/
already_AddRefed<TextureHost>
CreateTextureHostWithBackend(TextureClient* aClient,
ISurfaceAllocator* aDeallocator,
LayersBackend& aLayersBackend)
{
if (!aClient) {
@ -153,7 +154,7 @@ CreateTextureHostWithBackend(TextureClient* aClient,
aClient->ToSurfaceDescriptor(descriptor);
wr::MaybeExternalImageId id = Nothing();
return TextureHost::Create(descriptor, nullptr, aLayersBackend,
return TextureHost::Create(descriptor, aDeallocator, aLayersBackend,
aClient->GetFlags(), id);
}

View File

@ -85,8 +85,11 @@ RenderCompositorANGLE::Initialize()
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
// Do not use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, since it makes HWND unreusable.
//desc.BufferCount = 2;
//desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.BufferCount = 1;
desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
desc.Scaling = DXGI_SCALING_NONE;
desc.Flags = 0;

View File

@ -43,7 +43,8 @@ public:
// Other, internal-only methods:
virtual void SetHasImage() = 0;
virtual bool NotificationsDeferred() const = 0;
virtual void SetNotificationsDeferred(bool aDeferNotifications) = 0;
virtual void MarkPendingNotify() = 0;
virtual void ClearPendingNotify() = 0;
virtual already_AddRefed<nsIEventTarget> GetEventTarget() const
{

View File

@ -95,7 +95,8 @@ public:
// Other notifications are ignored.
virtual void SetHasImage() override { }
virtual bool NotificationsDeferred() const override { return false; }
virtual void SetNotificationsDeferred(bool) override { }
virtual void MarkPendingNotify() override { }
virtual void ClearPendingNotify() override { }
private:
virtual ~NextPartObserver() { }
@ -122,7 +123,7 @@ private:
MultipartImage::MultipartImage(Image* aFirstPart)
: ImageWrapper(aFirstPart)
, mDeferNotifications(false)
, mPendingNotify(false)
{
mNextPartObserver = new NextPartObserver(this);
}
@ -333,13 +334,19 @@ MultipartImage::SetHasImage()
bool
MultipartImage::NotificationsDeferred() const
{
return mDeferNotifications;
return mPendingNotify;
}
void
MultipartImage::SetNotificationsDeferred(bool aDeferNotifications)
MultipartImage::MarkPendingNotify()
{
mDeferNotifications = aDeferNotifications;
mPendingNotify = true;
}
void
MultipartImage::ClearPendingNotify()
{
mPendingNotify = false;
}
} // namespace image

View File

@ -59,7 +59,8 @@ public:
virtual void OnLoadComplete(bool aLastPart) override;
virtual void SetHasImage() override;
virtual bool NotificationsDeferred() const override;
virtual void SetNotificationsDeferred(bool aDeferNotifications) override;
virtual void MarkPendingNotify() override;
virtual void ClearPendingNotify() override;
protected:
virtual ~MultipartImage();
@ -76,7 +77,7 @@ private:
RefPtr<ProgressTracker> mTracker;
RefPtr<NextPartObserver> mNextPartObserver;
RefPtr<Image> mNextPart;
bool mDeferNotifications : 1;
bool mPendingNotify : 1;
};
} // namespace image

View File

@ -141,7 +141,7 @@ class AsyncNotifyRunnable : public Runnable
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
MOZ_ASSERT(mTracker, "mTracker should not be null");
for (uint32_t i = 0; i < mObservers.Length(); ++i) {
mObservers[i]->SetNotificationsDeferred(false);
mObservers[i]->ClearPendingNotify();
mTracker->SyncNotify(mObservers[i]);
}
@ -171,6 +171,11 @@ ProgressTracker::Notify(IProgressObserver* aObserver)
{
MOZ_ASSERT(NS_IsMainThread());
if (aObserver->NotificationsDeferred()) {
// There is a pending notification, or the observer isn't ready yet.
return;
}
if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
RefPtr<Image> image = GetImage();
if (image && image->GetURI()) {
@ -185,7 +190,7 @@ ProgressTracker::Notify(IProgressObserver* aObserver)
}
}
aObserver->SetNotificationsDeferred(true);
aObserver->MarkPendingNotify();
// If we have an existing runnable that we can use, we just append this
// observer to its list of observers to be notified. This ensures we don't
@ -221,7 +226,7 @@ class AsyncNotifyCurrentStateRunnable : public Runnable
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
mObserver->SetNotificationsDeferred(false);
mObserver->ClearPendingNotify();
mProgressTracker->SyncNotify(mObserver);
return NS_OK;
@ -241,6 +246,11 @@ ProgressTracker::NotifyCurrentState(IProgressObserver* aObserver)
{
MOZ_ASSERT(NS_IsMainThread());
if (aObserver->NotificationsDeferred()) {
// There is a pending notification, or the observer isn't ready yet.
return;
}
if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
RefPtr<Image> image = GetImage();
nsAutoCString spec;
@ -251,7 +261,7 @@ ProgressTracker::NotifyCurrentState(IProgressObserver* aObserver)
"ProgressTracker::NotifyCurrentState", "uri", spec.get());
}
aObserver->SetNotificationsDeferred(true);
aObserver->MarkPendingNotify();
nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this,
aObserver);
@ -516,7 +526,7 @@ ProgressTracker::RemoveObserver(IProgressObserver* aObserver)
if (aObserver->NotificationsDeferred() && runnable) {
runnable->RemoveObserver(aObserver);
aObserver->SetNotificationsDeferred(false);
aObserver->ClearPendingNotify();
}
return removed;

View File

@ -1768,7 +1768,7 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
// In the mean time, we must defer notifications because we are added to
// the imgRequest's proxy list, and we can get extra notifications
// resulting from methods such as StartDecoding(). See bug 579122.
proxy->SetNotificationsDeferred(true);
proxy->MarkValidating();
// Attach the proxy without notifying
request->GetValidator()->AddProxy(proxy);
@ -1834,7 +1834,7 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
// In the mean time, we must defer notifications because we are added to
// the imgRequest's proxy list, and we can get extra notifications
// resulting from methods such as StartDecoding(). See bug 579122.
req->SetNotificationsDeferred(true);
req->MarkValidating();
// Add the proxy without notifying
hvc->AddProxy(req);
@ -2936,13 +2936,45 @@ imgCacheValidator::AddProxy(imgRequestProxy* aProxy)
// the network.
aProxy->AddToLoadGroup();
mProxies.AppendObject(aProxy);
mProxies.AppendElement(aProxy);
}
void
imgCacheValidator::RemoveProxy(imgRequestProxy* aProxy)
{
mProxies.RemoveObject(aProxy);
mProxies.RemoveElement(aProxy);
}
void
imgCacheValidator::UpdateProxies()
{
// We have finished validating the request, so we can safely take ownership
// of the proxy list. imgRequestProxy::SyncNotifyListener can mutate the list
// if imgRequestProxy::CancelAndForgetObserver is called by its owner. Note
// that any potential notifications should still be suppressed in
// imgRequestProxy::ChangeOwner because we haven't cleared the validating
// flag yet, and thus they will remain deferred.
AutoTArray<RefPtr<imgRequestProxy>, 4> proxies(Move(mProxies));
for (auto& proxy : proxies) {
// First update the state of all proxies before notifying any of them
// to ensure a consistent state (e.g. in case the notification causes
// other proxies to be touched indirectly.)
MOZ_ASSERT(proxy->IsValidating());
MOZ_ASSERT(proxy->NotificationsDeferred(),
"Proxies waiting on cache validation should be "
"deferring notifications!");
if (mNewRequest) {
proxy->ChangeOwner(mNewRequest);
}
proxy->ClearValidating();
}
for (auto& proxy : proxies) {
// Notify synchronously, because we're already in OnStartRequest, an
// asynchronously-called function.
proxy->SyncNotifyListener();
}
}
/** nsIRequestObserver methods **/
@ -2982,25 +3014,11 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
}
if (isFromCache && sameURI) {
uint32_t count = mProxies.Count();
for (int32_t i = count-1; i>=0; i--) {
imgRequestProxy* proxy = static_cast<imgRequestProxy*>(mProxies[i]);
// Proxies waiting on cache validation should be deferring
// notifications. Undefer them.
MOZ_ASSERT(proxy->NotificationsDeferred(),
"Proxies waiting on cache validation should be "
"deferring notifications!");
proxy->SetNotificationsDeferred(false);
// Notify synchronously, because we're already in OnStartRequest, an
// asynchronously-called function.
proxy->SyncNotifyListener();
}
// We don't need to load this any more.
aRequest->Cancel(NS_BINDING_ABORTED);
// Clear the validator before updating the proxies. The notifications may
// clone an existing request, and its state could be inconsistent.
mRequest->SetLoadId(context);
mRequest->SetValidator(nullptr);
@ -3009,6 +3027,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
mNewRequest = nullptr;
mNewEntry = nullptr;
UpdateProxies();
return NS_OK;
}
}
@ -3035,6 +3054,8 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
// Doom the old request's cache entry
mRequest->RemoveFromCache();
// Clear the validator before updating the proxies. The notifications may
// clone an existing request, and its state could be inconsistent.
mRequest->SetValidator(nullptr);
mRequest = nullptr;
@ -3055,17 +3076,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
// changes the caching behaviour for imgRequests.
mImgLoader->PutIntoCache(mNewRequest->CacheKey(), mNewEntry);
uint32_t count = mProxies.Count();
for (int32_t i = count-1; i>=0; i--) {
imgRequestProxy* proxy = static_cast<imgRequestProxy*>(mProxies[i]);
proxy->ChangeOwner(mNewRequest);
// Notify synchronously, because we're already in OnStartRequest, an
// asynchronously-called function.
proxy->SetNotificationsDeferred(false);
proxy->SyncNotifyListener();
}
UpdateProxies();
mNewRequest = nullptr;
mNewEntry = nullptr;

View File

@ -568,6 +568,7 @@ public:
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
private:
void UpdateProxies();
virtual ~imgCacheValidator();
nsCOMPtr<nsIStreamListener> mDestListener;
@ -576,7 +577,7 @@ private:
nsCOMPtr<nsIChannel> mRedirectChannel;
RefPtr<imgRequest> mRequest;
nsCOMArray<imgIRequest> mProxies;
AutoTArray<RefPtr<imgRequestProxy>, 4> mProxies;
RefPtr<imgRequest> mNewRequest;
RefPtr<imgCacheEntry> mNewEntry;

View File

@ -120,7 +120,8 @@ imgRequestProxy::imgRequestProxy() :
mForceDispatchLoadGroup(false),
mListenerIsStrongRef(false),
mDecodeRequested(false),
mDeferNotifications(false),
mPendingNotify(false),
mValidating(false),
mHadListener(false),
mHadDispatch(false)
{
@ -163,15 +164,13 @@ imgRequestProxy::~imgRequestProxy()
// above assert.
NullOutListener();
if (GetOwner()) {
/* Call RemoveProxy with a successful status. This will keep the
channel, if still downloading data, from being canceled if 'this' is
the last observer. This allows the image to continue to download and
be cached even if no one is using it currently.
*/
mCanceled = true;
GetOwner()->RemoveProxy(this, NS_OK);
}
/* Call RemoveProxy with a successful status. This will keep the
channel, if still downloading data, from being canceled if 'this' is
the last observer. This allows the image to continue to download and
be cached even if no one is using it currently.
*/
mCanceled = true;
RemoveFromOwner(NS_OK);
RemoveFromLoadGroup();
LOG_FUNC(gImgLog, "imgRequestProxy::~imgRequestProxy");
@ -237,6 +236,7 @@ imgRequestProxy::ChangeOwner(imgRequest* aNewOwner)
GetOwner()->RemoveProxy(this, NS_OK);
mBehaviour->SetOwner(aNewOwner);
MOZ_ASSERT(!GetValidator(), "New owner cannot be validating!");
// If we were locked, apply the locks here
for (uint32_t i = 0; i < oldLockCount; i++) {
@ -251,14 +251,29 @@ imgRequestProxy::ChangeOwner(imgRequest* aNewOwner)
}
AddToOwner(nullptr);
return NS_OK;
}
void
imgRequestProxy::MarkValidating()
{
MOZ_ASSERT(GetValidator());
mValidating = true;
}
void
imgRequestProxy::ClearValidating()
{
MOZ_ASSERT(mValidating);
MOZ_ASSERT(!GetValidator());
mValidating = false;
// If we'd previously requested a synchronous decode, request a decode on the
// new image.
if (mDecodeRequested) {
mDecodeRequested = false;
StartDecoding(imgIContainer::FLAG_NONE);
}
return NS_OK;
}
bool
@ -351,11 +366,28 @@ imgRequestProxy::AddToOwner(nsIDocument* aLoadingDocument)
mEventTarget = do_GetMainThread();
}
if (!GetOwner()) {
imgRequest* owner = GetOwner();
if (!owner) {
return;
}
GetOwner()->AddProxy(this);
owner->AddProxy(this);
}
void
imgRequestProxy::RemoveFromOwner(nsresult aStatus)
{
imgRequest* owner = GetOwner();
if (owner) {
if (mValidating) {
imgCacheValidator* validator = owner->GetValidator();
MOZ_ASSERT(validator);
validator->RemoveProxy(this);
mValidating = false;
}
owner->RemoveProxy(this, aStatus);
}
}
void
@ -494,10 +526,7 @@ imgRequestProxy::Cancel(nsresult status)
void
imgRequestProxy::DoCancel(nsresult status)
{
if (GetOwner()) {
GetOwner()->RemoveProxy(this, status);
}
RemoveFromOwner(status);
RemoveFromLoadGroup();
NullOutListener();
}
@ -519,17 +548,7 @@ imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
mCanceled = true;
mForceDispatchLoadGroup = true;
imgRequest* owner = GetOwner();
if (owner) {
imgCacheValidator* validator = owner->GetValidator();
if (validator) {
validator->RemoveProxy(this);
}
owner->RemoveProxy(this, aStatus);
}
RemoveFromOwner(aStatus);
RemoveFromLoadGroup();
mForceDispatchLoadGroup = false;
@ -541,8 +560,11 @@ imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
NS_IMETHODIMP
imgRequestProxy::StartDecoding(uint32_t aFlags)
{
// Flag this, so we know to transfer the request if our owner changes
mDecodeRequested = true;
// Flag this, so we know to request after validation if pending.
if (IsValidating()) {
mDecodeRequested = true;
return NS_OK;
}
RefPtr<Image> image = GetImage();
if (image) {
@ -559,8 +581,11 @@ imgRequestProxy::StartDecoding(uint32_t aFlags)
bool
imgRequestProxy::StartDecodingWithResult(uint32_t aFlags)
{
// Flag this, so we know to transfer the request if our owner changes
mDecodeRequested = true;
// Flag this, so we know to request after validation if pending.
if (IsValidating()) {
mDecodeRequested = true;
return false;
}
RefPtr<Image> image = GetImage();
if (image) {
@ -717,8 +742,16 @@ imgRequestProxy::GetImage(imgIContainer** aImage)
NS_IMETHODIMP
imgRequestProxy::GetImageStatus(uint32_t* aStatus)
{
RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
*aStatus = progressTracker->GetImageStatus();
if (IsValidating()) {
// We are currently validating the image, and so our status could revert if
// we discard the cache. We should also be deferring notifications, such
// that the caller will be notified when validation completes. Rather than
// risk misleading the caller, return nothing.
*aStatus = imgIRequest::STATUS_NONE;
} else {
RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
*aStatus = progressTracker->GetImageStatus();
}
return NS_OK;
}
@ -859,15 +892,16 @@ imgRequestProxy::PerformClone(imgINotificationObserver* aObserver,
// surprised.
NS_ADDREF(*aClone = clone);
if (GetOwner() && GetOwner()->GetValidator()) {
imgCacheValidator* validator = GetValidator();
if (validator) {
// Note that if we have a validator, we don't want to issue notifications at
// here because we want to defer until that completes. AddProxy will add us
// to the load group; we cannot avoid that in this case, because we don't
// know when the validation will complete, and if it will cause us to
// discard our cached state anyways. We are probably already blocked by the
// original LoadImage(WithChannel) request in any event.
clone->SetNotificationsDeferred(true);
GetOwner()->GetValidator()->AddProxy(clone);
clone->MarkValidating();
validator->AddProxy(clone);
} else {
// We only want to add the request to the load group of the owning document
// if it is still in progress. Some callers cannot handle a supurious load
@ -1270,6 +1304,16 @@ imgRequestProxy::GetOwner() const
return mBehaviour->GetOwner();
}
imgCacheValidator*
imgRequestProxy::GetValidator() const
{
imgRequest* owner = GetOwner();
if (!owner) {
return nullptr;
}
return owner->GetValidator();
}
////////////////// imgRequestProxyStatic methods
class StaticBehaviour : public ProxyBehaviour

View File

@ -30,6 +30,7 @@
{0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95} \
}
class imgCacheValidator;
class imgINotificationObserver;
class imgStatusNotifyRunnable;
class ProxyBehaviour;
@ -111,15 +112,25 @@ public:
virtual void SetHasImage() override;
// Whether we want notifications from ProgressTracker to be deferred until
// an event it has scheduled has been fired.
// an event it has scheduled has been fired and/or validation is complete.
virtual bool NotificationsDeferred() const override
{
return mDeferNotifications;
return IsValidating() || mPendingNotify;
}
virtual void SetNotificationsDeferred(bool aDeferNotifications) override
virtual void MarkPendingNotify() override
{
mDeferNotifications = aDeferNotifications;
mPendingNotify = true;
}
virtual void ClearPendingNotify() override
{
mPendingNotify = false;
}
bool IsValidating() const
{
return mValidating;
}
void MarkValidating();
void ClearValidating();
bool IsOnEventTarget() const;
already_AddRefed<nsIEventTarget> GetEventTarget() const override;
@ -194,6 +205,7 @@ protected:
already_AddRefed<Image> GetImage() const;
bool HasImage() const;
imgRequest* GetOwner() const;
imgCacheValidator* GetValidator() const;
nsresult PerformClone(imgINotificationObserver* aObserver,
nsIDocument* aLoadingDocument,
@ -212,6 +224,7 @@ private:
friend class imgCacheValidator;
void AddToOwner(nsIDocument* aLoadingDocument);
void RemoveFromOwner(nsresult aStatus);
nsresult DispatchWithTargetIfAvailable(already_AddRefed<nsIRunnable> aEvent);
void DispatchWithTarget(already_AddRefed<nsIRunnable> aEvent);
@ -241,7 +254,8 @@ private:
// Whether we want to defer our notifications by the non-virtual Observer
// interfaces as image loads proceed.
bool mDeferNotifications : 1;
bool mPendingNotify : 1;
bool mValidating : 1;
bool mHadListener : 1;
bool mHadDispatch : 1;
};

View File

@ -10,6 +10,9 @@ dumpStringRepresentation("");
print("\nResult of coercion to string:");
dumpStringRepresentation();
print("\nString with an index value:");
dumpStringRepresentation((12345).toString());
print("\ns = Simple short atom:");
var s = "xxxxxxxx";
dumpStringRepresentation(s);

View File

@ -5505,7 +5505,8 @@ CodeGenerator::generateBody()
TrackedOptimizations* last = nullptr;
#if defined(JS_ION_PERF)
perfSpewer->startBasicBlock(current->mir(), masm);
if (!perfSpewer->startBasicBlock(current->mir(), masm))
return false;
#endif
for (LInstructionIterator iter = current->begin(); iter != current->end(); iter++) {
@ -8653,24 +8654,14 @@ CodeGenerator::visitSpectreMaskIndex(LSpectreMaskIndex* lir)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
const LAllocation* index = lir->index();
const LAllocation* length = lir->length();
Register index = ToRegister(lir->index());
Register output = ToRegister(lir->output());
if (index->isConstant()) {
int32_t idx = ToInt32(index);
if (length->isRegister())
masm.spectreMaskIndex(idx, ToRegister(length), output);
else
masm.spectreMaskIndex(idx, ToAddress(length), output);
return;
}
Register indexReg = ToRegister(index);
if (length->isRegister())
masm.spectreMaskIndex(indexReg, ToRegister(length), output);
masm.spectreMaskIndex(index, ToRegister(length), output);
else
masm.spectreMaskIndex(indexReg, ToAddress(length), output);
masm.spectreMaskIndex(index, ToAddress(length), output);
}
class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>

View File

@ -232,7 +232,7 @@ DefaultJitOptions::DefaultJitOptions()
Warn(forcedRegisterAllocatorEnv, env);
}
SET_DEFAULT(spectreIndexMasking, false);
SET_DEFAULT(spectreIndexMasking, true);
// Toggles whether unboxed plain objects can be created by the VM.
SET_DEFAULT(disableUnboxedObjects, false);

View File

@ -3163,16 +3163,8 @@ LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins)
MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
MOZ_ASSERT(ins->type() == MIRType::Int32);
// On 64-bit platforms, the length must be in a register, so
// MacroAssembler::maskIndex can emit more efficient code.
#if JS_BITS_PER_WORD == 64
LAllocation lengthUse = useRegister(ins->length());
#else
LAllocation lengthUse = useAny(ins->length());
#endif
LSpectreMaskIndex* lir =
new(alloc()) LSpectreMaskIndex(useRegisterOrConstant(ins->index()), lengthUse);
new(alloc()) LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
define(lir, ins);
}

View File

@ -3322,99 +3322,27 @@ MacroAssembler::debugAssertIsObject(const ValueOperand& val)
#endif
}
template <typename T>
void
MacroAssembler::computeSpectreIndexMaskGeneric(Register index, const T& length, Register output)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
MOZ_ASSERT(index != output);
// mask := ((index - length) & ~index) >> 31
mov(index, output);
sub32(length, output);
not32(index);
and32(index, output);
not32(index); // Restore index register to its original value.
rshift32Arithmetic(Imm32(31), output);
}
template <typename T>
void
MacroAssembler::computeSpectreIndexMask(int32_t index, const T& length, Register output)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
// mask := ((index - length) & ~index) >> 31
move32(Imm32(index), output);
sub32(length, output);
and32(Imm32(~index), output);
rshift32Arithmetic(Imm32(31), output);
}
void
MacroAssembler::computeSpectreIndexMask(Register index, Register length, Register output)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
MOZ_ASSERT(length != output);
MOZ_ASSERT(index != output);
#if JS_BITS_PER_WORD == 64
// On 64-bit platforms, we can use a faster algorithm:
//
// mask := (uint64_t(index) - uint64_t(length)) >> 32
//
// mask is 0x11…11 if index < length, 0 otherwise.
move32(index, output);
subPtr(length, output);
rshiftPtr(Imm32(32), output);
#else
computeSpectreIndexMaskGeneric(index, length, output);
#endif
}
void
MacroAssembler::spectreMaskIndex(int32_t index, Register length, Register output)
{
MOZ_ASSERT(length != output);
if (index == 0) {
move32(Imm32(index), output);
} else {
computeSpectreIndexMask(index, length, output);
and32(Imm32(index), output);
}
}
void
MacroAssembler::spectreMaskIndex(int32_t index, const Address& length, Register output)
{
MOZ_ASSERT(length.base != output);
if (index == 0) {
move32(Imm32(index), output);
} else {
computeSpectreIndexMask(index, length, output);
and32(Imm32(index), output);
}
}
void
MacroAssembler::spectreMaskIndex(Register index, Register length, Register output)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
MOZ_ASSERT(length != output);
MOZ_ASSERT(index != output);
computeSpectreIndexMask(index, length, output);
and32(index, output);
move32(Imm32(0), output);
cmp32Move32(Assembler::Below, index, length, index, output);
}
void
MacroAssembler::spectreMaskIndex(Register index, const Address& length, Register output)
{
MOZ_ASSERT(JitOptions.spectreIndexMasking);
MOZ_ASSERT(index != length.base);
MOZ_ASSERT(length.base != output);
MOZ_ASSERT(index != output);
computeSpectreIndexMaskGeneric(index, length, output);
and32(index, output);
move32(Imm32(0), output);
cmp32Move32(Assembler::Below, index, length, index, output);
}
void
@ -3429,38 +3357,6 @@ MacroAssembler::boundsCheck32PowerOfTwo(Register index, uint32_t length, Label*
and32(Imm32(length - 1), index);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, Register length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length);
MOZ_ASSERT(length != scratch);
MOZ_ASSERT(index != scratch);
branch32(Assembler::AboveOrEqual, index, length, failure);
if (JitOptions.spectreIndexMasking) {
computeSpectreIndexMask(index, length, scratch);
and32(scratch, index);
}
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, const Address& length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length.base);
MOZ_ASSERT(length.base != scratch);
MOZ_ASSERT(index != scratch);
branch32(Assembler::BelowOrEqual, length, index, failure);
if (JitOptions.spectreIndexMasking) {
computeSpectreIndexMaskGeneric(index, length, scratch);
and32(scratch, index);
}
}
namespace js {
namespace jit {

View File

@ -1359,6 +1359,24 @@ class MacroAssembler : public MacroAssemblerSpecific
DEFINED_ON(arm, arm64, x86_shared);
public:
inline void cmp32Move32(Condition cond, Register lhs, Register rhs, Register src,
Register dest)
DEFINED_ON(arm, arm64, x86_shared);
inline void cmp32Move32(Condition cond, Register lhs, const Address& rhs, Register src,
Register dest)
DEFINED_ON(arm, arm64, x86_shared);
// Performs a bounds check and zeroes the index register if out-of-bounds
// (to mitigate Spectre).
inline void boundsCheck32ForLoad(Register index, Register length, Register scratch,
Label* failure)
DEFINED_ON(arm, arm64, x86_shared);
inline void boundsCheck32ForLoad(Register index, const Address& length, Register scratch,
Label* failure)
DEFINED_ON(arm, arm64, x86_shared);
// ========================================================================
// Canonicalization primitives.
inline void canonicalizeDouble(FloatRegister reg);
@ -2055,18 +2073,6 @@ class MacroAssembler : public MacroAssemblerSpecific
store32(Imm32(key.constant()), dest);
}
private:
template <typename T>
void computeSpectreIndexMaskGeneric(Register index, const T& length, Register output);
void computeSpectreIndexMask(Register index, Register length, Register output);
template <typename T>
void computeSpectreIndexMask(int32_t index, const T& length, Register output);
public:
void spectreMaskIndex(int32_t index, Register length, Register output);
void spectreMaskIndex(int32_t index, const Address& length, Register output);
void spectreMaskIndex(Register index, Register length, Register output);
void spectreMaskIndex(Register index, const Address& length, Register output);
@ -2074,10 +2080,6 @@ class MacroAssembler : public MacroAssemblerSpecific
// masking.
void boundsCheck32PowerOfTwo(Register index, uint32_t length, Label* failure);
// Performs a bounds check and Spectre index masking.
void boundsCheck32ForLoad(Register index, Register length, Register scratch, Label* failure);
void boundsCheck32ForLoad(Register index, const Address& length, Register scratch, Label* failure);
template <typename T>
void guardedCallPreBarrier(const T& address, MIRType type) {
Label done;

View File

@ -129,24 +129,21 @@ js::jit::PerfFuncEnabled() {
return PerfMode == PERF_MODE_FUNC;
}
static bool
lockPerfMap(void)
{
if (!PerfEnabled())
return false;
PerfMutex->lock();
MOZ_ASSERT(PerfFilePtr);
return true;
}
static void
unlockPerfMap()
{
MOZ_ASSERT(PerfFilePtr);
fflush(PerfFilePtr);
PerfMutex->unlock();
namespace {
struct MOZ_RAII AutoLockPerfMap
{
AutoLockPerfMap() {
if (!PerfEnabled())
return;
PerfMutex->lock();
MOZ_ASSERT(PerfFilePtr);
}
~AutoLockPerfMap() {
MOZ_ASSERT(PerfFilePtr);
fflush(PerfFilePtr);
PerfMutex->unlock();
}
};
}
uint32_t PerfSpewer::nextFunctionIndex = 0;
@ -173,24 +170,36 @@ PerfSpewer::startBasicBlock(MBasicBlock* blk,
return basicBlocks_.append(r);
}
bool
void
PerfSpewer::endBasicBlock(MacroAssembler& masm)
{
if (!PerfBlockEnabled())
return true;
return;
masm.bind(&basicBlocks_.back().end);
return true;
}
bool
void
PerfSpewer::noteEndInlineCode(MacroAssembler& masm)
{
if (!PerfBlockEnabled())
return true;
return;
masm.bind(&endInlineCode);
return true;
}
void
PerfSpewer::WriteEntry(const AutoLockPerfMap&, uintptr_t address, size_t size,
const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
va_end(ap);
fprintf(PerfFilePtr, "%" PRIxPTR " %zx %s\n",
address,
size,
result.get());
}
void
@ -198,29 +207,19 @@ PerfSpewer::writeProfile(JSScript* script,
JitCode* code,
MacroAssembler& masm)
{
AutoLockPerfMap lock;
if (PerfFuncEnabled()) {
if (!lockPerfMap())
return;
uint32_t thisFunctionIndex = nextFunctionIndex++;
size_t size = code->instructionsSize();
if (size > 0) {
fprintf(PerfFilePtr, "%p %zx %s:%zu: Func%02d\n",
code->raw(),
size,
script->filename(),
script->lineno(),
thisFunctionIndex);
WriteEntry(lock, reinterpret_cast<uintptr_t>(code->raw()), size, "%s:%zu: Func%02" PRIu32,
script->filename(), script->lineno(), thisFunctionIndex);
}
unlockPerfMap();
return;
}
if (PerfBlockEnabled() && basicBlocks_.length() > 0) {
if (!lockPerfMap())
return;
uint32_t thisFunctionIndex = nextFunctionIndex++;
uintptr_t funcStart = uintptr_t(code->raw());
uintptr_t funcEndInlineCode = funcStart + endInlineCode.offset();
@ -230,8 +229,8 @@ PerfSpewer::writeProfile(JSScript* script,
size_t prologueSize = basicBlocks_[0].start.offset();
if (prologueSize > 0) {
fprintf(PerfFilePtr, "%zx %zx %s:%zu: Func%02d-Prologue\n",
funcStart, prologueSize, script->filename(), script->lineno(), thisFunctionIndex);
WriteEntry(lock, funcStart, prologueSize, "%s:%zu: Func%02" PRIu32 "-Prologue",
script->filename(), script->lineno(), thisFunctionIndex);
}
uintptr_t cur = funcStart + prologueSize;
@ -243,41 +242,31 @@ PerfSpewer::writeProfile(JSScript* script,
MOZ_ASSERT(cur <= blockStart);
if (cur < blockStart) {
fprintf(PerfFilePtr, "%" PRIxPTR " %" PRIxPTR " %s:%zu: Func%02d-Block?\n",
cur, blockStart - cur,
script->filename(), script->lineno(),
thisFunctionIndex);
WriteEntry(lock, cur, blockStart - cur, "%s:%zu: Func%02" PRIu32 "-Block?",
script->filename(), script->lineno(), thisFunctionIndex);
}
cur = blockEnd;
size_t size = blockEnd - blockStart;
if (size > 0) {
fprintf(PerfFilePtr, "%" PRIxPTR " %zx %s:%d:%d: Func%02d-Block%d\n",
blockStart, size,
r.filename, r.lineNumber, r.columnNumber,
thisFunctionIndex, r.id);
WriteEntry(lock, blockStart, size, "%s:%u:%u: Func%02" PRIu32 "d-Block%" PRIu32,
r.filename, r.lineNumber, r.columnNumber, thisFunctionIndex, r.id);
}
}
MOZ_ASSERT(cur <= funcEndInlineCode);
if (cur < funcEndInlineCode) {
fprintf(PerfFilePtr, "%" PRIxPTR " %" PRIxPTR " %s:%zu: Func%02d-Epilogue\n",
cur, funcEndInlineCode - cur,
script->filename(), script->lineno(),
thisFunctionIndex);
WriteEntry(lock, cur, funcEndInlineCode - cur, "%s:%zu: Func%02" PRIu32 "-Epilogue",
script->filename(), script->lineno(), thisFunctionIndex);
}
MOZ_ASSERT(funcEndInlineCode <= funcEnd);
if (funcEndInlineCode < funcEnd) {
fprintf(PerfFilePtr, "%" PRIxPTR " %" PRIxPTR " %s:%zu: Func%02d-OOL\n",
funcEndInlineCode, funcEnd - funcEndInlineCode,
script->filename(), script->lineno(),
thisFunctionIndex);
WriteEntry(lock, funcEndInlineCode, funcEnd - funcEndInlineCode,
"%s:%zu: Func%02" PRIu32 "-OOL",
script->filename(), script->lineno(), thisFunctionIndex);
}
unlockPerfMap();
return;
}
}
@ -287,17 +276,12 @@ js::jit::writePerfSpewerBaselineProfile(JSScript* script, JitCode* code)
if (!PerfEnabled())
return;
if (!lockPerfMap())
return;
size_t size = code->instructionsSize();
if (size > 0) {
fprintf(PerfFilePtr, "%" PRIxPTR " %zx %s:%zu: Baseline\n",
reinterpret_cast<uintptr_t>(code->raw()),
size, script->filename(), script->lineno());
AutoLockPerfMap lock;
PerfSpewer::WriteEntry(lock, reinterpret_cast<uintptr_t>(code->raw()), size,
"%s:%zu: Baseline", script->filename(), script->lineno());
}
unlockPerfMap();
}
void
@ -306,34 +290,35 @@ js::jit::writePerfSpewerJitCodeProfile(JitCode* code, const char* msg)
if (!code || !PerfEnabled())
return;
if (!lockPerfMap())
return;
size_t size = code->instructionsSize();
if (size > 0) {
fprintf(PerfFilePtr, "%" PRIxPTR " %zx %s (%p 0x%zx)\n",
reinterpret_cast<uintptr_t>(code->raw()),
size, msg, code->raw(), size);
AutoLockPerfMap lock;
PerfSpewer::WriteEntry(lock, reinterpret_cast<uintptr_t>(code->raw()), size,
"%s (%p 0x%zx)", msg, code->raw(), size);
}
}
unlockPerfMap();
void
js::jit::writePerfSpewerWasmMap(uintptr_t base, uintptr_t size, const char* filename,
const char* annotation)
{
if (!PerfFuncEnabled() || size == 0U)
return;
AutoLockPerfMap lock;
PerfSpewer::WriteEntry(lock, base, size, "%s: Function %s", filename, annotation);
}
void
js::jit::writePerfSpewerWasmFunctionMap(uintptr_t base, uintptr_t size,
const char* filename, unsigned lineno, unsigned colIndex,
const char* filename, unsigned lineno,
const char* funcName)
{
if (!PerfFuncEnabled() || size == 0U)
return;
if (!lockPerfMap())
return;
fprintf(PerfFilePtr, "%" PRIxPTR " %" PRIxPTR " %s:%u:%u: Function %s\n",
base, size, filename, lineno, colIndex, funcName);
unlockPerfMap();
AutoLockPerfMap lock;
PerfSpewer::WriteEntry(lock, base, size, "%s:%u: Function %s", filename, lineno, funcName);
}
#endif // defined (JS_ION_PERF)

View File

@ -12,6 +12,10 @@
# include "jit/MacroAssembler.h"
#endif
namespace {
struct AutoLockPerfMap;
}
namespace js {
namespace jit {
@ -67,10 +71,14 @@ class PerfSpewer
public:
virtual MOZ_MUST_USE bool startBasicBlock(MBasicBlock* blk, MacroAssembler& masm);
virtual MOZ_MUST_USE bool endBasicBlock(MacroAssembler& masm);
MOZ_MUST_USE bool noteEndInlineCode(MacroAssembler& masm);
virtual void endBasicBlock(MacroAssembler& masm);
void noteEndInlineCode(MacroAssembler& masm);
void writeProfile(JSScript* script, JitCode* code, MacroAssembler& masm);
static void WriteEntry(const AutoLockPerfMap&, uintptr_t address, size_t size,
const char* fmt, ...)
MOZ_FORMAT_PRINTF(4, 5);
};
void writePerfSpewerBaselineProfile(JSScript* script, JitCode* code);
@ -81,11 +89,13 @@ class WasmPerfSpewer : public PerfSpewer
{
public:
MOZ_MUST_USE bool startBasicBlock(MBasicBlock* blk, MacroAssembler& masm) { return true; }
MOZ_MUST_USE bool endBasicBlock(MacroAssembler& masm) { return true; }
void endBasicBlock(MacroAssembler& masm) { }
};
void writePerfSpewerWasmMap(uintptr_t base, uintptr_t size, const char* filename,
const char* annotation);
void writePerfSpewerWasmFunctionMap(uintptr_t base, uintptr_t size, const char* filename,
unsigned lineno, unsigned colIndex, const char* funcName);
unsigned lineno, const char* funcName);
#endif // JS_ION_PERF

View File

@ -2136,6 +2136,58 @@ MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
breakpoint();
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs, Register src,
Register dest)
{
cmp32(lhs, rhs);
ma_mov(src, dest, LeaveCC, cond);
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, const Address& rhs, Register src,
Register dest)
{
ScratchRegisterScope scratch(*this);
SecondScratchRegisterScope scratch2(*this);
ma_ldr(rhs, scratch, scratch2);
cmp32Move32(cond, lhs, scratch, src, dest);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, Register length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length);
MOZ_ASSERT(length != scratch);
MOZ_ASSERT(index != scratch);
if (JitOptions.spectreIndexMasking)
move32(Imm32(0), scratch);
branch32(Assembler::BelowOrEqual, length, index, failure);
if (JitOptions.spectreIndexMasking)
ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, const Address& length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length.base);
MOZ_ASSERT(length.base != scratch);
MOZ_ASSERT(index != scratch);
if (JitOptions.spectreIndexMasking)
move32(Imm32(0), scratch);
branch32(Assembler::BelowOrEqual, length, index, failure);
if (JitOptions.spectreIndexMasking)
ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
}
// ========================================================================
// Memory access primitives.
void

View File

@ -1710,6 +1710,50 @@ MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
MOZ_CRASH("branchToComputedAddress");
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs, Register src,
Register dest)
{
cmp32(lhs, rhs);
Csel(ARMRegister(dest, 32), ARMRegister(src, 32), ARMRegister(dest, 32), cond);
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, const Address& rhs, Register src,
Register dest)
{
cmp32(lhs, rhs);
Csel(ARMRegister(dest, 32), ARMRegister(src, 32), ARMRegister(dest, 32), cond);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, Register length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length);
MOZ_ASSERT(length != scratch);
MOZ_ASSERT(index != scratch);
branch32(Assembler::BelowOrEqual, length, index, failure);
if (JitOptions.spectreIndexMasking)
Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr, Assembler::Above);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, const Address& length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length.base);
MOZ_ASSERT(length.base != scratch);
MOZ_ASSERT(index != scratch);
branch32(Assembler::BelowOrEqual, length, index, failure);
if (JitOptions.spectreIndexMasking)
Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr, Assembler::Above);
}
// ========================================================================
// Memory access primitives.
void

View File

@ -1022,6 +1022,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void cmp32(const Address& lhs, Register rhs) {
cmp32(Operand(lhs.base, lhs.offset), rhs);
}
void cmp32(Register lhs, const Address& rhs) {
cmp32(lhs, Operand(rhs.base, rhs.offset));
}
void cmp32(const Operand& lhs, Imm32 rhs) {
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch32 = temps.AcquireW();
@ -1034,6 +1037,12 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
Mov(scratch32, lhs);
Cmp(scratch32, Operand(ARMRegister(rhs, 32)));
}
void cmp32(Register lhs, const Operand& rhs) {
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch32 = temps.AcquireW();
Mov(scratch32, rhs);
Cmp(scratch32, Operand(ARMRegister(lhs, 32)));
}
void cmpPtr(Register lhs, Imm32 rhs) {
Cmp(ARMRegister(lhs, 64), Operand(rhs.value));

View File

@ -469,6 +469,10 @@ class AssemblerX86Shared : public AssemblerShared
MOZ_CRASH("unexpected operand kind");
}
}
void cmovCCl(Condition cond, Register src, Register dest) {
X86Encoding::Condition cc = static_cast<X86Encoding::Condition>(cond);
masm.cmovCCl_rr(cc, src.encoding(), dest.encoding());
}
void cmovzl(const Operand& src, Register dest) {
cmovCCl(Condition::Zero, src, dest);
}

View File

@ -1094,6 +1094,58 @@ MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label)
j(cond, label);
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs, Register src,
Register dest)
{
cmp32(lhs, rhs);
cmovCCl(cond, src, dest);
}
void
MacroAssembler::cmp32Move32(Condition cond, Register lhs, const Address& rhs, Register src,
Register dest)
{
cmp32(lhs, Operand(rhs));
cmovCCl(cond, src, dest);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, Register length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length);
MOZ_ASSERT(length != scratch);
MOZ_ASSERT(index != scratch);
if (JitOptions.spectreIndexMasking)
move32(Imm32(0), scratch);
cmp32(index, length);
j(Assembler::AboveOrEqual, failure);
if (JitOptions.spectreIndexMasking)
cmovCCl(Assembler::AboveOrEqual, scratch, index);
}
void
MacroAssembler::boundsCheck32ForLoad(Register index, const Address& length, Register scratch,
Label* failure)
{
MOZ_ASSERT(index != length.base);
MOZ_ASSERT(length.base != scratch);
MOZ_ASSERT(index != scratch);
if (JitOptions.spectreIndexMasking)
move32(Imm32(0), scratch);
cmp32(index, Operand(length));
j(Assembler::AboveOrEqual, failure);
if (JitOptions.spectreIndexMasking)
cmovCCl(Assembler::AboveOrEqual, scratch, index);
}
// ========================================================================
// Canonicalization primitives.
void

View File

@ -5843,6 +5843,14 @@ JS_AtomizeAndPinStringN(JSContext* cx, const char* s, size_t length)
return atom;
}
JS_PUBLIC_API(JSString*)
JS_NewLatin1String(JSContext* cx, JS::Latin1Char* chars, size_t length)
{
AssertHeapIsIdle();
CHECK_REQUEST(cx);
return NewString<CanGC>(cx, chars, length);
}
JS_PUBLIC_API(JSString*)
JS_NewUCString(JSContext* cx, char16_t* chars, size_t length)
{

View File

@ -4722,6 +4722,9 @@ JS_AtomizeAndPinStringN(JSContext* cx, const char* s, size_t length);
extern JS_PUBLIC_API(JSString*)
JS_AtomizeAndPinString(JSContext* cx, const char* s);
extern JS_PUBLIC_API(JSString*)
JS_NewLatin1String(JSContext* cx, JS::Latin1Char* chars, size_t length);
extern JS_PUBLIC_API(JSString*)
JS_NewUCString(JSContext* cx, char16_t* chars, size_t length);

View File

@ -211,7 +211,7 @@ JSString::dumpRepresentationHeader(js::GenericPrinter& out, int indent, const ch
if (flags & ATOM_BIT) out.put(" ATOM");
if (isPermanentAtom()) out.put(" PERMANENT");
if (flags & LATIN1_CHARS_BIT) out.put(" LATIN1");
if (flags & INDEX_VALUE_BIT) out.put(" INDEX_VALUE(%u)", getIndexValue());
if (flags & INDEX_VALUE_BIT) out.printf(" INDEX_VALUE(%u)", getIndexValue());
out.putChar('\n');
}

View File

@ -587,7 +587,8 @@ static const unsigned MaxParams = 1000;
static const unsigned MaxBrTableElems = 1000000;
static const unsigned MaxMemoryInitialPages = 16384;
static const unsigned MaxMemoryMaximumPages = 65536;
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
static const unsigned MaxCodeSectionBytes = 1024 * 1024 * 1024;
static const unsigned MaxModuleBytes = MaxCodeSectionBytes;
static const unsigned MaxFunctionBytes = 7654321;
// A magic value of the FramePointer to indicate after a return to the entry

View File

@ -139,6 +139,14 @@ StaticallyUnlink(uint8_t* base, const LinkDataTier& linkData)
}
}
#ifdef JS_ION_PERF
static bool
AppendToString(const char* str, UTF8Bytes* bytes)
{
return bytes->append(str, strlen(str)) && bytes->append('\0');
}
#endif
static void
SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata)
{
@ -153,18 +161,15 @@ SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Met
return;
for (const CodeRange& codeRange : metadata.metadata(cs.tier()).codeRanges) {
if (!codeRange.isFunction())
if (!codeRange.hasFuncIndex())
continue;
uintptr_t start = uintptr_t(cs.base() + codeRange.begin());
uintptr_t end = uintptr_t(cs.base() + codeRange.end());
uintptr_t size = end - start;
uintptr_t size = codeRange.end() - codeRange.begin();
UTF8Bytes name;
if (!metadata.getFuncName(&bytecode, codeRange.funcIndex(), &name))
return;
if (!name.append('\0'))
return;
// Avoid "unused" warnings
(void)start;
@ -173,14 +178,36 @@ SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Met
#ifdef JS_ION_PERF
if (PerfFuncEnabled()) {
const char* file = metadata.filename.get();
unsigned line = codeRange.funcLineOrBytecode();
unsigned column = 0;
writePerfSpewerWasmFunctionMap(start, size, file, line, column, name.begin());
if (codeRange.isFunction()) {
if (!name.append('\0'))
return;
unsigned line = codeRange.funcLineOrBytecode();
writePerfSpewerWasmFunctionMap(start, size, file, line, name.begin());
} else if (codeRange.isInterpEntry()) {
if (!AppendToString(" slow entry", &name))
return;
writePerfSpewerWasmMap(start, size, file, name.begin());
} else if (codeRange.isImportInterpExit()) {
if (!AppendToString(" slow exit", &name))
return;
writePerfSpewerWasmMap(start, size, file, name.begin());
} else if (codeRange.isImportJitExit()) {
if (!AppendToString(" fast exit", &name))
return;
writePerfSpewerWasmMap(start, size, file, name.begin());
} else {
MOZ_CRASH("unhandled perf hasFuncIndex type");
}
}
#endif
#ifdef MOZ_VTUNE
if (vtune::IsProfilingActive())
vtune::MarkWasm(vtune::GenerateUniqueMethodID(), name.begin(), (void*)start, size);
if (!vtune::IsProfilingActive())
continue;
if (!codeRange.isFunction())
continue;
if (!name.append('\0'))
return;
vtune::MarkWasm(vtune::GenerateUniqueMethodID(), name.begin(), (void*)start, size);
#endif
}
}

View File

@ -211,9 +211,9 @@ ModuleGenerator::init(Metadata* maybeAsmJSMetadata)
// extra conservative. Note, podResizeToFit calls at the end will trim off
// unneeded capacity.
uint32_t codeSectionSize = env_->codeSection ? env_->codeSection->size : 0;
if (!masm_.reserve(size_t(1.2 * EstimateCompiledCodeSize(tier(), codeSectionSize))))
size_t codeSectionSize = env_->codeSection ? env_->codeSection->size : 0;
size_t estimatedCodeSize = 1.2 * EstimateCompiledCodeSize(tier(), codeSectionSize);
if (!masm_.reserve(Min(estimatedCodeSize, MaxCodeBytesPerProcess)))
return false;
if (!metadataTier_->codeRanges.reserve(2 * env_->numFuncDefs()))
@ -782,7 +782,7 @@ ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
}
batchedBytecode_ += funcBytecodeLength;
MOZ_ASSERT(batchedBytecode_ <= MaxModuleBytes);
MOZ_ASSERT(batchedBytecode_ <= MaxCodeSectionBytes);
return batchedBytecode_ <= threshold || launchBatchCompile();
}

View File

@ -2518,7 +2518,7 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
if (extraBytes)
envBytes_.shrinkTo(codeSection_.start);
if (codeSection_.size > MaxModuleBytes)
if (codeSection_.size > MaxCodeSectionBytes)
return rejectAndDestroyBeforeHelperThreadStarted(JSMSG_OUT_OF_MEMORY);
if (!codeBytes_.resize(codeSection_.size))

View File

@ -1126,9 +1126,15 @@ class CodeRange
bool isFunction() const {
return kind() == Function;
}
bool isInterpEntry() const {
return kind() == InterpEntry;
}
bool isImportExit() const {
return kind() == ImportJitExit || kind() == ImportInterpExit || kind() == BuiltinThunk;
}
bool isImportInterpExit() const {
return kind() == ImportInterpExit;
}
bool isImportJitExit() const {
return kind() == ImportJitExit;
}

View File

@ -1722,6 +1722,9 @@ wasm::DecodeModuleEnvironment(Decoder& d, ModuleEnvironment* env)
if (!d.startSection(SectionId::Code, env, &env->codeSection, "code"))
return false;
if (env->codeSection && env->codeSection->size > MaxCodeSectionBytes)
return d.fail("code section too big");
return true;
}

View File

@ -1,29 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Testcase for invalid path</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=601699 -->
<marker id="marker" markerWidth="10" markerHeight="10">
<circle cx="5" cy="5" r="5"/>
</marker>
<rect width="100%" height="100%" fill="lime"/>
<path id="path" fill="red" marker-mid="url(#marker)"/>
<script><![CDATA[
// Parser will throw out path without an initial moveto command, so we use
// script to inject one and see what happens.
var path = document.getElementById("path");
var curve = path.createSVGPathSegCurvetoCubicAbs(0, 400, 400, 400, 400, 0);
path.pathSegList.appendItem(curve);
]]></script>
</svg>

Before

Width:  |  Height:  |  Size: 808 B

View File

@ -340,7 +340,6 @@ pref(svg.paint-order.enabled,true) == paint-order-03.svg paint-order-03-ref.svg
#fuzzy(23,60) fails-if(d2d) == path-01.svg path-01-ref.svg
== path-02.svg pass.svg
== path-03.svg pass.svg
== path-04.svg pass.svg
== path-05.svg pass.svg
fuzzy-if(skiaContent,1,400) == path-06.svg path-06-ref.svg

View File

@ -1,17 +0,0 @@
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=327709 -->
<!-- Just checking for absence of assertion, nothing more -->
<svg xmlns="http://www.w3.org/2000/svg">
<script>
function init()
{
var apsl = document.getElementById("n126").animatedPathSegList;
apsl.appendItem(apsl.__proto__);
}
window.addEventListener("load", init, false);
</script>
<path id="n126" d="M 270 60 L 320 60 L 320 110 Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 418 B

View File

@ -15,7 +15,6 @@ load 325427-1.svg
load 326495-1.svg
load 326974-1.svg
load 327706-1.svg
load 327709-1.svg
load 327711-1.svg
load 328137-1.svg
load 329848-1.svg

View File

@ -1549,7 +1549,7 @@ pref("javascript.options.throw_on_debuggee_would_run", false);
pref("javascript.options.dump_stack_on_debuggee_would_run", false);
// Spectre security vulnerability mitigations.
pref("javascript.options.spectre.index_masking", false);
pref("javascript.options.spectre.index_masking", true);
// Streams API
pref("javascript.options.streams", false);

View File

@ -1,7 +1,4 @@
[historical.html]
[SVGPathSeg interface must be removed]
expected: FAIL
[SVGUnitTypes mixin interface must not be exposed]
expected: FAIL