зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
4cb1341e89
|
@ -132,6 +132,9 @@ endif
|
|||
$(addprefix install-,$(filter dist/%,$(install_manifests))): install-dist/%: $(install_manifest_depends)
|
||||
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$*)
|
||||
|
||||
# Dummy wrapper rule to allow the faster backend to piggy back
|
||||
install-dist_%: install-dist/% ;
|
||||
|
||||
install-_tests: $(install_manifest_depends)
|
||||
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
|
||||
|
||||
|
|
|
@ -1613,34 +1613,21 @@ DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
|
|||
mInvalidationList.AppendElement(dependentContent);
|
||||
}
|
||||
|
||||
// Update ARIA owns cache.
|
||||
if (relAttr == nsGkAtoms::aria_owns) {
|
||||
// Dependent content cannot point to other aria-owns content or
|
||||
// their parents. Ignore it if so.
|
||||
// XXX: note, this alg may make invalid the scenario when X owns Y
|
||||
// and Y owns Z, we should have something smarter to handle that.
|
||||
bool isvalid = true;
|
||||
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
|
||||
Accessible* owner = it.Key();
|
||||
nsIContent* parentEl = owner->GetContent();
|
||||
while (parentEl && parentEl != dependentContent) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (parentEl) {
|
||||
isvalid = false;
|
||||
break;
|
||||
}
|
||||
// ARIA owns cannot refer to itself or a parent. Ignore
|
||||
// the element if so.
|
||||
nsIContent* parentEl = relProviderEl;
|
||||
while (parentEl && parentEl != dependentContent) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (isvalid) {
|
||||
// ARIA owns also cannot refer to itself or a parent.
|
||||
nsIContent* parentEl = relProviderEl;
|
||||
while (parentEl && parentEl != dependentContent) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (parentEl) {
|
||||
isvalid = false;
|
||||
}
|
||||
|
||||
if (isvalid) {
|
||||
if (!parentEl) {
|
||||
// ARIA owns element cannot refer to an element in parents chain
|
||||
// of other ARIA owns element (including that ARIA owns element)
|
||||
// if it's inside of a dependent element subtree of that
|
||||
// ARIA owns element. Applied recursively.
|
||||
if (!IsInARIAOwnsLoop(relProviderEl, dependentContent)) {
|
||||
nsTArray<nsIContent*>* list =
|
||||
mARIAOwnsHash.LookupOrAdd(aRelProvider);
|
||||
list->AppendElement(dependentContent);
|
||||
|
@ -1759,6 +1746,45 @@ DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessible::IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl)
|
||||
{
|
||||
// ARIA owns element cannot refer to an element in parents chain of other ARIA
|
||||
// owns element (including that ARIA owns element) if it's inside of
|
||||
// a dependent element subtree of that ARIA owns element.
|
||||
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
|
||||
Accessible* otherOwner = it.Key();
|
||||
nsIContent* parentEl = otherOwner->GetContent();
|
||||
while (parentEl && parentEl != aDependentEl) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
|
||||
// The dependent element of this ARIA owns element contains some other ARIA
|
||||
// owns element, make sure this ARIA owns element is not in a subtree of
|
||||
// a dependent element of that other ARIA owns element. If not then
|
||||
// continue a check recursively.
|
||||
if (parentEl) {
|
||||
nsTArray<nsIContent*>* childEls = it.UserData();
|
||||
for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
|
||||
nsIContent* childEl = childEls->ElementAt(idx);
|
||||
nsIContent* parentEl = aOwnerEl;
|
||||
while (parentEl && parentEl != childEl) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (parentEl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsInARIAOwnsLoop(aOwnerEl, childEl)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
||||
nsIAtom* aAttribute)
|
||||
|
|
|
@ -436,6 +436,12 @@ protected:
|
|||
void RemoveDependentIDsFor(Accessible* aRelProvider,
|
||||
nsIAtom* aRelAttr = nullptr);
|
||||
|
||||
/**
|
||||
* Return true if given ARIA owner element and its referred content make
|
||||
* the loop closed.
|
||||
*/
|
||||
bool IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl);
|
||||
|
||||
/**
|
||||
* Update or recreate an accessible depending on a changed attribute.
|
||||
*
|
||||
|
|
|
@ -744,6 +744,9 @@ var Input = {
|
|||
case 'tripletap3':
|
||||
Utils.dispatchChromeEvent('accessibility-control', 'toggle-shade');
|
||||
break;
|
||||
case 'tap2':
|
||||
Utils.dispatchChromeEvent('accessibility-control', 'toggle-pause');
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -213,8 +213,7 @@ this.GestureTracker = { // jshint ignore:line
|
|||
*/
|
||||
handle: function GestureTracker_handle(aDetail, aTimeStamp) {
|
||||
Logger.gesture(() => {
|
||||
return ['Pointer event', aDetail.type, 'at:', aTimeStamp,
|
||||
JSON.stringify(aDetail.points)];
|
||||
return ['Pointer event', Utils.dpi, 'at:', aTimeStamp, JSON.stringify(aDetail)];
|
||||
});
|
||||
this[this.current ? '_update' : '_init'](aDetail, aTimeStamp);
|
||||
},
|
||||
|
@ -403,7 +402,12 @@ Gesture.prototype = {
|
|||
let identifier = point.identifier;
|
||||
let gesturePoint = this.points[identifier];
|
||||
if (gesturePoint) {
|
||||
gesturePoint.update(point);
|
||||
if (aType === 'pointerdown' && aCanCreate) {
|
||||
// scratch the previous pointer with that id.
|
||||
this.points[identifier] = new Point(point);
|
||||
} else {
|
||||
gesturePoint.update(point);
|
||||
}
|
||||
if (aNeedComplete) {
|
||||
// Since the gesture is completing and at least one of the gesture
|
||||
// points is updated, set the return value to true.
|
||||
|
|
|
@ -454,11 +454,11 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
|||
|
||||
if (accTree.children.length != childCount) {
|
||||
for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) {
|
||||
var accChild;
|
||||
var accChild = null, testChild = null;
|
||||
try {
|
||||
testChild = accTree.children[i];
|
||||
accChild = children.queryElementAt(i, nsIAccessible);
|
||||
|
||||
testChild = accTree.children[i];
|
||||
if (!testChild) {
|
||||
ok(false, prettyName(acc) + " has an extra child at index " + i +
|
||||
" : " + prettyName(accChild));
|
||||
|
@ -481,10 +481,10 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
|||
}
|
||||
info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
|
||||
" child at index " + i + " : " + prettyName(accChild));
|
||||
|
||||
} catch (e) {
|
||||
ok(false, prettyName(accTree) + " has an extra child at index " + i +
|
||||
ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
|
||||
" : " + prettyName(testChild) + ", " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -109,9 +109,10 @@ var originalConsecutiveGestureDelay =
|
|||
* Attach a listener for the mozAccessFuGesture event that tests its
|
||||
* type.
|
||||
* @param {Array} aExpectedGestures A stack of expected event types.
|
||||
* @param {String} aTitle Title of this sequence, if any.
|
||||
* Note: the listener is removed once the stack reaches 0.
|
||||
*/
|
||||
function testMozAccessFuGesture(aExpectedGestures) {
|
||||
function testMozAccessFuGesture(aExpectedGestures, aTitle) {
|
||||
var types = aExpectedGestures;
|
||||
function handleGesture(aEvent) {
|
||||
if (aEvent.detail.type !== types[0].type) {
|
||||
|
@ -120,8 +121,10 @@ function testMozAccessFuGesture(aExpectedGestures) {
|
|||
return;
|
||||
}
|
||||
is(!!aEvent.detail.edge, !!types[0].edge);
|
||||
is(aEvent.detail.touches.length, types[0].fingers || 1,
|
||||
'failed to count fingers: ' + types[0].type);
|
||||
ok(true, 'Received correct mozAccessFuGesture: ' +
|
||||
JSON.stringify(types.shift()) + '.');
|
||||
JSON.stringify(types.shift()) + '. (' + aTitle + ')');
|
||||
if (types.length === 0) {
|
||||
win.removeEventListener('mozAccessFuGesture', handleGesture);
|
||||
if (AccessFuTest.sequenceCleanup) {
|
||||
|
@ -168,7 +171,7 @@ function resetTimers() {
|
|||
*/
|
||||
AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) {
|
||||
AccessFuTest.addFunc(function testSequence() {
|
||||
testMozAccessFuGesture(aSequence.expectedGestures);
|
||||
testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title);
|
||||
var events = aSequence.events;
|
||||
function fireEvent(aEvent) {
|
||||
var event = {
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
|
@ -173,7 +173,7 @@
|
|||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
|
@ -187,7 +187,7 @@
|
|||
{"x": 1.5, "y": 1.5, "identifier": 2},
|
||||
{"x": 1.5, "y": 2, "identifier": 3}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 3 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
|
@ -263,6 +263,96 @@
|
|||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight", "edge": true }]
|
||||
"expectedGestures": [{ "type": "swiperight", "edge": true, "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"title": "Bug 1182311 - 3 finger triple tap is not reliable 1/2",
|
||||
"events": [
|
||||
{"points": [
|
||||
{"y": 1.88467, "x": 0.89311, "identifier": 0},
|
||||
{"y": 2.78481, "x": 0.56259, "identifier": 1},
|
||||
{"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.88467, "x": 0.89311, "identifier": 0},
|
||||
{"y": 2.78481, "x": 0.56259, "identifier": 1},
|
||||
{"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerup"},
|
||||
{"points": [
|
||||
{"y": 1.76512, "x": 0.98453, "identifier": 0},
|
||||
{"y": 1.1744, "x": 1.4346, "identifier": 1},
|
||||
{"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.76512, "x": 0.98453, "identifier": 0},
|
||||
{"y": 1.1744, "x": 1.4346, "identifier": 1},
|
||||
{"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerup"},
|
||||
{"points": [
|
||||
{"y": 1.30098, "x": 1.52602, "identifier": 0},
|
||||
{"y": 1.94093, "x": 1.02672, "identifier": 1},
|
||||
{"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.30098, "x": 1.52602, "identifier": 0},
|
||||
{"y": 1.94093, "x": 1.02672, "identifier": 1},
|
||||
{"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup",
|
||||
"removeConsecutiveGestureDelay": false}],
|
||||
"expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
|
||||
},
|
||||
{
|
||||
"title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2",
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.479167, "y": 2.53125}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.46875, "y": 2.53125}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.447917, "y": 2.46875}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.447917, "y": 2.489583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
|
||||
{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
|
||||
{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}],
|
||||
"removeConsecutiveGestureDelay": false}
|
||||
],
|
||||
"expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
|
||||
}
|
||||
|
||||
]
|
||||
|
|
|
@ -10,6 +10,7 @@ skip-if = true # Bug 561508
|
|||
[test_aria_imgmap.html]
|
||||
[test_aria_list.html]
|
||||
[test_aria_menu.html]
|
||||
[test_aria_owns.html]
|
||||
[test_aria_presentation.html]
|
||||
[test_aria_table.html]
|
||||
[test_brokencontext.html]
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>@aria-owns attribute testing</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="../role.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//enableLogging("tree"); // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [ // t1_1
|
||||
{ SECTION: [ // t1_2
|
||||
// no kids, no loop
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t1_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t2_1
|
||||
{ SECTION: [ // t2_2
|
||||
{ SECTION: [ // t2_3
|
||||
// no kids, no loop
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t2_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t3_3
|
||||
{ SECTION: [ // t3_1
|
||||
{ SECTION: [ // t3_2
|
||||
{ SECTION: [ // DOM child of t3_2
|
||||
// no kids, no loop
|
||||
] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t3_3", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t4_1
|
||||
{ SECTION: [ // DOM child of t4_1
|
||||
// no kids, no loop
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t4_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t5_1
|
||||
{ SECTION: [ // DOM child of t5_1
|
||||
{ SECTION: [ // t5_2
|
||||
{ SECTION: [ // DOM child of t5_2
|
||||
{ SECTION: [ // t5_3
|
||||
{ SECTION: [ // DOM child of t5_3
|
||||
// no kids, no loop
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t5_1", tree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="t1_1" aria-owns="t1_2"></div>
|
||||
<div id="t1_2" aria-owns="t1_1"></div>
|
||||
|
||||
<div id="t2_2" aria-owns="t2_3"></div>
|
||||
<div id="t2_1" aria-owns="t2_2"></div>
|
||||
<div id="t2_3" aria-owns="t2_1"></div>
|
||||
|
||||
<div id="t3_1" aria-owns="t3_2"></div>
|
||||
<div id="t3_2">
|
||||
<div aria-owns="t3_3"></div>
|
||||
</div>
|
||||
<div id="t3_3" aria-owns="t3_1"></div>
|
||||
|
||||
<div id="t4_1"><div aria-owns="t4_1"></div></div>
|
||||
|
||||
<div id="t5_1"><div aria-owns="t5_2"></div>
|
||||
<div id="t5_2"><div aria-owns="t5_3"></div></div>
|
||||
<div id="t5_3"><div aria-owns="t5_1"></div></div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -172,25 +172,13 @@
|
|||
// Test
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
gA11yEventDumpToConsole = true;
|
||||
enableLogging("tree"); // debug stuff
|
||||
//gA11yEventDumpToConsole = true;
|
||||
//enableLogging("tree"); // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
// nested and recursive aria-owns
|
||||
var tree =
|
||||
{ SECTION: [ // container
|
||||
{ SECTION: [ // child
|
||||
{ SECTION: [ // mid div
|
||||
{ SECTION: [] } // grandchild
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("container", tree);
|
||||
|
||||
// dynamic tests
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new removeARIAOwns());
|
||||
|
@ -214,12 +202,6 @@
|
|||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="container" aria-owns="child" aria-label="container"></div>
|
||||
<div id="child" aria-label="child">
|
||||
<div aria-owns="grandchild" aria-label="midchild"></div>
|
||||
</div>
|
||||
<div id="grandchild" aria-owns="container" aria-label="grandchild"></div>
|
||||
|
||||
<div id="container2" aria-owns="t2_checkbox t2_button">
|
||||
<div role="button" id="t2_button"></div>
|
||||
<div role="checkbox" id="t2_checkbox">
|
||||
|
|
|
@ -1885,7 +1885,7 @@ pref("browser.tabs.remote.autostart.2", true);
|
|||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
#if defined(XP_MACOSX) || defined(XP_WIN)
|
||||
#ifndef MOZ_MULET
|
||||
pref("layers.async-pan-zoom.enabled", true);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -472,15 +472,24 @@ var gTests = [
|
|||
})
|
||||
},
|
||||
{
|
||||
desc: "Sync button should open about:accounts page with `abouthome` entrypoint",
|
||||
desc: "Sync button should open about:preferences#sync",
|
||||
setup: function () {},
|
||||
run: Task.async(function* () {
|
||||
let syncButton = gBrowser.selectedBrowser.contentDocument.getElementById("sync");
|
||||
let oldOpenPrefs = window.openPreferences;
|
||||
let openPrefsPromise = new Promise(resolve => {
|
||||
window.openPreferences = function (pane, params) {
|
||||
resolve({ pane: pane, params: params });
|
||||
};
|
||||
});
|
||||
|
||||
yield EventUtils.synthesizeMouseAtCenter(syncButton, {}, gBrowser.contentWindow);
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, null, "load");
|
||||
is(gBrowser.currentURI.spec, "about:accounts?entrypoint=abouthome",
|
||||
"Entry point should be `abouthome`.");
|
||||
let result = yield openPrefsPromise;
|
||||
window.openPreferences = oldOpenPrefs;
|
||||
|
||||
is(result.pane, "paneSync", "openPreferences should be called with paneSync");
|
||||
is(result.params.urlParams.entrypoint, "abouthome", "openPreferences should be called with abouthome entrypoint");
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ add_task(function* ()
|
|||
yield* expectFocusOnF6(false, "html1", "html1",
|
||||
true, "basic focus content page with button focused");
|
||||
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
|
||||
return content.document.getElementById("button1").focus();
|
||||
});
|
||||
|
||||
|
|
|
@ -2,3 +2,6 @@
|
|||
test/coverage/desktop
|
||||
test/coverage/shared_standalone
|
||||
test/node_modules
|
||||
test/visual-regression/diff
|
||||
test/visual-regression/new
|
||||
test/visual-regression/refs
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
/* 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/. */
|
||||
// This mixin should be deprecated and a new solution implemented for
|
||||
// processing menus and taking care of menu positioning globally. This
|
||||
// new implementation should ensure all menus are positioned using the
|
||||
// same method of positioning
|
||||
|
||||
var loop = loop || {};
|
||||
loop.shared = loop.shared || {};
|
||||
|
@ -228,6 +232,11 @@ loop.shared.mixins = (function() {
|
|||
menu.style.marginTop = "auto";
|
||||
}
|
||||
|
||||
// Added call to _repositionMenu() if it exists, to allow a component to
|
||||
// add specific repositioning to a menu.
|
||||
if (this._repositionMenu) {
|
||||
this._repositionMenu();
|
||||
}
|
||||
menu.style.visibility = "visible";
|
||||
},
|
||||
|
||||
|
|
|
@ -203,11 +203,48 @@ loop.shared.views = (function(_, mozL10n) {
|
|||
},
|
||||
|
||||
/**
|
||||
* Show or hide the settings menu
|
||||
* Reposition Menu if cropped
|
||||
*
|
||||
* Added to reposition the menu if it is cropped on the left side because of
|
||||
* a long text string. This function measures how much the menu is cropped
|
||||
* on the left or right and adjusts the coordinates so the menu isn't cropped.
|
||||
* Also, sets the left style to auto, to prevent complexity in calculations
|
||||
*
|
||||
* The dropdownmenu mixin needs to be revamped, along with all components
|
||||
* using dropdown menus. Components should be utilizing a global function
|
||||
* for menu positions and it should be consistent throughout.
|
||||
*
|
||||
*/
|
||||
handleClick: function(event) {
|
||||
event.preventDefault();
|
||||
this.toggleDropdownMenu();
|
||||
_repositionMenu: function() {
|
||||
if (this.refs.menu && this.state.showMenu) {
|
||||
var menuNode = this.refs.menu && this.refs.menu.getDOMNode();
|
||||
|
||||
if (menuNode) {
|
||||
// Amount of pixels that the dropdown needs to stay away from the edges
|
||||
// of the page body. Copied from the mixin.
|
||||
var boundOffset = 4;
|
||||
var menuNodeRect = menuNode.getBoundingClientRect();
|
||||
var menuComputedStyle = window.getComputedStyle(menuNode);
|
||||
var documentBody = this.getDOMNode().ownerDocument.body;
|
||||
var bodyRect = documentBody.getBoundingClientRect();
|
||||
var menuLeft = parseFloat(menuNodeRect.left);
|
||||
var menuRight = parseFloat(menuNodeRect.right);
|
||||
var bodyRight = parseFloat(bodyRect.right);
|
||||
|
||||
menuNode.style.left = "auto";
|
||||
|
||||
// If menu is too close or cropped on left, move right
|
||||
if (menuLeft < -boundOffset) {
|
||||
menuNode.style.right =
|
||||
(parseFloat(menuComputedStyle.right) + menuLeft - boundOffset) + "px";
|
||||
}
|
||||
// If menu is too close or cropped on right, move left
|
||||
if (menuRight > bodyRight - boundOffset) {
|
||||
menuNode.style.right =
|
||||
(parseFloat(menuComputedStyle.right) + (menuRight - bodyRight) + boundOffset) + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -203,11 +203,48 @@ loop.shared.views = (function(_, mozL10n) {
|
|||
},
|
||||
|
||||
/**
|
||||
* Show or hide the settings menu
|
||||
* Reposition Menu if cropped
|
||||
*
|
||||
* Added to reposition the menu if it is cropped on the left side because of
|
||||
* a long text string. This function measures how much the menu is cropped
|
||||
* on the left or right and adjusts the coordinates so the menu isn't cropped.
|
||||
* Also, sets the left style to auto, to prevent complexity in calculations
|
||||
*
|
||||
* The dropdownmenu mixin needs to be revamped, along with all components
|
||||
* using dropdown menus. Components should be utilizing a global function
|
||||
* for menu positions and it should be consistent throughout.
|
||||
*
|
||||
*/
|
||||
handleClick: function(event) {
|
||||
event.preventDefault();
|
||||
this.toggleDropdownMenu();
|
||||
_repositionMenu: function() {
|
||||
if (this.refs.menu && this.state.showMenu) {
|
||||
var menuNode = this.refs.menu && this.refs.menu.getDOMNode();
|
||||
|
||||
if (menuNode) {
|
||||
// Amount of pixels that the dropdown needs to stay away from the edges
|
||||
// of the page body. Copied from the mixin.
|
||||
var boundOffset = 4;
|
||||
var menuNodeRect = menuNode.getBoundingClientRect();
|
||||
var menuComputedStyle = window.getComputedStyle(menuNode);
|
||||
var documentBody = this.getDOMNode().ownerDocument.body;
|
||||
var bodyRect = documentBody.getBoundingClientRect();
|
||||
var menuLeft = parseFloat(menuNodeRect.left);
|
||||
var menuRight = parseFloat(menuNodeRect.right);
|
||||
var bodyRight = parseFloat(bodyRect.right);
|
||||
|
||||
menuNode.style.left = "auto";
|
||||
|
||||
// If menu is too close or cropped on left, move right
|
||||
if (menuLeft < -boundOffset) {
|
||||
menuNode.style.right =
|
||||
(parseFloat(menuComputedStyle.right) + menuLeft - boundOffset) + "px";
|
||||
}
|
||||
// If menu is too close or cropped on right, move left
|
||||
if (menuRight > bodyRight - boundOffset) {
|
||||
menuNode.style.right =
|
||||
(parseFloat(menuComputedStyle.right) + (menuRight - bodyRight) + boundOffset) + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# How to use the visual regression tool
|
||||
|
||||
Note that this is a *work-in-progress*; watch out for *rough edges*. In
|
||||
particular, it can generate a fair number of false positives, most
|
||||
visually fairly obvious. That said, for CSS rule changes that may effect
|
||||
multiple views, it can be extremely handy for detecting subtle regressions.
|
||||
|
||||
It works by taking a snapshot of each view in the ui-showcase, and then
|
||||
comparing it to a previous version of the same snapshot, generating an image
|
||||
which shows differences between the two.
|
||||
|
||||
## Requirements:
|
||||
|
||||
```bash
|
||||
easy_install pip
|
||||
pip install selenium
|
||||
pip install Pillow
|
||||
```
|
||||
|
||||
## File hierarchy
|
||||
|
||||
./loop/test/visual-regression
|
||||
- README
|
||||
- screenshot -- the script that you will run
|
||||
- /refs -- initial screenshots
|
||||
- /new -- screenshots after changes have been made
|
||||
- /diff -- combination of reference screenshots, new and the visual diff between the two
|
||||
|
||||
You will need to create those 3 folders.
|
||||
|
||||
## Commands
|
||||
|
||||
```
|
||||
screenshot -h -- provides information
|
||||
screenshot --refs -- creates reference file
|
||||
screenshot --diffs -- creates new screenshots and the diff against the reference files
|
||||
```
|
||||
|
||||
## Typical session, to test a patch for regression against fx-team:
|
||||
|
||||
```bash
|
||||
git checkout fx-team
|
||||
cd browser/components/loop/test/visual-regression
|
||||
|
||||
# create the dirs you'll need
|
||||
mkdir refs new diff
|
||||
# generate the reference images from the ui-showcase
|
||||
# take a break; this takes at least 10 mins on a 2015 i7 Retina mac
|
||||
./screenshot --refs
|
||||
|
||||
# create a branch and apply the patch you want to check
|
||||
git checkout -b bugzilla-bug-1234
|
||||
git bz apply 1234
|
||||
|
||||
# generate the new images, and then diff them. take another long break.
|
||||
./screenshot --diffs
|
||||
|
||||
cd diff
|
||||
|
||||
# this is a mac command, other OSes will vary in how to view all the images
|
||||
open -a Preview *
|
||||
|
||||
# diffs have the reference image on left, the diff in the middle, and the
|
||||
# new image on right, all joined into a single image so you can see them
|
||||
# together. look for images that have red in the diff section to find potential
|
||||
# regressions
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
Because Selenium launches a separate browser window you can make changes to the
|
||||
CSS or markup without having to worry that it will affect the screenshots. You
|
||||
can generate the diffs after you have finished your changes before submitting
|
||||
the patch.
|
|
@ -0,0 +1,97 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from selenium import webdriver
|
||||
from PIL import Image
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
import subprocess
|
||||
import argparse
|
||||
import re
|
||||
from os import path
|
||||
|
||||
refs_location = path.join(path.dirname(__file__), "refs")
|
||||
newscreenshots_location = path.join(path.dirname(__file__), "new")
|
||||
diff_location = path.join(path.dirname(__file__), "diff")
|
||||
ui_showcase_url = "http://localhost:3000/ui/"
|
||||
|
||||
def take_screenshots(dir_name):
|
||||
fox = webdriver.Firefox()
|
||||
# Open the UI Showcase
|
||||
fox.get(ui_showcase_url)
|
||||
# Find all component containers
|
||||
elements = fox.find_elements_by_css_selector(".example")
|
||||
regex = re.compile(r"[/\\(),':\-]")
|
||||
|
||||
for element in elements:
|
||||
header = element.find_element_by_css_selector("h3")
|
||||
component = element.find_element_by_css_selector(".comp iframe")
|
||||
location = component.location
|
||||
size = component.size
|
||||
element_id = re.escape(re.sub(regex, '', header.get_attribute("id")))
|
||||
title = path.join(dir_name, element_id + ".png")
|
||||
print title
|
||||
|
||||
fox.save_screenshot(title) # saves screenshot of entire page
|
||||
|
||||
im = Image.open(title) # uses PIL library to open image in memory
|
||||
|
||||
left = location["x"]
|
||||
top = location["y"]
|
||||
right = location["x"] + size["width"]
|
||||
bottom = location["y"] + size["height"]
|
||||
|
||||
im = im.crop((left, top, right, bottom)) # defines crop points
|
||||
im.save(title) # saves new cropped image
|
||||
|
||||
fox.quit()
|
||||
|
||||
def diff_screenshots():
|
||||
onlyfiles = [ f for f in listdir(refs_location)
|
||||
if isfile(join(refs_location,f)) and f[-3:] == "png" ]
|
||||
|
||||
for f in onlyfiles:
|
||||
print f
|
||||
ref_file = path.join(refs_location, f)
|
||||
new_file = path.join(newscreenshots_location, f)
|
||||
diff_file = path.join(diff_location, f)
|
||||
compare_cmd = "compare '" + ref_file + "' '" + new_file + \
|
||||
"' '" + diff_file + "'"
|
||||
join_cmd = "convert +append '" + ref_file + "' '" + diff_file + \
|
||||
"' '" + new_file + "'" + " '" + diff_file + "_joined.png'"
|
||||
remove_cmd = "rm " + diff_file
|
||||
|
||||
cmd = compare_cmd + " ; " + join_cmd + " ; " + remove_cmd
|
||||
print cmd
|
||||
subprocess.Popen(cmd, shell=True)
|
||||
|
||||
def cleanup(clean_location):
|
||||
files = [ f for f in listdir(clean_location)
|
||||
if isfile(join(clean_location,f)) and f[-3:] == "png" ]
|
||||
|
||||
for f in files:
|
||||
remove_cmd = "rm " + re.escape(path.join(clean_location, f))
|
||||
subprocess.Popen(remove_cmd, shell=True)
|
||||
|
||||
description = "Firefox Hello test for visual regressions. Run once before " + \
|
||||
"making any changes with --refs to build the reference files " + \
|
||||
"and once more with your patch applied using --diffs. If any " + \
|
||||
"screenshots have changed they will show up in /test/diff."
|
||||
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument("-r", "--refs", action="store_true", help="Build the " +
|
||||
"reference screenshots.")
|
||||
parser.add_argument("-d", "--diffs", action="store_true", help="Compare " +
|
||||
"your changes against the reference screenshots.")
|
||||
parser.add_argument("-c", "--cleanup", action="store_true", help="Remove " +
|
||||
"all files from /diff and /new folders but not the " +
|
||||
"reference files")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.refs:
|
||||
take_screenshots(refs_location)
|
||||
if args.diffs:
|
||||
take_screenshots(newscreenshots_location)
|
||||
diff_screenshots()
|
||||
if args.cleanup:
|
||||
cleanup(newscreenshots_location)
|
||||
cleanup(diff_location)
|
|
@ -1370,7 +1370,7 @@
|
|||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 254,
|
||||
summary: "",
|
||||
summary: "Desktop Room Failure View",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(RoomFailureView, {
|
||||
|
|
|
@ -1370,7 +1370,7 @@
|
|||
<FramedExample
|
||||
dashed={true}
|
||||
height={254}
|
||||
summary=""
|
||||
summary="Desktop Room Failure View"
|
||||
width={298}>
|
||||
<div className="fx-embedded">
|
||||
<RoomFailureView
|
||||
|
|
|
@ -30,5 +30,10 @@ ac_add_options --enable-warnings-as-errors
|
|||
|
||||
. $topsrcdir/build/win64/mozconfig.vs2013
|
||||
|
||||
# Enable Adobe Primetime CDM on 64-bit Windows in Mozilla builds.
|
||||
# Enabled here on the assumption that downstream vendors will not be using
|
||||
# these build configs.
|
||||
ac_add_options --enable-eme=adobe
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
|
|
@ -143,21 +143,7 @@ var AboutHome = {
|
|||
break;
|
||||
|
||||
case "AboutHome:Sync":
|
||||
let weave = Cc["@mozilla.org/weave/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
||||
if (weave.fxAccountsEnabled) {
|
||||
fxAccounts.getSignedInUser().then(userData => {
|
||||
if (userData) {
|
||||
window.openPreferences("paneSync");
|
||||
} else {
|
||||
window.loadURI("about:accounts?entrypoint=abouthome");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.openPreferences("paneSync");
|
||||
}
|
||||
window.openPreferences("paneSync", { urlParams: { entrypoint: "abouthome" } });
|
||||
break;
|
||||
|
||||
case "AboutHome:Settings":
|
||||
|
|
|
@ -90,8 +90,8 @@
|
|||
.tab-icon-overlay {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: -12px;
|
||||
-moz-margin-start: -16px;
|
||||
margin-top: -8px;
|
||||
margin-inline-start: -15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@
|
|||
|
||||
.tab-icon-overlay[soundplaying],
|
||||
.tab-icon-overlay[muted]:not([crashed]) {
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.tab-icon-overlay[soundplaying]:hover,
|
||||
|
|
|
@ -28,7 +28,7 @@ define([AC_SUBST_SET],
|
|||
[ifdef([AC_SUBST_SET_$1], ,
|
||||
[define([AC_SUBST_SET_$1], )dnl
|
||||
AC_DIVERT_PUSH(MOZ_DIVERSION_SUBST)dnl
|
||||
(''' $1 ''', set(r''' [$]$1 '''.split()))
|
||||
(''' $1 ''', unique_list(r''' [$]$1 '''.split()))
|
||||
AC_DIVERT_POP()dnl
|
||||
])])])])
|
||||
|
||||
|
@ -129,6 +129,13 @@ topsrcdir = os.path.normpath(topsrcdir)
|
|||
|
||||
topobjdir = os.path.abspath(os.path.dirname(<<<__file__>>>))
|
||||
|
||||
def unique_list(l):
|
||||
result = []
|
||||
for i in l:
|
||||
if l not in result:
|
||||
result.append(i)
|
||||
return result
|
||||
|
||||
dnl All defines and substs are stored with an additional space at the beginning
|
||||
dnl and at the end of the string, to avoid any problem with values starting or
|
||||
dnl ending with quotes.
|
||||
|
@ -232,5 +239,5 @@ MOZ_ARG_ENABLE_STRING(build-backend,
|
|||
Enable additional build backends],
|
||||
[ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])
|
||||
|
||||
AC_SUBST_LIST([BUILD_BACKENDS])
|
||||
AC_SUBST_SET([BUILD_BACKENDS])
|
||||
])
|
||||
|
|
|
@ -30,14 +30,6 @@ typedef ASTConsumer *ASTConsumerPtr;
|
|||
|
||||
namespace {
|
||||
|
||||
QualType GetCallReturnType(const CallExpr *expr) {
|
||||
#if CLANG_VERSION_FULL >= 307
|
||||
return expr->getCallReturnType(expr->getCalleeDecl()->getASTContext());
|
||||
#else
|
||||
return expr->getCallReturnType();
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
class DiagnosticsMatcher {
|
||||
public:
|
||||
|
@ -503,13 +495,6 @@ const FieldDecl *getClassRefCntMember(const CXXRecordDecl *D) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const FieldDecl *getClassRefCntMember(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
return clazz ? getClassRefCntMember(clazz) : 0;
|
||||
}
|
||||
|
||||
const FieldDecl *getBaseRefCntMember(QualType T);
|
||||
|
||||
const FieldDecl *getBaseRefCntMember(const CXXRecordDecl *D) {
|
||||
|
@ -1317,8 +1302,6 @@ void DiagnosticsMatcher::NonMemMovableChecker::run(
|
|||
const ClassTemplateSpecializationDecl *specialization =
|
||||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
|
||||
SourceLocation requestLoc = specialization->getPointOfInstantiation();
|
||||
const CXXRecordDecl *templ =
|
||||
specialization->getSpecializedTemplate()->getTemplatedDecl();
|
||||
|
||||
// Report an error for every template argument which is non-memmovable
|
||||
const TemplateArgumentList &args =
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#! /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/.
|
||||
|
||||
'''Prints the given arguments in sorted order with duplicates removed.'''
|
||||
|
||||
import sys
|
||||
|
||||
print(' '.join(sorted(set(sys.argv[1:]))))
|
|
@ -53,6 +53,9 @@ default: $(TOPOBJDIR)/dist/bin/greprefs.js
|
|||
default: $(TOPOBJDIR)/dist/bin/platform.ini
|
||||
default: $(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini
|
||||
|
||||
# Targets from the recursive make backend to be built for a default build
|
||||
default: $(TOPOBJDIR)/config/makefiles/xpidl/xpidl
|
||||
|
||||
.PHONY: FORCE
|
||||
|
||||
# Extra define to trigger some workarounds. We should strive to limit the
|
||||
|
@ -189,15 +192,6 @@ jar-browser-themes-%-jar.mn: \
|
|||
$(TOPOBJDIR)/browser/themes/%/tab-selected-end.svg \
|
||||
$(TOPOBJDIR)/browser/themes/%/tab-selected-start.svg
|
||||
|
||||
# These files are manually generated from
|
||||
# toolkit/components/urlformatter/Makefile.in and are force-included so that
|
||||
# the corresponding defines don't end up in the command lines.
|
||||
KEYS = mozilla_api_key google_api_key google_oauth_api_key bing_api_key
|
||||
$(TOPOBJDIR)/dist/bin/components/nsURLFormatter.js: \
|
||||
$(addprefix $(TOPOBJDIR)/toolkit/components/urlformatter/, $(KEYS))
|
||||
$(TOPOBJDIR)/dist/bin/components/nsURLFormatter.js: defines += \
|
||||
$(addprefix -I $(TOPOBJDIR)/toolkit/components/urlformatter/,$(KEYS))
|
||||
|
||||
# Extra dependencies and/or definitions for preprocessed files.
|
||||
$(TOPOBJDIR)/dist/bin/application.ini: $(TOPOBJDIR)/config/buildid
|
||||
$(TOPOBJDIR)/dist/bin/application.ini: defines += \
|
||||
|
@ -207,3 +201,7 @@ $(TOPOBJDIR)/dist/bin/application.ini: defines += \
|
|||
$(TOPOBJDIR)/dist/bin/greprefs.js: $(TOPOBJDIR)/modules/libpref/greprefs.js
|
||||
$(TOPOBJDIR)/dist/bin/platform.ini: $(TOPOBJDIR)/toolkit/xre/platform.ini
|
||||
$(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini: $(TOPOBJDIR)/webapprt/webapprt.ini
|
||||
|
||||
# The xpidl target in config/makefiles/xpidl requires the install manifest for
|
||||
# dist/idl to have been processed.
|
||||
$(TOPOBJDIR)/config/makefiles/xpidl/xpidl: $(TOPOBJDIR)/install-dist_idl
|
||||
|
|
14
configure.in
14
configure.in
|
@ -2242,9 +2242,6 @@ ia64*-hpux*)
|
|||
# the same thing as C4244, we disable C4267, too.
|
||||
# MSVC warning C4345 warns of newly conformant behavior as of VS2003.
|
||||
# MSVC warning C4351 warns of newly conformant behavior as of VS2005.
|
||||
# MSVC warning C4482 warns when an enum value is refered specifing the
|
||||
# name of the enum itself. This behavior is allowed in C++11, and the
|
||||
# warning has been removed in VS2012.
|
||||
# MSVC warning C4800 warns when a value is implicitly cast to bool,
|
||||
# because this also forces narrowing to a single byte, which can be a
|
||||
# perf hit. But this matters so little in practice (and often we want
|
||||
|
@ -2252,7 +2249,7 @@ ia64*-hpux*)
|
|||
# MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign)
|
||||
# on non-Western system locales even if it is in a comment.
|
||||
CFLAGS="$CFLAGS -wd4244 -wd4267 -wd4819"
|
||||
CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4267 -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
|
||||
CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4267 -wd4345 -wd4351 -wd4800 -wd4819"
|
||||
if test -n "$CLANG_CL"; then
|
||||
# Suppress the clang-cl warning for the inline 'new' and 'delete' in mozalloc
|
||||
CXXFLAGS="$CXXFLAGS -Wno-inline-new-delete"
|
||||
|
@ -4034,6 +4031,8 @@ esac
|
|||
case "$MOZ_BUILD_APP" in
|
||||
browser)
|
||||
AC_DEFINE(MOZ_PHOENIX)
|
||||
|
||||
BUILD_BACKENDS="$BUILD_BACKENDS FasterMake"
|
||||
;;
|
||||
|
||||
xulrunner)
|
||||
|
@ -6309,9 +6308,6 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
|
|||
fi
|
||||
AC_SUBST(MOZ_GIO_COMPONENT)
|
||||
|
||||
dnl Remove dupes
|
||||
MOZ_EXTENSIONS=`$PYTHON ${srcdir}/build/unix/uniq.py ${MOZ_EXTENSIONS}`
|
||||
|
||||
dnl Ensure every extension exists, to avoid mostly-inscrutable error messages
|
||||
dnl when trying to build a nonexistent extension.
|
||||
for extension in $MOZ_EXTENSIONS; do
|
||||
|
@ -8382,8 +8378,6 @@ MOZ_ARG_ENABLE_STRING(necko-protocols,
|
|||
fi
|
||||
done],
|
||||
NECKO_PROTOCOLS="$NECKO_PROTOCOLS_DEFAULT")
|
||||
dnl Remove dupes
|
||||
NECKO_PROTOCOLS=`$PYTHON ${srcdir}/build/unix/uniq.py ${NECKO_PROTOCOLS}`
|
||||
AC_SUBST_SET(NECKO_PROTOCOLS)
|
||||
for p in $NECKO_PROTOCOLS; do
|
||||
AC_DEFINE_UNQUOTED(NECKO_PROTOCOL_$p)
|
||||
|
@ -8567,7 +8561,7 @@ AC_SUBST(MOZ_DEBUG_ENABLE_DEFS)
|
|||
AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
|
||||
AC_SUBST(MOZ_DEBUG_LDFLAGS)
|
||||
AC_SUBST(WARNINGS_AS_ERRORS)
|
||||
AC_SUBST(MOZ_EXTENSIONS)
|
||||
AC_SUBST_SET(MOZ_EXTENSIONS)
|
||||
AC_SUBST(MOZ_ENABLE_PROFILER_SPS)
|
||||
AC_SUBST(MOZ_JPROF)
|
||||
AC_SUBST(MOZ_INSTRUMENTS)
|
||||
|
|
|
@ -755,22 +755,6 @@ ThreadActor.prototype = {
|
|||
return this._tabClosed ? null : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle resume requests that include a forceCompletion request.
|
||||
*
|
||||
* @param Object aRequest
|
||||
* The request packet received over the RDP.
|
||||
* @returns A response packet.
|
||||
*/
|
||||
_forceCompletion: function (aRequest) {
|
||||
// TODO: remove this when Debugger.Frame.prototype.pop is implemented in
|
||||
// bug 736733.
|
||||
return {
|
||||
error: "notImplemented",
|
||||
message: "forced completion is not yet implemented."
|
||||
};
|
||||
},
|
||||
|
||||
_makeOnEnterFrame: function ({ pauseAndRespond }) {
|
||||
return aFrame => {
|
||||
const generatedLocation = this.sources.getFrameLocation(aFrame);
|
||||
|
@ -1012,10 +996,6 @@ ThreadActor.prototype = {
|
|||
};
|
||||
}
|
||||
|
||||
if (aRequest && aRequest.forceCompletion) {
|
||||
return this._forceCompletion(aRequest);
|
||||
}
|
||||
|
||||
let resumeLimitHandled;
|
||||
if (aRequest && aRequest.resumeLimit) {
|
||||
resumeLimitHandled = this._handleResumeLimit(aRequest)
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
|
||||
struct JSContext;
|
||||
|
||||
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
||||
// GetTickCount().
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
|
|
@ -11338,6 +11338,16 @@ LogFullScreenDenied(bool aLogFailure, const char* aMessage, nsIDocument* aDoc)
|
|||
aMessage);
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateViewportScrollbarOverrideForFullscreen(nsIDocument* aDoc)
|
||||
{
|
||||
if (nsIPresShell* presShell = aDoc->GetShell()) {
|
||||
if (nsPresContext* presContext = presShell->GetPresContext()) {
|
||||
presContext->UpdateViewportScrollbarStylesOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::CleanupFullscreenState()
|
||||
{
|
||||
|
@ -11357,6 +11367,7 @@ nsDocument::CleanupFullscreenState()
|
|||
}
|
||||
mFullScreenStack.Clear();
|
||||
mFullscreenRoot = nullptr;
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -11370,6 +11381,7 @@ nsDocument::FullScreenStackPush(Element* aElement)
|
|||
EventStateManager::SetFullScreenState(aElement, true);
|
||||
mFullScreenStack.AppendElement(do_GetWeakReference(aElement));
|
||||
NS_ASSERTION(GetFullScreenElement() == aElement, "Should match");
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11409,6 +11421,8 @@ nsDocument::FullScreenStackPop()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateViewportScrollbarOverrideForFullscreen(this);
|
||||
}
|
||||
|
||||
Element*
|
||||
|
|
|
@ -2469,7 +2469,11 @@ nsFocusManager::DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
|
|||
nsCOMPtr<nsPIDOMWindow> focusedWindow;
|
||||
startContent = GetFocusedDescendant(aWindow, true, getter_AddRefs(focusedWindow));
|
||||
}
|
||||
else {
|
||||
else if (aType != MOVEFOCUS_LASTDOC) {
|
||||
// Otherwise, start at the focused node. If MOVEFOCUS_LASTDOC is used,
|
||||
// then we are document-navigating backwards from chrome to the content
|
||||
// process, and we don't want to use this so that we start from the end
|
||||
// of the document.
|
||||
startContent = aWindow->GetFocusedNode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<script>
|
||||
var ac = new AudioContext();
|
||||
var runningPromise = new Promise(resolve => {
|
||||
ac.onstatechange = event => {
|
||||
if (ac.state == "running") {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
});
|
||||
fetch("audio.ogg").then(response => {
|
||||
return response.arrayBuffer();
|
||||
}).then(ab => {
|
||||
|
@ -17,7 +24,9 @@ fetch("audio.ogg").then(response => {
|
|||
|
||||
var suspendPromise;
|
||||
function suspendAC() {
|
||||
suspendPromise = ac.suspend();
|
||||
runningPromise.then(() => {
|
||||
suspendPromise = ac.suspend();
|
||||
});
|
||||
}
|
||||
|
||||
var resumePromise;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "BatteryManager.h"
|
||||
#include "Constants.h"
|
||||
|
@ -12,6 +13,7 @@
|
|||
#include "mozilla/dom/BatteryManagerBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
/**
|
||||
* We have to use macros here because our leak analysis tool things we are
|
||||
|
@ -129,6 +131,20 @@ void
|
|||
BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo)
|
||||
{
|
||||
mLevel = aBatteryInfo.level();
|
||||
|
||||
// Round to the nearest ten percent for non-chrome and non-certified apps
|
||||
nsIDocument* doc = GetOwner()->GetDoc();
|
||||
uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetAppStatus(&status);
|
||||
}
|
||||
|
||||
if (!nsContentUtils::IsChromeDoc(doc) &&
|
||||
status != nsIPrincipal::APP_STATUS_CERTIFIED)
|
||||
{
|
||||
mLevel = lround(mLevel * 10.0) / 10.0;
|
||||
}
|
||||
|
||||
mCharging = aBatteryInfo.charging();
|
||||
mRemainingTime = aBatteryInfo.remainingTime();
|
||||
|
||||
|
|
|
@ -66,10 +66,14 @@ private:
|
|||
*/
|
||||
void UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Represents the battery level, ranging from 0.0 (dead or removed?)
|
||||
* to 1.0 (fully charged)
|
||||
*/
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
/**
|
||||
* Represents the discharging time or the charging time, dpending on the
|
||||
* Represents the discharging time or the charging time, depending on the
|
||||
* current battery status (charging or not).
|
||||
*/
|
||||
double mRemainingTime;
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test for Bug 1201798</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="file_fullscreen-utils.js"></script>
|
||||
<style>
|
||||
html, body, #measure {
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
#ref-outer { width: 100px; height: 100px; overflow: scroll; }
|
||||
#ref-inner { width: 100%; height: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="measure"></div>
|
||||
<div style="height: 1000vh; width: 1000vw"></div>
|
||||
<div id="ref-outer">
|
||||
<div id="ref-inner"></div>
|
||||
</div>
|
||||
<div id="fullscreen"></div>
|
||||
<script type="text/javascript">
|
||||
|
||||
/** Test for Bug 1201798 */
|
||||
|
||||
var info = msg => opener.info("[scrollbar] " + msg);
|
||||
var ok = (cond, msg) => opener.ok(cond, "[scrollbar] " + msg);
|
||||
var is = (a, b, msg) => opener.is(a, b, "[scrollbar] " + msg);
|
||||
|
||||
var gVerticalScrollbarWidth, gHorizontalScrollbarWidth;
|
||||
var gMeasureDiv = document.getElementById("measure");
|
||||
var gFullscreenDiv = document.getElementById("fullscreen");
|
||||
|
||||
function getMeasureRect() {
|
||||
return gMeasureDiv.getBoundingClientRect();
|
||||
}
|
||||
|
||||
function triggerFrameReconstruction() {
|
||||
info("Triggering a force frame reconstruction");
|
||||
var docElem = document.documentElement;
|
||||
var wm = window.getComputedStyle(docElem).writingMode;
|
||||
if (wm == "horizontal-tb") {
|
||||
docElem.style.writingMode = "vertical-rl";
|
||||
} else {
|
||||
docElem.style.writingMode = "horizontal-tb";
|
||||
}
|
||||
docElem.getBoundingClientRect();
|
||||
}
|
||||
|
||||
function assertHasScrollbars(elem) {
|
||||
var rect = getMeasureRect();
|
||||
is(rect.width, screen.width - gVerticalScrollbarWidth,
|
||||
`Should have vertical scrollbar when ${elem} is in fullscreen`);
|
||||
is(rect.height, screen.height - gHorizontalScrollbarWidth,
|
||||
`Should have horizontal scrollbar when ${elem} is in fullscreen`);
|
||||
}
|
||||
|
||||
function assertHasNoScrollbars(elem) {
|
||||
var rect = getMeasureRect();
|
||||
is(rect.width, screen.width,
|
||||
`Should not have vertical scrollbar when ${elem} is in fullscreen`);
|
||||
is(rect.height, screen.height,
|
||||
`Should not have horizontal scrollbar when ${elem} is in fullscreen`);
|
||||
}
|
||||
|
||||
function checkScrollbars(elem, shouldHaveScrollbars) {
|
||||
is(elem, document.mozFullScreenElement,
|
||||
"Should only check the current fullscreen element");
|
||||
var assertFunc = shouldHaveScrollbars ?
|
||||
assertHasScrollbars : assertHasNoScrollbars;
|
||||
assertFunc(elem);
|
||||
triggerFrameReconstruction();
|
||||
assertFunc(elem);
|
||||
}
|
||||
|
||||
function begin() {
|
||||
if (window.matchMedia("(-moz-overlay-scrollbar").matches) {
|
||||
// If overlay scrollbar is enabled, the scrollbar is not measurable,
|
||||
// so we skip this test in that case.
|
||||
info("Skip this test because of overlay scrollbar");
|
||||
opener.nextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
var rectOuter = document.getElementById("ref-outer").getBoundingClientRect();
|
||||
var rectInner = document.getElementById("ref-inner").getBoundingClientRect();
|
||||
gVerticalScrollbarWidth = rectOuter.width - rectInner.width;
|
||||
gHorizontalScrollbarWidth = rectOuter.height - rectInner.height;
|
||||
ok(gVerticalScrollbarWidth != 0, "Should have vertical scrollbar");
|
||||
ok(gHorizontalScrollbarWidth != 0, "Should have horizontal scrollbar");
|
||||
|
||||
info("Entering fullscreen on root");
|
||||
addFullscreenChangeContinuation("enter", enteredFullscreenOnRoot);
|
||||
document.documentElement.mozRequestFullScreen();
|
||||
}
|
||||
|
||||
function enteredFullscreenOnRoot() {
|
||||
checkScrollbars(document.documentElement, true);
|
||||
info("Entering fullscreen on div");
|
||||
addFullscreenChangeContinuation("enter", enteredFullscreenOnDiv);
|
||||
gFullscreenDiv.mozRequestFullScreen();
|
||||
}
|
||||
|
||||
function enteredFullscreenOnDiv() {
|
||||
checkScrollbars(gFullscreenDiv, false);
|
||||
info("Exiting fullscreen on div");
|
||||
addFullscreenChangeContinuation("exit", exitedFullscreenOnDiv);
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
|
||||
function exitedFullscreenOnDiv() {
|
||||
checkScrollbars(document.documentElement, true);
|
||||
info("Exiting fullscreen on root");
|
||||
addFullscreenChangeContinuation("exit", exitedFullscreenOnRoot);
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
|
||||
function exitedFullscreenOnRoot() {
|
||||
opener.nextTest();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -60,6 +60,7 @@ support-files =
|
|||
file_fullscreen-navigation.html
|
||||
file_fullscreen-plugins.html
|
||||
file_fullscreen-rollback.html
|
||||
file_fullscreen-scrollbar.html
|
||||
file_fullscreen-selector.html
|
||||
file_fullscreen-svg-element.html
|
||||
file_fullscreen-utils.js
|
||||
|
|
|
@ -40,6 +40,7 @@ var gTestWindows = [
|
|||
"file_fullscreen-hidden.html",
|
||||
"file_fullscreen-svg-element.html",
|
||||
"file_fullscreen-navigation.html",
|
||||
"file_fullscreen-scrollbar.html",
|
||||
"file_fullscreen-selector.html"
|
||||
];
|
||||
|
||||
|
|
|
@ -646,10 +646,6 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
}
|
||||
sSingleton = this;
|
||||
|
||||
// Make sure there's an nsAutoScriptBlocker on the stack when dispatching
|
||||
// urgent messages.
|
||||
GetIPCChannel()->BlockScripts();
|
||||
|
||||
// If communications with the parent have broken down, take the process
|
||||
// down so it's not hanging around.
|
||||
bool abortOnError = true;
|
||||
|
|
|
@ -163,11 +163,6 @@ public:
|
|||
// Observe and it should never be called directly.
|
||||
NS_IMETHOD Observe(nsISupports *aSubject, const char * aTopic, const char16_t * aData) override
|
||||
{ MOZ_CRASH("Forbidden method"); return NS_OK; }
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
virtual CDMProxy* GetCDMProxy() { return nullptr; }
|
||||
#endif
|
||||
};
|
||||
|
||||
class MetadataContainer
|
||||
|
|
|
@ -140,7 +140,6 @@ void
|
|||
MediaDecoder::NotifyOwnerActivityChanged()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
if (!mOwner) {
|
||||
NS_WARNING("MediaDecoder without a decoder owner, can't update dormant");
|
||||
|
@ -155,6 +154,8 @@ MediaDecoder::NotifyOwnerActivityChanged()
|
|||
bool
|
||||
MediaDecoder::IsHeuristicDormantSupported() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return
|
||||
#if defined(MOZ_EME)
|
||||
// We disallow dormant for encrypted media until bug 1181864 is fixed.
|
||||
|
@ -168,7 +169,6 @@ void
|
|||
MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
if (!mDecoderStateMachine ||
|
||||
mPlayState == PLAY_STATE_SHUTDOWN ||
|
||||
|
@ -242,7 +242,6 @@ MediaDecoder::DormantTimerExpired(nsITimer* aTimer, void* aClosure)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aClosure);
|
||||
MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
|
||||
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
|
||||
decoder->UpdateDormantState(true /* aDormantTimeout */,
|
||||
false /* aActivity */);
|
||||
}
|
||||
|
@ -287,7 +286,6 @@ void
|
|||
MediaDecoder::Pause()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (mPlayState == PLAY_STATE_LOADING ||
|
||||
IsEnded()) {
|
||||
mNextState = PLAY_STATE_PAUSED;
|
||||
|
@ -356,6 +354,9 @@ MediaDecoder::MediaDecoder() :
|
|||
mLogicalPosition(0.0),
|
||||
mDuration(std::numeric_limits<double>::quiet_NaN()),
|
||||
mReentrantMonitor("media.decoder"),
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__)),
|
||||
#endif
|
||||
mIgnoreProgressData(false),
|
||||
mInfiniteStream(false),
|
||||
mOwner(nullptr),
|
||||
|
@ -463,6 +464,10 @@ MediaDecoder::Shutdown()
|
|||
|
||||
mShuttingDown = true;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
|
||||
#endif
|
||||
|
||||
// This changes the decoder state to SHUTDOWN and does other things
|
||||
// necessary to unblock the state machine thread if it's blocked, so
|
||||
// the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
|
||||
|
@ -501,17 +506,7 @@ MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
|
|||
if (aStreamListener) {
|
||||
*aStreamListener = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
// Hold the lock while we do this to set proper lock ordering
|
||||
// expectations for dynamic deadlock detectors: decoder lock(s)
|
||||
// should be grabbed before the cache lock
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
nsresult rv = mResource->Open(aStreamListener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
return mResource->Open(aStreamListener);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -575,7 +570,6 @@ nsresult
|
|||
MediaDecoder::Play()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
|
||||
|
||||
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
|
||||
|
@ -598,7 +592,6 @@ nsresult
|
|||
MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
NS_ENSURE_TRUE(!mShuttingDown, NS_ERROR_FAILURE);
|
||||
|
||||
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
|
||||
|
@ -795,7 +788,6 @@ void
|
|||
MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mSameOriginMedia = aSameOrigin;
|
||||
}
|
||||
|
||||
|
@ -850,7 +842,6 @@ MediaStatistics
|
|||
MediaDecoder::GetStatistics()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(mResource);
|
||||
|
||||
MediaStatistics result;
|
||||
|
@ -868,7 +859,6 @@ void
|
|||
MediaDecoder::ComputePlaybackRate()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(mResource);
|
||||
|
||||
int64_t length = mResource->GetLength();
|
||||
|
@ -887,7 +877,6 @@ void
|
|||
MediaDecoder::UpdatePlaybackRate()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
MOZ_ASSERT(mResource);
|
||||
|
||||
ComputePlaybackRate();
|
||||
|
@ -919,10 +908,7 @@ void
|
|||
MediaDecoder::NotifyBytesDownloaded()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
UpdatePlaybackRate();
|
||||
}
|
||||
UpdatePlaybackRate();
|
||||
if (mOwner) {
|
||||
mOwner->DownloadProgressed();
|
||||
}
|
||||
|
@ -943,10 +929,7 @@ MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
|
|||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
UpdatePlaybackRate();
|
||||
}
|
||||
UpdatePlaybackRate();
|
||||
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
// A final progress event will be fired by the MediaResource calling
|
||||
|
@ -977,7 +960,6 @@ MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(mDecoderStateMachine);
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (aOffset >= mDecoderPosition) {
|
||||
mPlaybackStatistics->AddBytes(aBytes);
|
||||
}
|
||||
|
@ -995,8 +977,6 @@ MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
|
|||
|
||||
bool fireEnded = false;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
// An additional seek was requested while the current seek was
|
||||
// in operation.
|
||||
UnpinForSeek();
|
||||
|
@ -1037,7 +1017,6 @@ void
|
|||
MediaDecoder::ChangeState(PlayState aState)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
if (mNextState == aState) {
|
||||
mNextState = PLAY_STATE_PAUSED;
|
||||
|
@ -1094,7 +1073,6 @@ void
|
|||
MediaDecoder::DurationChanged()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
double oldDuration = mDuration;
|
||||
if (IsInfinite()) {
|
||||
|
@ -1150,7 +1128,6 @@ MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
|
|||
void
|
||||
MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mMediaSeekable = aMediaSeekable;
|
||||
}
|
||||
|
||||
|
@ -1363,12 +1340,14 @@ MediaDecoder::NotifyDataArrived(uint32_t aLength,
|
|||
// Provide access to the state machine object
|
||||
MediaDecoderStateMachine*
|
||||
MediaDecoder::GetStateMachine() const {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mDecoderStateMachine;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::NotifyWaitingForResourcesStatusChanged()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->DispatchWaitingForResourcesStatusChanged();
|
||||
}
|
||||
|
@ -1377,6 +1356,7 @@ MediaDecoder::NotifyWaitingForResourcesStatusChanged()
|
|||
// Drop reference to state machine. Only called during shutdown dance.
|
||||
void
|
||||
MediaDecoder::BreakCycles() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
SetStateMachine(nullptr);
|
||||
}
|
||||
|
||||
|
@ -1428,22 +1408,30 @@ MediaDecoder::CanPlayThrough()
|
|||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
nsRefPtr<MediaDecoder::CDMProxyPromise>
|
||||
MediaDecoder::RequestCDMProxy() const
|
||||
{
|
||||
return mCDMProxyPromise;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mProxy = aProxy;
|
||||
// Awaken any readers waiting for the proxy.
|
||||
NotifyWaitingForResourcesStatusChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CDMProxy*
|
||||
MediaDecoder::GetCDMProxy()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
return mProxy;
|
||||
nsRefPtr<CDMProxy> proxy = aProxy;
|
||||
{
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
if (!caps.AreCapsKnown()) {
|
||||
nsRefPtr<MediaDecoder> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
self->mCDMProxyPromiseHolder.ResolveIfExists(proxy, __func__);
|
||||
});
|
||||
caps.CallOnMainThreadWhenCapsAvailable(r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mCDMProxyPromiseHolder.ResolveIfExists(proxy, __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -664,11 +664,13 @@ public:
|
|||
MediaDecoderOwner* GetOwner() override;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// This takes the decoder monitor.
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
typedef MozPromise<nsRefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
|
||||
|
||||
// Decoder monitor must be held.
|
||||
virtual CDMProxy* GetCDMProxy() override;
|
||||
// Resolved when a CDMProxy is available and the capabilities are known or
|
||||
// rejected when this decoder is about to shut down.
|
||||
nsRefPtr<CDMProxyPromise> RequestCDMProxy() const;
|
||||
|
||||
void SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_RAW
|
||||
|
@ -818,7 +820,8 @@ private:
|
|||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
|
||||
nsRefPtr<CDMProxyPromise> mCDMProxyPromise;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
|
|
@ -259,20 +259,10 @@ MediaDecoderReader::AsyncReadMetadata()
|
|||
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
||||
DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
|
||||
|
||||
if (IsWaitingMediaResources()) {
|
||||
return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__);
|
||||
}
|
||||
|
||||
// Attempt to read the metadata.
|
||||
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
|
||||
nsresult rv = ReadMetadata(&metadata->mInfo, getter_Transfers(metadata->mTags));
|
||||
|
||||
// Reading metadata can cause us to discover that we need resources (a hardware
|
||||
// resource initialized but not yet ready for use).
|
||||
if (IsWaitingMediaResources()) {
|
||||
return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__);
|
||||
}
|
||||
|
||||
// We're not waiting for anything. If we didn't get the metadata, that's an
|
||||
// error.
|
||||
if (NS_FAILED(rv) || !metadata->mInfo.HasValidMedia()) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
class MediaDecoderReader;
|
||||
|
||||
struct WaitForDataRejectValue
|
||||
|
@ -94,11 +95,6 @@ public:
|
|||
// on failure.
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0;
|
||||
|
||||
// True if this reader is waiting media resource allocation
|
||||
virtual bool IsWaitingMediaResources() { return false; }
|
||||
// True if this reader is waiting for a Content Decryption Module to become
|
||||
// available.
|
||||
virtual bool IsWaitingOnCDMResource() { return false; }
|
||||
// Release media resources they should be released in dormant state
|
||||
// The reader can be made usable again by calling ReadMetadata().
|
||||
virtual void ReleaseMediaResources() {};
|
||||
|
@ -195,6 +191,10 @@ public:
|
|||
// when to call SetIdle().
|
||||
virtual void SetIdle() { }
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual void SetCDMProxy(CDMProxy* aProxy) {}
|
||||
#endif
|
||||
|
||||
// Tell the reader that the data decoded are not for direct playback, so it
|
||||
// can accept more files, in particular those which have more channels than
|
||||
// available in the audio output.
|
||||
|
|
|
@ -205,7 +205,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
|
||||
mIsAudioPrerolling(false),
|
||||
mIsVideoPrerolling(false),
|
||||
mAudioCaptured(false),
|
||||
mAudioCaptured(false, "MediaDecoderStateMachine::mAudioCaptured"),
|
||||
mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"),
|
||||
mNotifyMetadataBeforeFirstFrame(false),
|
||||
mDispatchedEventToDecode(false),
|
||||
|
@ -219,7 +219,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mCorruptFrames(60),
|
||||
mDecodingFirstFrame(true),
|
||||
mSentLoadedMetadataEvent(false),
|
||||
mSentFirstFrameLoadedEvent(false),
|
||||
mSentFirstFrameLoadedEvent(false, "MediaDecoderStateMachine::mSentFirstFrameLoadedEvent"),
|
||||
mSentPlaybackEndedEvent(false),
|
||||
mStreamSink(new DecodedStream(mTaskQueue, mAudioQueue, mVideoQueue)),
|
||||
mResource(aDecoder->GetResource()),
|
||||
|
@ -302,6 +302,13 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
|
||||
|
||||
mMediaSink = CreateAudioSink();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromise.Begin(mDecoder->RequestCDMProxy()->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnCDMProxyReady,
|
||||
&MediaDecoderStateMachine::OnCDMProxyNotReady));
|
||||
#endif
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
|
@ -350,6 +357,8 @@ MediaDecoderStateMachine::InitializationTask()
|
|||
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
|
||||
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
|
||||
mWatchManager.Watch(mSameOriginMedia, &MediaDecoderStateMachine::SameOriginMediaChanged);
|
||||
mWatchManager.Watch(mSentFirstFrameLoadedEvent, &MediaDecoderStateMachine::AdjustAudioThresholds);
|
||||
mWatchManager.Watch(mAudioCaptured, &MediaDecoderStateMachine::AdjustAudioThresholds);
|
||||
|
||||
// Propagate mSameOriginMedia to mDecodedStream.
|
||||
SameOriginMediaChanged();
|
||||
|
@ -1315,6 +1324,10 @@ void MediaDecoderStateMachine::Shutdown()
|
|||
mPendingSeek.RejectIfExists(__func__);
|
||||
mCurrentSeek.RejectIfExists(__func__);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromise.DisconnectIfExists();
|
||||
#endif
|
||||
|
||||
if (IsPlaying()) {
|
||||
StopPlayback();
|
||||
}
|
||||
|
@ -1403,9 +1416,6 @@ MediaDecoderStateMachine::NotifyWaitingForResourcesStatusChanged()
|
|||
// Try again.
|
||||
SetState(DECODER_STATE_DECODING_NONE);
|
||||
ScheduleStateMachine();
|
||||
} else if (mState == DECODER_STATE_WAIT_FOR_CDM &&
|
||||
!mReader->IsWaitingOnCDMResource()) {
|
||||
StartDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2000,12 +2010,18 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
|
|||
// feeding in the CDM, which we need to decode the first frame (and
|
||||
// thus get the metadata). We could fix this if we could compute the start
|
||||
// time by demuxing without necessaring decoding.
|
||||
mNotifyMetadataBeforeFirstFrame = mDuration.Ref().isSome() || mReader->IsWaitingOnCDMResource();
|
||||
bool waitingForCDM =
|
||||
#ifdef MOZ_EME
|
||||
mInfo.IsEncrypted() && !mCDMProxy;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
mNotifyMetadataBeforeFirstFrame = mDuration.Ref().isSome() || waitingForCDM;
|
||||
if (mNotifyMetadataBeforeFirstFrame) {
|
||||
EnqueueLoadedMetadataEvent();
|
||||
}
|
||||
|
||||
if (mReader->IsWaitingOnCDMResource()) {
|
||||
if (waitingForCDM) {
|
||||
// Metadata parsing was successful but we're still waiting for CDM caps
|
||||
// to become available so that we can build the correct decryptor/decoder.
|
||||
SetState(DECODER_STATE_WAIT_FOR_CDM);
|
||||
|
@ -2070,6 +2086,33 @@ MediaDecoderStateMachine::IsDecodingFirstFrame()
|
|||
return mState == DECODER_STATE_DECODING && mDecodingFirstFrame;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::AdjustAudioThresholds()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
// Experiments show that we need to buffer more if audio is captured to avoid
|
||||
// audio glitch. See bug 1188643 comment 16 for the details.
|
||||
int64_t divisor = mAudioCaptured ? NO_VIDEO_AMPLE_AUDIO_DIVISOR / 2
|
||||
: NO_VIDEO_AMPLE_AUDIO_DIVISOR;
|
||||
|
||||
// We're playing audio only. We don't need to worry about slow video
|
||||
// decodes causing audio underruns, so don't buffer so much audio in
|
||||
// order to reduce memory usage.
|
||||
if (HasAudio() && !HasVideo() && mSentFirstFrameLoadedEvent) {
|
||||
mAmpleAudioThresholdUsecs = detail::AMPLE_AUDIO_USECS / divisor;
|
||||
mLowAudioThresholdUsecs = detail::LOW_AUDIO_USECS / divisor;
|
||||
mQuickBufferingLowDataThresholdUsecs =
|
||||
detail::QUICK_BUFFERING_LOW_DATA_USECS / divisor;
|
||||
|
||||
// Check if we need to stop audio prerolling for thresholds changed.
|
||||
if (mIsAudioPrerolling && DonePrerollingAudio()) {
|
||||
StopPrerollingAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
{
|
||||
|
@ -2090,15 +2133,6 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
|||
"transportSeekable=%d, mediaSeekable=%d",
|
||||
Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable.Ref());
|
||||
|
||||
if (HasAudio() && !HasVideo() && !mSentFirstFrameLoadedEvent) {
|
||||
// We're playing audio only. We don't need to worry about slow video
|
||||
// decodes causing audio underruns, so don't buffer so much audio in
|
||||
// order to reduce memory usage.
|
||||
mAmpleAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
|
||||
mLowAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
|
||||
mQuickBufferingLowDataThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
|
||||
}
|
||||
|
||||
// Get potentially updated metadata
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
|
@ -3021,6 +3055,27 @@ void MediaDecoderStateMachine::OnMediaSinkError()
|
|||
DecodeError();
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void
|
||||
MediaDecoderStateMachine::OnCDMProxyReady(nsRefPtr<CDMProxy> aProxy)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mCDMProxyPromise.Complete();
|
||||
mCDMProxy = aProxy;
|
||||
mReader->SetCDMProxy(aProxy);
|
||||
if (mState == DECODER_STATE_WAIT_FOR_CDM) {
|
||||
StartDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnCDMProxyNotReady()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mCDMProxyPromise.Complete();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
|
||||
{
|
||||
|
|
|
@ -654,6 +654,8 @@ private:
|
|||
// play time.
|
||||
bool NeedToSkipToNextKeyframe();
|
||||
|
||||
void AdjustAudioThresholds();
|
||||
|
||||
// The decoder object that created this state machine. The state machine
|
||||
// holds a strong reference to the decoder to ensure that the decoder stays
|
||||
// alive once media element has started the decoder shutdown process, and has
|
||||
|
@ -1136,7 +1138,7 @@ private:
|
|||
// True if we shouldn't play our audio (but still write it to any capturing
|
||||
// streams). When this is true, the audio thread will never start again after
|
||||
// it has stopped.
|
||||
bool mAudioCaptured;
|
||||
Watchable<bool> mAudioCaptured;
|
||||
|
||||
// True if the audio playback thread has finished. It is finished
|
||||
// when either all the audio frames have completed playing, or we've moved
|
||||
|
@ -1228,7 +1230,7 @@ private:
|
|||
// SetStartTime because the mStartTime already set before. Also we don't need
|
||||
// to decode any audio/video since the MediaDecoder will trigger a seek
|
||||
// operation soon.
|
||||
bool mSentFirstFrameLoadedEvent;
|
||||
Watchable<bool> mSentFirstFrameLoadedEvent;
|
||||
|
||||
bool mSentPlaybackEndedEvent;
|
||||
|
||||
|
@ -1247,6 +1249,13 @@ private:
|
|||
MediaEventListener mAudioQueueListener;
|
||||
MediaEventListener mVideoQueueListener;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void OnCDMProxyReady(nsRefPtr<CDMProxy> aProxy);
|
||||
void OnCDMProxyNotReady();
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The buffered range. Mirrored from the decoder thread.
|
||||
Mirror<media::TimeIntervals> mBuffered;
|
||||
|
|
|
@ -213,29 +213,24 @@ private:
|
|||
nsTArray<uint8_t> mInitData;
|
||||
nsString mInitDataType;
|
||||
};
|
||||
|
||||
void
|
||||
MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsRefPtr<CDMProxy> proxy = aProxy;
|
||||
nsRefPtr<MediaFormatReader> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
self->mCDMProxy = proxy;
|
||||
});
|
||||
OwnerThread()->DispatchDirectTask(r.forget());
|
||||
}
|
||||
#endif // MOZ_EME
|
||||
|
||||
bool MediaFormatReader::IsWaitingOnCDMResource() {
|
||||
bool
|
||||
MediaFormatReader::IsWaitingOnCDMResource() {
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
{
|
||||
if (!IsEncrypted()) {
|
||||
// Not encrypted, no need to wait for CDMProxy.
|
||||
return false;
|
||||
}
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
if (!proxy) {
|
||||
// We're encrypted, we need a CDMProxy to decrypt file.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We'll keep waiting if the CDM hasn't informed Gecko of its capabilities.
|
||||
{
|
||||
CDMCaps::AutoLock caps(proxy->Capabilites());
|
||||
LOG("capsKnown=%d", caps.AreCapsKnown());
|
||||
return !caps.AreCapsKnown();
|
||||
}
|
||||
return IsEncrypted() && !mCDMProxy;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -392,18 +387,8 @@ MediaFormatReader::EnsureDecodersCreated()
|
|||
// even if EME is disabled, so that if script tries and fails to create
|
||||
// a CDM, we can detect that and notify chrome and show some UI
|
||||
// explaining that we failed due to EME being disabled.
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
CDMCaps::AutoLock caps(proxy->Capabilites());
|
||||
mInfo.mVideo.mIsRenderedExternally = caps.CanRenderVideo();
|
||||
mInfo.mAudio.mIsRenderedExternally = caps.CanRenderAudio();
|
||||
}
|
||||
|
||||
mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy);
|
||||
MOZ_ASSERT(mCDMProxy);
|
||||
mPlatform = PlatformDecoderModule::CreateCDMWrapper(mCDMProxy);
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
#else
|
||||
// EME not supported.
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
|
||||
class MediaFormatReader final : public MediaDecoderReader
|
||||
{
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
|
@ -86,14 +88,18 @@ public:
|
|||
bool IsWaitForDataSupported() override { return true; }
|
||||
nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
|
||||
|
||||
bool IsWaitingOnCDMResource() override;
|
||||
|
||||
bool UseBufferingHeuristics() override
|
||||
{
|
||||
return mTrackDemuxersMayBlock;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void SetCDMProxy(CDMProxy* aProxy) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool IsWaitingOnCDMResource();
|
||||
|
||||
bool InitDemuxer();
|
||||
// Notify the demuxer that new data has been received.
|
||||
// The next queued task calling GetBuffered() is guaranteed to have up to date
|
||||
|
@ -391,10 +397,6 @@ private:
|
|||
{
|
||||
return mIsEncrypted;
|
||||
}
|
||||
// Accessed from multiple thread, in particular the MediaDecoderStateMachine,
|
||||
// however the value doesn't currently change after reading the metadata.
|
||||
// TODO handle change of encryption half-way. The above assumption will then
|
||||
// become incorrect.
|
||||
bool mIsEncrypted;
|
||||
|
||||
// Set to true if any of our track buffers may be blocking.
|
||||
|
|
|
@ -487,6 +487,12 @@ public:
|
|||
NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
|
||||
return (aTime*1000000)/mBuffer.GraphRate();
|
||||
}
|
||||
StreamTime SecondsToNearestStreamTime(double aSeconds)
|
||||
{
|
||||
NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
|
||||
"Bad seconds");
|
||||
return mBuffer.GraphRate() * aSeconds + 0.5;
|
||||
}
|
||||
StreamTime MicrosecondsToStreamTimeRoundDown(int64_t aMicroseconds) {
|
||||
return (aMicroseconds*mBuffer.GraphRate())/1000000;
|
||||
}
|
||||
|
|
|
@ -51,25 +51,6 @@ MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
|
|||
return new MediaDecoderStateMachine(this, reader);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MP4Decoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aProxy) {
|
||||
// The MediaFormatReader can't decrypt EME content until it has a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MediaFormatReader
|
||||
// remains in "waiting for resources" state until then.
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
|
||||
caps.CallOnMainThreadWhenCapsAvailable(task);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
IsSupportedAudioCodec(const nsAString& aCodec,
|
||||
bool& aOutContainsAAC,
|
||||
|
|
|
@ -25,10 +25,6 @@ public:
|
|||
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
#endif
|
||||
|
||||
// Returns true if aMIMEType is a type that we think we can render with the
|
||||
// a MP4 platform decoder backend. If aCodecs is non emtpy, it is filled
|
||||
// with a comma-delimited list of codecs to check support for. Notes in
|
||||
|
|
|
@ -606,10 +606,21 @@ GMPChild::GetGMPStorage()
|
|||
return mStorage;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvCrashPluginNow()
|
||||
static MOZ_NEVER_INLINE void
|
||||
CrashForApiTimeout()
|
||||
{
|
||||
MOZ_CRASH();
|
||||
// Never inline so that crash reports are distinctive.
|
||||
MOZ_CRASH("Bug 1209385; GMP API actor failed to respond.");
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvCrashPluginNow(const GMPCrashReason& aReason)
|
||||
{
|
||||
if (aReason == kGmpApiTimeout) {
|
||||
CrashForApiTimeout();
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ private:
|
|||
ProcessId aOtherPid) override;
|
||||
void GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild);
|
||||
|
||||
virtual bool RecvCrashPluginNow() override;
|
||||
virtual bool RecvCrashPluginNow(const GMPCrashReason& aReason) override;
|
||||
virtual bool RecvBeginAsyncShutdown() override;
|
||||
virtual bool RecvCloseActive() override;
|
||||
|
||||
|
|
|
@ -118,6 +118,18 @@ GMPContentParent::DecryptorDestroyed(GMPDecryptorParent* aSession)
|
|||
CloseIfUnused();
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::CrashPluginNow(GMPCrashReason aReason)
|
||||
{
|
||||
if (mParent) {
|
||||
mParent->Crash(aReason);
|
||||
} else {
|
||||
nsRefPtr<GeckoMediaPluginServiceChild> gmp(
|
||||
GeckoMediaPluginServiceChild::GetSingleton());
|
||||
gmp->CrashPluginNow(mPluginId, aReason);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::CloseIfUnused()
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/gmp/PGMPContentParent.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -61,6 +62,8 @@ public:
|
|||
return mPluginId;
|
||||
}
|
||||
|
||||
void CrashPluginNow(GMPCrashReason aReason);
|
||||
|
||||
private:
|
||||
~GMPContentParent();
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "gmp-audio-codec.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
|
@ -247,6 +249,13 @@ struct ParamTraits<GMPVideoCodec>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::GMPCrashReason>
|
||||
: public ContiguousEnumSerializer<mozilla::GMPCrashReason,
|
||||
mozilla::kPrefChange,
|
||||
mozilla::kInvalid>
|
||||
{};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // GMPMessageUtils_h_
|
||||
|
|
|
@ -119,10 +119,10 @@ GMPParent::Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir)
|
|||
}
|
||||
|
||||
void
|
||||
GMPParent::Crash()
|
||||
GMPParent::Crash(GMPCrashReason aReason)
|
||||
{
|
||||
if (mState != GMPStateNotLoaded) {
|
||||
unused << SendCrashPluginNow();
|
||||
unused << SendCrashPluginNow(aReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
|
@ -79,7 +80,7 @@ public:
|
|||
nsresult Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir);
|
||||
nsresult CloneFrom(const GMPParent* aOther);
|
||||
|
||||
void Crash();
|
||||
void Crash(GMPCrashReason aReason);
|
||||
|
||||
nsresult LoadProcess();
|
||||
|
||||
|
|
|
@ -215,6 +215,38 @@ GeckoMediaPluginServiceChild::UpdateTrialCreateState(const nsAString& aKeySystem
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginServiceChild::CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
{
|
||||
if (NS_GetCurrentThread() != mGMPThread) {
|
||||
mGMPThread->Dispatch(NS_NewRunnableMethodWithArgs<uint32_t, GMPCrashReason>(
|
||||
this, &GeckoMediaPluginServiceChild::CrashPluginNow,
|
||||
aPluginId, aReason), NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
class Callback : public GetServiceChildCallback
|
||||
{
|
||||
public:
|
||||
Callback(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
: mPluginId(aPluginId)
|
||||
, mReason(aReason)
|
||||
{ }
|
||||
|
||||
virtual void Done(GMPServiceChild* aService) override
|
||||
{
|
||||
aService->SendCrashPluginNow(mPluginId, mReason);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t mPluginId;
|
||||
GMPCrashReason mReason;
|
||||
};
|
||||
|
||||
UniquePtr<GetServiceChildCallback> callback(new Callback(aPluginId, aReason));
|
||||
GetServiceChild(Move(callback));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/gmp/PGMPServiceChild.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -52,6 +53,8 @@ public:
|
|||
NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState) override;
|
||||
|
||||
void CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason);
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
|
||||
|
|
|
@ -83,6 +83,7 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent,
|
|||
|
||||
static int32_t sMaxAsyncShutdownWaitMs = 0;
|
||||
static bool sHaveSetTimeoutPrefCache = false;
|
||||
static bool sKillHungPlugins = true;
|
||||
|
||||
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
||||
: mShuttingDown(false)
|
||||
|
@ -98,6 +99,9 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
|||
Preferences::AddIntVarCache(&sMaxAsyncShutdownWaitMs,
|
||||
"media.gmp.async-shutdown-timeout",
|
||||
GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT);
|
||||
Preferences::AddBoolVarCache(&sKillHungPlugins,
|
||||
"media.gmp.kill-hung-plugins",
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +515,7 @@ GeckoMediaPluginServiceParent::CrashPlugins()
|
|||
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->Crash();
|
||||
mPlugins[i]->Crash(kPrefChange);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1221,6 +1225,24 @@ GeckoMediaPluginServiceParent::UpdateTrialCreateState(const nsAString& aKeySyste
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginServiceParent::CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
if (aReason == kGmpApiTimeout && !sKillHungPlugins) {
|
||||
LOGD(("%s::%s(%u, %u) but killing hung plugins disabled.",
|
||||
__CLASS__, __FUNCTION__, aPluginId, aReason));
|
||||
return;
|
||||
}
|
||||
LOGD(("%s::%s(%u, %u)", __CLASS__, __FUNCTION__, aPluginId, aReason));
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (const auto& plugin : mPlugins) {
|
||||
if (plugin->GetPluginId() == aPluginId) {
|
||||
plugin->Crash(aReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ExtractHostName(const nsACString& aOrigin, nsACString& aOutData)
|
||||
{
|
||||
|
@ -1555,6 +1577,14 @@ GMPServiceParent::~GMPServiceParent()
|
|||
new DeleteTask<Transport>(GetTransport()));
|
||||
}
|
||||
|
||||
bool
|
||||
GMPServiceParent::RecvCrashPluginNow(const uint32_t& aPluginId,
|
||||
const GMPCrashReason& aReason)
|
||||
{
|
||||
mService->CrashPluginNow(aPluginId, aReason);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPServiceParent::RecvLoadGMP(const nsCString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
|
||||
|
@ -57,6 +58,8 @@ public:
|
|||
void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState);
|
||||
#endif // MOZ_CRASHREPORTER
|
||||
|
||||
void CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason);
|
||||
|
||||
private:
|
||||
friend class GMPServiceParent;
|
||||
|
||||
|
@ -223,6 +226,8 @@ public:
|
|||
nsCString* aVersion);
|
||||
virtual bool RecvUpdateGMPTrialCreateState(const nsString& aKeySystem,
|
||||
const uint32_t& aState) override;
|
||||
virtual bool RecvCrashPluginNow(const uint32_t& aPluginId,
|
||||
const GMPCrashReason& aReason) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
|
|
|
@ -37,6 +37,12 @@ SplitAt(const char* aDelims,
|
|||
nsCString
|
||||
ToBase64(const nsTArray<uint8_t>& aBytes);
|
||||
|
||||
enum GMPCrashReason {
|
||||
kPrefChange, // media.gmp.plugin.crash has been toggled.
|
||||
kGmpApiTimeout, // Some API did not respond.
|
||||
kInvalid,
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -188,6 +188,7 @@ GMPVideoDecoderParent::Reset()
|
|||
LOGD(("GMPVideoDecoderParent[%p]::ResetCompleteTimeout() timed out waiting for ResetComplete", self.get()));
|
||||
self->mResetCompleteTimeout = nullptr;
|
||||
LogToBrowserConsole(NS_LITERAL_STRING("GMPVideoDecoderParent timed out waiting for ResetComplete()"));
|
||||
self->mPlugin->CrashPluginNow(kGmpApiTimeout);
|
||||
});
|
||||
CancelResetCompleteTimeout();
|
||||
mResetCompleteTimeout = SimpleTimer::Create(task, 5000, mPlugin->GMPThread());
|
||||
|
|
|
@ -9,6 +9,7 @@ include protocol PGMPTimer;
|
|||
include protocol PGMPStorage;
|
||||
|
||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
using mozilla::GMPCrashReason from "GMPUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -33,7 +34,7 @@ parent:
|
|||
|
||||
child:
|
||||
async BeginAsyncShutdown();
|
||||
async CrashPluginNow();
|
||||
async CrashPluginNow(GMPCrashReason aReason);
|
||||
intr StartPlugin();
|
||||
async SetNodeId(nsCString nodeId);
|
||||
async CloseActive();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
include protocol PGMP;
|
||||
|
||||
using base::ProcessId from "base/process.h";
|
||||
using mozilla::GMPCrashReason from "GMPUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -23,6 +24,8 @@ parent:
|
|||
returns (nsCString id);
|
||||
|
||||
async UpdateGMPTrialCreateState(nsString keySystem, uint32_t status);
|
||||
|
||||
async CrashPluginNow(uint32_t pluginId, GMPCrashReason aReason);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -231,28 +231,6 @@ MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
|||
mDemuxer->GetMozDebugReaderData(aString);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aProxy) {
|
||||
// The sub readers can't decrypt EME content until they have a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MediaSourceReader
|
||||
// remains in "waiting for resources" state until then. We need to kick the
|
||||
// reader out of waiting if the CDM gets added with known capabilities.
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
if (!caps.AreCapsKnown()) {
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
|
||||
caps.CallOnMainThreadWhenCapsAvailable(task);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
double
|
||||
MediaSourceDecoder::GetDuration()
|
||||
{
|
||||
|
|
|
@ -66,10 +66,6 @@ public:
|
|||
void SetMediaSourceDuration(double aDuration, MSRangeRemovalAction aAction);
|
||||
double GetMediaSourceDuration();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
#endif
|
||||
|
||||
MediaSourceDemuxer* GetDemuxer()
|
||||
{
|
||||
return mDemuxer;
|
||||
|
|
|
@ -69,9 +69,8 @@ public:
|
|||
virtual void RecvTimelineEvent(uint32_t aIndex,
|
||||
dom::AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -98,8 +97,7 @@ public:
|
|||
switch (aIndex) {
|
||||
case AudioBufferSourceNode::START:
|
||||
MOZ_ASSERT(!mStart, "Another START?");
|
||||
mStart =
|
||||
mSource->FractionalTicksFromDestinationTime(mDestination, aParam);
|
||||
mStart = mDestination->SecondsToNearestStreamTime(aParam);
|
||||
// Round to nearest
|
||||
mBeginProcessing = mStart + 0.5;
|
||||
break;
|
||||
|
@ -471,7 +469,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
StreamTime streamPosition = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime streamPosition = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
// We've finished if we've gone past mStop, or if we're past mDuration when
|
||||
// looping is disabled.
|
||||
if (streamPosition >= mStop ||
|
||||
|
@ -670,7 +668,7 @@ AudioBufferSourceNode::Start(double aWhen, double aOffset,
|
|||
|
||||
// Don't set parameter unnecessarily
|
||||
if (aWhen > 0.0) {
|
||||
ns->SetDoubleParameter(START, mContext->DOMTimeToStreamTime(aWhen));
|
||||
ns->SetDoubleParameter(START, aWhen);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -304,16 +304,6 @@ public:
|
|||
void RegisterNode(AudioNode* aNode);
|
||||
void UnregisterNode(AudioNode* aNode);
|
||||
|
||||
double DOMTimeToStreamTime(double aTime) const
|
||||
{
|
||||
return aTime;
|
||||
}
|
||||
|
||||
double StreamTimeToDOMTime(double aTime) const
|
||||
{
|
||||
return aTime;
|
||||
}
|
||||
|
||||
void OnStateChanged(void* aPromise, AudioContextState aNewState);
|
||||
|
||||
BasicWaveFormCache* GetBasicWaveFormCache();
|
||||
|
|
|
@ -324,7 +324,8 @@ public:
|
|||
* ProcessBlock() will be called later, and it then should not change
|
||||
* aOutput. This is used only for DelayNodeEngine in a feedback loop.
|
||||
*/
|
||||
virtual void ProduceBlockBeforeInput(GraphTime aFrom,
|
||||
virtual void ProduceBlockBeforeInput(AudioNodeStream* aStream,
|
||||
GraphTime aFrom,
|
||||
AudioBlock* aOutput)
|
||||
{
|
||||
NS_NOTREACHED("ProduceBlockBeforeInput called on wrong engine\n");
|
||||
|
|
|
@ -148,15 +148,15 @@ AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, AudioContext* aContext,
|
|||
};
|
||||
|
||||
GraphImpl()->AppendMessage(new Message(this, aIndex,
|
||||
aContext->DestinationStream(),
|
||||
aContext->DOMTimeToStreamTime(aStreamTime)));
|
||||
aContext->DestinationStream(),
|
||||
aStreamTime));
|
||||
}
|
||||
|
||||
void
|
||||
AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
|
||||
double aStreamTime)
|
||||
{
|
||||
StreamTime ticks = TicksFromDestinationTime(aRelativeToStream, aStreamTime);
|
||||
StreamTime ticks = aRelativeToStream->SecondsToNearestStreamTime(aStreamTime);
|
||||
mEngine->SetStreamTimeParameter(aIndex, ticks);
|
||||
}
|
||||
|
||||
|
@ -617,7 +617,7 @@ AudioNodeStream::ProduceOutputBeforeInput(GraphTime aFrom)
|
|||
if (!mIsActive) {
|
||||
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
} else {
|
||||
mEngine->ProduceBlockBeforeInput(aFrom, &mLastChunks[0]);
|
||||
mEngine->ProduceBlockBeforeInput(this, aFrom, &mLastChunks[0]);
|
||||
NS_ASSERTION(mLastChunks[0].GetDuration() == WEBAUDIO_BLOCK_SIZE,
|
||||
"Invalid WebAudio chunk size");
|
||||
if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
|
||||
|
@ -666,50 +666,6 @@ AudioNodeStream::FinishOutput()
|
|||
}
|
||||
}
|
||||
|
||||
double
|
||||
AudioNodeStream::FractionalTicksFromDestinationTime(AudioNodeStream* aDestination,
|
||||
double aSeconds)
|
||||
{
|
||||
MOZ_ASSERT(aDestination->SampleRate() == SampleRate());
|
||||
MOZ_ASSERT(SampleRate() == GraphRate());
|
||||
|
||||
double destinationSeconds = std::max(0.0, aSeconds);
|
||||
double destinationFractionalTicks = destinationSeconds * SampleRate();
|
||||
MOZ_ASSERT(destinationFractionalTicks < STREAM_TIME_MAX);
|
||||
StreamTime destinationStreamTime = destinationFractionalTicks; // round down
|
||||
// MediaTime does not have the resolution of double
|
||||
double offset = destinationFractionalTicks - destinationStreamTime;
|
||||
|
||||
GraphTime graphTime =
|
||||
aDestination->StreamTimeToGraphTime(destinationStreamTime);
|
||||
StreamTime thisStreamTime = GraphTimeToStreamTime(graphTime);
|
||||
double thisFractionalTicks = thisStreamTime + offset;
|
||||
return thisFractionalTicks;
|
||||
}
|
||||
|
||||
StreamTime
|
||||
AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
|
||||
double aSeconds)
|
||||
{
|
||||
AudioNodeStream* destination = aDestination->AsAudioNodeStream();
|
||||
MOZ_ASSERT(destination);
|
||||
|
||||
double thisSeconds =
|
||||
FractionalTicksFromDestinationTime(destination, aSeconds);
|
||||
return NS_round(thisSeconds);
|
||||
}
|
||||
|
||||
double
|
||||
AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
|
||||
StreamTime aPosition)
|
||||
{
|
||||
MOZ_ASSERT(SampleRate() == aDestination->SampleRate());
|
||||
|
||||
GraphTime graphTime = StreamTimeToGraphTime(aPosition);
|
||||
StreamTime destinationTime = aDestination->GraphTimeToStreamTime(graphTime);
|
||||
return StreamTimeToSeconds(destinationTime);
|
||||
}
|
||||
|
||||
void
|
||||
AudioNodeStream::AddInput(MediaInputPort* aPort)
|
||||
{
|
||||
|
|
|
@ -150,25 +150,6 @@ public:
|
|||
AudioNodeEngine* Engine() { return mEngine; }
|
||||
TrackRate SampleRate() const { return mSampleRate; }
|
||||
|
||||
/**
|
||||
* Convert a time in seconds on the destination stream to ticks
|
||||
* on this stream, including fractional position between ticks.
|
||||
*/
|
||||
double FractionalTicksFromDestinationTime(AudioNodeStream* aDestination,
|
||||
double aSeconds);
|
||||
/**
|
||||
* Convert a time in seconds on the destination stream to StreamTime
|
||||
* on this stream.
|
||||
*/
|
||||
StreamTime TicksFromDestinationTime(MediaStream* aDestination,
|
||||
double aSeconds);
|
||||
/**
|
||||
* Get the destination stream time in seconds corresponding to a position on
|
||||
* this stream.
|
||||
*/
|
||||
double DestinationTimeFromTicks(AudioNodeStream* aDestination,
|
||||
StreamTime aPosition);
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
|
|
|
@ -42,11 +42,6 @@ public:
|
|||
return mNode->Context();
|
||||
}
|
||||
|
||||
double DOMTimeToStreamTime(double aTime) const
|
||||
{
|
||||
return mNode->Context()->DOMTimeToStreamTime(aTime);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// We override SetValueCurveAtTime to convert the Float32Array to the wrapper
|
||||
|
@ -129,13 +124,10 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
double streamTime = DOMTimeToStreamTime(aStartTime);
|
||||
|
||||
// Remove some events on the main thread copy.
|
||||
AudioEventTimeline::CancelScheduledValues(streamTime);
|
||||
AudioEventTimeline::CancelScheduledValues(aStartTime);
|
||||
|
||||
AudioTimelineEvent event(AudioTimelineEvent::Cancel,
|
||||
streamTime, 0.0f);
|
||||
AudioTimelineEvent event(AudioTimelineEvent::Cancel, aStartTime, 0.0f);
|
||||
|
||||
mCallback(mNode, event);
|
||||
}
|
||||
|
@ -214,8 +206,7 @@ private:
|
|||
const float* aCurve = nullptr,
|
||||
uint32_t aCurveLength = 0)
|
||||
{
|
||||
AudioTimelineEvent event(aType,
|
||||
DOMTimeToStreamTime(aTime), aValue,
|
||||
AudioTimelineEvent event(aType, aTime, aValue,
|
||||
aTimeConstant, aDuration, aCurve, aCurveLength);
|
||||
|
||||
if (!ValidateEvent(event, aRv)) {
|
||||
|
|
|
@ -78,7 +78,6 @@ class BiquadFilterNodeEngine final : public AudioNodeEngine
|
|||
public:
|
||||
BiquadFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
// Keep the default values in sync with the default values in
|
||||
// BiquadFilterNode::BiquadFilterNode
|
||||
|
@ -90,11 +89,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
enum Parameteres {
|
||||
TYPE,
|
||||
FREQUENCY,
|
||||
|
@ -113,10 +107,9 @@ public:
|
|||
void RecvTimelineEvent(uint32_t aIndex,
|
||||
AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -187,7 +180,7 @@ public:
|
|||
uint32_t numberOfChannels = mBiquads.Length();
|
||||
aOutput->AllocateChannels(numberOfChannels);
|
||||
|
||||
StreamTime pos = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime pos = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
|
||||
double freq = mFrequency.GetValueAtTime(pos);
|
||||
double q = mQ.GetValueAtTime(pos);
|
||||
|
@ -221,7 +214,6 @@ public:
|
|||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
// Not owned:
|
||||
// - mSource - probably not owned
|
||||
// - mDestination - probably not owned
|
||||
// - AudioParamTimelines - counted in the AudioNode
|
||||
size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
|
@ -235,7 +227,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
BiquadFilterType mType;
|
||||
AudioParamTimeline mFrequency;
|
||||
|
@ -259,7 +250,6 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
|
|||
BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination());
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
BiquadFilterNode::~BiquadFilterNode()
|
||||
|
|
|
@ -32,7 +32,6 @@ public:
|
|||
DelayNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination,
|
||||
double aMaxDelayTicks)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
// Keep the default value in sync with the default value in DelayNode::DelayNode.
|
||||
, mDelay(0.f)
|
||||
|
@ -52,20 +51,14 @@ public:
|
|||
return this;
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
enum Parameters {
|
||||
DELAY,
|
||||
};
|
||||
void RecvTimelineEvent(uint32_t aIndex,
|
||||
AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -83,7 +76,6 @@ public:
|
|||
AudioBlock* aOutput,
|
||||
bool* aFinished) override
|
||||
{
|
||||
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
|
||||
MOZ_ASSERT(aStream->SampleRate() == mDestination->SampleRate());
|
||||
|
||||
if (!aInput.IsSilentOrSubnormal()) {
|
||||
|
@ -118,18 +110,19 @@ public:
|
|||
// Skip output update if mLastChunks has already been set by
|
||||
// ProduceBlockBeforeInput() when in a cycle.
|
||||
if (!mHaveProducedBeforeInput) {
|
||||
UpdateOutputBlock(aFrom, aOutput, 0.0);
|
||||
UpdateOutputBlock(aStream, aFrom, aOutput, 0.0);
|
||||
}
|
||||
mHaveProducedBeforeInput = false;
|
||||
mBuffer.NextBlock();
|
||||
}
|
||||
|
||||
void UpdateOutputBlock(GraphTime aFrom, AudioBlock* aOutput, double minDelay)
|
||||
void UpdateOutputBlock(AudioNodeStream* aStream, GraphTime aFrom,
|
||||
AudioBlock* aOutput, double minDelay)
|
||||
{
|
||||
double maxDelay = mMaxDelay;
|
||||
double sampleRate = mSource->SampleRate();
|
||||
double sampleRate = aStream->SampleRate();
|
||||
ChannelInterpretation channelInterpretation =
|
||||
mSource->GetChannelInterpretation();
|
||||
aStream->GetChannelInterpretation();
|
||||
if (mDelay.HasSimpleValue()) {
|
||||
// If this DelayNode is in a cycle, make sure the delay value is at least
|
||||
// one block, even if that is greater than maxDelay.
|
||||
|
@ -141,7 +134,7 @@ public:
|
|||
// Compute the delay values for the duration of the input AudioChunk
|
||||
// If this DelayNode is in a cycle, make sure the delay value is at least
|
||||
// one block.
|
||||
StreamTime tick = mSource->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
float values[WEBAUDIO_BLOCK_SIZE];
|
||||
mDelay.GetValuesAtTime(tick, values,WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
|
@ -156,13 +149,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void ProduceBlockBeforeInput(GraphTime aFrom,
|
||||
virtual void ProduceBlockBeforeInput(AudioNodeStream* aStream,
|
||||
GraphTime aFrom,
|
||||
AudioBlock* aOutput) override
|
||||
{
|
||||
if (mLeftOverData <= 0) {
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
} else {
|
||||
UpdateOutputBlock(aFrom, aOutput, WEBAUDIO_BLOCK_SIZE);
|
||||
UpdateOutputBlock(aStream, aFrom, aOutput, WEBAUDIO_BLOCK_SIZE);
|
||||
}
|
||||
mHaveProducedBeforeInput = true;
|
||||
}
|
||||
|
@ -176,7 +170,6 @@ public:
|
|||
{
|
||||
size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
// Not owned:
|
||||
// - mSource - probably not owned
|
||||
// - mDestination - probably not owned
|
||||
// - mDelay - shares ref with AudioNode, don't count
|
||||
amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
|
@ -188,7 +181,6 @@ public:
|
|||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
AudioParamTimeline mDelay;
|
||||
DelayBuffer mBuffer;
|
||||
|
@ -211,7 +203,6 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
|
|||
aContext->SampleRate() * aMaxDelay);
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
DelayNode::~DelayNode()
|
||||
|
|
|
@ -36,7 +36,6 @@ public:
|
|||
explicit DynamicsCompressorNodeEngine(AudioNode* aNode,
|
||||
AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
// Keep the default value in sync with the default value in
|
||||
// DynamicsCompressorNode::DynamicsCompressorNode.
|
||||
|
@ -49,11 +48,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
enum Parameters {
|
||||
THRESHOLD,
|
||||
KNEE,
|
||||
|
@ -64,10 +58,9 @@ public:
|
|||
void RecvTimelineEvent(uint32_t aIndex,
|
||||
AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -110,7 +103,7 @@ public:
|
|||
aInput.ChannelCount());
|
||||
}
|
||||
|
||||
StreamTime pos = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime pos = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamThreshold,
|
||||
mThreshold.GetValueAtTime(pos));
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamKnee,
|
||||
|
@ -132,7 +125,6 @@ public:
|
|||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
// Not owned:
|
||||
// - mSource (probably)
|
||||
// - mDestination (probably)
|
||||
// - Don't count the AudioParamTimelines, their inner refs are owned by the
|
||||
// AudioNode.
|
||||
|
@ -180,7 +172,6 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
AudioParamTimeline mThreshold;
|
||||
AudioParamTimeline mKnee;
|
||||
|
@ -205,7 +196,6 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
|
|||
DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
DynamicsCompressorNode::~DynamicsCompressorNode()
|
||||
|
|
|
@ -28,27 +28,20 @@ class GainNodeEngine final : public AudioNodeEngine
|
|||
public:
|
||||
GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
// Keep the default value in sync with the default value in GainNode::GainNode.
|
||||
, mGain(1.f)
|
||||
{
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
enum Parameters {
|
||||
GAIN
|
||||
};
|
||||
void RecvTimelineEvent(uint32_t aIndex,
|
||||
AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -66,8 +59,6 @@ public:
|
|||
AudioBlock* aOutput,
|
||||
bool* aFinished) override
|
||||
{
|
||||
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
|
||||
|
||||
if (aInput.IsNull()) {
|
||||
// If input is silent, so is the output
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
@ -87,7 +78,7 @@ public:
|
|||
aOutput->AllocateChannels(aInput.ChannelCount());
|
||||
|
||||
// Compute the gain values for the duration of the input AudioChunk
|
||||
StreamTime tick = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
float computedGain[WEBAUDIO_BLOCK_SIZE];
|
||||
mGain.GetValuesAtTime(tick, computedGain, WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
|
@ -107,7 +98,6 @@ public:
|
|||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
// Not owned:
|
||||
// - mSource (probably)
|
||||
// - mDestination (probably)
|
||||
// - mGain - Internal ref owned by AudioNode
|
||||
return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
|
@ -118,7 +108,6 @@ public:
|
|||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
AudioParamTimeline mGain;
|
||||
};
|
||||
|
@ -133,7 +122,6 @@ GainNode::GainNode(AudioContext* aContext)
|
|||
GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
GainNode::~GainNode()
|
||||
|
|
|
@ -62,10 +62,9 @@ public:
|
|||
{
|
||||
mRecomputeParameters = true;
|
||||
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -295,7 +294,7 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
|
||||
|
||||
StreamTime ticks = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime ticks = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
if (mStart == -1) {
|
||||
ComputeSilence(aOutput);
|
||||
return;
|
||||
|
|
|
@ -245,20 +245,14 @@ public:
|
|||
uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
, mSharedBuffers(new SharedBuffers(mDestination->SampleRate()))
|
||||
, mBufferSize(aBufferSize)
|
||||
, mInputChannelCount(aNumberOfInputChannels)
|
||||
, mInputWriteIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
mSharedBuffers = new SharedBuffers(mSource->SampleRate());
|
||||
}
|
||||
|
||||
SharedBuffers* GetSharedBuffers() const
|
||||
{
|
||||
return mSharedBuffers;
|
||||
|
@ -345,7 +339,6 @@ public:
|
|||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
// Not owned:
|
||||
// - mSource (probably)
|
||||
// - mDestination (probably)
|
||||
size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mSharedBuffers->SizeOfIncludingThis(aMallocSizeOf);
|
||||
|
@ -365,14 +358,13 @@ private:
|
|||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// we now have a full input buffer ready to be sent to the main thread.
|
||||
StreamTime playbackTick = mSource->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime playbackTick = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
// Add the duration of the current sample
|
||||
playbackTick += WEBAUDIO_BLOCK_SIZE;
|
||||
// Add the delay caused by the main thread
|
||||
playbackTick += mSharedBuffers->DelaySoFar();
|
||||
// Compute the playback time in the coordinate system of the destination
|
||||
double playbackTime =
|
||||
mSource->DestinationTimeFromTicks(mDestination, playbackTick);
|
||||
double playbackTime = mDestination->StreamTimeToSeconds(playbackTick);
|
||||
|
||||
class Command final : public nsRunnable
|
||||
{
|
||||
|
@ -448,9 +440,7 @@ private:
|
|||
// them. Otherwise, we may be able to get away without creating them!
|
||||
nsRefPtr<AudioProcessingEvent> event =
|
||||
new AudioProcessingEvent(aNode, nullptr, nullptr);
|
||||
event->InitEvent(inputBuffer,
|
||||
inputChannelCount,
|
||||
context->StreamTimeToDOMTime(mPlaybackTime));
|
||||
event->InitEvent(inputBuffer, inputChannelCount, mPlaybackTime);
|
||||
aNode->DispatchTrustedEvent(event);
|
||||
|
||||
// Steal the output buffers if they have been set.
|
||||
|
@ -480,9 +470,8 @@ private:
|
|||
|
||||
friend class ScriptProcessorNode;
|
||||
|
||||
nsAutoPtr<SharedBuffers> mSharedBuffers;
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
nsAutoPtr<SharedBuffers> mSharedBuffers;
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mInputBuffer;
|
||||
const uint32_t mBufferSize;
|
||||
const uint32_t mInputChannelCount;
|
||||
|
@ -512,7 +501,6 @@ ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
|
|||
aNumberOfInputChannels);
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
ScriptProcessorNode::~ScriptProcessorNode()
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
StereoPannerNodeEngine(AudioNode* aNode,
|
||||
AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
// Keep the default value in sync with the default value in
|
||||
// StereoPannerNode::StereoPannerNode.
|
||||
|
@ -41,20 +40,14 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
enum Parameters {
|
||||
PAN
|
||||
};
|
||||
void RecvTimelineEvent(uint32_t aIndex,
|
||||
AudioTimelineEvent& aEvent) override
|
||||
{
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
MOZ_ASSERT(mDestination);
|
||||
WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
switch (aIndex) {
|
||||
|
@ -116,8 +109,6 @@ public:
|
|||
AudioBlock* aOutput,
|
||||
bool *aFinished) override
|
||||
{
|
||||
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
|
||||
|
||||
// The output of this node is always stereo, no matter what the inputs are.
|
||||
MOZ_ASSERT(aInput.ChannelCount() <= 2);
|
||||
aOutput->AllocateChannels(2);
|
||||
|
@ -149,7 +140,7 @@ public:
|
|||
bool onLeft[WEBAUDIO_BLOCK_SIZE];
|
||||
|
||||
float values[WEBAUDIO_BLOCK_SIZE];
|
||||
StreamTime tick = aStream->GraphTimeToStreamTime(aFrom);
|
||||
StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
|
||||
mPan.GetValuesAtTime(tick, values, WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
|
||||
|
@ -171,7 +162,6 @@ public:
|
|||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
AudioParamTimeline mPan;
|
||||
};
|
||||
|
@ -186,7 +176,6 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext)
|
|||
StereoPannerNodeEngine* engine = new StereoPannerNodeEngine(this, aContext->Destination());
|
||||
mStream = AudioNodeStream::Create(aContext, engine,
|
||||
AudioNodeStream::NO_STREAM_FLAGS);
|
||||
engine->SetSourceStream(mStream);
|
||||
}
|
||||
|
||||
StereoPannerNode::~StereoPannerNode()
|
||||
|
|
|
@ -13,14 +13,12 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
void WebAudioUtils::ConvertAudioTimelineEventToTicks(AudioTimelineEvent& aEvent,
|
||||
AudioNodeStream* aSource,
|
||||
AudioNodeStream* aDest)
|
||||
{
|
||||
MOZ_ASSERT(!aSource || aSource->SampleRate() == aDest->SampleRate());
|
||||
aEvent.SetTimeInTicks(
|
||||
aSource->TicksFromDestinationTime(aDest, aEvent.Time<double>()));
|
||||
aEvent.mTimeConstant *= aSource->SampleRate();
|
||||
aEvent.mDuration *= aSource->SampleRate();
|
||||
aDest->SecondsToNearestStreamTime(aEvent.Time<double>()));
|
||||
aEvent.mTimeConstant *= aDest->SampleRate();
|
||||
aEvent.mDuration *= aDest->SampleRate();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -64,7 +64,6 @@ namespace WebAudioUtils {
|
|||
* destination streams as well.
|
||||
*/
|
||||
void ConvertAudioTimelineEventToTicks(AudioTimelineEvent& aEvent,
|
||||
AudioNodeStream* aSource,
|
||||
AudioNodeStream* aDest);
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,31 +10,41 @@
|
|||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("This test needs to wait until after the AudioContext's timer has started.");
|
||||
addLoadEvent(
|
||||
function() {
|
||||
const delay = 0.1;
|
||||
var context = new AudioContext();
|
||||
SimpleTest.executeSoon( // to ensure that AudioContext has started
|
||||
function() {
|
||||
setTimeout( // wait for |delay|
|
||||
function() {
|
||||
var sp = context.createScriptProcessor(256);
|
||||
sp.connect(context.destination);
|
||||
sp.onaudioprocess =
|
||||
function(e) {
|
||||
var minimum =
|
||||
(delay + e.inputBuffer.length/context.sampleRate) *
|
||||
(1.0 - 1.0/Math.pow(2.0,52.0)); // double precision
|
||||
ok(e.playbackTime >= minimum,
|
||||
"playbackTime " + e.playbackTime +
|
||||
" beyond expected minimum " + minimum);
|
||||
sp.onaudioprocess = null;
|
||||
SimpleTest.finish();
|
||||
};
|
||||
}, 1000 * delay);
|
||||
});
|
||||
});
|
||||
|
||||
var context = new AudioContext();
|
||||
const delay = 0.1;
|
||||
|
||||
function doTest() {
|
||||
const processorBufferLength = 256;
|
||||
// |currentTime| may include double precision floating point
|
||||
// rounding errors, so round to nearest integer sample to ignore these.
|
||||
var minimumPlaybackSample =
|
||||
Math.round(context.currentTime * context.sampleRate) +
|
||||
processorBufferLength;
|
||||
var sp = context.createScriptProcessor(processorBufferLength);
|
||||
sp.connect(context.destination);
|
||||
sp.onaudioprocess =
|
||||
function(e) {
|
||||
is(e.inputBuffer.length, processorBufferLength,
|
||||
"expected buffer length");
|
||||
var playbackSample = Math.round(e.playbackTime * context.sampleRate)
|
||||
ok(playbackSample >= minimumPlaybackSample,
|
||||
"playbackSample " + playbackSample +
|
||||
" beyond expected minimum " + minimumPlaybackSample);
|
||||
sp.onaudioprocess = null;
|
||||
SimpleTest.finish();
|
||||
};
|
||||
}
|
||||
|
||||
// Wait until AudioDestinationNode has accumulated enough 'extra' time so that
|
||||
// a failure would be easily detected.
|
||||
(function waitForExtraTime() {
|
||||
if (context.currentTime < delay) {
|
||||
SimpleTest.executeSoon(waitForExtraTime);
|
||||
} else {
|
||||
doTest();
|
||||
}
|
||||
})();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -27,6 +27,9 @@ function handleRequest(request, response)
|
|||
if (secData.allowOrigin)
|
||||
response.setHeader("Access-Control-Allow-Origin", secData.allowOrigin);
|
||||
|
||||
if (secData.withCred)
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
|
||||
if (isPreflight) {
|
||||
if (secData.allowHeaders)
|
||||
response.setHeader("Access-Control-Allow-Headers", secData.allowHeaders);
|
||||
|
|
|
@ -417,6 +417,86 @@ function runTest() {
|
|||
{ pass: 0,
|
||||
method: "DELETE"
|
||||
},
|
||||
{ newTest: "*******" },
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "x-my-header": "myValue" },
|
||||
allowHeaders: "x-my-header",
|
||||
cacheTime: 3600
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "x-my-header": "myValue" },
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
headers: { "x-my-header": "myValue" },
|
||||
},
|
||||
{ newTest: "*******" },
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "x-my-header": "myValue" },
|
||||
allowHeaders: "x-my-header",
|
||||
cacheTime: 3600
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
headers: { "y-my-header": "myValue" },
|
||||
allowHeaders: "y-my-header",
|
||||
cacheTime: 2
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
headers: { "y-my-header": "myValue" },
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "x-my-header": "myValue" },
|
||||
},
|
||||
{ pause: 2.1 },
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "x-my-header": "myValue" },
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
headers: { "x-my-header": "myValue" },
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
headers: { "y-my-header": "myValue" },
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
withCred: true,
|
||||
headers: { "y-my-header": "myValue" },
|
||||
},
|
||||
{ newTest: "*******" },
|
||||
{ pass: 1,
|
||||
method: "DELETE",
|
||||
allowMethods: "DELETE",
|
||||
cacheTime: 3600
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
headers: { "DELETE": "myvalue" },
|
||||
},
|
||||
{ newTest: "*******" },
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
headers: { "x-my-header": "myValue" },
|
||||
allowHeaders: "x-my-header",
|
||||
cacheTime: 3600
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "3600",
|
||||
headers: { "x-my-header": "myvalue" },
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < 110; i++) {
|
||||
|
@ -448,12 +528,14 @@ function runTest() {
|
|||
url: baseURL + "c=" + unique,
|
||||
method: test.method,
|
||||
headers: test.headers,
|
||||
withCred: test.withCred,
|
||||
};
|
||||
|
||||
sec = { allowOrigin: test.noOrigin ? "" : origin,
|
||||
allowHeaders: test.allowHeaders,
|
||||
allowMethods: test.allowMethods,
|
||||
cacheTime: test.cacheTime };
|
||||
cacheTime: test.cacheTime,
|
||||
withCred: test.withCred };
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", setStateURL + escape(sec.toSource()), true);
|
||||
xhr.onloadend = function() { gen.next(); }
|
||||
|
|
|
@ -6,3 +6,4 @@ skip-if = buildapp == 'b2g' || os == 'android'
|
|||
[test_offsets.js]
|
||||
[test_offsets.xul]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_spacetopagedown.html]
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
var windowUtils = SpecialPowers.getDOMWindowUtils(window);
|
||||
|
||||
function pressKey(isShift)
|
||||
{
|
||||
return new Promise(resolve => {
|
||||
synthesizeKey(" ", { shiftKey: isShift });
|
||||
windowUtils.advanceTimeAndRefresh(100);
|
||||
SimpleTest.executeSoon(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function initTest()
|
||||
{
|
||||
SpecialPowers.pushPrefEnv({"set":[["general.smoothScroll", false]]}, runTest);
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
Task.async(function () {
|
||||
yield pressKey(false);
|
||||
|
||||
ok(window.scrollY > 0, "Space with no focus" + window.scrollY);
|
||||
yield pressKey(true);
|
||||
is(window.scrollY, 0, "Shift+Space with no focus");
|
||||
|
||||
let checkbox = document.getElementById("checkbox");
|
||||
checkbox.focus();
|
||||
yield pressKey(false);
|
||||
|
||||
is(window.scrollY, 0, "Space with checkbox focused");
|
||||
ok(checkbox.checked, "Space with checkbox focused, checked");
|
||||
yield pressKey(true);
|
||||
is(window.scrollY, 0, "Shift+Space with checkbox focused");
|
||||
ok(!checkbox.checked, "Space with checkbox focused, unchecked");
|
||||
|
||||
let input = document.getElementById("input");
|
||||
input.focus();
|
||||
yield pressKey(false);
|
||||
is(window.scrollY, 0, "Space with input focused");
|
||||
is(input.value, " ", "Space with input focused, value");
|
||||
yield pressKey(true);
|
||||
is(window.scrollY, 0, "Shift+Space with input focused");
|
||||
is(input.value, " ", "Space with input focused, value");
|
||||
|
||||
windowUtils.restoreNormalRefresh();
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="SimpleTest.waitForFocus(initTest)">
|
||||
|
||||
<input id="checkbox" type="checkbox">Checkbox
|
||||
<input id="input">
|
||||
<p style="height: 4000px">Text</p>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -459,6 +459,10 @@ nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEv
|
|||
else
|
||||
controller = GetController(aTarget); // We're attached to the receiver possibly.
|
||||
|
||||
// We are the default action for this command.
|
||||
// Stop any other default action from executing.
|
||||
aEvent->PreventDefault();
|
||||
|
||||
if (mEventName == nsGkAtoms::keypress &&
|
||||
mDetail == nsIDOMKeyEvent::DOM_VK_SPACE &&
|
||||
mMisc == 1) {
|
||||
|
@ -491,10 +495,6 @@ nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEv
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are the default action for this command.
|
||||
// Stop any other default action from executing.
|
||||
aEvent->PreventDefault();
|
||||
|
||||
if (controller)
|
||||
controller->DoCommand(command.get());
|
||||
|
|
|
@ -2555,25 +2555,12 @@ XULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
|
|||
if (aIsDynamic)
|
||||
mResolutionPhase = nsForwardReference::eStart;
|
||||
|
||||
// Chrome documents are allowed to load overlays from anywhere.
|
||||
// In all other cases, the overlay is only allowed to load if
|
||||
// the master document and prototype document have the same origin.
|
||||
|
||||
bool documentIsChrome = IsChromeURI(mDocumentURI);
|
||||
if (!documentIsChrome) {
|
||||
// Make sure we're allowed to load this overlay.
|
||||
rv = NodePrincipal()->CheckMayLoad(aURI, true, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
*aFailureFromContent = true;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Look in the prototype cache for the prototype document with
|
||||
// the specified overlay URI. Only use the cache if the containing
|
||||
// document is chrome otherwise it may not have a system principal and
|
||||
// the cached document will, see bug 565610.
|
||||
bool overlayIsChrome = IsChromeURI(aURI);
|
||||
bool documentIsChrome = IsChromeURI(mDocumentURI);
|
||||
mCurrentPrototype = overlayIsChrome && documentIsChrome ?
|
||||
nsXULPrototypeCache::GetInstance()->GetPrototype(aURI) : nullptr;
|
||||
|
||||
|
@ -2657,12 +2644,13 @@ XULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
|
|||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
aURI,
|
||||
NodePrincipal(),
|
||||
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
group);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = channel->AsyncOpen(listener, nullptr);
|
||||
rv = channel->AsyncOpen2(listener);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
# 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/.
|
||||
|
||||
DIRS += CONFIG['MOZ_EXTENSIONS'].split()
|
||||
DIRS += CONFIG['MOZ_EXTENSIONS']
|
||||
|
|
|
@ -27,8 +27,12 @@ public:
|
|||
virtual IntSize GetSize() const { return mA->GetSize(); }
|
||||
virtual SurfaceFormat GetFormat() const { return mA->GetFormat(); }
|
||||
|
||||
/* Readback from this surface type is not supported! */
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface() { return nullptr; }
|
||||
// This is implemented for debugging purposes only (used by dumping
|
||||
// client-side textures for paint dumps), for which we don't care about
|
||||
// component alpha, so we just use the first of the two surfaces.
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface() {
|
||||
return mA->GetDataSurface();
|
||||
}
|
||||
private:
|
||||
friend class DualSurface;
|
||||
friend class DualPattern;
|
||||
|
|
|
@ -16,17 +16,22 @@ Autodesk, Inc.
|
|||
BlackBerry Limited
|
||||
Cable Television Laboratories, Inc.
|
||||
Cloud Party, Inc.
|
||||
Imagination Technologies Ltd.
|
||||
Intel Corporation
|
||||
Mozilla Corporation
|
||||
Turbulenz
|
||||
Klarälvdalens Datakonsult AB
|
||||
Microsoft Corporation
|
||||
Microsoft Open Technologies, Inc.
|
||||
NVIDIA Corporation
|
||||
Opera Software ASA
|
||||
The Qt Company Ltd.
|
||||
|
||||
Jacek Caban
|
||||
Mark Callow
|
||||
Ginn Chen
|
||||
Tibor den Ouden
|
||||
Régis Fénéon
|
||||
James Hauxwell
|
||||
Sam Hocevar
|
||||
Pierre Leveille
|
||||
|
@ -35,3 +40,4 @@ Boying Lu
|
|||
Aitor Moreno
|
||||
Yuri O'Donnell
|
||||
Josh Soref
|
||||
Maks Naumov
|
||||
|
|
|
@ -2,26 +2,20 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
if (is_win) {
|
||||
# Only needed on Windows.
|
||||
gles_gypi = exec_script(
|
||||
"//build/gypi_to_gn.py",
|
||||
[ rebase_path("src/libGLESv2.gypi") ],
|
||||
"scope",
|
||||
[ "src/libGLESv2.gypi" ])
|
||||
# import the use_x11 variable
|
||||
import("//build/config/ui.gni")
|
||||
|
||||
egl_gypi = exec_script(
|
||||
"//build/gypi_to_gn.py",
|
||||
[ rebase_path("src/libEGL.gypi") ],
|
||||
"scope",
|
||||
[ "src/libEGL.gypi" ])
|
||||
}
|
||||
gles_gypi = exec_script(
|
||||
"//build/gypi_to_gn.py",
|
||||
[ rebase_path("src/libGLESv2.gypi") ],
|
||||
"scope",
|
||||
[ "src/libGLESv2.gypi" ])
|
||||
|
||||
compiler_gypi = exec_script(
|
||||
"//build/gypi_to_gn.py",
|
||||
[ rebase_path("src/compiler.gypi") ],
|
||||
"scope",
|
||||
[ "src/compiler.gypi" ])
|
||||
"//build/gypi_to_gn.py",
|
||||
[ rebase_path("src/compiler.gypi") ],
|
||||
"scope",
|
||||
[ "src/compiler.gypi" ])
|
||||
|
||||
# This config is exported to dependent targets (and also applied to internal
|
||||
# ones).
|
||||
|
@ -39,6 +33,32 @@ config("internal_config") {
|
|||
]
|
||||
}
|
||||
|
||||
angle_enable_d3d9 = false
|
||||
angle_enable_d3d11 = false
|
||||
angle_enable_gl = false
|
||||
|
||||
if (is_win) {
|
||||
angle_enable_d3d9 = true
|
||||
angle_enable_d3d11 = true
|
||||
angle_enable_gl = true
|
||||
|
||||
import("//build/config/win/visual_studio_version.gni")
|
||||
copy("copy_compiler_dll") {
|
||||
sources = [ "$windows_sdk_path/Redist/D3D/$target_cpu/d3dcompiler_47.dll" ]
|
||||
outputs = [ "$root_build_dir/d3dcompiler_47.dll" ]
|
||||
}
|
||||
} # is_win
|
||||
|
||||
if (is_linux) {
|
||||
angle_enable_gl = true
|
||||
}
|
||||
|
||||
angle_enable_hlsl = false
|
||||
|
||||
if (angle_enable_d3d9 || angle_enable_d3d11) {
|
||||
angle_enable_hlsl = true
|
||||
}
|
||||
|
||||
component("translator") {
|
||||
sources = [
|
||||
"src/compiler/translator/ShaderLang.cpp",
|
||||
|
@ -47,6 +67,11 @@ component("translator") {
|
|||
|
||||
defines = [ "ANGLE_TRANSLATOR_IMPLEMENTATION" ]
|
||||
|
||||
if (angle_enable_hlsl) {
|
||||
sources += rebase_path(compiler_gypi.angle_translator_lib_hlsl_sources, ".", "src")
|
||||
defines += [ "ANGLE_ENABLE_HLSL" ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
|
@ -89,9 +114,32 @@ config("translator_static_config") {
|
|||
defines = [ "ANGLE_TRANSLATOR_STATIC" ]
|
||||
}
|
||||
|
||||
config("debug_annotations_config") {
|
||||
if (is_debug) {
|
||||
defines = [
|
||||
"ANGLE_ENABLE_DEBUG_ANNOTATIONS",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
static_library("angle_common") {
|
||||
sources = rebase_path(gles_gypi.libangle_common_sources, ".", "src")
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
":debug_annotations_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
}
|
||||
|
||||
static_library("translator_lib") {
|
||||
sources = rebase_path(compiler_gypi.angle_translator_lib_sources, ".", "src")
|
||||
|
||||
if (angle_enable_hlsl) {
|
||||
sources += rebase_path(compiler_gypi.angle_translator_lib_hlsl_sources, ".", "src")
|
||||
defines = [ "ANGLE_ENABLE_HLSL" ]
|
||||
}
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
|
@ -104,6 +152,10 @@ static_library("translator_lib") {
|
|||
":includes",
|
||||
":preprocessor",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
":angle_common",
|
||||
]
|
||||
}
|
||||
|
||||
static_library("translator_static") {
|
||||
|
@ -112,6 +164,10 @@ static_library("translator_static") {
|
|||
"src/compiler/translator/ShaderVars.cpp",
|
||||
]
|
||||
|
||||
if (angle_enable_hlsl) {
|
||||
defines = [ "ANGLE_ENABLE_HLSL" ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
|
@ -143,97 +199,150 @@ action("commit_id") {
|
|||
public_configs = [ ":commit_id_config" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
angle_enable_d3d9 = true
|
||||
angle_enable_d3d11 = true
|
||||
config("libANGLE_config") {
|
||||
cflags = []
|
||||
defines = []
|
||||
if (angle_enable_d3d9) {
|
||||
defines += [ "ANGLE_ENABLE_D3D9" ]
|
||||
}
|
||||
if (angle_enable_d3d11) {
|
||||
defines += [ "ANGLE_ENABLE_D3D11" ]
|
||||
}
|
||||
if (angle_enable_gl) {
|
||||
defines += [ "ANGLE_ENABLE_OPENGL" ]
|
||||
}
|
||||
if (use_x11) {
|
||||
defines += [ "ANGLE_USE_X11" ]
|
||||
}
|
||||
defines += [
|
||||
"GL_APICALL=",
|
||||
"GL_GLEXT_PROTOTYPES=",
|
||||
"EGLAPI=",
|
||||
]
|
||||
if (is_win) {
|
||||
cflags += [ "/wd4530" ] # C++ exception handler used, but unwind semantics are not enabled.
|
||||
}
|
||||
}
|
||||
|
||||
shared_library("libGLESv2") {
|
||||
sources = rebase_path(gles_gypi.angle_libangle_sources, ".", "src")
|
||||
sources += [
|
||||
"src/libGLESv2/libGLESv2.cpp",
|
||||
"src/libGLESv2/libGLESv2.def",
|
||||
"src/libGLESv2/libGLESv2.rc",
|
||||
]
|
||||
static_library("libANGLE") {
|
||||
sources = rebase_path(gles_gypi.libangle_sources, ".", "src")
|
||||
|
||||
defines = [
|
||||
include_dirs = []
|
||||
libs = []
|
||||
defines = [
|
||||
"LIBANGLE_IMPLEMENTATION",
|
||||
]
|
||||
|
||||
# Shared D3D sources.
|
||||
if (angle_enable_d3d9 || angle_enable_d3d11) {
|
||||
sources += rebase_path(gles_gypi.libangle_d3d_shared_sources, ".", "src")
|
||||
|
||||
defines += [
|
||||
"ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ " +
|
||||
"\"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }",
|
||||
"GL_APICALL=",
|
||||
"GL_GLEXT_PROTOTYPES=",
|
||||
"EGLAPI=",
|
||||
]
|
||||
libs = []
|
||||
|
||||
# Windows-specific sources.
|
||||
sources += rebase_path(gles_gypi.angle_libangle_win_sources, ".", "src")
|
||||
|
||||
# Shared D3dD sources.
|
||||
if (angle_enable_d3d9 || angle_enable_d3d11) {
|
||||
sources += rebase_path(gles_gypi.angle_d3d_shared_sources, ".", "src")
|
||||
}
|
||||
|
||||
if (angle_enable_d3d9) {
|
||||
sources += rebase_path(gles_gypi.angle_d3d9_sources, ".", "src")
|
||||
defines += [ "ANGLE_ENABLE_D3D9" ]
|
||||
libs += [ "d3d9.lib" ]
|
||||
}
|
||||
|
||||
if (angle_enable_d3d11) {
|
||||
sources += rebase_path(gles_gypi.angle_d3d11_sources, ".", "src")
|
||||
defines += [ "ANGLE_ENABLE_D3D11" ]
|
||||
libs += [ "dxguid.lib" ]
|
||||
}
|
||||
|
||||
if (is_debug) {
|
||||
defines += [ "ANGLE_ENABLE_PERF" ]
|
||||
libs += [ "d3d9.lib" ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
|
||||
include_dirs = [ "src/libGLESv2" ]
|
||||
|
||||
deps = [
|
||||
":commit_id",
|
||||
":includes",
|
||||
":translator",
|
||||
#":copy_compiler_dll", TODO(GYP)
|
||||
"\"d3dcompiler_47.dll\", \"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }",
|
||||
]
|
||||
}
|
||||
|
||||
shared_library("libEGL") {
|
||||
sources = rebase_path(egl_gypi.angle_libegl_sources, ".", "src")
|
||||
if (angle_enable_d3d9) {
|
||||
sources += rebase_path(gles_gypi.libangle_d3d9_sources, ".", "src")
|
||||
libs += [ "d3d9.lib" ]
|
||||
}
|
||||
|
||||
defines = [
|
||||
"GL_APICALL=",
|
||||
"GL_GLEXT_PROTOTYPES=",
|
||||
"EGLAPI=",
|
||||
]
|
||||
if (angle_enable_d3d11) {
|
||||
sources += rebase_path(gles_gypi.libangle_d3d11_sources, ".", "src")
|
||||
sources += rebase_path(gles_gypi.libangle_d3d11_win32_sources, ".", "src")
|
||||
libs += [ "dxguid.lib" ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
if (angle_enable_gl) {
|
||||
sources += rebase_path(gles_gypi.libangle_gl_sources, ".", "src")
|
||||
include_dirs += [ "src/third_party/khronos" ]
|
||||
|
||||
if (is_debug) {
|
||||
defines += [
|
||||
"ANGLE_ENABLE_PERF",
|
||||
"ANGLE_GENERATE_SHADER_DEBUG_INFO"
|
||||
]
|
||||
if (is_win) {
|
||||
sources += rebase_path(gles_gypi.libangle_gl_wgl_sources, ".", "src")
|
||||
}
|
||||
if (use_x11) {
|
||||
sources += rebase_path(gles_gypi.libangle_gl_glx_sources, ".", "src")
|
||||
libs += [ "X11" ]
|
||||
}
|
||||
}
|
||||
|
||||
include_dirs = [ "src/libGLESv2" ]
|
||||
libs = [ "d3d9.lib" ]
|
||||
|
||||
deps = [
|
||||
":commit_id",
|
||||
":includes",
|
||||
":libGLESv2",
|
||||
if (is_debug) {
|
||||
defines += [
|
||||
"ANGLE_GENERATE_SHADER_DEBUG_INFO",
|
||||
]
|
||||
}
|
||||
} # is_win
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":commit_id_config",
|
||||
":debug_annotations_config",
|
||||
":libANGLE_config",
|
||||
":internal_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":commit_id",
|
||||
":includes",
|
||||
":translator_static",
|
||||
":angle_common",
|
||||
]
|
||||
|
||||
if (is_win) {
|
||||
deps += [ ":copy_compiler_dll" ]
|
||||
}
|
||||
}
|
||||
|
||||
shared_library("libGLESv2") {
|
||||
sources = rebase_path(gles_gypi.libglesv2_sources, ".", "src")
|
||||
|
||||
if (is_win) {
|
||||
ldflags = [ "/DEF:" +
|
||||
rebase_path("src/libGLESv2/libGLESv2.def", root_build_dir) ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
":commit_id_config",
|
||||
":debug_annotations_config",
|
||||
":libANGLE_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
|
||||
defines = [
|
||||
"LIBGLESV2_IMPLEMENTATION",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":includes",
|
||||
":libANGLE",
|
||||
]
|
||||
}
|
||||
|
||||
shared_library("libEGL") {
|
||||
sources = rebase_path(gles_gypi.libegl_sources, ".", "src")
|
||||
|
||||
if (is_win) {
|
||||
ldflags = [ "/DEF:" +
|
||||
rebase_path("src/libEGL/libEGL.def", root_build_dir) ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":internal_config",
|
||||
":commit_id_config",
|
||||
":libANGLE_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
|
||||
defines = [
|
||||
"LIBEGL_IMPLEMENTATION",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":includes",
|
||||
":libGLESv2",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This is the official list of people who can contribute
|
||||
# This is the official list of people who can contribute
|
||||
# (and who have contributed) code to the ANGLE project
|
||||
# repository.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
|
@ -40,6 +40,7 @@ Google Inc.
|
|||
thestig@chromium.org
|
||||
Justin Schuh
|
||||
Scott Graham
|
||||
Corentin Wallez
|
||||
|
||||
Adobe Systems Inc.
|
||||
Alexandru Chiculita
|
||||
|
@ -52,9 +53,12 @@ Autodesk, Inc.
|
|||
Cloud Party, Inc.
|
||||
Conor Dickinson
|
||||
|
||||
Digia Plc
|
||||
The Qt Company Ltd.
|
||||
Andrew Knight
|
||||
|
||||
Imagination Technologies Ltd.
|
||||
Gregoire Payen de La Garanderie
|
||||
|
||||
Intel Corporation
|
||||
Jin Yang
|
||||
Andy Chen
|
||||
|
@ -80,10 +84,23 @@ Mark Banner (standard8mbp)
|
|||
David Kilzer
|
||||
Jacek Caban
|
||||
Tibor den Ouden
|
||||
Régis Fénéon
|
||||
|
||||
Microsoft Corporation
|
||||
Cooper Partin
|
||||
Austin Kinross
|
||||
Minmin Gong
|
||||
Shawn Hargreaves
|
||||
|
||||
Microsoft Open Technologies, Inc.
|
||||
Cooper Partin
|
||||
Austin Kinross
|
||||
Cooper Partin
|
||||
Austin Kinross
|
||||
|
||||
NVIDIA Corporation
|
||||
Olli Etuaho
|
||||
Arun Patole
|
||||
Qingqing Deng
|
||||
Kimmo Kinnunen
|
||||
|
||||
Opera Software ASA
|
||||
Daniel Bratell
|
||||
|
|
|
@ -1,15 +1,67 @@
|
|||
vars = {
|
||||
'chromium_git': 'https://chromium.googlesource.com',
|
||||
}
|
||||
|
||||
deps = {
|
||||
"third_party/gyp":
|
||||
"http://gyp.googlecode.com/svn/trunk@1987",
|
||||
Var('chromium_git') + "/external/gyp@b4781fc38236b0fb1238969c918a75a200cfffdb",
|
||||
|
||||
"tests/third_party/googletest":
|
||||
"http://googletest.googlecode.com/svn/trunk@629",
|
||||
# TODO(kbr): figure out how to better stay in sync with Chromium's
|
||||
# versions of googletest and googlemock.
|
||||
"src/tests/third_party/googletest":
|
||||
Var('chromium_git') + "/external/googletest.git@23574bf2333f834ff665f894c97bef8a5b33a0a9",
|
||||
|
||||
"tests/third_party/googlemock":
|
||||
"http://googlemock.googlecode.com/svn/trunk@410",
|
||||
"src/tests/third_party/googlemock":
|
||||
Var('chromium_git') + "/external/googlemock.git@b2cb211e49d872101d991201362d7b97d7d69910",
|
||||
|
||||
"third_party/deqp/src":
|
||||
"https://android.googlesource.com/platform/external/deqp@92f7752da82925ca5e7288c5b4814efa7a381d89",
|
||||
|
||||
"third_party/libpng":
|
||||
"https://android.googlesource.com/platform/external/libpng@094e181e79a3d6c23fd005679025058b7df1ad6c",
|
||||
|
||||
"third_party/zlib":
|
||||
Var('chromium_git') + "/chromium/src/third_party/zlib@afd8c4593c010c045902f6c0501718f1823064a3",
|
||||
|
||||
"buildtools":
|
||||
Var('chromium_git') + '/chromium/buildtools.git@125d157607de4d7c95bf8b02dd580aae17962f19',
|
||||
}
|
||||
|
||||
hooks = [
|
||||
# Pull clang-format binaries using checked-in hashes.
|
||||
{
|
||||
'name': 'clang_format_win',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=win32',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'buildtools/win/clang-format.exe.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'clang_format_mac',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=darwin',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'buildtools/mac/clang-format.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'clang_format_linux',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--platform=linux*',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-clang-format',
|
||||
'-s', 'buildtools/linux64/clang-format.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
# A change to a .gyp, .gypi, or to GYP itself should run the generator.
|
||||
"pattern": ".",
|
||||
|
|
|
@ -8,12 +8,13 @@ ANGLE is used as the default WebGL backend for both Google Chrome and Mozilla Fi
|
|||
Portions of the ANGLE shader compiler are used as a shader validator and translator by WebGL implementations across multiple platforms. It is used on Mac OS X, Linux, and in mobile variants of the browsers. Having one shader validator helps to ensure that a consistent set of GLSL ES shaders are accepted across browsers and platforms. The shader translator can be used to translate shaders to other shading languages, and to optionally apply shader modifications to work around bugs or quirks in the native graphics drivers. The translator targets Desktop GLSL, Direct3D HLSL, and even ESSL for native GLES2 platforms.
|
||||
|
||||
##Building
|
||||
For building instructions, visit the [dev setup wiki](https://code.google.com/p/angleproject/wiki/DevSetup).
|
||||
View the [Dev setup instructions](doc/DevSetup.md).
|
||||
|
||||
##Contributing
|
||||
* Join our [Google group](https://groups.google.com/group/angleproject) to keep up to date.
|
||||
* Read about ANGLE development on the [wiki](http://code.google.com/p/angleproject/w/list).
|
||||
* Become a [code contributor](https://code.google.com/p/angleproject/wiki/ContributingCode).
|
||||
* Join us on IRC in the #ANGLEproject channel on FreeNode.
|
||||
* Read about ANGLE development in our [documentation](doc).
|
||||
* Become a [code contributor](doc/ContributingCode.md).
|
||||
* File bugs in the [issue tracker](http://code.google.com/p/angleproject/issues/list) (preferably with an isolated test-case).
|
||||
* Read about WebGL on the [Khronos WebGL Wiki](http://khronos.org/webgl/wiki/Main_Page).
|
||||
* Learn about implementation details in the [OpenGL Insights chapter on ANGLE](http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-ANGLE.pdf) and this [ANGLE presentation](https://code.google.com/p/angleproject/downloads/detail?name=ANGLE%20and%20Cross-Platform%20WebGL%20Support.pdf&can=2&q=).
|
||||
|
|
|
@ -33,12 +33,12 @@ extern "C" {
|
|||
** used to make the header, and the header can be found at
|
||||
** http://www.opengl.org/registry/
|
||||
**
|
||||
** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $
|
||||
** Khronos $Revision: 29318 $ on $Date: 2015-01-02 03:16:10 -0800 (Fri, 02 Jan 2015) $
|
||||
*/
|
||||
|
||||
#include <EGL/eglplatform.h>
|
||||
|
||||
/* Generated on date 20140610 */
|
||||
/* Generated on date 20150102 */
|
||||
|
||||
/* Generated C header for:
|
||||
* API: egl
|
||||
|
@ -240,6 +240,7 @@ EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
|
|||
typedef void *EGLSync;
|
||||
typedef intptr_t EGLAttrib;
|
||||
typedef khronos_utime_nanoseconds_t EGLTime;
|
||||
typedef void *EGLImage;
|
||||
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
|
||||
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
|
||||
#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
|
||||
|
@ -281,10 +282,14 @@ typedef khronos_utime_nanoseconds_t EGLTime;
|
|||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
|
||||
#define EGL_IMAGE_PRESERVED 0x30D2
|
||||
#define EGL_NO_IMAGE ((EGLImage)0)
|
||||
EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
|
||||
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
|
||||
EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
|
||||
EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
|
||||
EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
|
||||
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
|
||||
EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
|
||||
EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
|
||||
EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче