Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-09-30 14:00:16 +02:00
Родитель 53f3764f8a 7a4aaa0466
Коммит 4cb1341e89
1068 изменённых файлов: 147099 добавлений и 47456 удалений

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

@ -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();
});

3
browser/components/loop/.gitignore поставляемый
Просмотреть файл

@ -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

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

@ -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);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше