mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
4f4600f00c
@ -191,6 +191,82 @@ let OutputGenerator = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds math roles to the output, for a MathML accessible.
|
||||
* @param {Array} aOutput Output array.
|
||||
* @param {nsIAccessible} aAccessible current accessible object.
|
||||
* @param {String} aRoleStr aAccessible's role string.
|
||||
*/
|
||||
_addMathRoles: function _addMathRoles(aOutput, aAccessible, aRoleStr) {
|
||||
// First, determine the actual role to use (e.g. mathmlfraction).
|
||||
let roleStr = aRoleStr;
|
||||
switch(aAccessible.role) {
|
||||
case Roles.MATHML_CELL:
|
||||
case Roles.MATHML_ENCLOSED:
|
||||
case Roles.MATHML_LABELED_ROW:
|
||||
case Roles.MATHML_ROOT:
|
||||
case Roles.MATHML_SQUARE_ROOT:
|
||||
case Roles.MATHML_TABLE:
|
||||
case Roles.MATHML_TABLE_ROW:
|
||||
// Use the default role string.
|
||||
break;
|
||||
case Roles.MATHML_MULTISCRIPTS:
|
||||
case Roles.MATHML_OVER:
|
||||
case Roles.MATHML_SUB:
|
||||
case Roles.MATHML_SUB_SUP:
|
||||
case Roles.MATHML_SUP:
|
||||
case Roles.MATHML_UNDER:
|
||||
case Roles.MATHML_UNDER_OVER:
|
||||
// For scripted accessibles, use the string 'mathmlscripted'.
|
||||
roleStr = 'mathmlscripted';
|
||||
break;
|
||||
case Roles.MATHML_FRACTION:
|
||||
// From a semantic point of view, the only important point is to
|
||||
// distinguish between fractions that have a bar and those that do not.
|
||||
// Per the MathML 3 spec, the latter happens iff the linethickness
|
||||
// attribute is of the form [zero-float][optional-unit]. In that case,
|
||||
// we use the string 'mathmlfractionwithoutbar'.
|
||||
let linethickness = Utils.getAttributes(aAccessible).linethickness;
|
||||
if (linethickness) {
|
||||
let numberMatch = linethickness.match(/^(?:\d|\.)+/);
|
||||
if (numberMatch && !parseFloat(numberMatch[0])) {
|
||||
roleStr += 'withoutbar';
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Otherwise, do not output the actual role.
|
||||
roleStr = null;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the math role based on the position in the parent accessible
|
||||
// (e.g. numerator for the first child of a mathmlfraction).
|
||||
let mathRole = Utils.getMathRole(aAccessible);
|
||||
if (mathRole) {
|
||||
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift']
|
||||
({string: this._getOutputName(mathRole)});
|
||||
}
|
||||
if (roleStr) {
|
||||
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift']
|
||||
({string: this._getOutputName(roleStr)});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds MathML menclose notations to the output.
|
||||
* @param {Array} aOutput Output array.
|
||||
* @param {nsIAccessible} aAccessible current accessible object.
|
||||
*/
|
||||
_addMencloseNotations: function _addMencloseNotations(aOutput, aAccessible) {
|
||||
let notations = Utils.getAttributes(aAccessible).notation || 'longdiv';
|
||||
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift'].apply(
|
||||
aOutput, [for (notation of notations.split(' '))
|
||||
{string: this._getOutputName('notation-' + notation)}
|
||||
]
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an entry type attribute to the description if available.
|
||||
* @param {Array} aOutput Output array.
|
||||
@ -212,7 +288,7 @@ let OutputGenerator = {
|
||||
|
||||
_addState: function _addState(aOutput, aState, aRoleStr) {}, // jshint ignore:line
|
||||
|
||||
_addRole: function _addRole(aOutput, aRoleStr) {}, // jshint ignore:line
|
||||
_addRole: function _addRole(aOutput, aAccessible, aRoleStr) {}, // jshint ignore:line
|
||||
|
||||
get outputOrder() {
|
||||
if (!this._utteranceOrder) {
|
||||
@ -301,7 +377,67 @@ let OutputGenerator = {
|
||||
'dialog': INCLUDE_DESC | INCLUDE_NAME,
|
||||
'chrome window': IGNORE_EXPLICIT_NAME,
|
||||
'app root': IGNORE_EXPLICIT_NAME,
|
||||
'statusbar': NAME_FROM_SUBTREE_RULE },
|
||||
'statusbar': NAME_FROM_SUBTREE_RULE,
|
||||
'mathml table': INCLUDE_DESC | INCLUDE_NAME,
|
||||
'mathml labeled row': NAME_FROM_SUBTREE_RULE,
|
||||
'mathml table row': NAME_FROM_SUBTREE_RULE,
|
||||
'mathml cell': INCLUDE_DESC | INCLUDE_NAME,
|
||||
'mathml fraction': INCLUDE_DESC,
|
||||
'mathml square root': INCLUDE_DESC,
|
||||
'mathml root': INCLUDE_DESC,
|
||||
'mathml enclosed': INCLUDE_DESC,
|
||||
'mathml sub': INCLUDE_DESC,
|
||||
'mathml sup': INCLUDE_DESC,
|
||||
'mathml sub sup': INCLUDE_DESC,
|
||||
'mathml under': INCLUDE_DESC,
|
||||
'mathml over': INCLUDE_DESC,
|
||||
'mathml under over': INCLUDE_DESC,
|
||||
'mathml multiscripts': INCLUDE_DESC,
|
||||
'mathml identifier': INCLUDE_DESC,
|
||||
'mathml number': INCLUDE_DESC,
|
||||
'mathml operator': INCLUDE_DESC,
|
||||
'mathml text': INCLUDE_DESC,
|
||||
'mathml string literal': INCLUDE_DESC,
|
||||
'mathml row': INCLUDE_DESC,
|
||||
'mathml style': INCLUDE_DESC,
|
||||
'mathml error': INCLUDE_DESC },
|
||||
|
||||
mathmlRolesSet: new Set([
|
||||
Roles.MATHML_MATH,
|
||||
Roles.MATHML_IDENTIFIER,
|
||||
Roles.MATHML_NUMBER,
|
||||
Roles.MATHML_OPERATOR,
|
||||
Roles.MATHML_TEXT,
|
||||
Roles.MATHML_STRING_LITERAL,
|
||||
Roles.MATHML_GLYPH,
|
||||
Roles.MATHML_ROW,
|
||||
Roles.MATHML_FRACTION,
|
||||
Roles.MATHML_SQUARE_ROOT,
|
||||
Roles.MATHML_ROOT,
|
||||
Roles.MATHML_FENCED,
|
||||
Roles.MATHML_ENCLOSED,
|
||||
Roles.MATHML_STYLE,
|
||||
Roles.MATHML_SUB,
|
||||
Roles.MATHML_SUP,
|
||||
Roles.MATHML_SUB_SUP,
|
||||
Roles.MATHML_UNDER,
|
||||
Roles.MATHML_OVER,
|
||||
Roles.MATHML_UNDER_OVER,
|
||||
Roles.MATHML_MULTISCRIPTS,
|
||||
Roles.MATHML_TABLE,
|
||||
Roles.LABELED_ROW,
|
||||
Roles.MATHML_TABLE_ROW,
|
||||
Roles.MATHML_CELL,
|
||||
Roles.MATHML_ACTION,
|
||||
Roles.MATHML_ERROR,
|
||||
Roles.MATHML_STACK,
|
||||
Roles.MATHML_LONG_DIVISION,
|
||||
Roles.MATHML_STACK_GROUP,
|
||||
Roles.MATHML_STACK_ROW,
|
||||
Roles.MATHML_STACK_CARRIES,
|
||||
Roles.MATHML_STACK_CARRY,
|
||||
Roles.MATHML_STACK_LINE
|
||||
]),
|
||||
|
||||
objectOutputFunctions: {
|
||||
_generateBaseOutput:
|
||||
@ -311,7 +447,7 @@ let OutputGenerator = {
|
||||
if (aFlags & INCLUDE_DESC) {
|
||||
this._addState(output, aState, aRoleStr);
|
||||
this._addType(output, aAccessible, aRoleStr);
|
||||
this._addRole(output, aRoleStr);
|
||||
this._addRole(output, aAccessible, aRoleStr);
|
||||
}
|
||||
|
||||
if (aFlags & INCLUDE_VALUE && aAccessible.value.trim()) {
|
||||
@ -348,7 +484,7 @@ let OutputGenerator = {
|
||||
aAccessible.groupPosition({}, itemof, itemno);
|
||||
let output = [];
|
||||
this._addState(output, aState);
|
||||
this._addRole(output, aRoleStr);
|
||||
this._addRole(output, aAccessible, aRoleStr);
|
||||
output.push({
|
||||
string: 'objItemOfN',
|
||||
args: [itemno.value, itemof.value]
|
||||
@ -374,7 +510,7 @@ let OutputGenerator = {
|
||||
if (table.isProbablyForLayout()) {
|
||||
return output;
|
||||
}
|
||||
this._addRole(output, aRoleStr);
|
||||
this._addRole(output, aAccessible, aRoleStr);
|
||||
output.push.call(output, {
|
||||
string: this._getOutputName('tblColumnInfo'),
|
||||
count: table.columnCount
|
||||
@ -394,6 +530,23 @@ let OutputGenerator = {
|
||||
this._addName(output, aAccessible, aFlags);
|
||||
this._addLandmark(output, aAccessible);
|
||||
return output;
|
||||
},
|
||||
|
||||
// Use the table output functions for MathML tabular elements.
|
||||
mathmltable: function mathmltable() {
|
||||
return this.objectOutputFunctions.table.apply(this, arguments);
|
||||
},
|
||||
|
||||
mathmlcell: function mathmlcell() {
|
||||
return this.objectOutputFunctions.cell.apply(this, arguments);
|
||||
},
|
||||
|
||||
mathmlenclosed: function mathmlenclosed(aAccessible, aRoleStr, aState,
|
||||
aFlags, aContext) {
|
||||
let output = this.objectOutputFunctions.defaultFunc.
|
||||
apply(this, [aAccessible, aRoleStr, aState, aFlags, aContext]);
|
||||
this._addMencloseNotations(output, aAccessible);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -597,8 +750,12 @@ this.UtteranceGenerator = { // jshint ignore:line
|
||||
return aContext.newAncestry;
|
||||
},
|
||||
|
||||
_addRole: function _addRole(aOutput, aRoleStr) {
|
||||
aOutput.push({string: this._getOutputName(aRoleStr)});
|
||||
_addRole: function _addRole(aOutput, aAccessible, aRoleStr) {
|
||||
if (this.mathmlRolesSet.has(aAccessible.role)) {
|
||||
this._addMathRoles(aOutput, aAccessible, aRoleStr);
|
||||
} else {
|
||||
aOutput.push({string: this._getOutputName(aRoleStr)});
|
||||
}
|
||||
},
|
||||
|
||||
_addState: function _addState(aOutput, aState, aRoleStr) {
|
||||
@ -657,7 +814,7 @@ this.UtteranceGenerator = { // jshint ignore:line
|
||||
_getListUtterance:
|
||||
function _getListUtterance(aAccessible, aRoleStr, aFlags, aItemCount) {
|
||||
let utterance = [];
|
||||
this._addRole(utterance, aRoleStr);
|
||||
this._addRole(utterance, aAccessible, aRoleStr);
|
||||
utterance.push({
|
||||
string: this._getOutputName('listItemsCount'),
|
||||
count: aItemCount
|
||||
@ -805,8 +962,12 @@ this.BrailleGenerator = { // jshint ignore:line
|
||||
return OutputGenerator._getOutputName(aName) + 'Abbr';
|
||||
},
|
||||
|
||||
_addRole: function _addRole(aBraille, aRoleStr) {
|
||||
aBraille.push({string: this._getOutputName(aRoleStr)});
|
||||
_addRole: function _addRole(aBraille, aAccessible, aRoleStr) {
|
||||
if (this.mathmlRolesSet.has(aAccessible.role)) {
|
||||
this._addMathRoles(aBraille, aAccessible, aRoleStr);
|
||||
} else {
|
||||
aBraille.push({string: this._getOutputName(aRoleStr)});
|
||||
}
|
||||
},
|
||||
|
||||
_addState: function _addState(aBraille, aState, aRoleStr) {
|
||||
|
@ -102,7 +102,8 @@ var gSimpleTraversalRoles =
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.STATUSBAR,
|
||||
Roles.SWITCH];
|
||||
Roles.SWITCH,
|
||||
Roles.MATHML_MATH];
|
||||
|
||||
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
|
||||
// An object is simple, if it either has a single child lineage,
|
||||
|
@ -415,21 +415,41 @@ this.Utils = { // jshint ignore:line
|
||||
},
|
||||
|
||||
getLandmarkName: function getLandmarkName(aAccessible) {
|
||||
const landmarks = [
|
||||
return this.matchRoles(aAccessible, [
|
||||
'banner',
|
||||
'complementary',
|
||||
'contentinfo',
|
||||
'main',
|
||||
'navigation',
|
||||
'search'
|
||||
];
|
||||
]);
|
||||
},
|
||||
|
||||
getMathRole: function getMathRole(aAccessible) {
|
||||
return this.matchRoles(aAccessible, [
|
||||
'base',
|
||||
'close-fence',
|
||||
'denominator',
|
||||
'numerator',
|
||||
'open-fence',
|
||||
'overscript',
|
||||
'presubscript',
|
||||
'presuperscript',
|
||||
'root-index',
|
||||
'subscript',
|
||||
'superscript',
|
||||
'underscript'
|
||||
]);
|
||||
},
|
||||
|
||||
matchRoles: function matchRoles(aAccessible, aRoles) {
|
||||
let roles = this.getAttributes(aAccessible)['xml-roles'];
|
||||
if (!roles) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Looking up a role that would match a landmark.
|
||||
return this.matchAttributeValue(roles, landmarks);
|
||||
// Looking up a role that would match any in the provided roles.
|
||||
return this.matchAttributeValue(roles, aRoles);
|
||||
},
|
||||
|
||||
getEmbeddedControl: function getEmbeddedControl(aLabel) {
|
||||
@ -884,8 +904,12 @@ PivotContext.prototype = {
|
||||
if (!aAccessible) {
|
||||
return null;
|
||||
}
|
||||
if ([Roles.CELL, Roles.COLUMNHEADER, Roles.ROWHEADER].indexOf(
|
||||
aAccessible.role) < 0) {
|
||||
if ([
|
||||
Roles.CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.MATHML_CELL
|
||||
].indexOf(aAccessible.role) < 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
@ -950,7 +974,9 @@ PivotContext.prototype = {
|
||||
cellInfo.current.columnHeaderCells))];
|
||||
}
|
||||
cellInfo.rowHeaders = [];
|
||||
if (cellInfo.rowChanged && cellInfo.current.role === Roles.CELL) {
|
||||
if (cellInfo.rowChanged &&
|
||||
(cellInfo.current.role === Roles.CELL ||
|
||||
cellInfo.current.role === Roles.MATHML_CELL)) {
|
||||
cellInfo.rowHeaders = [headers for (headers of getHeaders( // jshint ignore:line
|
||||
cellInfo.current.rowHeaderCells))];
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ skip-if = buildapp == 'mulet'
|
||||
[test_hints.html]
|
||||
[test_landmarks.html]
|
||||
[test_live_regions.html]
|
||||
[test_output_mathml.html]
|
||||
[test_output.html]
|
||||
[test_quicknav_modes.html]
|
||||
[test_tables.html]
|
||||
|
@ -145,5 +145,11 @@
|
||||
<div aria-label="Last sync: 30min ago" id="statusbar-2" role="status"></div>
|
||||
|
||||
<span id="switch-1" role="switch" aria-checked="false" aria-label="Light switch"></span>
|
||||
<p>This is a MathML formula <math id="math-1" display="block">
|
||||
<mfrac>
|
||||
<mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>
|
||||
<msqrt><mn>3</mn><mo>/</mo><mn>4</mn></msqrt>
|
||||
</mfrac>
|
||||
</math> with some text after.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
305
accessible/tests/mochitest/jsat/test_output_mathml.html
Normal file
305
accessible/tests/mochitest/jsat/test_output_mathml.html
Normal file
@ -0,0 +1,305 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>[AccessFu] MathML Accessibility Support</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="output.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest() {
|
||||
// Test the following accOrElmOrID.
|
||||
var tests = [{
|
||||
accOrElmOrID: "math-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"open-fence"},"(","x",",","y",{"string":"close-fence"},")"],
|
||||
["(",{"string":"open-fence"},"x",",","y",")",{"string":"close-fence"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"open-fenceAbbr"},"(","x",",","y",{"string":"close-fenceAbbr"},")"],
|
||||
["(",{"string":"open-fenceAbbr"},"x",",","y",")",{"string":"close-fenceAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mfrac-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlfraction"},{"string":"numerator"},"a",{"string":"denominator"},"b"],
|
||||
["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfraction"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlfractionAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"],
|
||||
["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mfrac-2",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlfractionwithoutbar"},{"string":"numerator"},"a",{"string":"denominator"},"b"],
|
||||
["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfractionwithoutbar"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlfractionwithoutbarAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"],
|
||||
["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionwithoutbarAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "msub-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b"],
|
||||
["a",{"string":"base"},"b",{"string":"subscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "msup-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"superscript"},"b"],
|
||||
["a",{"string":"base"},"b",{"string":"superscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"superscriptAbbr"},"b"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "msubsup-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c"],
|
||||
["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mmultiscripts-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c",{"string":"superscript"},"d",{"string":"presubscript"},"e",{"string":"presubscript"},"f",{"string":"presuperscript"},"g"],
|
||||
["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},"d",{"string":"superscript"},"e",{"string":"presubscript"},"f",{"string":"presubscript"},"g",{"string":"presuperscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"presubscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presuperscriptAbbr"},"g"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"superscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presubscriptAbbr"},"g",{"string":"presuperscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "munder-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b"],
|
||||
["a",{"string":"base"},"b",{"string":"underscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mover-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"overscript"},"b"],
|
||||
["a",{"string":"base"},"b",{"string":"overscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"overscriptAbbr"},"b"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "munderover-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b",{"string":"overscript"},"c"],
|
||||
["a",{"string":"base"},"b",{"string":"underscript"},"c",{"string":"overscript"},{"string":"mathmlscripted"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b",{"string":"overscriptAbbr"},"c"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},"c",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mroot-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlroot"},{"string":"base"},"a",{"string":"root-index"},"b"],
|
||||
["a",{"string":"base"},"b",{"string":"root-index"},{"string":"mathmlroot"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlrootAbbr"},{"string":"baseAbbr"},"a",{"string":"root-indexAbbr"},"b"],
|
||||
["a",{"string":"baseAbbr"},"b",{"string":"root-indexAbbr"},{"string":"mathmlrootAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "mtable-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2},{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"a",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"d",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},"f"],
|
||||
["a",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"d",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"f",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2},{"string":"cellInfoAbbr","args":[1,1]},"a",{"string":"cellInfoAbbr","args":[2,1]},"b",{"string":"cellInfoAbbr","args":[3,1]},"c",{"string":"cellInfoAbbr","args":[1,2]},"d",{"string":"cellInfoAbbr","args":[2,2]},"e",{"string":"cellInfoAbbr","args":[3,2]},"f"],
|
||||
["a",{"string":"cellInfoAbbr","args":[1,1]},"b",{"string":"cellInfoAbbr","args":[2,1]},"c",{"string":"cellInfoAbbr","args":[3,1]},"d",{"string":"cellInfoAbbr","args":[1,2]},"e",{"string":"cellInfoAbbr","args":[2,2]},"f",{"string":"cellInfoAbbr","args":[3,2]},{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "menclose-1",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlenclosed"},{"string":"notation-longdiv"},"a"],
|
||||
["a",{"string":"notation-longdiv"},{"string":"mathmlenclosed"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlenclosedAbbr"},{"string":"notation-longdivAbbr"},"a"],
|
||||
["a",{"string":"notation-longdivAbbr"},{"string":"mathmlenclosedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "menclose-2",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlenclosed"},{"string":"notation-circle"},"a"],
|
||||
["a",{"string":"notation-circle"},{"string":"mathmlenclosed"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlenclosedAbbr"},{"string":"notation-circleAbbr"},"a"],
|
||||
["a",{"string":"notation-circleAbbr"},{"string":"mathmlenclosedAbbr"}]
|
||||
]
|
||||
}, {
|
||||
accOrElmOrID: "menclose-3",
|
||||
expectedUtterance: [
|
||||
[{"string":"mathmlenclosed"},{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},"a"],
|
||||
["a",{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},{"string":"mathmlenclosed"}]
|
||||
],
|
||||
expectedBraille: [
|
||||
[{"string":"mathmlenclosedAbbr"},{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},"a"],
|
||||
["a",{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},{"string":"mathmlenclosedAbbr"}]
|
||||
]
|
||||
}];
|
||||
|
||||
// Test all possible utterance order preference values.
|
||||
tests.forEach(function run(test) {
|
||||
var outputOrderValues = [0, 1];
|
||||
outputOrderValues.forEach(function testOutputOrder(outputOrder) {
|
||||
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, outputOrder);
|
||||
testOutput(test.expectedUtterance[outputOrder], test.accOrElmOrID,
|
||||
test.oldAccOrElmOrID, 1);
|
||||
testOutput(test.expectedBraille[outputOrder], test.accOrElmOrID,
|
||||
test.oldAccOrElmOrID, 0);
|
||||
});
|
||||
});
|
||||
|
||||
// If there was an original utterance order preference, revert to it.
|
||||
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1163374"
|
||||
title="[AccessFu] MathML Accessibility Support">
|
||||
Mozilla Bug 1163374
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
|
||||
<math id="math-1"><mo>(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>)</mo></math>
|
||||
|
||||
<math>
|
||||
<mfrac id="mfrac-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</mfrac>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<mfrac id="mfrac-2" linethickness="0px">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</mfrac>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<msub id="msub-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</msub>
|
||||
</math>
|
||||
<math>
|
||||
<msup id="msup-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</msup>
|
||||
</math>
|
||||
<math>
|
||||
<msubsup id="msubsup-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
<mi>c</mi>
|
||||
</msubsup>
|
||||
</math>
|
||||
<math>
|
||||
<mmultiscripts id="mmultiscripts-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
<mi>c</mi>
|
||||
<none/>
|
||||
<mi>d</mi>
|
||||
<mprescripts/>
|
||||
<mi>e</mi>
|
||||
<none/>
|
||||
<mi>f</mi>
|
||||
<mi>g</mi>
|
||||
</mmultiscripts>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<munder id="munder-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</munder>
|
||||
</math>
|
||||
<math>
|
||||
<mover id="mover-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</mover>
|
||||
</math>
|
||||
<math>
|
||||
<munderover id="munderover-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
<mi>c</mi>
|
||||
</munderover>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<mroot id="mroot-1">
|
||||
<mi>a</mi>
|
||||
<mi>b</mi>
|
||||
</mroot>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<mtable id="mtable-1">
|
||||
<mtr>
|
||||
<mtd><mi>a</mi></mtd>
|
||||
<mtd><mi>b</mi></mtd>
|
||||
<mtd><mi>c</mi></mtd>
|
||||
</mtr>
|
||||
<mtr>
|
||||
<mtd><mi>d</mi></mtd>
|
||||
<mtd><mi>e</mi></mtd>
|
||||
<mtd><mi>f</mi></mtd>
|
||||
</mtr>
|
||||
</mtable>
|
||||
</math>
|
||||
|
||||
<math>
|
||||
<menclose id="menclose-1"><mi>a</mi></menclose>
|
||||
</math>
|
||||
<math>
|
||||
<menclose id="menclose-2" notation="circle"><mi>a</mi></menclose>
|
||||
</math>
|
||||
<math>
|
||||
<menclose id="menclose-3" notation="left top bottom"><mi>a</mi></menclose>
|
||||
</math>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -124,7 +124,8 @@
|
||||
'5 8', 'gridcell4', 'Just an innocuous separator',
|
||||
'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
|
||||
'Dirt', 'Messy Stuff', 'statusbar-1', 'statusbar-2',
|
||||
'switch-1']);
|
||||
'switch-1', 'This is a MathML formula ', 'math-1',
|
||||
'with some text after.']);
|
||||
|
||||
gQueue.invoke();
|
||||
}
|
||||
|
@ -5610,11 +5610,24 @@ function handleLinkClick(event, href, linkNode) {
|
||||
catch (e) { }
|
||||
}
|
||||
|
||||
// first get document wide referrer policy, then
|
||||
// get referrer attribute from clicked link and parse it and
|
||||
// allow per element referrer to overrule the document wide referrer if enabled
|
||||
let referrerPolicy = doc.referrerPolicy;
|
||||
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
|
||||
linkNode) {
|
||||
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
|
||||
getAttribute("referrer"));
|
||||
if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
|
||||
referrerPolicy = referrerAttrValue;
|
||||
}
|
||||
}
|
||||
|
||||
urlSecurityCheck(href, doc.nodePrincipal);
|
||||
let params = { charset: doc.characterSet,
|
||||
allowMixedContent: persistAllowMixedContentInChildTab,
|
||||
referrerURI: referrerURI,
|
||||
referrerPolicy: doc.referrerPolicy,
|
||||
referrerPolicy: referrerPolicy,
|
||||
noReferrer: BrowserUtils.linkHasNoReferrer(linkNode) };
|
||||
openLinkIn(href, where, params);
|
||||
event.preventDefault();
|
||||
|
@ -105,6 +105,17 @@ let handleContentContextMenu = function (event) {
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.outerWindowID;
|
||||
|
||||
// get referrer attribute from clicked link and parse it
|
||||
// if per element referrer is enabled, the element referrer overrules
|
||||
// the document wide referrer
|
||||
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
|
||||
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
|
||||
getAttribute("referrer"));
|
||||
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
|
||||
referrerPolicy = referrerAttrValue;
|
||||
}
|
||||
}
|
||||
|
||||
let disableSetDesktopBg = null;
|
||||
// Media related cache info parent needs for saving
|
||||
let contentType = null;
|
||||
@ -351,10 +362,23 @@ let ClickEventHandler = {
|
||||
|
||||
let [href, node] = this._hrefAndLinkNodeForClickEvent(event);
|
||||
|
||||
// get referrer attribute from clicked link and parse it
|
||||
// if per element referrer is enabled, the element referrer overrules
|
||||
// the document wide referrer
|
||||
let referrerPolicy = ownerDoc.referrerPolicy;
|
||||
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
|
||||
node) {
|
||||
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
|
||||
getAttribute("referrer"));
|
||||
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
|
||||
referrerPolicy = referrerAttrValue;
|
||||
}
|
||||
}
|
||||
|
||||
let json = { button: event.button, shiftKey: event.shiftKey,
|
||||
ctrlKey: event.ctrlKey, metaKey: event.metaKey,
|
||||
altKey: event.altKey, href: null, title: null,
|
||||
bookmark: false, referrerPolicy: ownerDoc.referrerPolicy };
|
||||
bookmark: false, referrerPolicy: referrerPolicy };
|
||||
|
||||
if (href) {
|
||||
try {
|
||||
|
@ -180,6 +180,11 @@ bool isIgnoredPathForImplicitCtor(const Decl *decl) {
|
||||
begin->compare_lower(StringRef("graphite2")) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (begin->compare_lower(StringRef("chromium")) == 0) {
|
||||
// Ignore security/sandbox/chromium but not ipc/chromium.
|
||||
++begin;
|
||||
return begin != end && begin->compare_lower(StringRef("sandbox")) == 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -77,6 +77,7 @@
|
||||
#include "IHistory.h"
|
||||
#include "nsViewSourceHandler.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
#include "nsICookieService.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
// so we can associate the document URI with the load group.
|
||||
@ -207,10 +208,6 @@
|
||||
#endif
|
||||
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
// Values for the network.cookie.cookieBehavior pref are documented in
|
||||
// nsCookieService.cpp
|
||||
#define COOKIE_BEHAVIOR_ACCEPT 0 // Allow all cookies.
|
||||
#define COOKIE_BEHAVIOR_REJECT_FOREIGN 1 // Reject all third-party cookies.
|
||||
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
@ -13509,6 +13506,16 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
|
||||
nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
|
||||
uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
|
||||
|
||||
// get referrer attribute from clicked link and parse it
|
||||
// if per element referrer is enabled, the element referrer overrules
|
||||
// the document wide referrer
|
||||
if (IsElementAnchor(aContent)) {
|
||||
net::ReferrerPolicy refPolEnum = aContent->AsElement()->GetReferrerPolicy();
|
||||
if (refPolEnum != net::RP_Unset) {
|
||||
refererPolicy = refPolEnum;
|
||||
}
|
||||
}
|
||||
|
||||
// referer could be null here in some odd cases, but that's ok,
|
||||
// we'll just load the link w/o sending a referer in those cases.
|
||||
|
||||
@ -14068,8 +14075,8 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate,
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
if (isThirdPartyURI &&
|
||||
(Preferences::GetInt("network.cookie.cookieBehavior",
|
||||
COOKIE_BEHAVIOR_ACCEPT) ==
|
||||
COOKIE_BEHAVIOR_REJECT_FOREIGN)) {
|
||||
nsICookieService::BEHAVIOR_ACCEPT) ==
|
||||
nsICookieService::BEHAVIOR_REJECT_FOREIGN)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -20,46 +20,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationTimeline)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
namespace {
|
||||
struct AddAnimationParams {
|
||||
AnimationTimeline::AnimationSequence& mSequence;
|
||||
#ifdef DEBUG
|
||||
// This is only used for a pointer-equality assertion
|
||||
AnimationTimeline* mTimeline;
|
||||
#endif
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static PLDHashOperator
|
||||
AppendAnimationToSequence(nsRefPtrHashKey<dom::Animation>* aKey,
|
||||
void* aParams)
|
||||
{
|
||||
Animation* animation = aKey->GetKey();
|
||||
AddAnimationParams* params = static_cast<AddAnimationParams*>(aParams);
|
||||
|
||||
MOZ_ASSERT(animation->IsRelevant(),
|
||||
"Animations registered with a timeline should be relevant");
|
||||
MOZ_ASSERT(animation->GetTimeline() == params->mTimeline,
|
||||
"Animation should refer to this timeline");
|
||||
|
||||
// Bug 1174575: Until we implement a suitable PseudoElement interface we
|
||||
// don't have anything to return for the |target| attribute of
|
||||
// KeyframeEffect(ReadOnly) objects that refer to pseudo-elements.
|
||||
// Rather than return some half-baked version of these objects (e.g.
|
||||
// we a null effect attribute) we simply don't provide access to animations
|
||||
// whose effect refers to a pseudo-element until we can support them properly.
|
||||
Element* target;
|
||||
nsCSSPseudoElements::Type pseudoType;
|
||||
animation->GetEffect()->GetTarget(target, pseudoType);
|
||||
if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
params->mSequence.AppendElement(animation);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTimeline::GetAnimations(AnimationSequence& aAnimations)
|
||||
{
|
||||
@ -71,12 +31,28 @@ AnimationTimeline::GetAnimations(AnimationSequence& aAnimations)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
AddAnimationParams params{ aAnimations, this };
|
||||
#else
|
||||
AddAnimationParams params{ aAnimations };
|
||||
#endif
|
||||
mAnimations.EnumerateEntries(AppendAnimationToSequence, ¶ms);
|
||||
for (auto iter = mAnimations.Iter(); !iter.Done(); iter.Next()) {
|
||||
Animation* animation = iter.Get()->GetKey();
|
||||
|
||||
MOZ_ASSERT(animation->IsRelevant(),
|
||||
"Animations registered with a timeline should be relevant");
|
||||
MOZ_ASSERT(animation->GetTimeline() == this,
|
||||
"Animation should refer to this timeline");
|
||||
|
||||
// Bug 1174575: Until we implement a suitable PseudoElement interface we
|
||||
// don't have anything to return for the |target| attribute of
|
||||
// KeyframeEffect(ReadOnly) objects that refer to pseudo-elements.
|
||||
// Rather than return some half-baked version of these objects (e.g.
|
||||
// we a null effect attribute) we simply don't provide access to animations
|
||||
// whose effect refers to a pseudo-element until we can support them
|
||||
// properly.
|
||||
Element* target;
|
||||
nsCSSPseudoElements::Type pseudoType;
|
||||
animation->GetEffect()->GetTarget(target, pseudoType);
|
||||
if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
aAnimations.AppendElement(animation);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort animations by priority
|
||||
aAnimations.Sort(AnimationPtrComparator<nsRefPtr<Animation>>());
|
||||
|
@ -48,60 +48,56 @@ PendingAnimationTracker::IsWaiting(const dom::Animation& aAnimation,
|
||||
return aSet.Contains(const_cast<dom::Animation*>(&aAnimation));
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
TriggerAnimationAtTime(nsRefPtrHashKey<dom::Animation>* aKey,
|
||||
void* aReadyTime)
|
||||
{
|
||||
dom::Animation* animation = aKey->GetKey();
|
||||
dom::AnimationTimeline* timeline = animation->GetTimeline();
|
||||
|
||||
// If the animation does not have a timeline, just drop it from the map.
|
||||
// The animation will detect that it is not being tracked and will trigger
|
||||
// itself on the next tick where it has a timeline.
|
||||
if (!timeline) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
// When the timeline's refresh driver is under test control, its values
|
||||
// have no correspondance to wallclock times so we shouldn't try to convert
|
||||
// aReadyTime (which is a wallclock time) to a timeline value. Instead, the
|
||||
// animation will be started/paused when the refresh driver is next
|
||||
// advanced since this will trigger a call to TriggerPendingAnimationsNow.
|
||||
if (!timeline->TracksWallclockTime()) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
Nullable<TimeDuration> readyTime =
|
||||
timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime));
|
||||
animation->TriggerOnNextTick(readyTime);
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp&
|
||||
aReadyTime)
|
||||
{
|
||||
mPlayPendingSet.EnumerateEntries(TriggerAnimationAtTime,
|
||||
const_cast<TimeStamp*>(&aReadyTime));
|
||||
mPausePendingSet.EnumerateEntries(TriggerAnimationAtTime,
|
||||
const_cast<TimeStamp*>(&aReadyTime));
|
||||
}
|
||||
auto triggerAnimationsAtReadyTime = [aReadyTime](AnimationSet& aAnimationSet)
|
||||
{
|
||||
for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
|
||||
dom::Animation* animation = iter.Get()->GetKey();
|
||||
dom::AnimationTimeline* timeline = animation->GetTimeline();
|
||||
|
||||
PLDHashOperator
|
||||
TriggerAnimationNow(nsRefPtrHashKey<dom::Animation>* aKey, void*)
|
||||
{
|
||||
aKey->GetKey()->TriggerNow();
|
||||
return PL_DHASH_NEXT;
|
||||
// If the animation does not have a timeline, just drop it from the map.
|
||||
// The animation will detect that it is not being tracked and will trigger
|
||||
// itself on the next tick where it has a timeline.
|
||||
if (!timeline) {
|
||||
iter.Remove();
|
||||
}
|
||||
|
||||
// When the timeline's refresh driver is under test control, its values
|
||||
// have no correspondance to wallclock times so we shouldn't try to
|
||||
// convert aReadyTime (which is a wallclock time) to a timeline value.
|
||||
// Instead, the animation will be started/paused when the refresh driver
|
||||
// is next advanced since this will trigger a call to
|
||||
// TriggerPendingAnimationsNow.
|
||||
if (!timeline->TracksWallclockTime()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Nullable<TimeDuration> readyTime = timeline->ToTimelineTime(aReadyTime);
|
||||
animation->TriggerOnNextTick(readyTime);
|
||||
|
||||
iter.Remove();
|
||||
}
|
||||
};
|
||||
|
||||
triggerAnimationsAtReadyTime(mPlayPendingSet);
|
||||
triggerAnimationsAtReadyTime(mPausePendingSet);
|
||||
}
|
||||
|
||||
void
|
||||
PendingAnimationTracker::TriggerPendingAnimationsNow()
|
||||
{
|
||||
mPlayPendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
|
||||
mPlayPendingSet.Clear();
|
||||
mPausePendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
|
||||
mPausePendingSet.Clear();
|
||||
auto triggerAndClearAnimations = [](AnimationSet& aAnimationSet) {
|
||||
for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Get()->GetKey()->TriggerNow();
|
||||
}
|
||||
aAnimationSet.Clear();
|
||||
};
|
||||
|
||||
triggerAndClearAnimations(mPlayPendingSet);
|
||||
triggerAndClearAnimations(mPausePendingSet);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -62,3 +62,4 @@ support-files = document-timeline/file_document-timeline.html
|
||||
skip-if = buildapp == 'mulet'
|
||||
[mozilla/test_deferred_start.html]
|
||||
support-files = mozilla/file_deferred_start.html
|
||||
skip-if = (toolkit == 'gonk' && debug)
|
||||
|
@ -140,6 +140,7 @@
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/VRDevice.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -3485,3 +3486,16 @@ Element::FontSizeInflation()
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
net::ReferrerPolicy
|
||||
Element::GetReferrerPolicy()
|
||||
{
|
||||
if (Preferences::GetBool("network.http.enablePerElementReferrer", false) &&
|
||||
IsHTMLElement()) {
|
||||
const nsAttrValue* referrerValue = GetParsedAttr(nsGkAtoms::referrer);
|
||||
if (referrerValue && referrerValue->Type() == nsAttrValue::eEnum) {
|
||||
return net::ReferrerPolicy(referrerValue->GetEnumValue());
|
||||
}
|
||||
}
|
||||
return net::RP_Unset;
|
||||
}
|
@ -1060,6 +1060,8 @@ public:
|
||||
*/
|
||||
float FontSizeInflation();
|
||||
|
||||
net::ReferrerPolicy GetReferrerPolicy();
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Named-bools for use with SetAttrAndNotify to make call sites easier to
|
||||
|
@ -937,30 +937,26 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||
}
|
||||
|
||||
// get document wide referrer policy
|
||||
mozilla::net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
|
||||
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", false);
|
||||
// if referrer attributes are enabled in preferences, load img referrer attribute
|
||||
nsresult rv;
|
||||
if (referrerAttributeEnabled) {
|
||||
mozilla::net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
|
||||
// if the image does not provide a referrer attribute, ignore this
|
||||
if (imgReferrerPolicy != mozilla::net::RP_Unset) {
|
||||
referrerPolicy = imgReferrerPolicy;
|
||||
}
|
||||
// if the image does not provide a referrer attribute, ignore this
|
||||
net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
|
||||
net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
|
||||
if (imgReferrerPolicy != net::RP_Unset) {
|
||||
referrerPolicy = imgReferrerPolicy;
|
||||
}
|
||||
|
||||
// Not blocked. Do the load.
|
||||
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
|
||||
nsCOMPtr<nsIContent> content =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
||||
aDocument->NodePrincipal(),
|
||||
aDocument->GetDocumentURI(),
|
||||
referrerPolicy,
|
||||
this, loadFlags,
|
||||
content->LocalName(),
|
||||
getter_AddRefs(req),
|
||||
policyType);
|
||||
nsresult rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
||||
aDocument->NodePrincipal(),
|
||||
aDocument->GetDocumentURI(),
|
||||
referrerPolicy,
|
||||
this, loadFlags,
|
||||
content->LocalName(),
|
||||
getter_AddRefs(req),
|
||||
policyType);
|
||||
|
||||
// Tell the document to forget about the image preload, if any, for
|
||||
// this URI, now that we might have another imgRequestProxy for it.
|
||||
|
@ -240,6 +240,8 @@ support-files =
|
||||
file_audioLoop.html
|
||||
file_webaudioLoop.html
|
||||
file_webaudioLoop2.html
|
||||
referrer_helper.js
|
||||
referrer_testserver.sjs
|
||||
|
||||
[test_anonymousContent_api.html]
|
||||
[test_anonymousContent_append_after_reflow.html]
|
||||
@ -672,6 +674,8 @@ support-files = referrerHelper.js
|
||||
[test_bug1165501.html]
|
||||
support-files = referrerHelper.js
|
||||
[test_img_referrer.html]
|
||||
[test_anchor_area_referrer.html]
|
||||
[test_anchor_area_referrer_changing.html]
|
||||
[test_caretPositionFromPoint.html]
|
||||
[test_classList.html]
|
||||
# This test fails on the Mac for some reason
|
||||
|
98
dom/base/test/referrer_helper.js
Normal file
98
dom/base/test/referrer_helper.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* common functionality for iframe, anchor, and area referrer attribute tests
|
||||
*/
|
||||
const GET_RESULT = sjs + 'action=get-test-results';
|
||||
const RESET_STATE = sjs + 'action=resetState';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* Listen for notifications from the child.
|
||||
* These are sent in case of error, or when the loads we await have completed.
|
||||
*/
|
||||
window.addEventListener("message", function(event) {
|
||||
if (event.data == "childLoadComplete") {
|
||||
// all loads happen, continue the test.
|
||||
advance();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* helper to perform an XHR
|
||||
* to do checkIndividualResults and resetState
|
||||
*/
|
||||
function doXHR(aUrl, onSuccess, onFail) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = "json";
|
||||
xhr.onload = function () {
|
||||
onSuccess(xhr);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
onFail(xhr);
|
||||
};
|
||||
xhr.open('GET', aUrl, true);
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the results via XHR and passes to checker.
|
||||
*/
|
||||
function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
|
||||
var onload = xhr => {
|
||||
var results = xhr.response;
|
||||
info(JSON.stringify(xhr.response));
|
||||
ok(aName in results, aName + " tests have to be performed.");
|
||||
is(results[aName].policy, aExpectedReferrer, aTestname + ' --- ' + results[aName].policy + ' (' + results[aName].referrer + ')');
|
||||
advance();
|
||||
};
|
||||
var onerror = xhr => {
|
||||
ok(false, "Can't get results from the counter server.");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
doXHR(GET_RESULT, onload, onerror);
|
||||
}
|
||||
|
||||
function resetState() {
|
||||
doXHR(RESET_STATE,
|
||||
advance,
|
||||
function(xhr) {
|
||||
ok(false, "error in reset state");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* testing if anchor and area referrer attributes are honoured (1174913)
|
||||
*/
|
||||
var tests = (function() {
|
||||
|
||||
// enable referrer attribute
|
||||
yield SpecialPowers.pushPrefEnv({"set": [['network.http.enablePerElementReferrer', true]]}, advance);
|
||||
|
||||
var iframe = document.getElementById("testframe");
|
||||
|
||||
for (var j = 0; j < testCases.length; j++) {
|
||||
var actions = testCases[j].ACTION;
|
||||
var tests = testCases[j].TESTS;
|
||||
for (var k = 0; k < actions.length; k++) {
|
||||
var actionString = actions[k];
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
yield resetState();
|
||||
var searchParams = new URLSearchParams();
|
||||
searchParams.append(ACTION, actionString);
|
||||
searchParams.append(NAME, tests[i].NAME);
|
||||
for (var l of PARAMS) {
|
||||
if (tests[i][l]) {
|
||||
searchParams.append(window[l], tests[i][l]);
|
||||
}
|
||||
}
|
||||
yield iframe.src = sjs + searchParams.toString();
|
||||
yield checkIndividualResults(tests[i].DESC, tests[i].RESULT, tests[i].NAME);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
180
dom/base/test/referrer_testserver.sjs
Normal file
180
dom/base/test/referrer_testserver.sjs
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Test server for iframe, anchor, and area referrer attributes.
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
|
||||
*/
|
||||
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
const BASE_URL = 'example.com/tests/dom/base/test/referrer_testserver.sjs';
|
||||
const SHARED_KEY = 'referrer_testserver.sjs';
|
||||
const ATTRIBUTE_POLICY = 'attributePolicy';
|
||||
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
|
||||
const NAME = 'name';
|
||||
const META_POLICY = 'metaPolicy';
|
||||
const REL = 'rel';
|
||||
|
||||
function createTestUrl(aPolicy, aAction, aName, aType) {
|
||||
return 'http://' + BASE_URL + '?' +
|
||||
'action=' + aAction + '&' +
|
||||
'policy=' + aPolicy + '&' +
|
||||
'name=' + aName + '&' +
|
||||
'type=' + aType;
|
||||
}
|
||||
|
||||
function buildAnchorString(aMetaPolicy, aReferrerPolicy, aName, aRelString){
|
||||
if (aReferrerPolicy) {
|
||||
return `<a href="${createTestUrl(aReferrerPolicy, 'test', aName, 'link')}" referrer="${aReferrerPolicy}" id="link" ${aRelString}>${aReferrerPolicy}</a>`;
|
||||
}
|
||||
return `<a href="${createTestUrl(aMetaPolicy, 'test', aName, 'link')}" id="link" ${aRelString}>link</a>`;
|
||||
}
|
||||
|
||||
function buildAreaString(aMetaPolicy, aReferrerPolicy, aName, aRelString){
|
||||
var result = `<img src="file_mozfiledataurl_img.jpg" alt="image" usemap="#imageMap">`;
|
||||
result += `<map name="imageMap">`;
|
||||
if (aReferrerPolicy) {
|
||||
result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(aReferrerPolicy, 'test', aName, 'link')}" alt="theArea" referrer="${aReferrerPolicy}" id="link" ${aRelString}>`;
|
||||
} else {
|
||||
result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(aMetaPolicy, 'test', aName, 'link')}" alt="theArea" id="link" ${aRelString}>`;
|
||||
}
|
||||
result += `</map>`;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// test page using anchor or area referrer attribute
|
||||
function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aRel, aStringBuilder, aChangingMethod) {
|
||||
var metaString = '';
|
||||
if (aMetaPolicy) {
|
||||
metaString = '<head><meta name="referrer" content="' + aMetaPolicy + '"></head>';
|
||||
}
|
||||
var changeString = '';
|
||||
if (aChangingMethod === 'setAttribute') {
|
||||
changeString = `document.getElementById("link").setAttribute("referrer", "${aNewAttributePolicy}")`;
|
||||
} else if (aChangingMethod === 'property') {
|
||||
changeString = `document.getElementById("link").referrer = "${aNewAttributePolicy}"`;
|
||||
}
|
||||
var relString = '';
|
||||
if (aRel) {
|
||||
relString = `rel="noreferrer"`;
|
||||
}
|
||||
var elementString = aStringBuilder(aMetaPolicy, aAttributePolicy, aName, relString);
|
||||
|
||||
return `<!DOCTYPE HTML>
|
||||
<html>
|
||||
${metaString}
|
||||
<body>
|
||||
${elementString}
|
||||
<script>
|
||||
window.addEventListener("load", function() {
|
||||
${changeString}
|
||||
document.getElementById("link").click();
|
||||
}.bind(window), false);
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
function handleRequest(request, response) {
|
||||
var params = new URLSearchParams(request.queryString);
|
||||
var action = params.get('action');
|
||||
|
||||
response.setHeader('Cache-Control', 'no-cache', false);
|
||||
response.setHeader('Content-Type', 'text/html; charset=utf-8', false);
|
||||
|
||||
if (action === 'resetState') {
|
||||
setSharedState(SHARED_KEY, "{}");
|
||||
response.write("");
|
||||
return;
|
||||
}
|
||||
if (action === 'get-test-results') {
|
||||
// ?action=get-result
|
||||
response.setHeader('Cache-Control', 'no-cache', false);
|
||||
response.setHeader('Content-Type', 'text/plain', false);
|
||||
response.write(getSharedState(SHARED_KEY));
|
||||
return;
|
||||
}
|
||||
if (action === 'redirect') {
|
||||
response.write('<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>');
|
||||
return;
|
||||
}
|
||||
if (action === 'test') {
|
||||
// ?action=test&policy=origin&name=name
|
||||
var policy = params.get('policy');
|
||||
var name = params.get('name');
|
||||
var type = params.get('type');
|
||||
var result = getSharedState(SHARED_KEY);
|
||||
|
||||
result = result ? JSON.parse(result) : {};
|
||||
|
||||
var referrerLevel = "none";
|
||||
var test = {}
|
||||
if (request.hasHeader('Referer')) {
|
||||
var referrer = request.getHeader("Referer");
|
||||
if (referrer.indexOf("referrer_testserver") > 0) {
|
||||
referrerLevel = "full";
|
||||
} else if (referrer.indexOf("http://mochi.test:8888") == 0) {
|
||||
referrerLevel = "origin";
|
||||
} else {
|
||||
// this is never supposed to happen
|
||||
referrerLevel = "other-origin";
|
||||
}
|
||||
test.referrer = referrer;
|
||||
} else {
|
||||
test.referrer = '';
|
||||
}
|
||||
test.policy = referrerLevel;
|
||||
test.expected = policy;
|
||||
|
||||
result[name] = test;
|
||||
|
||||
setSharedState(SHARED_KEY, JSON.stringify(result));
|
||||
|
||||
if (type === "link") {
|
||||
// forward link click to redirect URL to finish test
|
||||
var loc = "http://" + BASE_URL + "?action=redirect";
|
||||
response.setStatusLine('1.1', 302, 'Found');
|
||||
response.setHeader('Location', loc, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// parse test arguments and start test
|
||||
var attributePolicy = params.get(ATTRIBUTE_POLICY) || '';
|
||||
var newAttributePolicy = params.get(NEW_ATTRIBUTE_POLICY) || '';
|
||||
var metaPolicy = params.get(META_POLICY) || '';
|
||||
var rel = params.get(REL) || '';
|
||||
var name = params.get(NAME);
|
||||
|
||||
// anchor & area
|
||||
var _getPage = createAETestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name, rel);
|
||||
var _getAnchorPage = _getPage.bind(null, buildAnchorString);
|
||||
var _getAreaPage = _getPage.bind(null, buildAreaString);
|
||||
|
||||
// aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder
|
||||
if (action === 'generate-anchor-policy-test') {
|
||||
response.write(_getAnchorPage());
|
||||
return;
|
||||
}
|
||||
if (action === 'generate-anchor-changing-policy-test-set-attribute') {
|
||||
response.write(_getAnchorPage('setAttribute'));
|
||||
return;
|
||||
}
|
||||
if (action === 'generate-anchor-changing-policy-test-property') {
|
||||
response.write(_getAnchorPage('property'));
|
||||
return;
|
||||
}
|
||||
if (action === 'generate-area-policy-test') {
|
||||
response.write(_getAreaPage());
|
||||
return;
|
||||
}
|
||||
if (action === 'generate-area-changing-policy-test-set-attribute') {
|
||||
response.write(_getAreaPage('setAttribute'));
|
||||
return;
|
||||
}
|
||||
if (action === 'generate-area-changing-policy-test-property') {
|
||||
response.write(_getAreaPage('property'));
|
||||
return;
|
||||
}
|
||||
|
||||
response.write("I don't know action " + action);
|
||||
return;
|
||||
}
|
116
dom/base/test/test_anchor_area_referrer.html
Normal file
116
dom/base/test/test_anchor_area_referrer.html
Normal file
@ -0,0 +1,116 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test anchor and area policy attribute for Bug 1174913</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<!--
|
||||
Testing that anchor and area referrer attributes are honoured correctly
|
||||
* anchor tag with referrer attribute (generate-anchor-policy-test)
|
||||
* regression tests that meta referrer is still working even if attribute referrers are enabled (generate-anchor-policy-test)
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
|
||||
-->
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
const sjs = "/tests/dom/base/test/referrer_testserver.sjs?";
|
||||
const ATTRIBUTE_POLICY = 'attributePolicy';
|
||||
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
|
||||
const NAME = 'name';
|
||||
const META_POLICY = 'metaPolicy';
|
||||
const DESC = 'description';
|
||||
const RESULT = 'result';
|
||||
const ACTION = 'action';
|
||||
const TESTS = 'tests';
|
||||
const REL = 'rel';
|
||||
const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
|
||||
|
||||
const testCases = [
|
||||
{ACTION: ["generate-anchor-policy-test", "generate-area-policy-test"],
|
||||
TESTS: [
|
||||
{ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-with-origin-in-meta',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "unsafe-url (anchor) with origin in meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NAME: 'origin-with-unsafe-url-in-meta',
|
||||
META_POLICY: 'unsafe-url',
|
||||
DESC: "origin (anchor) with unsafe-url in meta",
|
||||
RESULT: 'origin'},
|
||||
{ATTRIBUTE_POLICY: 'no-referrer',
|
||||
NAME: 'no-referrer-with-origin-in-meta',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "no-referrer (anchor) with origin in meta",
|
||||
RESULT: 'none'},
|
||||
{NAME: 'no-referrer-in-meta',
|
||||
META_POLICY: 'no-referrer',
|
||||
DESC: "no-referrer in meta",
|
||||
RESULT: 'none'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NAME: 'origin-with-no-meta',
|
||||
META_POLICY: '',
|
||||
DESC: "origin (anchor) with no meta",
|
||||
RESULT: 'origin'},
|
||||
// setting rel=noreferrer -> we expect no referrer
|
||||
{ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-with-origin-in-meta-rel',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "unsafe-url (anchor) with origin in meta and rel=noreferrer",
|
||||
RESULT: 'none',
|
||||
REL: 'noreferrer'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NAME: 'origin-with-unsafe-url-in-meta-rel',
|
||||
META_POLICY: 'unsafe-url',
|
||||
DESC: "origin (anchor) with unsafe-url in meta and rel=noreferrer",
|
||||
RESULT: 'none',
|
||||
REL: 'noreferrer'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NAME: 'origin-with-no-meta-rel',
|
||||
META_POLICY: '',
|
||||
DESC: "origin (anchor) with no meta and rel=noreferrer",
|
||||
RESULT: 'none',
|
||||
REL: 'noreferrer'},
|
||||
// setting invalid refer values -> we expect either full referrer (default)
|
||||
// or whatever is specified in the meta referrer policy
|
||||
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
|
||||
NAME: 'origin-when-cross-origin-with-no-meta',
|
||||
META_POLICY: '',
|
||||
DESC: "origin-when-cross-origin (anchor) with no meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'default',
|
||||
NAME: 'default-with-no-meta',
|
||||
META_POLICY: '',
|
||||
DESC: "default (anchor) with no meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'something',
|
||||
NAME: 'something-with-no-meta',
|
||||
META_POLICY: '',
|
||||
DESC: "something (anchor) with no meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
|
||||
NAME: 'origin-when-cross-origin-with-no-referrer-in-meta',
|
||||
META_POLICY: 'no-referrer',
|
||||
DESC: "origin-when-cross-origin (anchor) with no-referrer in meta",
|
||||
RESULT: 'none'},
|
||||
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
|
||||
NAME: 'origin-when-cross-origin-with-unsafe-url-in-meta',
|
||||
META_POLICY: 'unsafe-url',
|
||||
DESC: "origin-when-cross-origin (anchor) with unsafe-url in meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
|
||||
NAME: 'origin-when-cross-origin-with-origin-in-meta',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "origin-when-cross-origin (anchor) with origin in meta",
|
||||
RESULT: 'origin'}]}
|
||||
];
|
||||
</script>
|
||||
<script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
|
||||
</head>
|
||||
<body onload="tests.next();">
|
||||
<iframe id="testframe"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
75
dom/base/test/test_anchor_area_referrer_changing.html
Normal file
75
dom/base/test/test_anchor_area_referrer_changing.html
Normal file
@ -0,0 +1,75 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test anchor and area policy attribute for Bug 1174913</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<!--
|
||||
Testing that anchor and area referrer attributes are honoured correctly
|
||||
This test is split due to errors on b2g
|
||||
* testing setAttribute and .referrer (generate-anchor-changing-test)
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
|
||||
-->
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
const sjs = "/tests/dom/base/test/referrer_testserver.sjs?";
|
||||
const ATTRIBUTE_POLICY = 'attributePolicy';
|
||||
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
|
||||
const NAME = 'name';
|
||||
const META_POLICY = 'metaPolicy';
|
||||
const DESC = 'description';
|
||||
const RESULT = 'result';
|
||||
const ACTION = 'action';
|
||||
const TESTS = 'tests';
|
||||
const REL = 'rel';
|
||||
const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
|
||||
|
||||
const testCases = [
|
||||
{ACTION: ["generate-anchor-changing-policy-test-set-attribute", "generate-area-changing-policy-test-set-attribute"],
|
||||
TESTS: [
|
||||
{ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NEW_ATTRIBUTE_POLICY: 'no-referrer',
|
||||
NAME: 'no-referrer-unsafe-url-with-origin-in-meta',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "no-referrer (anchor, orginally unsafe-url) with origin in meta",
|
||||
RESULT: 'none'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-origin-with-no-referrer-in-meta',
|
||||
META_POLICY: 'no-referrer',
|
||||
DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'origin',
|
||||
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-origin-with-no-referrer-in-meta-rel',
|
||||
META_POLICY: 'no-referrer',
|
||||
DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta and rel=noreferrer",
|
||||
RESULT: 'none',
|
||||
REL: 'noreferrer'}]},
|
||||
{ACTION: ["generate-anchor-changing-policy-test-property", "generate-area-changing-policy-test-property"],
|
||||
TESTS: [
|
||||
{ATTRIBUTE_POLICY: 'no-referrer',
|
||||
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-no-referrer-with-origin-in-meta',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta",
|
||||
RESULT: 'full'},
|
||||
{ATTRIBUTE_POLICY: 'no-referrer',
|
||||
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
|
||||
NAME: 'unsafe-url-no-referrer-with-origin-in-meta-rel',
|
||||
META_POLICY: 'origin',
|
||||
DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta and rel=noreferrer",
|
||||
RESULT: 'none',
|
||||
REL: 'noreferrer'}]}
|
||||
];
|
||||
</script>
|
||||
<script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
|
||||
</head>
|
||||
<body onload="tests.next();">
|
||||
<iframe id="testframe"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -123,6 +123,14 @@ public:
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::rel, aValue, rv);
|
||||
}
|
||||
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
|
||||
}
|
||||
void GetReferrer(nsAString& aReferrer)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
|
||||
}
|
||||
nsDOMTokenList* RelList();
|
||||
void GetHreflang(DOMString& aValue)
|
||||
{
|
||||
|
@ -128,6 +128,15 @@ public:
|
||||
}
|
||||
nsDOMTokenList* RelList();
|
||||
|
||||
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
|
||||
}
|
||||
void GetReferrer(nsAString& aReferrer)
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
|
||||
}
|
||||
|
||||
// The Link::GetOrigin is OK for us
|
||||
|
||||
using Link::GetProtocol;
|
||||
|
@ -195,10 +195,10 @@ public:
|
||||
}
|
||||
void GetReferrer(nsAString& aReferrer)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrer, nullptr, aReferrer);
|
||||
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
|
||||
}
|
||||
|
||||
mozilla::net::ReferrerPolicy
|
||||
net::ReferrerPolicy
|
||||
GetImageReferrerPolicy() override
|
||||
{
|
||||
return GetReferrerPolicy();
|
||||
|
@ -105,8 +105,6 @@
|
||||
#include "mozilla/dom/HTMLBodyElement.h"
|
||||
#include "imgIContainer.h"
|
||||
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
@ -233,17 +233,6 @@ public:
|
||||
mScrollgrab = aValue;
|
||||
}
|
||||
|
||||
mozilla::net::ReferrerPolicy
|
||||
GetReferrerPolicy()
|
||||
{
|
||||
nsAutoString aPolicyString;
|
||||
GetEnumAttr(nsGkAtoms::referrer, nullptr, aPolicyString);
|
||||
if (aPolicyString.IsEmpty()) {
|
||||
return mozilla::net::RP_Unset;
|
||||
}
|
||||
return mozilla::net::ReferrerPolicyFromString(aPolicyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an attribute is an event (onclick, etc.)
|
||||
* @param aName the attribute
|
||||
|
@ -9616,27 +9616,16 @@ UpdateRefcountFunction::WillCommit()
|
||||
"DatabaseConnection::UpdateRefcountFunction::WillCommit",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
struct Helper final
|
||||
{
|
||||
static PLDHashOperator
|
||||
Update(const uint64_t& aKey, FileInfoEntry* aValue, void* aUserArg)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
|
||||
auto* function = static_cast<DatabaseUpdateFunction*>(aUserArg);
|
||||
MOZ_ASSERT(function);
|
||||
|
||||
if (aValue->mDelta && !function->Update(aKey, aValue->mDelta)) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
DatabaseUpdateFunction function(this);
|
||||
for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto key = iter.Key();
|
||||
FileInfoEntry* value = iter.Data();
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
mFileInfoEntries.EnumerateRead(Helper::Update, &function);
|
||||
if (value->mDelta && !function.Update(key, value->mDelta)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = function.ErrorCode();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -9662,22 +9651,15 @@ UpdateRefcountFunction::DidCommit()
|
||||
"DatabaseConnection::UpdateRefcountFunction::DidCommit",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
struct Helper final
|
||||
{
|
||||
static PLDHashOperator
|
||||
Update(const uint64_t& aKey, FileInfoEntry* aValue, void* /* aUserArg */)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto value = iter.Data();
|
||||
|
||||
if (aValue->mDelta) {
|
||||
aValue->mFileInfo->UpdateDBRefs(aValue->mDelta);
|
||||
}
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
if (value->mDelta) {
|
||||
value->mFileInfo->UpdateDBRefs(value->mDelta);
|
||||
}
|
||||
};
|
||||
|
||||
mFileInfoEntries.EnumerateRead(Helper::Update, nullptr);
|
||||
}
|
||||
|
||||
if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterCommit))) {
|
||||
NS_WARNING("RemoveJournals failed!");
|
||||
@ -9733,20 +9715,11 @@ UpdateRefcountFunction::RollbackSavepoint()
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
MOZ_ASSERT(mInSavepoint);
|
||||
|
||||
struct Helper
|
||||
{
|
||||
static PLDHashOperator
|
||||
Rollback(const uint64_t& aKey, FileInfoEntry* aValue, void* /* aUserArg */)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
MOZ_ASSERT(aValue);
|
||||
|
||||
aValue->mDelta -= aValue->mSavepointDelta;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
mSavepointEntriesIndex.EnumerateRead(Helper::Rollback, nullptr);
|
||||
for (auto iter = mSavepointEntriesIndex.ConstIter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
auto value = iter.Data();
|
||||
value->mDelta -= value->mSavepointDelta;
|
||||
}
|
||||
|
||||
mInSavepoint = false;
|
||||
mSavepointEntriesIndex.Clear();
|
||||
@ -10815,31 +10788,6 @@ ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
struct Helper
|
||||
{
|
||||
static PLDHashOperator
|
||||
MaybeScheduleTransaction(nsPtrHashKey<TransactionInfo>* aKey,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
TransactionInfo* transactionInfo = aKey->GetKey();
|
||||
MOZ_ASSERT(transactionInfo);
|
||||
|
||||
TransactionInfo* finishedInfo = static_cast<TransactionInfo*>(aClosure);
|
||||
MOZ_ASSERT(finishedInfo);
|
||||
|
||||
MOZ_ASSERT(transactionInfo->mBlockedOn.Contains(finishedInfo));
|
||||
|
||||
transactionInfo->mBlockedOn.RemoveEntry(finishedInfo);
|
||||
if (!transactionInfo->mBlockedOn.Count()) {
|
||||
transactionInfo->Schedule();
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"ConnectionPool::NoteFinishedTransaction",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
@ -10894,8 +10842,18 @@ ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
|
||||
blockInfo->mLastBlockingWrites.RemoveElement(transactionInfo);
|
||||
}
|
||||
|
||||
transactionInfo->mBlocking.EnumerateEntries(Helper::MaybeScheduleTransaction,
|
||||
transactionInfo);
|
||||
for (auto iter = transactionInfo->mBlocking.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
TransactionInfo* blockedInfo = iter.Get()->GetKey();
|
||||
MOZ_ASSERT(blockedInfo);
|
||||
MOZ_ASSERT(blockedInfo->mBlockedOn.Contains(transactionInfo));
|
||||
|
||||
blockedInfo->mBlockedOn.RemoveEntry(transactionInfo);
|
||||
if (!blockedInfo->mBlockedOn.Count()) {
|
||||
blockedInfo->Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
if (transactionInfo->mIsWriteTransaction) {
|
||||
MOZ_ASSERT(dbInfo->mWriteTransactionCount);
|
||||
@ -11731,38 +11689,13 @@ FullObjectStoreMetadata::HasLiveIndexes() const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
public:
|
||||
static bool
|
||||
HasLiveIndexes(const FullObjectStoreMetadata* aMetadata)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aMetadata);
|
||||
|
||||
bool hasLiveIndexes = false;
|
||||
aMetadata->mIndexes.EnumerateRead(&Enumerate, &hasLiveIndexes);
|
||||
|
||||
return hasLiveIndexes;
|
||||
for (auto iter = mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (!iter.Data()->mDeleted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
|
||||
{
|
||||
auto* result = static_cast<bool*>(aClosure);
|
||||
MOZ_ASSERT(result);
|
||||
|
||||
if (!aValue->mDeleted) {
|
||||
*result = true;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
return Helper::HasLiveIndexes(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<FullDatabaseMetadata>
|
||||
@ -11770,79 +11703,6 @@ FullDatabaseMetadata::Duplicate() const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS IndexClosure final
|
||||
{
|
||||
FullObjectStoreMetadata& mNew;
|
||||
|
||||
public:
|
||||
explicit IndexClosure(FullObjectStoreMetadata& aNew)
|
||||
: mNew(aNew)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Copy(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<IndexClosure*>(aClosure);
|
||||
|
||||
nsRefPtr<FullIndexMetadata> newMetadata = new FullIndexMetadata();
|
||||
|
||||
newMetadata->mCommonMetadata = aValue->mCommonMetadata;
|
||||
|
||||
if (NS_WARN_IF(!closure->mNew.mIndexes.Put(aKey, newMetadata,
|
||||
fallible))) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS ObjectStoreClosure final
|
||||
{
|
||||
FullDatabaseMetadata& mNew;
|
||||
|
||||
public:
|
||||
explicit ObjectStoreClosure(FullDatabaseMetadata& aNew)
|
||||
: mNew(aNew)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Copy(const uint64_t& aKey, FullObjectStoreMetadata* aValue, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* objClosure = static_cast<ObjectStoreClosure*>(aClosure);
|
||||
|
||||
nsRefPtr<FullObjectStoreMetadata> newMetadata =
|
||||
new FullObjectStoreMetadata();
|
||||
|
||||
newMetadata->mCommonMetadata = aValue->mCommonMetadata;
|
||||
newMetadata->mNextAutoIncrementId = aValue->mNextAutoIncrementId;
|
||||
newMetadata->mComittedAutoIncrementId = aValue->mComittedAutoIncrementId;
|
||||
|
||||
IndexClosure idxClosure(*newMetadata);
|
||||
aValue->mIndexes.EnumerateRead(IndexClosure::Copy, &idxClosure);
|
||||
|
||||
if (NS_WARN_IF(aValue->mIndexes.Count() !=
|
||||
newMetadata->mIndexes.Count())) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!objClosure->mNew.mObjectStores.Put(aKey, newMetadata,
|
||||
fallible))) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
// FullDatabaseMetadata contains two hash tables of pointers that we need to
|
||||
// duplicate so we can't just use the copy constructor.
|
||||
nsRefPtr<FullDatabaseMetadata> newMetadata =
|
||||
@ -11853,14 +11713,41 @@ FullDatabaseMetadata::Duplicate() const
|
||||
newMetadata->mNextObjectStoreId = mNextObjectStoreId;
|
||||
newMetadata->mNextIndexId = mNextIndexId;
|
||||
|
||||
ObjectStoreClosure closure(*newMetadata);
|
||||
mObjectStores.EnumerateRead(ObjectStoreClosure::Copy, &closure);
|
||||
for (auto iter = mObjectStores.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto key = iter.Key();
|
||||
auto value = iter.Data();
|
||||
|
||||
if (NS_WARN_IF(mObjectStores.Count() !=
|
||||
newMetadata->mObjectStores.Count())) {
|
||||
return nullptr;
|
||||
nsRefPtr<FullObjectStoreMetadata> newOSMetadata =
|
||||
new FullObjectStoreMetadata();
|
||||
|
||||
newOSMetadata->mCommonMetadata = value->mCommonMetadata;
|
||||
newOSMetadata->mNextAutoIncrementId = value->mNextAutoIncrementId;
|
||||
newOSMetadata->mComittedAutoIncrementId = value->mComittedAutoIncrementId;
|
||||
|
||||
for (auto iter = value->mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto key = iter.Key();
|
||||
auto value = iter.Data();
|
||||
|
||||
nsRefPtr<FullIndexMetadata> newIndexMetadata = new FullIndexMetadata();
|
||||
|
||||
newIndexMetadata->mCommonMetadata = value->mCommonMetadata;
|
||||
|
||||
if (NS_WARN_IF(!newOSMetadata->mIndexes.Put(key, newIndexMetadata,
|
||||
fallible))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(value->mIndexes.Count() == newOSMetadata->mIndexes.Count());
|
||||
|
||||
if (NS_WARN_IF(!newMetadata->mObjectStores.Put(key, newOSMetadata,
|
||||
fallible))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mObjectStores.Count() == newMetadata->mObjectStores.Count());
|
||||
|
||||
return newMetadata.forget();
|
||||
}
|
||||
|
||||
@ -12357,10 +12244,11 @@ Database::Invalidate()
|
||||
return false;
|
||||
}
|
||||
|
||||
aTable.EnumerateEntries(Collect, &transactions);
|
||||
|
||||
if (NS_WARN_IF(transactions.Length() != count)) {
|
||||
return false;
|
||||
for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (NS_WARN_IF(!transactions.AppendElement(iter.Get()->GetKey(),
|
||||
fallible))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (count) {
|
||||
@ -12376,23 +12264,6 @@ Database::Invalidate()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static PLDHashOperator
|
||||
Collect(nsPtrHashKey<TransactionBase>* aEntry, void* aUserData)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aUserData);
|
||||
|
||||
auto* array =
|
||||
static_cast<FallibleTArray<nsRefPtr<TransactionBase>>*>(aUserData);
|
||||
|
||||
if (NS_WARN_IF(!array->AppendElement(aEntry->GetKey(), fallible))) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
if (mInvalidated) {
|
||||
@ -12629,39 +12500,6 @@ Database::AllocPBackgroundIDBTransactionParent(
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS Closure final
|
||||
{
|
||||
const nsString& mName;
|
||||
FallibleTArray<nsRefPtr<FullObjectStoreMetadata>>& mObjectStores;
|
||||
|
||||
public:
|
||||
Closure(const nsString& aName,
|
||||
FallibleTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores)
|
||||
: mName(aName)
|
||||
, mObjectStores(aObjectStores)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Find(const uint64_t& aKey,
|
||||
FullObjectStoreMetadata* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<Closure*>(aClosure);
|
||||
|
||||
if (closure->mName == aValue->mCommonMetadata.name() &&
|
||||
!aValue->mDeleted) {
|
||||
MOZ_ALWAYS_TRUE(closure->mObjectStores.AppendElement(aValue, fallible));
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
// Once a database is closed it must not try to open new transactions.
|
||||
if (NS_WARN_IF(mClosed)) {
|
||||
if (!mInvalidated) {
|
||||
@ -12715,13 +12553,16 @@ Database::AllocPBackgroundIDBTransactionParent(
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t oldLength = fallibleObjectStores.Length();
|
||||
for (auto iter = objectStores.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto value = iter.Data();
|
||||
MOZ_ASSERT(iter.Key());
|
||||
|
||||
Closure closure(name, fallibleObjectStores);
|
||||
objectStores.EnumerateRead(Closure::Find, &closure);
|
||||
|
||||
if (NS_WARN_IF((oldLength + 1) != fallibleObjectStores.Length())) {
|
||||
return nullptr;
|
||||
if (name == value->mCommonMetadata.name() && !value->mDeleted) {
|
||||
if (NS_WARN_IF(!fallibleObjectStores.AppendElement(value, fallible))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,27 +432,12 @@ IDBDatabase::RefreshSpec(bool aMayDelete)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
public:
|
||||
static PLDHashOperator
|
||||
RefreshTransactionsSpec(nsPtrHashKey<IDBTransaction>* aTransaction,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aTransaction);
|
||||
aTransaction->GetKey()->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
bool mayDelete = *static_cast<bool*>(aClosure);
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction = aTransaction->GetKey();
|
||||
transaction->RefreshSpec(mayDelete);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
mTransactions.EnumerateEntries(Helper::RefreshTransactionsSpec, &aMayDelete);
|
||||
for (auto iter = mTransactions.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsRefPtr<IDBTransaction> transaction = iter.Get()->GetKey();
|
||||
MOZ_ASSERT(transaction);
|
||||
transaction->AssertIsOnOwningThread();
|
||||
transaction->RefreshSpec(aMayDelete);
|
||||
}
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
@ -916,7 +901,19 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
|
||||
StrongTransactionArray transactionsToAbort;
|
||||
transactionsToAbort.SetCapacity(transactionTable.Count());
|
||||
|
||||
transactionTable.EnumerateEntries(Collect, &transactionsToAbort);
|
||||
for (auto iter = transactionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
IDBTransaction* transaction = iter.Get()->GetKey();
|
||||
MOZ_ASSERT(transaction);
|
||||
|
||||
transaction->AssertIsOnOwningThread();
|
||||
|
||||
// Transactions that are already done can simply be ignored. Otherwise
|
||||
// there is a race here and it's possible that the transaction has not
|
||||
// been successfully committed yet so we will warn the user.
|
||||
if (!transaction->IsDone()) {
|
||||
transactionsToAbort.AppendElement(transaction);
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(transactionsToAbort.Length() <= transactionTable.Count());
|
||||
|
||||
if (transactionsToAbort.IsEmpty()) {
|
||||
@ -968,29 +965,6 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
|
||||
aDatabase->LogWarning(kWarningMessage, filename, lineNo);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static PLDHashOperator
|
||||
Collect(nsPtrHashKey<IDBTransaction>* aTransactionKey, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aTransactionKey);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
IDBTransaction* transaction = aTransactionKey->GetKey();
|
||||
MOZ_ASSERT(transaction);
|
||||
|
||||
transaction->AssertIsOnOwningThread();
|
||||
|
||||
// Transactions that are already done can simply be ignored. Otherwise
|
||||
// there is a race here and it's possible that the transaction has not
|
||||
// been successfully committed yet so we will warn the user.
|
||||
if (!transaction->IsDone()) {
|
||||
auto* array = static_cast<StrongTransactionArray*>(aClosure);
|
||||
array->AppendElement(transaction);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
Helper::AbortTransactions(this, aShouldWarn);
|
||||
@ -1254,27 +1228,6 @@ IDBDatabase::ExpireFileActors(bool aExpireAll)
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
MaybeExpireReceivedBlobs(nsISupportsHashKey* aKey,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(!aClosure);
|
||||
|
||||
nsISupports* key = aKey->GetKey();
|
||||
MOZ_ASSERT(key);
|
||||
|
||||
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(key);
|
||||
MOZ_ASSERT(weakRef);
|
||||
|
||||
nsCOMPtr<nsISupports> referent = do_QueryReferent(weakRef);
|
||||
if (!referent) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
if (mBackgroundActor && mFileActors.Count()) {
|
||||
@ -1290,8 +1243,18 @@ IDBDatabase::ExpireFileActors(bool aExpireAll)
|
||||
if (aExpireAll) {
|
||||
mReceivedBlobs.Clear();
|
||||
} else {
|
||||
mReceivedBlobs.EnumerateEntries(&Helper::MaybeExpireReceivedBlobs,
|
||||
nullptr);
|
||||
for (auto iter = mReceivedBlobs.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsISupports* key = iter.Get()->GetKey();
|
||||
MOZ_ASSERT(key);
|
||||
|
||||
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(key);
|
||||
MOZ_ASSERT(weakRef);
|
||||
|
||||
nsCOMPtr<nsISupports> referent = do_QueryReferent(weakRef);
|
||||
if (!referent) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,24 +753,13 @@ IndexedDatabaseManager::InvalidateAllFileManagers()
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
public:
|
||||
static PLDHashOperator
|
||||
Enumerate(const nsACString& aKey,
|
||||
FileManagerInfo* aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(!aKey.IsEmpty());
|
||||
MOZ_ASSERT(aValue);
|
||||
for (auto iter = mFileManagerInfos.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto value = iter.Data();
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
aValue->InvalidateAllFileManagers();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
value->InvalidateAllFileManagers();
|
||||
}
|
||||
|
||||
mFileManagerInfos.EnumerateRead(Helper::Enumerate, nullptr);
|
||||
mFileManagerInfos.Clear();
|
||||
}
|
||||
|
||||
@ -1003,29 +992,19 @@ IndexedDatabaseManager::Notify(nsITimer* aTimer)
|
||||
MOZ_ASSERT(IsMainProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
public:
|
||||
static PLDHashOperator
|
||||
CreateAndDispatchRunnables(FileManager* aFileManager,
|
||||
nsTArray<int64_t>* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(!aValue->IsEmpty());
|
||||
for (auto iter = mPendingDeleteInfos.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto key = iter.Key();
|
||||
auto value = iter.Data();
|
||||
MOZ_ASSERT(!value->IsEmpty());
|
||||
|
||||
nsRefPtr<DeleteFilesRunnable> runnable =
|
||||
new DeleteFilesRunnable(aFileManager, *aValue);
|
||||
nsRefPtr<DeleteFilesRunnable> runnable =
|
||||
new DeleteFilesRunnable(key, *value);
|
||||
|
||||
MOZ_ASSERT(aValue->IsEmpty());
|
||||
MOZ_ASSERT(value->IsEmpty());
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
mPendingDeleteInfos.EnumerateRead(Helper::CreateAndDispatchRunnables,
|
||||
nullptr);
|
||||
mPendingDeleteInfos.Clear();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -75,9 +75,31 @@ definitionlist = definition list
|
||||
term = term
|
||||
definition = definition
|
||||
|
||||
mathmltable = math table
|
||||
mathmlcell = cell
|
||||
mathmlenclosed = enclosed
|
||||
mathmlfraction = fraction
|
||||
mathmlfractionwithoutbar = fraction without bar
|
||||
mathmlroot = root
|
||||
mathmlscripted = scripted
|
||||
mathmlsquareroot = square root
|
||||
|
||||
# More sophisticated roles which are not actual numeric roles
|
||||
textarea = text area
|
||||
|
||||
base = base
|
||||
close-fence = closing fence
|
||||
denominator = denominator
|
||||
numerator = numerator
|
||||
open-fence = opening fence
|
||||
overscript = overscript
|
||||
presubscript = presubscript
|
||||
presuperscript = presuperscript
|
||||
root-index = root index
|
||||
subscript = subscript
|
||||
superscript = superscript
|
||||
underscript = underscript
|
||||
|
||||
# Text input types
|
||||
textInputType_date = date
|
||||
textInputType_email = e-mail
|
||||
@ -191,6 +213,26 @@ quicknav_Separator = Separators
|
||||
quicknav_Table = Tables
|
||||
quicknav_Checkbox = Check boxes
|
||||
|
||||
# MathML menclose notations.
|
||||
# See developer.mozilla.org/docs/Web/MathML/Element/menclose#attr-notation
|
||||
notation-longdiv = long division
|
||||
notation-actuarial = actuarial
|
||||
notation-phasorangle = phasor angle
|
||||
notation-radical = radical
|
||||
notation-box = box
|
||||
notation-roundedbox = rounded box
|
||||
notation-circle = circle
|
||||
notation-left = left
|
||||
notation-right = right
|
||||
notation-top = top
|
||||
notation-bottom = bottom
|
||||
notation-updiagonalstrike = up diagonal strike
|
||||
notation-downdiagonalstrike = down diagonal strike
|
||||
notation-verticalstrike = vertical strike
|
||||
notation-horizontalstrike = horizontal strike
|
||||
notation-updiagonalarrow = up diagonal arrow
|
||||
notation-madruwb = madruwb
|
||||
|
||||
# Shortened role names for braille
|
||||
menubarAbbr = menu bar
|
||||
scrollbarAbbr = scroll bar
|
||||
@ -274,3 +316,43 @@ stateCheckedAbbr = (x)
|
||||
stateUncheckedAbbr = ( )
|
||||
statePressedAbbr = (x)
|
||||
stateUnpressedAbbr = ( )
|
||||
|
||||
mathmlenclosedAbbr = enclosed
|
||||
mathmltableAbbr = tbl
|
||||
mathmlcellAbbr = cell
|
||||
mathmlfractionAbbr = frac
|
||||
mathmlfractionwithoutbarAbbr = frac no bar
|
||||
mathmlrootAbbr = root
|
||||
mathmlscriptedAbbr = scripted
|
||||
mathmlsquarerootAbbr = sqrt
|
||||
|
||||
baseAbbr = base
|
||||
close-fenceAbbr = close
|
||||
denominatorAbbr = den
|
||||
numeratorAbbr = num
|
||||
open-fenceAbbr = open
|
||||
overscriptAbbr = over
|
||||
presubscriptAbbr = presub
|
||||
presuperscriptAbbr = presup
|
||||
root-indexAbbr = index
|
||||
subscriptAbbr = sub
|
||||
superscriptAbbr = sup
|
||||
underscriptAbbr = under
|
||||
|
||||
notation-longdivAbbr = longdiv
|
||||
notation-actuarialAbbr = act
|
||||
notation-phasorangleAbbr = phasang
|
||||
notation-radicalAbbr = rad
|
||||
notation-boxAbbr = box
|
||||
notation-roundedboxAbbr = rndbox
|
||||
notation-circleAbbr = circ
|
||||
notation-leftAbbr = lft
|
||||
notation-rightAbbr = rght
|
||||
notation-topAbbr = top
|
||||
notation-bottomAbbr = bot
|
||||
notation-updiagonalstrikeAbbr = updiagstrike
|
||||
notation-downdiagonalstrikeAbbr = dwndiagstrike
|
||||
notation-verticalstrikeAbbr = vstrike
|
||||
notation-horizontalstrikeAbbr = hstrike
|
||||
notation-updiagonalarrowAbbr = updiagarrow
|
||||
notation-madruwbAbbr = madruwb
|
||||
|
@ -1663,16 +1663,38 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RequestAudioData();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::RequestAudioData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
|
||||
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
|
||||
|
||||
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
||||
__func__, &MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||
|
||||
return NS_OK;
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
|
||||
__func__, &MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||
} else {
|
||||
mAudioDataRequest.Begin(
|
||||
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<AudioData>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1713,26 +1735,52 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool skipToNextKeyFrame = NeedToSkipToNextKeyframe();
|
||||
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
|
||||
bool forceDecodeAhead = static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
|
||||
RequestVideoData();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::RequestVideoData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
// Time the video decode, so that if it's slow, we can increase our low
|
||||
// audio threshold to reduce the chance of an audio underrun while we're
|
||||
// waiting for a video decode to complete.
|
||||
mVideoDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
|
||||
NeedToSkipToNextKeyframe();
|
||||
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
|
||||
bool forceDecodeAhead = mSentFirstFrameLoadedEvent &&
|
||||
static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
|
||||
|
||||
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
|
||||
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
|
||||
currentTime);
|
||||
|
||||
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime, forceDecodeAhead)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
return NS_OK;
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mVideoDataRequest.Begin(
|
||||
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime, forceDecodeAhead)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
} else {
|
||||
mVideoDataRequest.Begin(
|
||||
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime, forceDecodeAhead)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -2028,30 +2076,10 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
} else {
|
||||
if (HasAudio()) {
|
||||
mAudioDataRequest.Begin(
|
||||
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<AudioData>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded)
|
||||
);
|
||||
RequestAudioData();
|
||||
}
|
||||
if (HasVideo()) {
|
||||
mVideoDecodeStartTime = TimeStamp::Now();
|
||||
mVideoDataRequest.Begin(
|
||||
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData, false, int64_t(0), false)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
RequestVideoData();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,20 +567,26 @@ protected:
|
||||
|
||||
nsresult DispatchAudioDecodeTaskIfNeeded();
|
||||
|
||||
// Ensures a to decode audio has been dispatched to the decode task queue.
|
||||
// Ensures a task to decode audio has been dispatched to the decode task queue.
|
||||
// If a task to decode has already been dispatched, this does nothing,
|
||||
// otherwise this dispatches a task to do the decode.
|
||||
// This is called on the state machine or decode threads.
|
||||
// The decoder monitor must be held.
|
||||
nsresult EnsureAudioDecodeTaskQueued();
|
||||
// Start a task to decode audio.
|
||||
// The decoder monitor must be held.
|
||||
void RequestAudioData();
|
||||
|
||||
nsresult DispatchVideoDecodeTaskIfNeeded();
|
||||
|
||||
// Ensures a to decode video has been dispatched to the decode task queue.
|
||||
// Ensures a task to decode video has been dispatched to the decode task queue.
|
||||
// If a task to decode has already been dispatched, this does nothing,
|
||||
// otherwise this dispatches a task to do the decode.
|
||||
// The decoder monitor must be held.
|
||||
nsresult EnsureVideoDecodeTaskQueued();
|
||||
// Start a task to decode video.
|
||||
// The decoder monitor must be held.
|
||||
void RequestVideoData();
|
||||
|
||||
// Re-evaluates the state and determines whether we need to dispatch
|
||||
// events to run the decode, or if not whether we should set the reader
|
||||
|
@ -628,6 +628,7 @@ RTCPeerConnection.prototype = {
|
||||
},
|
||||
|
||||
createOffer: function(optionsOrOnSuccess, onError, options) {
|
||||
// This entry-point handles both new and legacy call sig. Decipher which one
|
||||
let onSuccess;
|
||||
if (typeof optionsOrOnSuccess == "function") {
|
||||
onSuccess = optionsOrOnSuccess;
|
||||
@ -694,7 +695,14 @@ RTCPeerConnection.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
createAnswer: function(onSuccess, onError) {
|
||||
createAnswer: function(optionsOrOnSuccess, onError) {
|
||||
// This entry-point handles both new and legacy call sig. Decipher which one
|
||||
let onSuccess, options;
|
||||
if (typeof optionsOrOnSuccess == "function") {
|
||||
onSuccess = optionsOrOnSuccess;
|
||||
} else {
|
||||
options = optionsOrOnSuccess;
|
||||
}
|
||||
return this._legacyCatch(onSuccess, onError, () => {
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
|
@ -34,7 +34,8 @@ typedef android::MediaCodecProxy MediaCodecProxy;
|
||||
namespace mozilla {
|
||||
|
||||
GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
|
||||
: mAudioChannels(aConfig.mChannels)
|
||||
: mLastDecodedTime(0)
|
||||
, mAudioChannels(aConfig.mChannels)
|
||||
, mAudioRate(aConfig.mRate)
|
||||
, mAudioProfile(aConfig.mProfile)
|
||||
, mAudioBuffer(nullptr)
|
||||
@ -164,6 +165,14 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
ReleaseAudioBuffer();
|
||||
GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastDecodedTime = timeUs;
|
||||
|
||||
const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
|
||||
size_t dataOffset = mAudioBuffer->range_offset();
|
||||
size_t size = mAudioBuffer->range_length();
|
||||
@ -196,6 +205,8 @@ GonkAudioDecoderManager::Flush()
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ private:
|
||||
|
||||
void ReleaseAudioBuffer();
|
||||
|
||||
int64_t mLastDecodedTime;
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioRate;
|
||||
const uint32_t mAudioProfile;
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static bool sIsWMFEnabled = false;
|
||||
static bool sDXVAEnabled = false;
|
||||
static int sNumDecoderThreads = -1;
|
||||
static bool sIsIntelDecoderEnabled = false;
|
||||
@ -72,7 +71,6 @@ void
|
||||
WMFDecoderModule::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
sIsWMFEnabled = Preferences::GetBool("media.windows-media-foundation.enabled", false);
|
||||
sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
|
||||
sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false);
|
||||
SetNumOfDecoderThreads();
|
||||
@ -88,9 +86,7 @@ WMFDecoderModule::GetNumDecoderThreads()
|
||||
nsresult
|
||||
WMFDecoderModule::Startup()
|
||||
{
|
||||
if (sIsWMFEnabled) {
|
||||
mWMFInitialized = SUCCEEDED(wmf::MFStartup());
|
||||
}
|
||||
mWMFInitialized = SUCCEEDED(wmf::MFStartup());
|
||||
return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -40,12 +40,12 @@ function check_mp4(v, enabled) {
|
||||
|
||||
// H.264 Constrained Baseline Profile Level 3.0, mp3
|
||||
check("video/mp4; codecs=\"avc1.42E01E, mp3\"", "probably");
|
||||
|
||||
|
||||
check("video/mp4; codecs=\"avc1.42001E, mp4a.40.2\"", "probably");
|
||||
check("video/mp4; codecs=\"avc1.58A01E, mp4a.40.2\"", "probably");
|
||||
|
||||
|
||||
const ProbablyIfNotLinux = !IsLinuxGStreamer() ? "probably" : "";
|
||||
|
||||
|
||||
// H.264 Main Profile Level 3.0, AAC-LC
|
||||
check("video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"", "probably");
|
||||
// H.264 Main Profile Level 3.1, AAC-LC
|
||||
@ -74,7 +74,7 @@ function check_mp4(v, enabled) {
|
||||
check("audio/mp4; codecs=mp4a.40.5", ProbablyIfNotLinux);
|
||||
check("audio/x-m4a; codecs=\"mp4a.40.5\"", ProbablyIfNotLinux);
|
||||
check("audio/x-m4a; codecs=mp4a.40.5", ProbablyIfNotLinux);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function check_mp3(v, enabled) {
|
||||
@ -134,12 +134,12 @@ function IsMP4ReaderAvailable() {
|
||||
return prefs && (IsWindowsVistaOrLater() || IsMacOSSnowLeopardOrLater() || IsJellyBeanOrLater());
|
||||
}
|
||||
|
||||
var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
|
||||
getPref("media.omx.enabled") ||
|
||||
getPref("media.gstreamer.enabled") ||
|
||||
IsMP4ReaderAvailable();
|
||||
var haveMp4 = IsWindowsVistaOrLater() ||
|
||||
getPref("media.omx.enabled") ||
|
||||
getPref("media.gstreamer.enabled") ||
|
||||
IsMP4ReaderAvailable();
|
||||
// TODO: Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
|
||||
|
||||
|
||||
check_mp4(document.getElementById('v'), haveMp4);
|
||||
|
||||
var haveMp3 = getPref("media.directshow.enabled") ||
|
||||
|
@ -38,10 +38,10 @@
|
||||
|
||||
navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true })
|
||||
.then(stream => pc1.addStream(v1.mozSrcObject = stream))
|
||||
.then(() => pc1.createOffer())
|
||||
.then(() => pc1.createOffer({})) // check that createOffer accepts arg.
|
||||
.then(offer => pc1.setLocalDescription(offer))
|
||||
.then(() => pc2.setRemoteDescription(pc1.localDescription))
|
||||
.then(() => pc2.createAnswer())
|
||||
.then(() => pc2.createAnswer({})) // check that createAnswer accepts arg.
|
||||
.then(answer => pc2.setLocalDescription(answer))
|
||||
.then(() => pc1.setRemoteDescription(pc2.localDescription))
|
||||
.then(() => delivered)
|
||||
|
@ -750,8 +750,16 @@ nsresult WebMReader::SeekInternal(int64_t aTarget)
|
||||
uint64_t target = aTarget * NS_PER_USEC;
|
||||
|
||||
if (mSeekPreroll) {
|
||||
target = std::max(uint64_t(StartTime() * NS_PER_USEC),
|
||||
target - mSeekPreroll);
|
||||
uint64_t startTime = uint64_t(StartTime()) * NS_PER_USEC;
|
||||
if (target < mSeekPreroll || target - mSeekPreroll < startTime) {
|
||||
target = startTime;
|
||||
} else {
|
||||
target -= mSeekPreroll;
|
||||
}
|
||||
LOG(LogLevel::Debug,
|
||||
("Reader [%p] SeekPreroll: %f StartTime: %f AdjustedTarget: %f",
|
||||
this, double(mSeekPreroll) / NS_PER_S,
|
||||
double(startTime) / NS_PER_S, double(target) / NS_PER_S));
|
||||
}
|
||||
int r = nestegg_track_seek(mContext, trackToSeek, target);
|
||||
if (r != 0) {
|
||||
|
@ -668,7 +668,7 @@ MessagePort::MessagesReceived(nsTArray<MessagePortMessage>& aMessages)
|
||||
RemoveDocFromBFCache();
|
||||
|
||||
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> data;
|
||||
if (!NS_WARN_IF(SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
|
||||
if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
|
||||
data))) {
|
||||
// OOM, We cannot continue.
|
||||
return;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsICookiePermission.h"
|
||||
#include "nsICookieService.h"
|
||||
|
||||
#include "mozilla/dom/StorageBinding.h"
|
||||
#include "mozilla/dom/StorageEvent.h"
|
||||
@ -228,10 +229,6 @@ DOMStorage::BroadcastChangeNotification(const nsSubstring& aKey,
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
static const uint32_t ASK_BEFORE_ACCEPT = 1;
|
||||
static const uint32_t ACCEPT_SESSION = 2;
|
||||
static const uint32_t BEHAVIOR_REJECT = 2;
|
||||
|
||||
static const char kPermissionType[] = "cookie";
|
||||
static const char kStorageEnabled[] = "dom.storage.enabled";
|
||||
static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
|
||||
@ -282,11 +279,12 @@ DOMStorage::CanUseStorage(DOMStorage* aStorage)
|
||||
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
|
||||
|
||||
// Treat "ask every time" as "reject always".
|
||||
if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT)) {
|
||||
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
|
||||
lifetimePolicy == nsICookieService::ASK_BEFORE_ACCEPT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lifetimePolicy == ACCEPT_SESSION && aStorage) {
|
||||
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION && aStorage) {
|
||||
aStorage->mIsSessionOnly = true;
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ using namespace mozilla::dom::bluetooth;
|
||||
static void BinderDeadCallback(status_t aErr);
|
||||
static void InternalSetAudioRoutes(SwitchState aState);
|
||||
// Refer AudioService.java from Android
|
||||
static uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
5, // voice call
|
||||
15, // system
|
||||
15, // ring
|
||||
@ -94,7 +94,7 @@ static bool sA2dpSwitchDone = true;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace gonk {
|
||||
static VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = {
|
||||
static const VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = {
|
||||
{"audio.volume.content", VOLUME_MEDIA},
|
||||
{"audio.volume.notification", VOLUME_NOTIFICATION},
|
||||
{"audio.volume.alarm", VOLUME_ALARM},
|
||||
@ -763,7 +763,7 @@ nsresult
|
||||
AudioManager::ValidateVolumeIndex(uint32_t aCategory, uint32_t aIndex) const
|
||||
{
|
||||
uint32_t maxIndex = GetMaxVolumeByCategory(aCategory);
|
||||
if (aIndex < 0 || aIndex > maxIndex) {
|
||||
if (aIndex > maxIndex) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
@ -947,7 +947,7 @@ AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex)
|
||||
|
||||
nsresult
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) {
|
||||
if (aIndex < 0 || aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
if (aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mCurrentStreamVolumeTbl[aStream] = aIndex;
|
||||
@ -1122,7 +1122,7 @@ AudioManager::UpdateProfileState(AudioOutputProfiles aProfile, bool aActive)
|
||||
// are other profiles. The bluetooth and headset have the same priotity.
|
||||
uint32_t profilesNum = mAudioProfiles.Length();
|
||||
MOZ_ASSERT(profilesNum == DEVICE_TOTAL_NUMBER, "Error profile numbers!");
|
||||
for (uint32_t idx = profilesNum - 1; idx >= 0; --idx) {
|
||||
for (int32_t idx = profilesNum - 1; idx >= 0; --idx) {
|
||||
if (mAudioProfiles[idx]->GetActive()) {
|
||||
mPresentProfile = static_cast<AudioOutputProfiles>(idx);
|
||||
break;
|
||||
@ -1148,4 +1148,4 @@ AudioManager::UpdateVolumeFromProfile(AudioProfileData* aProfileData)
|
||||
SetVolumeByCategory(gVolumeData[idx].mCategory,
|
||||
aProfileData->mVolumeTable[gVolumeData[idx].mCategory]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ interface HTMLAnchorElement : HTMLElement {
|
||||
attribute DOMString ping;
|
||||
[SetterThrows]
|
||||
attribute DOMString rel;
|
||||
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
||||
attribute DOMString referrer;
|
||||
readonly attribute DOMTokenList relList;
|
||||
[SetterThrows]
|
||||
attribute DOMString hreflang;
|
||||
|
@ -28,6 +28,8 @@ interface HTMLAreaElement : HTMLElement {
|
||||
attribute DOMString ping;
|
||||
[SetterThrows]
|
||||
attribute DOMString rel;
|
||||
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
||||
attribute DOMString referrer;
|
||||
readonly attribute DOMTokenList relList;
|
||||
|
||||
// not implemented.
|
||||
|
@ -52,7 +52,14 @@ dictionary RTCDataChannelInit {
|
||||
unsigned short stream; // now id
|
||||
};
|
||||
|
||||
dictionary RTCOfferOptions {
|
||||
dictionary RTCOfferAnswerOptions {
|
||||
// boolean voiceActivityDetection = true; // TODO: support this (Bug 1184712)
|
||||
};
|
||||
|
||||
dictionary RTCAnswerOptions : RTCOfferAnswerOptions {
|
||||
};
|
||||
|
||||
dictionary RTCOfferOptions : RTCOfferAnswerOptions {
|
||||
long offerToReceiveVideo;
|
||||
long offerToReceiveAudio;
|
||||
boolean mozDontOfferDataChannel;
|
||||
@ -88,7 +95,7 @@ interface mozRTCPeerConnection : EventTarget {
|
||||
[Pref="media.peerconnection.identity.enabled"]
|
||||
Promise<DOMString> getIdentityAssertion();
|
||||
Promise<mozRTCSessionDescription> createOffer (optional RTCOfferOptions options);
|
||||
Promise<mozRTCSessionDescription> createAnswer ();
|
||||
Promise<mozRTCSessionDescription> createAnswer (optional RTCAnswerOptions options);
|
||||
Promise<void> setLocalDescription (mozRTCSessionDescription description);
|
||||
Promise<void> setRemoteDescription (mozRTCSessionDescription description);
|
||||
readonly attribute mozRTCSessionDescription? localDescription;
|
||||
|
@ -76,11 +76,15 @@ using namespace mozilla::dom;
|
||||
static nsresult
|
||||
GetDOMEventTarget(nsWebBrowser* aInBrowser, EventTarget** aTarget)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aInBrowser);
|
||||
if (!aInBrowser) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
aInBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
|
||||
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
|
||||
if (!domWindow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
|
||||
NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
|
||||
|
@ -360,7 +360,10 @@ nsWebBrowser::SetParentURIContentListener(
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowser::GetContentDOMWindow(nsIDOMWindow** aResult)
|
||||
{
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
if (!mDocShell) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> retval = mDocShell->GetWindow();
|
||||
retval.forget(aResult);
|
||||
return *aResult ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -141,10 +142,15 @@ struct CStringHashPolicy
|
||||
#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0),
|
||||
#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize),
|
||||
#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
|
||||
#define SUB_OTHER_SIZE(tabKind, servoKind, mSize) MOZ_ASSERT(mSize >= other.mSize); \
|
||||
mSize -= other.mSize;
|
||||
#define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
|
||||
MOZ_ASSERT(mSize >= other.mSize); \
|
||||
mSize -= other.mSize;
|
||||
#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
|
||||
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) n += (ServoSizes::servoKind == ServoSizes::GCHeapUsed) ? mSize : 0;
|
||||
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
|
||||
/* Avoid self-comparison warnings by comparing enums indirectly. */ \
|
||||
n += (mozilla::IsSame<int[ServoSizes::servoKind], int[ServoSizes::GCHeapUsed]>::value) \
|
||||
? mSize \
|
||||
: 0;
|
||||
#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize);
|
||||
#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize);
|
||||
|
||||
|
@ -604,6 +604,156 @@ condIf(const ParseNode* pn, ParseNodeKind kind)
|
||||
}
|
||||
|
||||
static bool
|
||||
Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
FullParseHandler& handler, const ReadOnlyCompileOptions& options,
|
||||
bool inGenexpLambda, SyntacticContext sc);
|
||||
|
||||
static bool
|
||||
FoldTypeOfExpr(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
|
||||
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_TYPEOFEXPR));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode*& expr = node->pn_kid;
|
||||
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
|
||||
return false;
|
||||
|
||||
// Constant-fold the entire |typeof| if given a constant with known type.
|
||||
RootedPropertyName result(cx);
|
||||
if (expr->isKind(PNK_STRING) || expr->isKind(PNK_TEMPLATE_STRING))
|
||||
result = cx->names().string;
|
||||
else if (expr->isKind(PNK_NUMBER))
|
||||
result = cx->names().number;
|
||||
else if (expr->isKind(PNK_NULL))
|
||||
result = cx->names().object;
|
||||
else if (expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE))
|
||||
result = cx->names().boolean;
|
||||
else if (expr->isKind(PNK_FUNCTION))
|
||||
result = cx->names().function;
|
||||
|
||||
if (result) {
|
||||
handler.prepareNodeForMutation(node);
|
||||
|
||||
node->setKind(PNK_STRING);
|
||||
node->setArity(PN_NULLARY);
|
||||
node->setOp(JSOP_NOP);
|
||||
node->pn_atom = result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FoldVoid(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
|
||||
const ReadOnlyCompileOptions& options, bool inGenexpLambda, SyntacticContext sc)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_VOID));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode*& expr = node->pn_kid;
|
||||
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
|
||||
return false;
|
||||
|
||||
if (sc == SyntacticContext::Condition) {
|
||||
if (expr->isKind(PNK_TRUE) ||
|
||||
expr->isKind(PNK_FALSE) ||
|
||||
expr->isKind(PNK_STRING) ||
|
||||
expr->isKind(PNK_TEMPLATE_STRING) ||
|
||||
expr->isKind(PNK_NUMBER) ||
|
||||
expr->isKind(PNK_NULL) ||
|
||||
expr->isKind(PNK_FUNCTION))
|
||||
{
|
||||
handler.prepareNodeForMutation(node);
|
||||
node->setKind(PNK_FALSE);
|
||||
node->setArity(PN_NULLARY);
|
||||
node->setOp(JSOP_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FoldDeleteExpr(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
|
||||
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode*& expr = node->pn_kid;
|
||||
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
|
||||
return false;
|
||||
|
||||
// Expression deletion evaluates the expression, then evaluates to
|
||||
// true. For trivial expressions, eliminate the expression evaluation.
|
||||
if (expr->isKind(PNK_TRUE) ||
|
||||
expr->isKind(PNK_FALSE) ||
|
||||
expr->isKind(PNK_STRING) ||
|
||||
expr->isKind(PNK_TEMPLATE_STRING) ||
|
||||
expr->isKind(PNK_NUMBER) ||
|
||||
expr->isKind(PNK_NULL) ||
|
||||
expr->isKind(PNK_FUNCTION))
|
||||
{
|
||||
handler.prepareNodeForMutation(node);
|
||||
node->setKind(PNK_TRUE);
|
||||
node->setArity(PN_NULLARY);
|
||||
node->setOp(JSOP_TRUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
|
||||
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEELEM) || node->isKind(PNK_DELETESUPERELEM));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM) || node->pn_kid->isKind(PNK_SUPERELEM));
|
||||
|
||||
ParseNode*& expr = node->pn_kid;
|
||||
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
|
||||
return false;
|
||||
|
||||
// If we're deleting an element, but constant-folding converted our
|
||||
// element reference into a dotted property access, we must *also*
|
||||
// morph the node's kind.
|
||||
//
|
||||
// In principle this also applies to |super["foo"] -> super.foo|,
|
||||
// but we don't constant-fold |super["foo"]| yet.
|
||||
if (node->isKind(PNK_DELETEELEM)) {
|
||||
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
|
||||
if (expr->isKind(PNK_DOT))
|
||||
node->setKind(PNK_DELETEPROP);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FoldDeleteProperty(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
|
||||
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEPROP) || node->isKind(PNK_DELETESUPERPROP));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT) || node->pn_kid->isKind(PNK_SUPERPROP));
|
||||
|
||||
ParseNode*& expr = node->pn_kid;
|
||||
#ifdef DEBUG
|
||||
ParseNodeKind oldKind = expr->getKind();
|
||||
#endif
|
||||
|
||||
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(expr->isKind(oldKind),
|
||||
"kind should have remained invariant under folding");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
FullParseHandler& handler, const ReadOnlyCompileOptions& options,
|
||||
bool inGenexpLambda, SyntacticContext sc)
|
||||
@ -629,6 +779,169 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
ParseNode* pn2 = nullptr;
|
||||
ParseNode* pn3 = nullptr;
|
||||
|
||||
switch (pn->getKind()) {
|
||||
case PNK_NEWTARGET:
|
||||
case PNK_NOP:
|
||||
case PNK_REGEXP:
|
||||
case PNK_STRING:
|
||||
case PNK_TRUE:
|
||||
case PNK_FALSE:
|
||||
case PNK_NULL:
|
||||
case PNK_ELISION:
|
||||
case PNK_NUMBER:
|
||||
case PNK_DEBUGGER:
|
||||
case PNK_BREAK:
|
||||
case PNK_CONTINUE:
|
||||
case PNK_TEMPLATE_STRING:
|
||||
case PNK_THIS:
|
||||
case PNK_GENERATOR:
|
||||
case PNK_EXPORT_BATCH_SPEC:
|
||||
case PNK_OBJECT_PROPERTY_NAME:
|
||||
case PNK_SUPERPROP:
|
||||
case PNK_FRESHENBLOCK:
|
||||
MOZ_ASSERT(pn->isArity(PN_NULLARY));
|
||||
goto afterFolding;
|
||||
|
||||
case PNK_TYPEOFNAME:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
|
||||
MOZ_ASSERT(!pn->pn_kid->maybeExpr());
|
||||
return true;
|
||||
|
||||
case PNK_TYPEOFEXPR:
|
||||
return FoldTypeOfExpr(cx, pn, handler, options, inGenexpLambda);
|
||||
|
||||
case PNK_VOID:
|
||||
return FoldVoid(cx, pn, handler, options, inGenexpLambda, sc);
|
||||
|
||||
case PNK_DELETENAME: {
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
|
||||
return true;
|
||||
}
|
||||
|
||||
case PNK_DELETEEXPR:
|
||||
return FoldDeleteExpr(cx, pn, handler, options, inGenexpLambda);
|
||||
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
return FoldDeleteElement(cx, pn, handler, options, inGenexpLambda);
|
||||
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
return FoldDeleteProperty(cx, pn, handler, options, inGenexpLambda);
|
||||
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_THROW:
|
||||
case PNK_POS:
|
||||
case PNK_NEG:
|
||||
case PNK_PREINCREMENT:
|
||||
case PNK_POSTINCREMENT:
|
||||
case PNK_PREDECREMENT:
|
||||
case PNK_POSTDECREMENT:
|
||||
case PNK_COMPUTED_NAME:
|
||||
case PNK_ARRAYPUSH:
|
||||
case PNK_SPREAD:
|
||||
case PNK_MUTATEPROTO:
|
||||
case PNK_EXPORT:
|
||||
case PNK_SEMI:
|
||||
case PNK_ASSIGN:
|
||||
case PNK_ADDASSIGN:
|
||||
case PNK_SUBASSIGN:
|
||||
case PNK_BITORASSIGN:
|
||||
case PNK_BITXORASSIGN:
|
||||
case PNK_BITANDASSIGN:
|
||||
case PNK_LSHASSIGN:
|
||||
case PNK_RSHASSIGN:
|
||||
case PNK_URSHASSIGN:
|
||||
case PNK_MULASSIGN:
|
||||
case PNK_DIVASSIGN:
|
||||
case PNK_MODASSIGN:
|
||||
case PNK_ELEM:
|
||||
case PNK_SUPERELEM:
|
||||
case PNK_COLON:
|
||||
case PNK_CASE:
|
||||
case PNK_SHORTHAND:
|
||||
case PNK_DOWHILE:
|
||||
case PNK_WHILE:
|
||||
case PNK_SWITCH:
|
||||
case PNK_LETBLOCK:
|
||||
case PNK_FOR:
|
||||
case PNK_CLASSMETHOD:
|
||||
case PNK_WITH:
|
||||
case PNK_CLASSNAMES:
|
||||
case PNK_DEFAULT:
|
||||
case PNK_YIELD_STAR:
|
||||
case PNK_YIELD:
|
||||
case PNK_RETURN:
|
||||
case PNK_IMPORT:
|
||||
case PNK_EXPORT_FROM:
|
||||
case PNK_EXPORT_DEFAULT:
|
||||
case PNK_CONDITIONAL:
|
||||
case PNK_FORIN:
|
||||
case PNK_FOROF:
|
||||
case PNK_FORHEAD:
|
||||
case PNK_CLASS:
|
||||
case PNK_IF:
|
||||
case PNK_TRY:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_BITOR:
|
||||
case PNK_BITXOR:
|
||||
case PNK_BITAND:
|
||||
case PNK_STRICTEQ:
|
||||
case PNK_EQ:
|
||||
case PNK_STRICTNE:
|
||||
case PNK_NE:
|
||||
case PNK_LT:
|
||||
case PNK_LE:
|
||||
case PNK_GT:
|
||||
case PNK_GE:
|
||||
case PNK_INSTANCEOF:
|
||||
case PNK_IN:
|
||||
case PNK_LSH:
|
||||
case PNK_RSH:
|
||||
case PNK_URSH:
|
||||
case PNK_ADD:
|
||||
case PNK_SUB:
|
||||
case PNK_STAR:
|
||||
case PNK_DIV:
|
||||
case PNK_MOD:
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_STATEMENTLIST:
|
||||
case PNK_ARGSBODY:
|
||||
case PNK_ARRAYCOMP:
|
||||
case PNK_VAR:
|
||||
case PNK_CONST:
|
||||
case PNK_LET:
|
||||
case PNK_GLOBALCONST:
|
||||
case PNK_OBJECT:
|
||||
case PNK_CLASSMETHODLIST:
|
||||
case PNK_TEMPLATE_STRING_LIST:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_EXPORT_SPEC_LIST:
|
||||
case PNK_IMPORT_SPEC_LIST:
|
||||
case PNK_CATCHLIST:
|
||||
case PNK_LABEL:
|
||||
case PNK_DOT:
|
||||
case PNK_LEXICALSCOPE:
|
||||
case PNK_NAME:
|
||||
case PNK_FUNCTION:
|
||||
case PNK_CATCH:
|
||||
case PNK_EXPORT_SPEC:
|
||||
case PNK_IMPORT_SPEC:
|
||||
case PNK_CALLSITEOBJ:
|
||||
break; // for now
|
||||
|
||||
case PNK_LIMIT: // invalid sentinel value
|
||||
MOZ_CRASH("invalid node kind");
|
||||
}
|
||||
|
||||
// First, recursively fold constants on the children of this node.
|
||||
switch (pn->getArity()) {
|
||||
case PN_CODE:
|
||||
@ -653,7 +966,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
|
||||
// Don't fold a parenthesized call expression. See bug 537673.
|
||||
ParseNode** listp = &pn->pn_head;
|
||||
if ((pn->isKind(PNK_CALL) || pn->isKind(PNK_NEW)) && (*listp)->isInParens())
|
||||
if ((pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE)) && (*listp)->isInParens())
|
||||
listp = &(*listp)->pn_next;
|
||||
|
||||
for (; *listp; listp = &(*listp)->pn_next) {
|
||||
@ -728,13 +1041,12 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
break;
|
||||
|
||||
case PN_UNARY:
|
||||
MOZ_ASSERT(!IsDeleteKind(pn->getKind()),
|
||||
"should have been handled above");
|
||||
if (pn->pn_kid) {
|
||||
SyntacticContext kidsc =
|
||||
pn->isKind(PNK_NOT)
|
||||
? SyntacticContext::Condition
|
||||
: IsDeleteKind(pn->getKind())
|
||||
? SyntacticContext::Delete
|
||||
: SyntacticContext::Other;
|
||||
SyntacticContext kidsc = pn->isKind(PNK_NOT)
|
||||
? SyntacticContext::Condition
|
||||
: SyntacticContext::Other;
|
||||
if (!Fold(cx, &pn->pn_kid, handler, options, inGenexpLambda, kidsc))
|
||||
return false;
|
||||
}
|
||||
@ -1021,6 +1333,8 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
case PNK_TYPEOFNAME:
|
||||
case PNK_TYPEOFEXPR:
|
||||
case PNK_VOID:
|
||||
MOZ_CRASH("should have been fully handled above");
|
||||
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_POS:
|
||||
@ -1137,6 +1451,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
default:;
|
||||
}
|
||||
|
||||
afterFolding:
|
||||
if (sc == SyntacticContext::Condition) {
|
||||
Truthiness t = Boolish(pn);
|
||||
if (t != Unknown) {
|
||||
|
@ -5732,7 +5732,7 @@ ICInNativeDoesNotExistCompiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.loadPtr(Address(ICStubReg, shapeOffset), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failurePopR0Scratch);
|
||||
}
|
||||
masm.addPtr(Imm32(sizeof(size_t)), StackPointer);
|
||||
masm.addToStackPtr(Imm32(sizeof(size_t)));
|
||||
|
||||
// Shape and type checks succeeded, ok to proceed.
|
||||
masm.moveValue(BooleanValue(false), R0);
|
||||
|
@ -1019,6 +1019,8 @@ class ICStubCompiler
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
MOZ_ASSERT(!regs.has(ICTailCallReg));
|
||||
MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_ASSERT(!regs.has(ICTailCallReg));
|
||||
#endif
|
||||
regs.take(BaselineFrameReg);
|
||||
regs.take(ICStubReg);
|
||||
|
@ -2528,7 +2528,7 @@ namespace JS {
|
||||
template <typename Outer>
|
||||
class PropertyDescriptorOperations
|
||||
{
|
||||
const JSPropertyDescriptor * desc() const { return static_cast<const Outer*>(this)->extract(); }
|
||||
const JSPropertyDescriptor* desc() const { return static_cast<const Outer*>(this)->extract(); }
|
||||
|
||||
bool has(unsigned bit) const {
|
||||
MOZ_ASSERT(bit != 0);
|
||||
@ -2770,17 +2770,12 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
|
||||
|
||||
namespace js {
|
||||
|
||||
template <>
|
||||
struct GCMethods<JSPropertyDescriptor> {
|
||||
static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class RootedBase<JSPropertyDescriptor>
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>
|
||||
{
|
||||
friend class JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
|
||||
friend class JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
|
||||
friend class JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>;
|
||||
friend class JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>;
|
||||
const JSPropertyDescriptor* extract() const {
|
||||
return static_cast<const JS::Rooted<JSPropertyDescriptor>*>(this)->address();
|
||||
}
|
||||
@ -2791,9 +2786,9 @@ class RootedBase<JSPropertyDescriptor>
|
||||
|
||||
template <>
|
||||
class HandleBase<JSPropertyDescriptor>
|
||||
: public JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >
|
||||
: public JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor>>
|
||||
{
|
||||
friend class JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >;
|
||||
friend class JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor>>;
|
||||
const JSPropertyDescriptor* extract() const {
|
||||
return static_cast<const JS::Handle<JSPropertyDescriptor>*>(this)->address();
|
||||
}
|
||||
@ -2801,10 +2796,10 @@ class HandleBase<JSPropertyDescriptor>
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<JSPropertyDescriptor>
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>
|
||||
{
|
||||
friend class JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
|
||||
friend class JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
|
||||
friend class JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>;
|
||||
friend class JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>;
|
||||
const JSPropertyDescriptor* extract() const {
|
||||
return static_cast<const JS::MutableHandle<JSPropertyDescriptor>*>(this)->address();
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 1182373;
|
||||
var summary =
|
||||
"Don't let constant-folding in the MemberExpression part of a tagged " +
|
||||
"template cause an incorrect |this| be passed to the callee";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var prop = "global";
|
||||
|
||||
var obj = { prop: "obj", f: function() { return this.prop; } };
|
||||
|
||||
assertEq(obj.f``, "obj");
|
||||
assertEq((true ? obj.f : null)``, "global");
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -7,7 +7,6 @@
|
||||
EXPORTS += [
|
||||
'nsAXPCNativeCallContext.h',
|
||||
'nsTArrayHelpers.h',
|
||||
'SandboxPrivate.h',
|
||||
'xpc_map_end.h',
|
||||
]
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
// This interface is public only because it is used in jsd.
|
||||
// Once jsd is gone this file should be moved back to xpconnect/src.
|
||||
|
||||
class SandboxPrivate : public nsIGlobalObject,
|
||||
public nsIScriptObjectPrincipal,
|
@ -343,7 +343,7 @@ private:
|
||||
uint32_t count = GetChildCount();
|
||||
mFlags.mHasHashedFrames = 1;
|
||||
uint32_t minLength = std::max(kMinChildCountForHashtable,
|
||||
uint32_t(PL_DHASH_DEFAULT_INITIAL_LENGTH));
|
||||
uint32_t(PLDHashTable::kDefaultInitialLength));
|
||||
mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >(std::max(count, minLength));
|
||||
for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
|
||||
mFrames->PutEntry(f);
|
||||
|
@ -28,7 +28,9 @@
|
||||
* does not have <atomic>. So be sure to check for <atomic> support
|
||||
* along with C++0x support.
|
||||
*/
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#if defined(_MSC_VER)
|
||||
# define MOZ_HAVE_CXX11_ATOMICS
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
/*
|
||||
* Clang doesn't like <atomic> from libstdc++ before 4.7 due to the
|
||||
* loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline
|
||||
@ -42,8 +44,6 @@
|
||||
# elif MOZ_USING_LIBCXX && defined(__clang__)
|
||||
# define MOZ_HAVE_CXX11_ATOMICS
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# define MOZ_HAVE_CXX11_ATOMICS
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -289,7 +289,6 @@ pref("media.decoder.heuristic.dormant.enabled", true);
|
||||
pref("media.decoder.heuristic.dormant.timeout", 60000);
|
||||
|
||||
#ifdef MOZ_WMF
|
||||
pref("media.windows-media-foundation.enabled", true);
|
||||
pref("media.wmf.decoder.thread-count", -1);
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
|
@ -19,7 +19,7 @@ enum ReferrerPolicy {
|
||||
|
||||
/* spec tokens: default no-referrer-when-downgrade */
|
||||
RP_No_Referrer_When_Downgrade = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
RP_Default = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
RP_Default = nsIHttpChannel::REFERRER_POLICY_DEFAULT,
|
||||
|
||||
/* spec tokens: origin-when-cross-origin */
|
||||
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
|
||||
@ -31,28 +31,47 @@ enum ReferrerPolicy {
|
||||
RP_Unset = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE
|
||||
};
|
||||
|
||||
/* spec tokens: never no-referrer */
|
||||
const char kRPS_Never[] = "never";
|
||||
const char kRPS_No_Referrer[] = "no-referrer";
|
||||
|
||||
/* spec tokens: origin */
|
||||
const char kRPS_Origin[] = "origin";
|
||||
|
||||
/* spec tokens: default no-referrer-when-downgrade */
|
||||
const char kRPS_Default[] = "default";
|
||||
const char kRPS_No_Referrer_When_Downgrade[] = "no-referrer-when-downgrade";
|
||||
|
||||
/* spec tokens: origin-when-cross-origin */
|
||||
const char kRPS_Origin_When_Cross_Origin[] = "origin-when-cross-origin";
|
||||
const char kRPS_Origin_When_Crossorigin[] = "origin-when-crossorigin";
|
||||
|
||||
/* spec tokens: always unsafe-url */
|
||||
const char kRPS_Always[] = "always";
|
||||
const char kRPS_Unsafe_URL[] = "unsafe-url";
|
||||
|
||||
inline ReferrerPolicy
|
||||
ReferrerPolicyFromString(const nsAString& content)
|
||||
{
|
||||
// This is implemented step by step as described in the Referrer Policy
|
||||
// specification, section 6.4 "Determine token's Policy".
|
||||
if (content.LowerCaseEqualsLiteral("never") ||
|
||||
content.LowerCaseEqualsLiteral("no-referrer")) {
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Never) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer)) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral("origin")) {
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Origin)) {
|
||||
return RP_Origin;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral("default") ||
|
||||
content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")) {
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Default) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
return RP_No_Referrer_When_Downgrade;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral("origin-when-cross-origin") ||
|
||||
content.LowerCaseEqualsLiteral("origin-when-crossorigin")) {
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)) {
|
||||
return RP_Origin_When_Crossorigin;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral("always") ||
|
||||
content.LowerCaseEqualsLiteral("unsafe-url")) {
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Always) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
return RP_Unsafe_URL;
|
||||
}
|
||||
// Spec says if none of the previous match, use No_Referrer.
|
||||
@ -63,15 +82,42 @@ ReferrerPolicyFromString(const nsAString& content)
|
||||
inline bool
|
||||
IsValidReferrerPolicy(const nsAString& content)
|
||||
{
|
||||
return content.LowerCaseEqualsLiteral("never")
|
||||
|| content.LowerCaseEqualsLiteral("no-referrer")
|
||||
|| content.LowerCaseEqualsLiteral("origin")
|
||||
|| content.LowerCaseEqualsLiteral("default")
|
||||
|| content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")
|
||||
|| content.LowerCaseEqualsLiteral("origin-when-cross-origin")
|
||||
|| content.LowerCaseEqualsLiteral("origin-when-crossorigin")
|
||||
|| content.LowerCaseEqualsLiteral("always")
|
||||
|| content.LowerCaseEqualsLiteral("unsafe-url");
|
||||
return content.LowerCaseEqualsLiteral(kRPS_Never)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Default)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Always)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsValidAttributeReferrerPolicy(const nsAString& aContent)
|
||||
{
|
||||
// Spec allows only these three policies at the moment
|
||||
// See bug 1178337
|
||||
return aContent.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_Origin)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
|
||||
}
|
||||
|
||||
inline ReferrerPolicy
|
||||
AttributeReferrerPolicyFromString(const nsAString& aContent)
|
||||
{
|
||||
// if the referrer attribute string is empty, return RP_Unset
|
||||
if (aContent.IsEmpty()) {
|
||||
return RP_Unset;
|
||||
}
|
||||
// if the referrer attribute string is not empty and contains a valid
|
||||
// referrer policy, return the according enum value
|
||||
if (IsValidAttributeReferrerPolicy(aContent)) {
|
||||
return ReferrerPolicyFromString(aContent);
|
||||
}
|
||||
// in any other case the referrer attribute contains an invalid
|
||||
// policy value, we thus return RP_No_Referrer
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
|
@ -11,7 +11,7 @@ interface nsIPrefBranch;
|
||||
/**
|
||||
* nsINetUtil provides various network-related utility methods.
|
||||
*/
|
||||
[scriptable, uuid(ca68c485-9db3-4c12-82a6-4fab7948e2d5)]
|
||||
[scriptable, uuid(885d6940-1001-46e7-92ec-d494a78d7784)]
|
||||
interface nsINetUtil : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -192,4 +192,16 @@ interface nsINetUtil : nsISupports
|
||||
out AUTF8String aCharset,
|
||||
out long aCharsetStart,
|
||||
out long aCharsetEnd);
|
||||
|
||||
/**
|
||||
* Parse an attribute referrer policy string (no-referrer, origin, unsafe-url)
|
||||
* and return the according integer code (defined in nsIHttpChannel.idl)
|
||||
*
|
||||
* @param aPolicyString
|
||||
* the policy string given as attribute
|
||||
* @return aPolicyEnum
|
||||
* referrer policy code from nsIHttpChannel.idl, (see parser in
|
||||
* ReferrerPolicy.h for details)
|
||||
*/
|
||||
unsigned long parseAttributePolicyString(in AString aPolicyString);
|
||||
};
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "CaptivePortalService.h"
|
||||
#include "ReferrerPolicy.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsINetworkManager.h"
|
||||
@ -1690,6 +1691,16 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// parse policyString to policy enum value (see ReferrerPolicy.h)
|
||||
NS_IMETHODIMP
|
||||
nsIOService::ParseAttributePolicyString(const nsAString& policyString,
|
||||
uint32_t *outPolicyEnum)
|
||||
{
|
||||
NS_ENSURE_ARG(outPolicyEnum);
|
||||
*outPolicyEnum = (uint32_t)mozilla::net::AttributeReferrerPolicyFromString(policyString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsISpeculativeConnect
|
||||
class IOServiceProxyCallback final : public nsIProtocolProxyCallback
|
||||
{
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsINetworkManager.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -17,12 +17,6 @@ using namespace mozilla::ipc;
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// Behavior pref constants
|
||||
static const int32_t BEHAVIOR_ACCEPT = 0;
|
||||
static const int32_t BEHAVIOR_REJECTFOREIGN = 1;
|
||||
// static const int32_t BEHAVIOR_REJECT = 2;
|
||||
static const int32_t BEHAVIOR_LIMITFOREIGN = 3;
|
||||
|
||||
// Pref string constants
|
||||
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
|
||||
static const char kPrefThirdPartySession[] =
|
||||
@ -46,7 +40,7 @@ NS_IMPL_ISUPPORTS(CookieServiceChild,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
CookieServiceChild::CookieServiceChild()
|
||||
: mCookieBehavior(BEHAVIOR_ACCEPT)
|
||||
: mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
|
||||
, mThirdPartySession(false)
|
||||
{
|
||||
NS_ASSERTION(IsNeckoChild(), "not a child process");
|
||||
@ -80,7 +74,9 @@ CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
|
||||
int32_t val;
|
||||
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
|
||||
mCookieBehavior =
|
||||
val >= BEHAVIOR_ACCEPT && val <= BEHAVIOR_LIMITFOREIGN ? val : BEHAVIOR_ACCEPT;
|
||||
val >= nsICookieService::BEHAVIOR_ACCEPT &&
|
||||
val <= nsICookieService::BEHAVIOR_LIMIT_FOREIGN
|
||||
? val : nsICookieService::BEHAVIOR_ACCEPT;
|
||||
|
||||
bool boolval;
|
||||
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
|
||||
@ -95,7 +91,9 @@ CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
|
||||
bool
|
||||
CookieServiceChild::RequireThirdPartyCheck()
|
||||
{
|
||||
return mCookieBehavior == BEHAVIOR_REJECTFOREIGN || mCookieBehavior == BEHAVIOR_LIMITFOREIGN || mThirdPartySession;
|
||||
return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
|
||||
mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
|
||||
mThirdPartySession;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -109,13 +109,6 @@ static const uint32_t kMaxCookiesPerHost = 150;
|
||||
static const uint32_t kMaxBytesPerCookie = 4096;
|
||||
static const uint32_t kMaxBytesPerPath = 1024;
|
||||
|
||||
// behavior pref constants
|
||||
static const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies
|
||||
static const uint32_t BEHAVIOR_REJECTFOREIGN = 1; // reject all third-party cookies
|
||||
static const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies
|
||||
static const uint32_t BEHAVIOR_LIMITFOREIGN = 3; // reject third-party cookies unless the
|
||||
// eTLD already has at least one cookie
|
||||
|
||||
// pref string constants
|
||||
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
|
||||
static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
|
||||
@ -711,7 +704,7 @@ NS_IMPL_ISUPPORTS(nsCookieService,
|
||||
|
||||
nsCookieService::nsCookieService()
|
||||
: mDBState(nullptr)
|
||||
, mCookieBehavior(BEHAVIOR_ACCEPT)
|
||||
, mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
|
||||
, mThirdPartySession(false)
|
||||
, mMaxNumberOfCookies(kMaxNumberOfCookies)
|
||||
, mMaxCookiesPerHost(kMaxCookiesPerHost)
|
||||
@ -3490,22 +3483,22 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
|
||||
}
|
||||
|
||||
// check default prefs
|
||||
if (mCookieBehavior == BEHAVIOR_REJECT) {
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
|
||||
return STATUS_REJECTED;
|
||||
}
|
||||
|
||||
// check if cookie is foreign
|
||||
if (aIsForeign) {
|
||||
if (mCookieBehavior == BEHAVIOR_ACCEPT && mThirdPartySession)
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT && mThirdPartySession)
|
||||
return STATUS_ACCEPT_SESSION;
|
||||
|
||||
if (mCookieBehavior == BEHAVIOR_REJECTFOREIGN) {
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
|
||||
return STATUS_REJECTED;
|
||||
}
|
||||
|
||||
if (mCookieBehavior == BEHAVIOR_LIMITFOREIGN) {
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
uint32_t priorCookieCount = 0;
|
||||
nsAutoCString hostFromURI;
|
||||
aHostURI->GetHost(hostFromURI);
|
||||
|
@ -71,9 +71,26 @@ interface nsIChannel;
|
||||
* to set the cookie.
|
||||
* data : the referrer, or "?" if unknown
|
||||
*/
|
||||
[scriptable, uuid(2aaa897a-293c-4d2b-a657-8c9b7136996d)]
|
||||
[scriptable, uuid(f5807c53-de48-461a-8117-bd156bc2dcf0)]
|
||||
interface nsICookieService : nsISupports
|
||||
{
|
||||
/*
|
||||
* Possible values for the "network.cookie.cookieBehavior" preference.
|
||||
*/
|
||||
const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies
|
||||
const uint32_t BEHAVIOR_REJECT_FOREIGN = 1; // reject all third-party cookies
|
||||
const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies
|
||||
const uint32_t BEHAVIOR_LIMIT_FOREIGN = 3; // reject third-party cookies unless the
|
||||
// eTLD already has at least one cookie
|
||||
|
||||
/*
|
||||
* Possible values for the "network.cookie.lifetimePolicy" preference.
|
||||
*/
|
||||
const uint32_t ACCEPT_NORMALLY = 0; // accept normally
|
||||
const uint32_t ASK_BEFORE_ACCEPT = 1; // ask before accepting
|
||||
const uint32_t ACCEPT_SESSION = 2; // downgrade to session
|
||||
const uint32_t ACCEPT_FOR_N_DAYS = 3; // limit lifetime to N days
|
||||
|
||||
/*
|
||||
* Get the complete cookie string associated with the URI.
|
||||
*
|
||||
|
@ -454,25 +454,24 @@ nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
|
||||
class NotifyDNSResolution: public nsRunnable
|
||||
{
|
||||
public:
|
||||
NotifyDNSResolution(nsMainThreadPtrHandle<nsIObserverService> &aObs,
|
||||
const nsACString &aHostname)
|
||||
: mObs(aObs)
|
||||
, mHostname(aHostname)
|
||||
explicit NotifyDNSResolution(const nsACString &aHostname)
|
||||
: mHostname(aHostname)
|
||||
{
|
||||
MOZ_ASSERT(mObs);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mObs->NotifyObservers(nullptr,
|
||||
"dns-resolution-request",
|
||||
NS_ConvertUTF8toUTF16(mHostname).get());
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->NotifyObservers(nullptr,
|
||||
"dns-resolution-request",
|
||||
NS_ConvertUTF8toUTF16(mHostname).get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsIObserverService> mObs;
|
||||
nsCString mHostname;
|
||||
};
|
||||
|
||||
@ -606,8 +605,6 @@ nsDNSService::Init()
|
||||
|
||||
nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
|
||||
nsRefPtr<nsHostResolver> res;
|
||||
nsresult rv = nsHostResolver::Create(maxCacheEntries,
|
||||
defaultCacheLifetime,
|
||||
@ -635,10 +632,6 @@ nsDNSService::Init()
|
||||
}
|
||||
}
|
||||
mNotifyResolution = notifyResolution;
|
||||
if (mNotifyResolution) {
|
||||
mObserverService =
|
||||
new nsMainThreadPtrHolder<nsIObserverService>(obs);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MOZILLA_XPCOMRT_API)
|
||||
@ -760,8 +753,7 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname,
|
||||
}
|
||||
|
||||
if (mNotifyResolution) {
|
||||
NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
|
||||
aHostname));
|
||||
NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
|
||||
}
|
||||
|
||||
if (!res)
|
||||
@ -874,8 +866,7 @@ nsDNSService::Resolve(const nsACString &aHostname,
|
||||
}
|
||||
|
||||
if (mNotifyResolution) {
|
||||
NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
|
||||
aHostname));
|
||||
NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
@ -61,7 +59,6 @@ private:
|
||||
bool mOffline;
|
||||
bool mNotifyResolution;
|
||||
bool mOfflineLocalhost;
|
||||
nsMainThreadPtrHandle<nsIObserverService> mObserverService;
|
||||
nsTHashtable<nsCStringHashKey> mLocalDomains;
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ TEST_DIRS += [
|
||||
'test_cert_version',
|
||||
'test_intermediate_basic_usage_constraints',
|
||||
'test_pinning_dynamic',
|
||||
'test_ocsp_url',
|
||||
]
|
||||
|
||||
if not CONFIG['MOZ_NO_SMART_CARDS']:
|
||||
|
@ -26,6 +26,7 @@ extKeyUsage:[serverAuth,clientAuth,codeSigning,emailProtection
|
||||
nsSGC, # Netscape Server Gated Crypto
|
||||
OCSPSigning,timeStamping]
|
||||
subjectAlternativeName:[<dNSName>,...]
|
||||
authorityInformationAccess:<OCSP URI>
|
||||
|
||||
Where:
|
||||
[] indicates an optional field or component of a field
|
||||
@ -48,14 +49,14 @@ or as the subject public key information field, respectively.
|
||||
|
||||
from pyasn1.codec.der import decoder
|
||||
from pyasn1.codec.der import encoder
|
||||
from pyasn1.type import constraint, namedtype, tag, univ, useful
|
||||
from pyasn1.type import constraint, tag, univ, useful
|
||||
from pyasn1_modules import rfc2459
|
||||
import base64
|
||||
import binascii
|
||||
import datetime
|
||||
import hashlib
|
||||
import sys
|
||||
import rsa
|
||||
|
||||
import pykey
|
||||
|
||||
class UnknownBaseError(Exception):
|
||||
"""Base class for handling unexpected input in this module."""
|
||||
@ -99,14 +100,6 @@ class UnknownKeyPurposeTypeError(UnknownBaseError):
|
||||
self.category = 'keyPurpose'
|
||||
|
||||
|
||||
class UnknownKeySpecificationError(UnknownBaseError):
|
||||
"""Helper exception type to handle unknown key specifications."""
|
||||
|
||||
def __init__(self, value):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'key specification'
|
||||
|
||||
|
||||
class UnknownKeyTargetError(UnknownBaseError):
|
||||
"""Helper exception type to handle unknown key targets."""
|
||||
|
||||
@ -128,6 +121,18 @@ def getASN1Tag(asn1Type):
|
||||
type from the pyasn1 package"""
|
||||
return asn1Type.baseTagSet.getBaseTag().asTuple()[2]
|
||||
|
||||
def stringToAccessDescription(string):
|
||||
"""Helper function that takes a string representing a URI
|
||||
presumably identifying an OCSP authority information access
|
||||
location. Returns an AccessDescription usable by pyasn1."""
|
||||
accessMethod = rfc2459.id_ad_ocsp
|
||||
accessLocation = rfc2459.GeneralName()
|
||||
accessLocation.setComponentByName('uniformResourceIdentifier', string)
|
||||
sequence = univ.Sequence()
|
||||
sequence.setComponentByPosition(0, accessMethod)
|
||||
sequence.setComponentByPosition(1, accessLocation)
|
||||
return sequence
|
||||
|
||||
def stringToAlgorithmIdentifier(string):
|
||||
"""Helper function that converts a description of an algorithm
|
||||
to a representation usable by the pyasn1 package"""
|
||||
@ -166,97 +171,10 @@ def datetimeToTime(dt):
|
||||
time.setComponentByName('generalTime', useful.GeneralizedTime(dt.strftime('%Y%m%d%H%M%SZ')))
|
||||
return time
|
||||
|
||||
def byteStringToHexifiedBitString(string):
|
||||
"""Takes a string of bytes and returns a hex string representing
|
||||
those bytes for use with pyasn1.type.univ.BitString. It must be of
|
||||
the form "'<hex bytes>'H", where the trailing 'H' indicates to
|
||||
pyasn1 that the input is a hex string."""
|
||||
return "'%s'H" % binascii.hexlify(string)
|
||||
|
||||
class RSAPublicKey(univ.Sequence):
|
||||
"""Helper type for encoding an RSA public key"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('N', univ.Integer()),
|
||||
namedtype.NamedType('E', univ.Integer()))
|
||||
|
||||
|
||||
class Certificate:
|
||||
"""Utility class for reading a certificate specification and
|
||||
generating a signed x509 certificate"""
|
||||
|
||||
# For reference, when encoded as a subject public key info, the
|
||||
# base64-encoded sha-256 hash of this key is
|
||||
# VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
|
||||
sharedRSA_N = long(
|
||||
'00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
|
||||
'6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
|
||||
'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
|
||||
'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
|
||||
'2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
|
||||
'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
|
||||
'31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
|
||||
'95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
|
||||
'fe4923fa7251c431d503acda180a35ed8d', 16)
|
||||
sharedRSA_E = 65537L
|
||||
sharedRSA_D = long(
|
||||
'009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
|
||||
'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
|
||||
'3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
|
||||
'39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
|
||||
'7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
|
||||
'79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
|
||||
'6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
|
||||
'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
|
||||
'5b62b30e6011f224725946eec57c6d9441', 16)
|
||||
sharedRSA_P = long(
|
||||
'00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
|
||||
'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
|
||||
'8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
|
||||
'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
|
||||
'3ca5d19301f48c742b', 16)
|
||||
sharedRSA_Q = long(
|
||||
'00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
|
||||
'8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
|
||||
'1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
|
||||
'28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
|
||||
'5810a77b9845bc3127', 16)
|
||||
# For reference, when encoded as a subject public key info, the
|
||||
# base64-encoded sha-256 hash of this key is
|
||||
# K+uamI+1JmrxMsBxEfGOoydEDJVMa5MY/eaTj+43Lzc=
|
||||
alternateRSA_N = long(
|
||||
'00cd6e66a71b9a104c7c5f270b5869da966a52e547f8a026eef128c4d51f'
|
||||
'a7d949b1df8a1e342c59cbad0fb6ef867427bd9e76f2e9bf0b582745c646'
|
||||
'4446db7bdd4d0f2f361da724ff206d070b3d75ad87d690fa307dcccc2ad1'
|
||||
'4283921f9621f2a564e7e9f708a98556194df12fb4b0a2f0b89f76ac7e59'
|
||||
'668285aa50f14f310b6ebd8f001d0c115393bd27f3334f67780abfe0b19e'
|
||||
'5ac3414c5b4a3819fbed39198050e1c660e44cacaf108cbe1671d5a14602'
|
||||
'6090f371b2873d419eeb6de982fb493c3d4d33fb8a12bd65f1c59a3494dd'
|
||||
'd7e1131aa45e896d817bbb28e6fd4c2323ed17a26dc8e4e49281decc641e'
|
||||
'f7b7acfe65e7c0e5212fb2a9d472902c35', 16)
|
||||
alternateRSA_E = 65537L
|
||||
alternateRSA_D = long(
|
||||
'6ae6e0946550aeda9e7e059b69ceebe90a3b490542e4545e53309bfd2c13'
|
||||
'f486dd012ea6b90fbb4aba2c4b4e29f1981c9cb1d986b9dbf56bba6b8b75'
|
||||
'4c4a3b12d65ee87a88c3ca04d9a2e2df7e84166171cecfe31c13cecb194a'
|
||||
'3b9d76c271b80b498f45b93fd0b78a2e70d8e9b26598e51bae1fdb7384a2'
|
||||
'4b99b31f9bf351d9692c00d6f05c30424be4b4de55331ac77532c3fdaf74'
|
||||
'95dbf7aef601b517ed227d0efa3de443d56d8b29e556f6be938eabf4c0e4'
|
||||
'2e2fe38bec60cba5b5ff9192b68620ee4b629b9d0b64b9a8810809813b0b'
|
||||
'04e485d97fdad2961c0982a589863643974e3900dd8a75112a0fffc59f4b'
|
||||
'24c31307901dd04a848b02db32f61a01', 16)
|
||||
alternateRSA_P = long(
|
||||
'00feeacc987c0494cb5e9550eefb9dc56f9d957022a11539dae04c6361ab'
|
||||
'd5081dce2a6aec0905450886f5bb7e56e8bd2bef37cfa16fbda5ffc268ca'
|
||||
'e0499017552c37fa4a041341d67d4d69d093d8950f50672fb085b636560e'
|
||||
'2446689474b29be7abeba358ab7bc4cde3fd065d46f762adeb5c4b54ccca'
|
||||
'651a14b498311615b1', 16)
|
||||
alternateRSA_Q = long(
|
||||
'00ce4dca3fdda86b8c800c268082446633c8aaf0f20c729878092198585b'
|
||||
'd2ed134a7bdb2c93f829f99e6e9070db6598b3113627fd87bf6bc46cb2e5'
|
||||
'121777cbea9c41e74c9c2c248931dbccb5ae8a1dccfad284784cc35b8329'
|
||||
'abc420ce95640085dbf325fa7f6a2a567d487c1ef67d07a56c6beade9404'
|
||||
'd039ba01adf328ebc5', 16)
|
||||
|
||||
def __init__(self, paramStream, now=datetime.datetime.utcnow()):
|
||||
self.versionValue = 2 # a value of 2 is X509v3
|
||||
self.signature = 'sha256WithRSAEncryption'
|
||||
@ -267,13 +185,8 @@ class Certificate:
|
||||
self.subject = 'Default Subject'
|
||||
self.signatureAlgorithm = 'sha256WithRSAEncryption'
|
||||
self.extensions = None
|
||||
self.subjectRSA_N = self.sharedRSA_N
|
||||
self.subjectRSA_E = self.sharedRSA_E
|
||||
self.issuerRSA_N = self.sharedRSA_N
|
||||
self.issuerRSA_E = self.sharedRSA_E
|
||||
self.issuerRSA_D = self.sharedRSA_D
|
||||
self.issuerRSA_P = self.sharedRSA_P
|
||||
self.issuerRSA_Q = self.sharedRSA_Q
|
||||
self.subjectKey = pykey.RSAKey()
|
||||
self.issuerKey = pykey.RSAKey()
|
||||
self.decodeParams(paramStream)
|
||||
self.serialNumber = self.generateSerialNumber()
|
||||
|
||||
@ -347,24 +260,18 @@ class Certificate:
|
||||
self.addExtKeyUsage(value)
|
||||
elif extensionType == 'subjectAlternativeName':
|
||||
self.addSubjectAlternativeName(value)
|
||||
elif extensionType == 'authorityInformationAccess':
|
||||
self.addAuthorityInformationAccess(value)
|
||||
else:
|
||||
raise UnknownExtensionTypeError(extensionType)
|
||||
|
||||
def setupKey(self, subjectOrIssuer, value):
|
||||
if value == 'alternate':
|
||||
if subjectOrIssuer == 'subject':
|
||||
self.subjectRSA_N = self.alternateRSA_N
|
||||
self.subjectRSA_E = self.alternateRSA_E
|
||||
elif subjectOrIssuer == 'issuer':
|
||||
self.issuerRSA_N = self.alternateRSA_N
|
||||
self.issuerRSA_E = self.alternateRSA_E
|
||||
self.issuerRSA_D = self.alternateRSA_D
|
||||
self.issuerRSA_P = self.alternateRSA_P
|
||||
self.issuerRSA_Q = self.alternateRSA_Q
|
||||
else:
|
||||
raise UnknownKeyTargetError(subjectOrIssuer)
|
||||
if subjectOrIssuer == 'subject':
|
||||
self.subjectKey = pykey.RSAKey(value)
|
||||
elif subjectOrIssuer == 'issuer':
|
||||
self.issuerKey = pykey.RSAKey(value)
|
||||
else:
|
||||
raise UnknownKeySpecificationError(value)
|
||||
raise UnknownKeyTargetError(subjectOrIssuer)
|
||||
|
||||
def addExtension(self, extensionType, extensionValue):
|
||||
if not self.extensions:
|
||||
@ -429,6 +336,12 @@ class Certificate:
|
||||
count += 1
|
||||
self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName)
|
||||
|
||||
def addAuthorityInformationAccess(self, ocspURI):
|
||||
sequence = univ.Sequence()
|
||||
accessDescription = stringToAccessDescription(ocspURI)
|
||||
sequence.setComponentByPosition(0, accessDescription)
|
||||
self.addExtension(rfc2459.id_pe_authorityInfoAccess, sequence)
|
||||
|
||||
def getVersion(self):
|
||||
return rfc2459.Version(self.versionValue).subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))
|
||||
@ -460,21 +373,6 @@ class Certificate:
|
||||
def getSignatureAlgorithm(self):
|
||||
return stringToAlgorithmIdentifier(self.signature)
|
||||
|
||||
def getSubjectPublicKey(self):
|
||||
rsaKey = RSAPublicKey()
|
||||
rsaKey.setComponentByName('N', univ.Integer(self.subjectRSA_N))
|
||||
rsaKey.setComponentByName('E', univ.Integer(self.subjectRSA_E))
|
||||
return univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
|
||||
|
||||
def getSubjectPublicKeyInfo(self):
|
||||
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
|
||||
algorithmIdentifier.setComponentByName('parameters', univ.Null())
|
||||
spki = rfc2459.SubjectPublicKeyInfo()
|
||||
spki.setComponentByName('algorithm', algorithmIdentifier)
|
||||
spki.setComponentByName('subjectPublicKey', self.getSubjectPublicKey())
|
||||
return spki
|
||||
|
||||
def toDER(self):
|
||||
tbsCertificate = rfc2459.TBSCertificate()
|
||||
tbsCertificate.setComponentByName('version', self.getVersion())
|
||||
@ -483,7 +381,8 @@ class Certificate:
|
||||
tbsCertificate.setComponentByName('issuer', self.getIssuer())
|
||||
tbsCertificate.setComponentByName('validity', self.getValidity())
|
||||
tbsCertificate.setComponentByName('subject', self.getSubject())
|
||||
tbsCertificate.setComponentByName('subjectPublicKeyInfo', self.getSubjectPublicKeyInfo())
|
||||
tbsCertificate.setComponentByName('subjectPublicKeyInfo',
|
||||
self.subjectKey.asSubjectPublicKeyInfo())
|
||||
if self.extensions:
|
||||
extensions = rfc2459.Extensions().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
|
||||
@ -492,14 +391,11 @@ class Certificate:
|
||||
extensions.setComponentByPosition(count, extension)
|
||||
count += 1
|
||||
tbsCertificate.setComponentByName('extensions', extensions)
|
||||
tbsDER = encoder.encode(tbsCertificate)
|
||||
rsaPrivateKey = rsa.PrivateKey(self.issuerRSA_N, self.issuerRSA_E, self.issuerRSA_D,
|
||||
self.issuerRSA_P, self.issuerRSA_Q)
|
||||
signature = rsa.sign(tbsDER, rsaPrivateKey, 'SHA-256')
|
||||
certificate = rfc2459.Certificate()
|
||||
certificate.setComponentByName('tbsCertificate', tbsCertificate)
|
||||
certificate.setComponentByName('signatureAlgorithm', self.getSignatureAlgorithm())
|
||||
certificate.setComponentByName('signatureValue', byteStringToHexifiedBitString(signature))
|
||||
tbsDER = encoder.encode(tbsCertificate)
|
||||
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER))
|
||||
return encoder.encode(certificate)
|
||||
|
||||
def toPEM(self):
|
||||
|
282
security/manager/ssl/tests/unit/pykey.py
Executable file
282
security/manager/ssl/tests/unit/pykey.py
Executable file
@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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/.
|
||||
|
||||
"""
|
||||
Reads a key specification from stdin or a file and outputs a
|
||||
PKCS #8 file representing the (private) key. Also provides
|
||||
methods for signing data and representing the key as a subject
|
||||
public key info for use with pyasn1.
|
||||
|
||||
The key specification format is currently very simple. If it is
|
||||
empty, one RSA key is used. If it consists of the string
|
||||
'alternate', a different RSA key is used. In the future it will
|
||||
be possible to specify other properties of the key (type,
|
||||
strength, signature algorithm, etc.).
|
||||
"""
|
||||
|
||||
from pyasn1.codec.der import encoder
|
||||
from pyasn1.type import univ, namedtype
|
||||
from pyasn1_modules import rfc2459
|
||||
import base64
|
||||
import binascii
|
||||
import rsa
|
||||
import sys
|
||||
|
||||
def byteStringToHexifiedBitString(string):
|
||||
"""Takes a string of bytes and returns a hex string representing
|
||||
those bytes for use with pyasn1.type.univ.BitString. It must be of
|
||||
the form "'<hex bytes>'H", where the trailing 'H' indicates to
|
||||
pyasn1 that the input is a hex string."""
|
||||
return "'%s'H" % binascii.hexlify(string)
|
||||
|
||||
class UnknownBaseError(Exception):
|
||||
"""Base class for handling unexpected input in this module."""
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.category = 'input'
|
||||
|
||||
def __str__(self):
|
||||
return 'Unknown %s type "%s"' % (self.category, repr(self.value))
|
||||
|
||||
|
||||
class UnknownKeySpecificationError(UnknownBaseError):
|
||||
"""Helper exception type to handle unknown key specifications."""
|
||||
|
||||
def __init__(self, value):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'key specification'
|
||||
|
||||
|
||||
class RSAPublicKey(univ.Sequence):
|
||||
"""Helper type for encoding an RSA public key"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('N', univ.Integer()),
|
||||
namedtype.NamedType('E', univ.Integer()))
|
||||
|
||||
|
||||
class RSAPrivateKey(univ.Sequence):
|
||||
"""Helper type for encoding an RSA private key"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer()),
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer()),
|
||||
namedtype.NamedType('privateExponent', univ.Integer()),
|
||||
namedtype.NamedType('prime1', univ.Integer()),
|
||||
namedtype.NamedType('prime2', univ.Integer()),
|
||||
namedtype.NamedType('exponent1', univ.Integer()),
|
||||
namedtype.NamedType('exponent2', univ.Integer()),
|
||||
namedtype.NamedType('coefficient', univ.Integer()),
|
||||
)
|
||||
|
||||
|
||||
class PrivateKeyInfo(univ.Sequence):
|
||||
"""Helper type for encoding a PKCS #8 private key info"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer()),
|
||||
namedtype.NamedType('privateKeyAlgorithm', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('privateKey', univ.OctetString())
|
||||
)
|
||||
|
||||
|
||||
class RSAKey:
|
||||
# For reference, when encoded as a subject public key info, the
|
||||
# base64-encoded sha-256 hash of this key is
|
||||
# VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
|
||||
sharedRSA_N = long(
|
||||
'00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
|
||||
'6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
|
||||
'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
|
||||
'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
|
||||
'2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
|
||||
'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
|
||||
'31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
|
||||
'95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
|
||||
'fe4923fa7251c431d503acda180a35ed8d', 16)
|
||||
sharedRSA_E = 65537L
|
||||
sharedRSA_D = long(
|
||||
'009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
|
||||
'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
|
||||
'3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
|
||||
'39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
|
||||
'7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
|
||||
'79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
|
||||
'6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
|
||||
'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
|
||||
'5b62b30e6011f224725946eec57c6d9441', 16)
|
||||
sharedRSA_P = long(
|
||||
'00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
|
||||
'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
|
||||
'8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
|
||||
'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
|
||||
'3ca5d19301f48c742b', 16)
|
||||
sharedRSA_Q = long(
|
||||
'00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
|
||||
'8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
|
||||
'1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
|
||||
'28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
|
||||
'5810a77b9845bc3127', 16)
|
||||
sharedRSA_exp1 = long(
|
||||
'0096472b41a610c0ade1af2266c1600e3671355ba42d4b5a0eb4e9d7eb35'
|
||||
'81400ba5dd132cdb1a5e9328c7bbc0bbb0155ea192972edf97d12751d8fc'
|
||||
'f6ae572a30b1ea309a8712dd4e33241db1ee455fc093f5bc9b592d756e66'
|
||||
'21474f32c07af22fb275d340792b32ba2590bbb261aefb95a258eea53765'
|
||||
'5315be9c24d191992d', 16)
|
||||
sharedRSA_exp2 = long(
|
||||
'28b450a7a75a856413b2bda6f7a63e3d964fb9ecf50e3823ef6cc8e8fa26'
|
||||
'ee413f8b9d1205540f12bbe7a0c76828b7ba65ad83cca4d0fe2a220114e1'
|
||||
'b35d03d5a85bfe2706bd50fce6cfcdd571b46ca621b8ed47d605bbe765b0'
|
||||
'aa4a0665ac25364da20154032e1204b8559d3e34fb5b177c9a56ff93510a'
|
||||
'5a4a6287c151de2d', 16)
|
||||
sharedRSA_coef = long(
|
||||
'28067b9355801d2ef52dfa96d8adb589673cf8ee8a9c6ff72aeeabe9ef6b'
|
||||
'e58a4f4abf05f788947dc851fdaa34542147a71a246bfb054ee76aa346ab'
|
||||
'cd2692cfc9e44c51e6f069c735e073ba019f6a7214961c91b26871caeabf'
|
||||
'8f064418a02690e39a8d5ff3067b7cdb7f50b1f53418a703966c4fc774bf'
|
||||
'7402af6c43247f43', 16)
|
||||
|
||||
# For reference, when encoded as a subject public key info, the
|
||||
# base64-encoded sha-256 hash of this key is
|
||||
# MQj2tt1yGAfwFpWETYUCVrZxk2CD2705NKBQUlAaKJI=
|
||||
alternateRSA_N = long(
|
||||
'00c175c65266099f77082a6791f1b876c37f5ce538b06c4acd22b1cbd46f'
|
||||
'a65ada2add41c8c2498ac4a3b3c1f61487f41b698941bd80a51c3c120244'
|
||||
'c584a4c4483305e5138c0106cf08be9a862760bae6a2e8f36f23c5d98313'
|
||||
'b9dfaf378345dace51d4d6dcd2a6cb3cc706ebcd3070ec98cce40aa591d7'
|
||||
'295a7f71c5be66691d2b2dfec84944590bc5a3ea49fd93b1d753405f1773'
|
||||
'7699958666254797ed426908880811422069988a43fee48ce68781dd22b6'
|
||||
'a69cd28375131f932b128ce286fa7d251c062ad27ef016f187cdd54e832b'
|
||||
'35b8930f74ba90aa8bc76167242ab1fd6d62140d18c4c0b8c68fc3748457'
|
||||
'324ad7de86e6552f1d1e191d712168d3bb', 16)
|
||||
alternateRSA_E = 65537L
|
||||
alternateRSA_D = long(
|
||||
'7e3f6d7cb839ef66ae5d7dd92ff5410bb341dc14728d39034570e1a37079'
|
||||
'0f30f0681355fff41e2ad4e9a9d9fcebfbd127bdfab8c00affb1f3cea732'
|
||||
'7ead47aa1621f2ac1ee14ca02f04b3b2786017980b181a449d03b03e69d1'
|
||||
'12b83571e55434f012056575d2832ed6731dce799e37c83f6d51c55ab71e'
|
||||
'b58015af05e1af15c747603ef7f27d03a6ff049d96bbf854c1e4e50ef5b0'
|
||||
'58d0fb08180e0ac7f7be8f2ff1673d97fc9e55dba838077bbf8a7cff2962'
|
||||
'857785269cd9d5bad2b57469e4afcd33c4ca2d2f699f11e7c8fbdcd484f0'
|
||||
'8d8efb8a3cb8a972eb24bed972efaae4bb712093e48fe94a46eb629a8750'
|
||||
'78c4021a9a2c93c9a70390e9d0a54401', 16)
|
||||
alternateRSA_P = long(
|
||||
'00e63fc725a6ba76925a7ff8cb59c4f56dd7ec83fe85bf1f53e11cac9a81'
|
||||
'258bcfc0ae819077b0f2d1477aaf868de6a8ecbeaf7bb22b196f2a9ad82d'
|
||||
'3286f0d0cc29de719e5f2be8e509b7284d5963edd362f927887a4c4a8979'
|
||||
'9d340d51b301ac7601ab27179024fcaadd38bf6522af63eb16461ec02a7f'
|
||||
'27b06fe09ddda7c0a1', 16)
|
||||
alternateRSA_Q = long(
|
||||
'00d718b1fe9f8f99f00e832ae1fbdc6fe2ab27f34e049c498010fa0eb708'
|
||||
'4852182346083b5c96c3eee5592c014a410c6b930b165c13b5c26aa32eac'
|
||||
'6e7c925a8551c25134f2f4a72c6421f19a73148a0edfaba5d3a6888b35cb'
|
||||
'a18c00fd38ee5aaf0b545731d720761bbccdee744a52ca415e98e4de01cd'
|
||||
'fe764c1967b3e8cadb', 16)
|
||||
alternateRSA_exp1 = long(
|
||||
'01e5aca266c94a88d22e13c2b92ea247116c657a076817bdfd30db4b3a9d'
|
||||
'3095b9a4b6749647e2f84e7a784fc7838b08c85971cf7a036fa30e3b91c3'
|
||||
'c4d0df278f80c1b6e859d8456adb137defaa9f1f0ac5bac9a9184fd4ea27'
|
||||
'9d722ea626f160d78aad7bc83845ccb29df115c83f61b7622b99bd439c60'
|
||||
'9b5790a63c595181', 16)
|
||||
alternateRSA_exp2 = long(
|
||||
'0080cc45d10d2484ee0d1297fc07bf80b3beff461ea27e1f38f371789c3a'
|
||||
'f66b4a0edd2192c227791db4f1c77ae246bf342f31856b0f56581b58a95b'
|
||||
'1131c0c5396db2a8c3c6f39ea2e336bc205ae6a2a0b36869fca98cbba733'
|
||||
'cf01319a6f9bb26b7ca23d3017fc551cd8da8afdd17f6fa2e30d34868798'
|
||||
'1cd6234d571e90b7df', 16)
|
||||
alternateRSA_coef = long(
|
||||
'6f77c0c1f2ae7ac169561cca499c52bdfbe04cddccdbdc12aec5a85691e8'
|
||||
'594b7ee29908f30e7b96aa6254b80ed4aeec9b993782bdfc79b69d8d58c6'
|
||||
'8870fa4be1bc0c3527288c5c82bb4aebaf15edff110403fc78e6ace6a828'
|
||||
'27bf42f0cfa751e507651c5638db9393dd23dd1f6b295151de44b77fe55a'
|
||||
'7b0df271e19a65c0', 16)
|
||||
|
||||
def __init__(self, specification = None):
|
||||
if not specification:
|
||||
self.RSA_N = self.sharedRSA_N
|
||||
self.RSA_E = self.sharedRSA_E
|
||||
self.RSA_D = self.sharedRSA_D
|
||||
self.RSA_P = self.sharedRSA_P
|
||||
self.RSA_Q = self.sharedRSA_Q
|
||||
self.RSA_exp1 = self.sharedRSA_exp1
|
||||
self.RSA_exp2 = self.sharedRSA_exp2
|
||||
self.RSA_coef = self.sharedRSA_coef
|
||||
elif specification == 'alternate':
|
||||
self.RSA_N = self.alternateRSA_N
|
||||
self.RSA_E = self.alternateRSA_E
|
||||
self.RSA_D = self.alternateRSA_D
|
||||
self.RSA_P = self.alternateRSA_P
|
||||
self.RSA_Q = self.alternateRSA_Q
|
||||
self.RSA_exp1 = self.alternateRSA_exp1
|
||||
self.RSA_exp2 = self.alternateRSA_exp2
|
||||
self.RSA_coef = self.alternateRSA_coef
|
||||
else:
|
||||
raise UnknownKeySpecificationError(specification)
|
||||
|
||||
def toDER(self):
|
||||
privateKeyInfo = PrivateKeyInfo()
|
||||
privateKeyInfo.setComponentByName('version', 0)
|
||||
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
|
||||
algorithmIdentifier.setComponentByName('parameters', univ.Null())
|
||||
privateKeyInfo.setComponentByName('privateKeyAlgorithm', algorithmIdentifier)
|
||||
rsaPrivateKey = RSAPrivateKey()
|
||||
rsaPrivateKey.setComponentByName('version', 0)
|
||||
rsaPrivateKey.setComponentByName('modulus', self.RSA_N)
|
||||
rsaPrivateKey.setComponentByName('publicExponent', self.RSA_E)
|
||||
rsaPrivateKey.setComponentByName('privateExponent', self.RSA_D)
|
||||
rsaPrivateKey.setComponentByName('prime1', self.RSA_P)
|
||||
rsaPrivateKey.setComponentByName('prime2', self.RSA_Q)
|
||||
rsaPrivateKey.setComponentByName('exponent1', self.RSA_exp1)
|
||||
rsaPrivateKey.setComponentByName('exponent2', self.RSA_exp2)
|
||||
rsaPrivateKey.setComponentByName('coefficient', self.RSA_coef)
|
||||
rsaPrivateKeyEncoded = encoder.encode(rsaPrivateKey)
|
||||
privateKeyInfo.setComponentByName('privateKey', univ.OctetString(rsaPrivateKeyEncoded))
|
||||
return encoder.encode(privateKeyInfo)
|
||||
|
||||
def toPEM(self):
|
||||
output = '-----BEGIN PRIVATE KEY-----'
|
||||
der = self.toDER()
|
||||
b64 = base64.b64encode(der)
|
||||
while b64:
|
||||
output += '\n' + b64[:64]
|
||||
b64 = b64[64:]
|
||||
output += '\n-----END PRIVATE KEY-----'
|
||||
return output
|
||||
|
||||
def asSubjectPublicKeyInfo(self):
|
||||
"""Returns a subject public key info representing
|
||||
this key for use by pyasn1."""
|
||||
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
|
||||
algorithmIdentifier.setComponentByName('parameters', univ.Null())
|
||||
spki = rfc2459.SubjectPublicKeyInfo()
|
||||
spki.setComponentByName('algorithm', algorithmIdentifier)
|
||||
rsaKey = RSAPublicKey()
|
||||
rsaKey.setComponentByName('N', univ.Integer(self.RSA_N))
|
||||
rsaKey.setComponentByName('E', univ.Integer(self.RSA_E))
|
||||
subjectPublicKey = univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
|
||||
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
|
||||
return spki
|
||||
|
||||
def sign(self, data):
|
||||
"""Returns a hexified bit string representing a
|
||||
signature by this key over the specified data.
|
||||
Intended for use with pyasn1.type.univ.BitString"""
|
||||
rsaPrivateKey = rsa.PrivateKey(self.RSA_N, self.RSA_E, self.RSA_D, self.RSA_P, self.RSA_Q)
|
||||
signature = rsa.sign(data, rsaPrivateKey, 'SHA-256')
|
||||
return byteStringToHexifiedBitString(signature)
|
||||
|
||||
|
||||
# The build harness will call this function with an output file-like
|
||||
# object and a path to a file containing a specification. This will
|
||||
# read the specification and output the key as ASCII-encoded PKCS #8.
|
||||
def main(output, inputPath):
|
||||
with open(inputPath) as configStream:
|
||||
output.write(RSAKey(configStream.read()).toPEM())
|
||||
|
||||
# When run as a standalone program, this will read a specification from
|
||||
# stdin and output the certificate as PEM to stdout.
|
||||
if __name__ == '__main__':
|
||||
print RSAKey(sys.stdin.read()).toPEM()
|
@ -25,14 +25,14 @@ function start_ocsp_responder(expectedCertNames, expectedPaths) {
|
||||
}
|
||||
|
||||
function check_cert_err(cert_name, expected_error) {
|
||||
let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".der");
|
||||
let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".pem");
|
||||
return checkCertErrorGeneric(certdb, cert, expected_error,
|
||||
certificateUsageSSLServer);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
addCertFromFile(certdb, "test_ocsp_url/ca.der", 'CTu,CTu,CTu');
|
||||
addCertFromFile(certdb, "test_ocsp_url/int.der", ',,');
|
||||
addCertFromFile(certdb, "test_ocsp_url/ca.pem", 'CTu,CTu,CTu');
|
||||
addCertFromFile(certdb, "test_ocsp_url/int.pem", ',,');
|
||||
|
||||
// Enabled so that we can force ocsp failure responses.
|
||||
Services.prefs.setBoolPref("security.OCSP.require", true);
|
||||
@ -44,7 +44,7 @@ function run_test() {
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
let ocspResponder = failingOCSPResponder();
|
||||
check_cert_err("bad-scheme",SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
|
||||
check_cert_err("bad-scheme", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:bad-scheme
|
||||
extension:authorityInformationAccess:/www.example.com
|
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
issuer:ca
|
||||
subject:ca
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:empty-port
|
||||
extension:authorityInformationAccess:http://www.example.com:/
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:empty-scheme-url
|
||||
extension:authorityInformationAccess:://www.example.com:8888/
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:ftp-url
|
||||
extension:authorityInformationAccess:ftp://www.example.com:8888/
|
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import tempfile, os, sys
|
||||
|
||||
libpath = os.path.abspath('../psm_common_py')
|
||||
sys.path.append(libpath)
|
||||
import CertUtils
|
||||
|
||||
srcdir = os.getcwd()
|
||||
db = tempfile.mkdtemp()
|
||||
|
||||
def generate_ca_cert(db_dir, dest_dir, noise_file, name):
|
||||
return CertUtils.generate_ca_cert(db_dir, dest_dir, noise_file, name,
|
||||
3, True)
|
||||
|
||||
def generate_child_cert(db_dir, dest_dir, noise_file, name, ca_nick, is_ee,
|
||||
ocsp_url):
|
||||
return CertUtils.generate_child_cert(db_dir, dest_dir, noise_file, name,
|
||||
ca_nick, 3, True, is_ee, ocsp_url)
|
||||
|
||||
def generate_certs():
|
||||
[noise_file, pwd_file] = CertUtils.init_nss_db(srcdir)
|
||||
generate_ca_cert(srcdir, srcdir, noise_file, 'ca')
|
||||
generate_child_cert(srcdir, srcdir, noise_file, 'int', 'ca', False, '')
|
||||
nick_baseurl = { 'no-path-url': "http://www.example.com:8888",
|
||||
'ftp-url': "ftp://www.example.com:8888/",
|
||||
'no-scheme-url': "www.example.com:8888/",
|
||||
'empty-scheme-url': "://www.example.com:8888/",
|
||||
'no-host-url': "http://:8888/",
|
||||
'hTTp-url': "hTTp://www.example.com:8888/hTTp-url",
|
||||
'https-url': "https://www.example.com:8888/https-url",
|
||||
'bad-scheme': "/www.example.com",
|
||||
'empty-port': "http://www.example.com:/",
|
||||
'unknown-scheme': "ttp://www.example.com",
|
||||
'negative-port': "http://www.example.com:-1",
|
||||
'no-scheme-host-port': "/" }
|
||||
for nick, url in nick_baseurl.iteritems():
|
||||
generate_child_cert(srcdir, srcdir, noise_file, nick, 'int', True, url)
|
||||
|
||||
generate_certs()
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:hTTp-url
|
||||
extension:authorityInformationAccess:hTTp://www.example.com:8888/hTTp-url
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:https-url
|
||||
extension:authorityInformationAccess:https://www.example.com:8888/https-url
|
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
issuer:ca
|
||||
subject:int
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
Binary file not shown.
42
security/manager/ssl/tests/unit/test_ocsp_url/moz.build
Normal file
42
security/manager/ssl/tests/unit/test_ocsp_url/moz.build
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
test_certificates = (
|
||||
'bad-scheme.pem',
|
||||
'ca.pem',
|
||||
'empty-port.pem',
|
||||
'empty-scheme-url.pem',
|
||||
'ftp-url.pem',
|
||||
'hTTp-url.pem',
|
||||
'https-url.pem',
|
||||
'int.pem',
|
||||
'negative-port.pem',
|
||||
'no-host-url.pem',
|
||||
'no-path-url.pem',
|
||||
'no-scheme-host-port.pem',
|
||||
'no-scheme-url.pem',
|
||||
'unknown-scheme.pem',
|
||||
)
|
||||
|
||||
for test_certificate in test_certificates:
|
||||
input_file = test_certificate + '.certspec'
|
||||
GENERATED_FILES += [test_certificate]
|
||||
props = GENERATED_FILES[test_certificate]
|
||||
props.script = '../pycert.py'
|
||||
props.inputs = [input_file, '!/config/buildid']
|
||||
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_ocsp_url += ['!%s' % test_certificate]
|
||||
|
||||
test_keys = (
|
||||
'int.key',
|
||||
)
|
||||
|
||||
for test_key in test_keys:
|
||||
input_file = test_key + '.keyspec'
|
||||
GENERATED_FILES += [test_key]
|
||||
props = GENERATED_FILES[test_key]
|
||||
props.script = '../pykey.py'
|
||||
props.inputs = [input_file]
|
||||
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_ocsp_url += ['!%s' % test_key]
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:negative-port
|
||||
extension:authorityInformationAccess:http://www.example.com:-1
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:no-host-url
|
||||
extension:authorityInformationAccess:http://:8888/
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:int
|
||||
subject:no-path-url
|
||||
extension:authorityInformationAccess:http://www.example.com:8888
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user