Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-03-12 18:05:45 -04:00
commit 347d41d8f5
348 changed files with 4165 additions and 2305 deletions

View File

@ -711,6 +711,9 @@ getRoleCB(AtkObject *aAtkObj)
aAtkObj->role = ATK_ROLE_PANEL;
else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
aAtkObj->role = ATK_ROLE_TEXT;
else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16))
aAtkObj->role = ATK_ROLE_UNKNOWN;
return aAtkObj->role;
}

View File

@ -1130,7 +1130,7 @@ ROLE(MATHML_ROW,
ROLE(MATHML_FRACTION,
"mathml fraction",
ATK_ROLE_UNKNOWN,
ATK_ROLE_MATH_FRACTION,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,
@ -1138,7 +1138,7 @@ ROLE(MATHML_FRACTION,
ROLE(MATHML_SQUARE_ROOT,
"mathml square root",
ATK_ROLE_UNKNOWN,
ATK_ROLE_MATH_ROOT,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,
@ -1146,7 +1146,7 @@ ROLE(MATHML_SQUARE_ROOT,
ROLE(MATHML_ROOT,
"mathml root",
ATK_ROLE_UNKNOWN,
ATK_ROLE_MATH_ROOT,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,

View File

@ -703,10 +703,11 @@ pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000);
pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000);
pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000);
// Number of different background levels for background processes. We use
// these different levels to force the low-memory killer to kill processes in
// a LRU order.
pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5);
// Number of different background/foreground levels for background/foreground
// processes. We use these different levels to force the low-memory killer to
// kill processes in a LRU order.
pref("dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 5);
pref("dom.ipc.processPriorityManager.FOREGROUND.LRUPoolLevels", 3);
// Kernel parameters for process priorities. These affect how processes are
// killed on low-memory and their relative CPU priorities.

View File

@ -1,3 +1,4 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_aboutCrashed.xul]

View File

@ -213,7 +213,6 @@ skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
[browser_bug561623.js]
skip-if = e10s
[browser_bug561636.js]
skip-if = e10s # Bug 1093677 - automated form submission from the test doesn't seem to quite work yet
[browser_bug562649.js]
[browser_bug563588.js]
[browser_bug565575.js]
@ -243,7 +242,6 @@ skip-if = e10s
skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for e10s
[browser_bug594131.js]
[browser_bug595507.js]
skip-if = e10s # Bug 1093677 - automated form submission from the test doesn't seem to quite work yet
[browser_bug596687.js]
[browser_bug597218.js]
[browser_bug609700.js]

View File

@ -14,13 +14,6 @@ function checkPopupHide()
"[Test " + testId + "] The invalid form popup should not be shown");
}
function checkPopupMessage(doc)
{
is(gInvalidFormPopup.firstChild.textContent,
doc.getElementById('i').validationMessage,
"[Test " + testId + "] The panel should show the message from validationMessage");
}
let gObserver = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
@ -29,9 +22,17 @@ let gObserver = {
}
};
var testId = 0;
function incrementTest()
{
testId++;
info("Starting next part of test");
}
function getDocHeader()
{
return "data:text/html,<html><head><meta charset='utf-8'></head><body>" + getEmptyFrame();
return "<html><head><meta charset='utf-8'></head><body>" + getEmptyFrame();
}
function getDocFooter()
@ -45,460 +46,327 @@ function getEmptyFrame()
"name='t' srcdoc=\"<html><head><meta charset='utf-8'></head><body>form target</body></html>\"></iframe>";
}
var testId = -1;
function nextTest()
function* openNewTab(uri, background)
{
testId++;
if (testId >= tests.length) {
finish();
return;
let tab = gBrowser.addTab();
let browser = gBrowser.getBrowserForTab(tab);
if (!background) {
gBrowser.selectedTab = tab;
}
executeSoon(tests[testId]);
yield promiseTabLoadEvent(tab, "data:text/html," + escape(uri));
return browser;
}
function test()
function* clickChildElement(browser)
{
waitForExplicitFinish();
waitForFocus(nextTest);
yield ContentTask.spawn(browser, {}, function* () {
content.document.getElementById('s').click();
});
}
var tests = [
function* blurChildElement(browser)
{
yield ContentTask.spawn(browser, {}, function* () {
content.document.getElementById('i').blur();
});
}
function* checkChildFocus(browser, message)
{
let [activeElement, validMsg] =
yield ContentTask.spawn(browser, message, function* (msg) {
var focused = content.document.activeElement == content.document.getElementById('i');
var validMsg = true;
if (msg) {
validMsg = (msg == content.document.getElementById('i').validationMessage);
}
return [focused, validMsg];
});
is(activeElement, true, "Test " + testId + " First invalid element should be focused");
is(validMsg, true, "Test " + testId + " The panel should show the message from validationMessage");
}
/**
* In this test, we check that no popup appears if the form is valid.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
let doc = gBrowser.contentDocument;
doc.getElementById('s').click();
yield clickChildElement(browser);
yield new Promise((resolve, reject) => {
// XXXndeakin This isn't really going to work when the content is another process
executeSoon(function() {
checkPopupHide();
// Clean-up
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
resolve();
});
}, true);
});
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that, when an invalid form is submitted,
* the invalid element is focused and a popup appears.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that, when an invalid form is submitted,
* the first invalid element is focused and a popup appears.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input><input id='i' required><input required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that, we hide the popup by interacting with the
* invalid element if the element becomes valid.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden");
EventUtils.synthesizeKey("a", {});
yield popupHiddenPromise;
EventUtils.synthesizeKey("a", {});
executeSoon(function () {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that, we don't hide the popup by interacting with the
* invalid element if the element is still invalid.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input type='email' id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
checkPopupMessage(doc);
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
yield new Promise((resolve, reject) => {
EventUtils.synthesizeKey("a", {});
executeSoon(function () {
checkPopupShow();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
checkPopupShow();
resolve();
})
});
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that we can hide the popup by blurring the invalid
* element.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden");
yield blurChildElement(browser);
yield popupHiddenPromise;
doc.getElementById('i').blur();
executeSoon(function () {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that we can hide the popup by pressing TAB.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden");
EventUtils.synthesizeKey("VK_TAB", {});
yield popupHiddenPromise;
EventUtils.synthesizeKey("VK_TAB", {});
executeSoon(function () {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that the popup will hide if we move to another tab.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser1 = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser1);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser1, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
checkPopupMessage(doc);
let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden");
// Create a new tab and move to it.
gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
let browser2 = yield openNewTab("data:text/html,<html></html>");
yield popupHiddenPromise;
executeSoon(function() {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeTab(gBrowser.getTabForBrowser(browser1));
gBrowser.removeTab(gBrowser.getTabForBrowser(browser2));
});
/**
* In this test, we check that nothing happen if the invalid form is
* submitted in a background tab.
*/
function()
add_task(function* ()
{
// Observers don't propagate currently across processes. We may add support for this in the
// future via the addon compat layer.
if (gBrowser.isRemoteBrowser) {
nextTest();
if (gMultiProcessBrowser) {
return;
}
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri, true);
isnot(gBrowser.selectedBrowser, browser, "This tab should have been loaded in background");
gObserver.notifyInvalidSubmit = function() {
executeSoon(function() {
checkPopupHide();
// Clean-up
Services.obs.removeObserver(gObserver, "invalidformsubmit");
gObserver.notifyInvalidSubmit = function () {};
gBrowser.removeTab(tab);
nextTest();
});
};
Services.obs.addObserver(gObserver, "invalidformsubmit", false);
tab.linkedBrowser.addEventListener("load", function(e) {
// Ignore load events from the iframe.
if (tab.linkedBrowser.contentDocument == e.target) {
let browser = e.currentTarget;
browser.removeEventListener("load", arguments.callee, true);
isnot(gBrowser.selectedBrowser, browser,
"This tab should have been loaded in background");
let notifierPromise = new Promise((resolve, reject) => {
gObserver.notifyInvalidSubmit = function() {
executeSoon(function() {
browser.contentDocument.getElementById('s').click();
});
}
}, true);
checkPopupHide();
tab.linkedBrowser.loadURI(uri);
},
// Clean-up
Services.obs.removeObserver(gObserver, "invalidformsubmit");
gObserver.notifyInvalidSubmit = function () {};
resolve();
});
};
Services.obs.addObserver(gObserver, "invalidformsubmit", false);
executeSoon(function () {
browser.contentDocument.getElementById('s').click();
});
});
yield notifierPromise;
gBrowser.removeTab(gBrowser.getTabForBrowser(browser));
});
/**
* In this test, we check that the author defined error message is shown.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input x-moz-errormessage='foo' required id='i'><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
is(gInvalidFormPopup.firstChild.textContent, "foo",
"The panel should show the author defined error message");
is(gInvalidFormPopup.firstChild.textContent, "foo",
"The panel should show the author defined error message");
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
});
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
gBrowser.removeCurrentTab();
});
/**
* In this test, we check that the message is correctly updated when it changes.
*/
function()
add_task(function* ()
{
incrementTest();
let uri = getDocHeader() + "<form target='t' action='data:text/html,'><input type='email' required id='i'><input id='s' type='submit'></form>" + getDocFooter();
let tab = gBrowser.addTab();
let browser = yield openNewTab(uri);
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield clickChildElement(browser);
yield popupShownPromise;
let doc = gBrowser.contentDocument;
let input = doc.getElementById('i');
is(doc.activeElement, input, "First invalid element should be focused");
checkPopupShow();
yield checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
checkPopupShow();
let inputPromise = promiseWaitForEvent(gBrowser.contentDocument.getElementById('i'), "input");
EventUtils.synthesizeKey('f', {});
yield inputPromise;
is(gInvalidFormPopup.firstChild.textContent, input.validationMessage,
"The panel should show the current validation message");
input.addEventListener('input', function() {
input.removeEventListener('input', arguments.callee, false);
executeSoon(function() {
// Now, the element suffers from another error, the message should have
// been updated.
is(gInvalidFormPopup.firstChild.textContent, input.validationMessage,
"The panel should show the current validation message");
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab);
nextTest();
});
}, false);
EventUtils.synthesizeKey('f', {});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
// Now, the element suffers from another error, the message should have
// been updated.
yield new Promise((resolve, reject) => {
// XXXndeakin This isn't really going to work when the content is another process
executeSoon(function() {
gBrowser.contentDocument.getElementById('s').click();
checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
resolve();
});
}, true);
});
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
},
];
gBrowser.removeCurrentTab();
});

View File

@ -1,40 +1,36 @@
var gInvalidFormPopup = document.getElementById('invalid-form-popup');
ok(gInvalidFormPopup,
"The browser should have a popup to show when a form is invalid");
/**
* Make sure that the form validation error message shows even if the form is in an iframe.
*/
function test()
{
waitForExplicitFinish();
add_task(function* () {
let uri = "<iframe src=\"data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>\"</iframe>";
var gInvalidFormPopup = document.getElementById('invalid-form-popup');
ok(gInvalidFormPopup,
"The browser should have a popup to show when a form is invalid");
let uri = "data:text/html,<iframe src=\"data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>\"</iframe>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
ok(gInvalidFormPopup.state == 'showing' || gInvalidFormPopup.state == 'open',
"The invalid form popup should be shown");
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
executeSoon(finish);
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument
.getElementById('s').click();
});
}, true);
let browser = gBrowser.getBrowserForTab(tab);
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.loadURI(uri);
}
yield promiseTabLoadEvent(tab, "data:text/html," + escape(uri));
let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
yield ContentTask.spawn(browser, {}, function* () {
content.document.getElementsByTagName('iframe')[0]
.contentDocument.getElementById('s').click();
});
yield popupShownPromise;
let activeElement = yield ContentTask.spawn(browser, {}, function* () {
let childdoc = content.document.getElementsByTagName('iframe')[0].contentDocument;
return childdoc.activeElement == childdoc.getElementById('i');
});
is(activeElement, true, "First invalid element should be focused");
ok(gInvalidFormPopup.state == 'showing' || gInvalidFormPopup.state == 'open',
"The invalid form popup should be shown");
gBrowser.removeCurrentTab();
});

View File

@ -4,17 +4,10 @@ let enabledPref = false;
let automaticPref = false;
let urlPref = "security.ssl.errorReporting.url";
let enforcement_level = 1;
function loadFrameScript() {
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIMessageListenerManager);
const ROOT = getRootDirectory(gTestPath);
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
}
let ROOT = getRootDirectory(gTestPath);
add_task(function*(){
waitForExplicitFinish();
loadFrameScript();
SimpleTest.requestCompleteLog();
yield testSendReportDisabled();
yield testSendReportManual(badChainURL, "succeed");
@ -41,7 +34,7 @@ function createNetworkErrorMessagePromise(aBrowser) {
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
let doc = aBrowser.contentDocument;
if (doc.getElementById("reportCertificateError")) {
if (doc && doc.getElementById("reportCertificateError")) {
// Wait until the documentURI changes (from about:blank) this should
// be the error page URI.
let documentURI = doc.documentURI;
@ -74,11 +67,12 @@ function createNetworkErrorMessagePromise(aBrowser) {
}
// check we can set the 'automatically send' pref
let testSetAutomatic = Task.async(function*() {
let testSetAutomatic = function*() {
setup();
let tab = gBrowser.addTab(badChainURL, {skipAnimation: true});
let browser = tab.linkedBrowser;
let mm = browser.messageManager;
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
gBrowser.selectedTab = tab;
@ -88,13 +82,15 @@ let testSetAutomatic = Task.async(function*() {
// ensure that setting automatic when unset works
let prefEnabled = new Promise(function(resolve, reject){
mm.addMessageListener("ssler-test:AutoPrefUpdated", function() {
let prefUpdateListener = function() {
mm.removeMessageListener("ssler-test:AutoPrefUpdated", prefUpdateListener);
if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
resolve();
} else {
reject();
}
});
};
mm.addMessageListener("ssler-test:AutoPrefUpdated", prefUpdateListener);
});
mm.sendAsyncMessage("ssler-test:SetAutoPref",{value:true});
@ -103,13 +99,15 @@ let testSetAutomatic = Task.async(function*() {
// ensure un-setting automatic, when set, works
let prefDisabled = new Promise(function(resolve, reject){
mm.addMessageListener("ssler-test:AutoPrefUpdated", function () {
let prefUpdateListener = function () {
mm.removeMessageListener("ssler-test:AutoPrefUpdated", prefUpdateListener);
if (!Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
resolve();
} else {
reject();
}
});
};
mm.addMessageListener("ssler-test:AutoPrefUpdated", prefUpdateListener);
});
mm.sendAsyncMessage("ssler-test:SetAutoPref",{value:false});
@ -118,10 +116,10 @@ let testSetAutomatic = Task.async(function*() {
gBrowser.removeTab(tab);
cleanup();
});
};
// test that manual report sending (with button clicks) works
let testSendReportManual = Task.async(function*(testURL, suffix) {
let testSendReportManual = function*(testURL, suffix) {
setup();
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
Services.prefs.setCharPref("security.ssl.errorReporting.url",
@ -130,6 +128,7 @@ let testSendReportManual = Task.async(function*(testURL, suffix) {
let tab = gBrowser.addTab(testURL, {skipAnimation: true});
let browser = tab.linkedBrowser;
let mm = browser.messageManager;
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
gBrowser.selectedTab = tab;
@ -141,49 +140,47 @@ let testSendReportManual = Task.async(function*(testURL, suffix) {
"ensure the correct error message came from about:neterror");
});
// Check the report starts on click
let btn = browser.contentDocument.getElementById("reportCertificateError");
// check the content script sends the message to report
let reportWillStart = new Promise(function(resolve, reject){
mm.addMessageListener("Browser:SendSSLErrorReport", function() {
resolve();
});
});
let deferredReportActivity = Promise.defer()
let deferredReportSucceeds = Promise.defer();
// ensure we see the correct statuses in the correct order...
mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
switch(message.data.reportStatus) {
case "activity":
deferredReportActivity.resolve(message.data.reportStatus);
break;
case "complete":
deferredReportSucceeds.resolve(message.data.reportStatus);
break;
case "error":
deferredReportSucceeds.reject();
deferredReportActivity.reject();
break;
}
});
let statusListener = function() {
let active = false;
return function(message) {
switch(message.data.reportStatus) {
case "activity":
if (!active) {
active = true;
}
break;
case "complete":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
if (active) {
deferredReportSucceeds.resolve(message.data.reportStatus);
} else {
deferredReportSucceeds.reject('activity should be seen before success');
}
break;
case "error":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
deferredReportSucceeds.reject();
break;
}
};
}();
mm.addMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
// ... once the button is clicked, that is
mm.sendAsyncMessage("ssler-test:SendBtnClick",{});
yield reportWillStart;
yield deferredReportActivity.promise;
yield deferredReportSucceeds.promise;
gBrowser.removeTab(tab);
cleanup();
});
};
// test that automatic sending works
let testSendReportAuto = Task.async(function*() {
let testSendReportAuto = function*() {
setup();
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", true);
@ -192,90 +189,85 @@ let testSendReportAuto = Task.async(function*() {
let tab = gBrowser.addTab(badChainURL, {skipAnimation: true});
let browser = tab.linkedBrowser;
let mm = browser.messageManager;
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
gBrowser.selectedTab = tab;
let reportWillStart = Promise.defer();
mm.addMessageListener("Browser:SendSSLErrorReport", function() {
reportWillStart.resolve();
});
let deferredReportActivity = Promise.defer();
let deferredReportSucceeds = Promise.defer();
mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
switch(message.data.reportStatus) {
case "activity":
deferredReportActivity.resolve(message.data.reportStatus);
break;
case "complete":
deferredReportSucceeds.resolve(message.data.reportStatus);
break;
case "error":
deferredReportSucceeds.reject();
deferredReportActivity.reject();
break;
}
});
// Ensure the error page loads
let netError = createNetworkErrorMessagePromise(browser);
yield netError;
// Ensure the reporting steps all occur with no interaction
yield reportWillStart;
yield deferredReportActivity.promise;
let reportWillStart = Promise.defer();
let startListener = function() {
mm.removeMessageListener("Browser:SendSSLErrorReport", startListener);
reportWillStart.resolve();
};
mm.addMessageListener("Browser:SendSSLErrorReport", startListener);
let deferredReportSucceeds = Promise.defer();
let statusListener = function(message) {
switch(message.data.reportStatus) {
case "complete":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
deferredReportSucceeds.resolve(message.data.reportStatus);
break;
case "error":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
deferredReportSucceeds.reject();
break;
}
};
mm.addMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
// Ensure the report is sent with no interaction
yield deferredReportSucceeds.promise;
gBrowser.removeTab(tab);
cleanup();
});
};
// test that an error is shown if there's a problem with the report server
let testSendReportError = Task.async(function*() {
let testSendReportError = function*() {
setup();
// set up prefs so error send is automatic and an error will occur
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", true);
Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?error");
// load the test URL so error page is seen
let tab = gBrowser.addTab(badChainURL, {skipAnimation: true});
let browser = tab.linkedBrowser;
let mm = browser.messageManager;
gBrowser.selectedTab = tab;
let mm = browser.messageManager;
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
// check the report send starts....
let reportWillStart = new Promise(function(resolve, reject){
mm.addMessageListener("Browser:SendSSLErrorReport", function() {
resolve();
});
});
let netError = createNetworkErrorMessagePromise(browser);
yield netError;
yield reportWillStart;
// and that errors are seen
let reportErrors = new Promise(function(resolve, reject) {
mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
let statusListener = function(message) {
switch(message.data.reportStatus) {
case "complete":
reject(message.data.reportStatus);
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
break;
case "error":
resolve(message.data.reportStatus);
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
break;
}
});
};
mm.addMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
});
// check that errors are sent
yield reportErrors;
gBrowser.removeTab(tab);
cleanup();
});
};
let testSendReportDisabled = Task.async(function*() {
let testSendReportDisabled = function*() {
setup();
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://offdomain.com");
@ -283,6 +275,7 @@ let testSendReportDisabled = Task.async(function*() {
let tab = gBrowser.addTab(badChainURL, {skipAnimation: true});
let browser = tab.linkedBrowser;
let mm = browser.messageManager;
mm.loadFrameScript(ROOT + "browser_ssl_error_reports_content.js", true);
gBrowser.selectedTab = tab;
@ -291,16 +284,19 @@ let testSendReportDisabled = Task.async(function*() {
yield netError;
let reportErrors = new Promise(function(resolve, reject) {
mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
let statusListener = function(message) {
switch(message.data.reportStatus) {
case "complete":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
reject(message.data.reportStatus);
break;
case "error":
mm.removeMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
resolve(message.data.reportStatus);
break;
}
});
};
mm.addMessageListener("ssler-test:SSLErrorReportStatus", statusListener);
});
// click the button
@ -311,7 +307,7 @@ let testSendReportDisabled = Task.async(function*() {
gBrowser.removeTab(tab);
cleanup();
});
};
function setup() {
// ensure the relevant prefs are set

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files = sample_feed.atom
[test_423060.xul]

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files = head.js
[test_0_bug510634.xul]

View File

@ -19,7 +19,6 @@
persist="screenX screenY width height"
onkeypress="gCookiesWindow.onWindowKeyPress(event);">
<script src="chrome://global/content/treeUtils.js"/>
<script src="chrome://browser/content/preferences/cookies.js"/>
<stringbundle id="bundlePreferences"

View File

@ -150,7 +150,7 @@ var gPermissionManager = {
// Re-do the sort, if the status changed from Block to Allow
// or vice versa, since if we're sorted on status, we may no
// longer be in order.
if (this._lastPermissionSortColumn.id == "statusCol") {
if (this._lastPermissionSortColumn == "statusCol") {
this._resortPermissions();
}
this._tree.treeBoxObject.invalidate();
@ -168,9 +168,10 @@ var gPermissionManager = {
_resortPermissions: function()
{
gTreeUtils.sort(this._tree, this._view, this._permissions,
this._lastPermissionSortColumn,
this._permissionsComparator,
this._lastPermissionSortColumn,
this._lastPermissionSortAscending);
!this._lastPermissionSortAscending); // keep sort direction
},
onHostInput: function (aSiteField)
@ -377,7 +378,7 @@ var gPermissionManager = {
// sort and display the table
this._tree.view = this._view;
this.onPermissionSort("rawHost", false);
this.onPermissionSort("rawHost");
// disable "remove all" button if there are none
document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
hosted_app.manifest
validator/*

View File

@ -74,7 +74,15 @@ let PerformanceIO = {
loadRecordingFromFile: function(file) {
let deferred = promise.defer();
let channel = NetUtil.newChannel(file);
let channel = NetUtil.newChannel2(file,
null,
null,
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
channel.contentType = "text/plain";
NetUtil.asyncFetch(channel, (inputStream, status) => {

View File

@ -9,7 +9,7 @@
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
*/
const { Cu } = require("chrome");
const { Ci, Cu } = require("chrome");
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
loader.lazyRequireGetter(this, "Services");
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
@ -25,7 +25,15 @@ const cachedThemes = {};
* Returns a string of the file found at URI
*/
function readURI (uri) {
let stream = NetUtil.newChannel(uri, "UTF-8", null).open();
let stream = NetUtil.newChannel2(uri,
"UTF-8",
null,
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER).open();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, { charset: "UTF-8" });
stream.close();

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
app/index.html
app/manifest.webapp

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
file_disableScript.html

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
662200a.html
662200b.html

View File

@ -1 +1,2 @@
[chrome/test_running_on_compositor.html]
skip-if = buildapp == 'b2g'

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
asmjs/*
file_bug_945152.html

View File

@ -2375,6 +2375,18 @@ nsDOMWindowUtils::IsInModalState(bool *retval)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDesktopModeViewport(bool aDesktopMode)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
static_cast<nsGlobalWindow*>(window.get())->SetDesktopModeViewport(aDesktopMode);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetOuterWindowID(uint64_t *aWindowID)
{
@ -2928,6 +2940,67 @@ nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResu
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::IsPartOfOpaqueLayer(nsIDOMElement* aElement, bool* aResult)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIFrame* frame = content->GetPrimaryFrame();
if (!frame) {
return NS_ERROR_FAILURE;
}
Layer* layer = FrameLayerBuilder::GetDebugSingleOldLayerForFrame(frame);
if (!layer || !layer->AsPaintedLayer()) {
return NS_ERROR_FAILURE;
}
*aResult = (layer->GetContentFlags() & Layer::CONTENT_OPAQUE);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::NumberOfAssignedPaintedLayers(nsIDOMElement** aElements,
uint32_t aCount,
uint32_t* aResult)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aElements) {
return NS_ERROR_INVALID_ARG;
}
nsTHashtable<nsPtrHashKey<PaintedLayer>> layers;
nsresult rv;
for (uint32_t i = 0; i < aCount; i++) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aElements[i], &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIFrame* frame = content->GetPrimaryFrame();
if (!frame) {
return NS_ERROR_FAILURE;
}
Layer* layer = FrameLayerBuilder::GetDebugSingleOldLayerForFrame(frame);
if (!layer || !layer->AsPaintedLayer()) {
return NS_ERROR_FAILURE;
}
layers.PutEntry(layer->AsPaintedLayer());
}
*aResult = layers.Count();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::EnableDialogs()
{

View File

@ -7895,6 +7895,15 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
CSSToScreenScale defaultScale = layoutDeviceScale
* LayoutDeviceToScreenScale(1.0);
// Get requested Desktopmode
nsPIDOMWindow* win = GetWindow();
if (win && win->IsDesktopModeViewport())
{
return nsViewportInfo(aDisplaySize,
defaultScale,
/*allowZoom*/false,
/*allowDoubleTapZoom*/ true);
}
if (!Preferences::GetBool("dom.meta-viewport.enabled", false)) {
return nsViewportInfo(aDisplaySize,

View File

@ -580,7 +580,8 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
mIsModalContentWindow(false),
mIsActive(false), mIsBackground(false),
mAudioMuted(false), mAudioVolume(1.0),
mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
mDesktopModeViewport(false), mInnerWindow(nullptr),
mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0
mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
mMarkedCCGeneration(0)

View File

@ -96,6 +96,17 @@ public:
}
// Outer windows only.
void SetDesktopModeViewport(bool aDesktopModeViewport)
{
MOZ_ASSERT(IsOuterWindow());
mDesktopModeViewport = aDesktopModeViewport;
}
bool IsDesktopModeViewport() const
{
MOZ_ASSERT(IsOuterWindow());
return mDesktopModeViewport;
}
virtual void SetIsBackground(bool aIsBackground)
{
MOZ_ASSERT(IsOuterWindow());
@ -783,6 +794,9 @@ protected:
bool mAudioMuted;
float mAudioVolume;
// current desktop mode flag.
bool mDesktopModeViewport;
// And these are the references between inner and outer windows.
nsPIDOMWindow* MOZ_NON_OWNING_REF mInnerWindow;
nsCOMPtr<nsPIDOMWindow> mOuterWindow;

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
file_url.jsm
file_empty.html

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
blockNoPlugins.xml
blockPluginHard.xml

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_csp_bug768029.html]
[test_csp_bug773891.html]

View File

@ -239,7 +239,6 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
&desc)) {
return false;
}
bool descIsOwn = desc.object() != nullptr;
if (!desc.object()) {
// Don't just use getPropertyDescriptor, unlike BaseProxyHandler::set,
// because that would call getOwnPropertyDescriptor on ourselves. Instead,
@ -253,8 +252,7 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
}
}
return js::SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id,
&desc, descIsOwn, vp, result);
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &desc, result);
}
bool

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_bug707564-chrome.html]
[test_bug775543.html]

View File

@ -50,9 +50,10 @@ const browserElementTestHelpers = {
enableProcessPriorityManager: function() {
this._setPrefs(
['dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2],
['dom.ipc.processPriorityManager.FOREGROUND.LRUPoolLevels', 2],
['dom.ipc.processPriorityManager.testMode', true],
['dom.ipc.processPriorityManager.enabled', true],
['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2]
['dom.ipc.processPriorityManager.enabled', true]
);
},
@ -187,28 +188,37 @@ function expectPriorityChange(childID, expectedPriority) {
});
}
// Returns a promise which is resolved or rejected the next time the background
// process childID changes its priority. We resolve if the backgroundLRU
// matches expectedBackgroundLRU and we reject otherwise.
// Returns a promise which is resolved or rejected the next time the
// process childID changes its priority. We resolve if the expectedPriority
// matches the priority and the LRU parameter matches expectedLRU and we
// reject otherwise.
function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) {
function expectPriorityWithLRUSet(childID, expectedPriority, expectedLRU) {
return new Promise(function(resolve, reject) {
var observed = false;
browserElementTestHelpers.addProcessPriorityObserver(
'process-priority-with-background-LRU-set',
'process-priority-with-LRU-set',
function(subject, topic, data) {
if (observed) {
return;
}
var [id, priority, backgroundLRU] = data.split(":");
var [id, priority, lru] = data.split(":");
if (id != childID) {
return;
}
is(backgroundLRU, expectedBackgroundLRU,
'Expected backgroundLRU ' + backgroundLRU +
' of childID ' + childID +
' to change to ' + expectedBackgroundLRU);
// Make sure we run the is() calls in this observer only once,
// otherwise we'll expect /every/ priority/LRU change to match
// expectedPriority/expectedLRU.
observed = true;
if (backgroundLRU == expectedBackgroundLRU) {
is(lru, expectedLRU,
'Expected LRU ' + lru +
' of childID ' + childID +
' to change to ' + expectedLRU);
if ((priority == expectedPriority) && (lru == expectedLRU)) {
resolve();
} else {
reject();

View File

@ -14,6 +14,7 @@ support-files = file_HighPriority.html
[test_BackgroundLRU.html]
[test_Audio.html]
support-files = file_Audio.html silence.ogg
[test_ForegroundLRU.html]
[test_Keyboard.html]
[test_MultipleFrames.html]
support-files = file_MultipleFrames.html

View File

@ -46,19 +46,22 @@ function runTest() {
document.body.appendChild(iframe2);
// At this point, we should have iframe1 in background already.
// We wait until another one is set to background, too.
// Once there are two in background, the first one (LRU order)
// should have 'backgroundLRU' equals 1
var p = expectPriorityWithBackgroundLRUSet(childID, '1');
// We wait until another process goes into the background, too.
// Once there are two in background, the first one should have its LRU
// adjustment value increased to 1.
var p = expectPriorityWithLRUSet(childID, 'BACKGROUND', '1');
iframe2.setVisible(false);
return p;
}).then(function() {
// Don't call removeChild immediately after calling setVisible.
// setVisible on remote browser is async method, so we should wait
// until it sends to the child process.
// When iframe2 is removed iframe1's LRU value should be decreased again.
var p = expectPriorityWithLRUSet(childID, 'BACKGROUND', '0');
document.body.removeChild(iframe2);
return p;
}).then(function() {
SimpleTest.finish();
});

View File

@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<!--
Test that creating three foreground processes causes the LRU value of the
oldest one to be increased by one. Also test that the LRU value is decreased
again when the younger processes go into the background.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
browserElementTestHelpers.enableProcessPriorityManager();
SpecialPowers.addPermission("embed-apps", true, document);
function runTest() {
var iframe1 = document.createElement('iframe');
iframe1.setAttribute('mozbrowser', true);
iframe1.src = 'file_MultipleFrames.html';
var iframe2 = null;
var childID = null;
// Wait for the first process to be created.
Promise.all([
expectProcessCreated('FOREGROUND').then(function(chid) {
childID = chid;
}),
expectMozbrowserEvent(iframe1, 'openwindow')
]).then(function() {
// Then wait for the second one.
var p = expectProcessCreated('FOREGROUND');
iframe2 = document.createElement('iframe');
iframe2.setAttribute('mozbrowser', true);
iframe2.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe2.src = browserElementTestHelpers.emptyPage1;
document.body.appendChild(iframe2);
return p;
}).then(function() {
// Then wait for the third one and for the first one's LRU value to be
// increased by one.
var p = Promise.all([
expectProcessCreated('FOREGROUND'),
expectPriorityWithLRUSet(childID, 'FOREGROUND', 1)
]);
document.body.appendChild(iframe2);
return p;
}).then(function() {
// Now hide the second and third processes, this will send them into the
// background and make the first process LRU value to be decreased.
var p = expectPriorityWithLRUSet(childID, 'FOREGROUND', 0)
iframe2.setVisible(false);
return p;
}).then(function() {
SimpleTest.finish();
});
document.body.appendChild(iframe1);
}
addEventListener('testready', runTest);
</script>
</body>
</html>

View File

@ -9,6 +9,7 @@
#include "GLContext.h"
#include "MurmurHash3.h"
#include "nsPrintfCString.h"
#include "nsTArray.h"
#include <string>
#include <vector>
#include "WebGLContext.h"
@ -34,7 +35,8 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
SH_ENFORCE_PACKING_RESTRICTIONS |
SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
SH_OBJECT_CODE |
SH_LIMIT_CALL_STACK_DEPTH;
SH_LIMIT_CALL_STACK_DEPTH |
SH_INIT_GL_POSITION;
if (resources.MaxExpressionComplexity > 0) {
options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
@ -146,7 +148,7 @@ ShaderValidator::Create(GLenum shaderType, ShShaderSpec spec,
if (!handle)
return nullptr;
return new ShaderValidator(handle, compileOptions);
return new ShaderValidator(handle, compileOptions, resources.MaxVaryingVectors);
}
ShaderValidator::~ShaderValidator()
@ -219,12 +221,22 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
const std::vector<sh::Varying>& vertList = *ShGetVaryings(prev->mHandle);
const std::vector<sh::Varying>& fragList = *ShGetVaryings(mHandle);
nsTArray<ShVariableInfo> staticUseVaryingList;
for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
const ShVariableInfo varInfo = { itrFrag->type,
(int)itrFrag->elementCount() };
static const char prefix[] = "gl_";
if (StartsWith(itrFrag->name, prefix))
if (StartsWith(itrFrag->name, prefix)) {
if (itrFrag->staticUse)
staticUseVaryingList.AppendElement(varInfo);
continue;
}
bool definedInVertShader = false;
bool staticVertUse = false;
for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
if (itrVert->name != itrFrag->name)
@ -239,6 +251,7 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
}
definedInVertShader = true;
staticVertUse = itrVert->staticUse;
break;
}
@ -249,6 +262,18 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
*out_log = error;
return false;
}
if (staticVertUse && itrFrag->staticUse)
staticUseVaryingList.AppendElement(varInfo);
}
if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors,
staticUseVaryingList.Elements(),
staticUseVaryingList.Length()))
{
*out_log = "Statically used varyings do not fit within packing limits. (see"
" GLSL ES Specification 1.0.17, p111)";
return false;
}
}

View File

@ -18,6 +18,7 @@ class ShaderValidator MOZ_FINAL
{
const ShHandle mHandle;
const int mCompileOptions;
const int mMaxVaryingVectors;
bool mHasRun;
public:
@ -27,9 +28,10 @@ public:
int compileOptions);
private:
ShaderValidator(ShHandle handle, int compileOptions)
ShaderValidator(ShHandle handle, int compileOptions, int maxVaryingVectors)
: mHandle(handle)
, mCompileOptions(compileOptions)
, mMaxVaryingVectors(maxVaryingVectors)
, mHasRun(false)
{ }

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files = nonchrome_webgl_debug_renderer_info.html
[test_webgl_debug_renderer_info.html]

View File

@ -1,5 +1,6 @@
[DEFAULT]
skip-if = os == "android"
skip-if = buildapp == 'b2g'
[test_contacts_shutdown.xul]
[test_contacts_upgrade.xul]

View File

@ -1,5 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'mulet'
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
[test_app_permissions.html]
[test_fs_app_permissions.html]

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files = file_stringencoding.jsm
[test_stringencoding.xul]

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
bug415498-doc1.html
bug415498-doc2.html

View File

@ -351,7 +351,7 @@ nsGenericHTMLElement::GetOffsetRect(CSSIntRect& aRect)
parent = frame;
}
else {
const bool isPositioned = frame->IsPositioned();
const bool isPositioned = frame->IsAbsPosContaininingBlock();
const bool isAbsolutelyPositioned = frame->IsAbsolutelyPositioned();
origin += frame->GetPositionIgnoringScrolling();
@ -359,7 +359,7 @@ nsGenericHTMLElement::GetOffsetRect(CSSIntRect& aRect)
content = parent->GetContent();
// Stop at the first ancestor that is positioned.
if (parent->IsPositioned()) {
if (parent->IsAbsPosContaininingBlock()) {
offsetParent = content;
break;
}

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
file_anchor_ping.html

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
submit_invalid_file.sjs
[test_autocompleteinfo.html]

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files=
file_browserid_rp_ok.html

View File

@ -303,7 +303,7 @@ var W3CTest = {
add_result_callback(W3CTest.result.bind(W3CTest));
add_completion_callback(W3CTest.finish.bind(W3CTest));
setup({
"output": false,
"output": W3CTest.runner && !W3CTest.runner.getParameterInfo().closeWhenDone,
"explicit_timeout": true
});
} catch (e) {

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files = chromeHelpers.js
[test_globalObjects_chrome.xul]

View File

@ -50,7 +50,7 @@ interface nsITranslationNodeList;
interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
[scriptable, uuid(6eaf87a1-b252-4c4e-a2fc-318120680335)]
[scriptable, uuid(b39cb73f-ff99-4744-9780-2c26f830c6f7)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -1275,6 +1275,11 @@ interface nsIDOMWindowUtils : nsISupports {
*/
[noscript] boolean isInModalState();
/**
* Request set internal desktopMode flag change.
*/
void setDesktopModeViewport(in boolean aDesktopModeViewport);
/**
* Suspend/resume timeouts on this window and its descendant windows.
*/
@ -1442,6 +1447,23 @@ interface nsIDOMWindowUtils : nsISupports {
*/
boolean checkAndClearPaintedState(in nsIDOMElement aElement);
/**
* Check whether all display items of the primary frame of aElement have been
* assigned to the same single PaintedLayer in the last paint. If that is the
* case, returns whether that PaintedLayer is opaque; if it's not the case, an
* exception is thrown.
*/
boolean isPartOfOpaqueLayer(in nsIDOMElement aElement);
/**
* Count the number of different PaintedLayers that the supplied elements have
* been assigned to in the last paint. Throws an exception if any of the
* elements doesn't have a primary frame, or if that frame's display items are
* assigned to any other layers than just a single PaintedLayer per element.
*/
unsigned long numberOfAssignedPaintedLayers([array, size_is(count)] in nsIDOMElement aElements,
in uint32_t count);
/**
* Get internal id of the stored blob, file or file handle.
*/

View File

@ -531,6 +531,14 @@ InitOnContentProcessCreated()
return;
}
PostForkPreload();
nsCOMPtr<nsIPermissionManager> permManager =
services::GetPermissionManager();
MOZ_ASSERT(permManager, "Unable to get permission manager");
nsresult rv = permManager->RefreshPermission();
if (NS_FAILED(rv)) {
MOZ_ASSERT(false, "Failed updating permission in child process");
}
#endif
nsCOMPtr<nsISystemMessageCache> smc =

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/Hal.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
@ -54,17 +55,18 @@
# define LOGP(fmt, ...) \
__android_log_print(ANDROID_LOG_INFO, \
"Gecko:ProcessPriorityManager", \
"[%schild-id=%llu, pid=%d] " fmt, \
"[%schild-id=%" PRIu64 ", pid=%d] " fmt, \
NameWithComma().get(), \
(long long unsigned) ChildID(), Pid(), ## __VA_ARGS__)
static_cast<uint64_t>(ChildID()), Pid(), ## __VA_ARGS__)
#elif defined(ENABLE_LOGGING)
# define LOG(fmt, ...) \
printf("ProcessPriorityManager - " fmt "\n", ##__VA_ARGS__)
# define LOGP(fmt, ...) \
printf("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt "\n", \
printf("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " \
fmt "\n", \
NameWithComma().get(), \
(unsigned long long) ChildID(), Pid(), ##__VA_ARGS__)
static_cast<uint64_t>(ChildID()), Pid(), ##__VA_ARGS__)
#elif defined(PR_LOGGING)
static PRLogModuleInfo*
@ -80,9 +82,9 @@
("ProcessPriorityManager - " fmt, ##__VA_ARGS__))
# define LOGP(fmt, ...) \
PR_LOG(GetPPMLog(), PR_LOG_DEBUG, \
("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt, \
("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " fmt, \
NameWithComma().get(), \
(unsigned long long) ChildID(), Pid(), ##__VA_ARGS__))
static_cast<uint64_t>(ChildID()), Pid(), ##__VA_ARGS__))
#else
#define LOG(fmt, ...)
#define LOGP(fmt, ...)
@ -96,6 +98,42 @@ namespace {
class ParticularProcessPriorityManager;
class ProcessLRUPool MOZ_FINAL
{
public:
/**
* Creates a new process LRU pool for the specified priority.
*/
ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias);
/**
* Used to remove a particular process priority manager from the LRU pool
* when the associated ContentParent is destroyed or its priority changes.
*/
void Remove(ParticularProcessPriorityManager* aParticularManager);
/**
* Used to add a particular process priority manager into the LRU pool when
* the associated ContentParent's priority changes.
*/
void Add(ParticularProcessPriorityManager* aParticularManager);
private:
ProcessPriority mPriority;
uint32_t mLRUPoolLevels;
uint32_t mLRUPoolSize;
uint32_t mBias;
nsTArray<ParticularProcessPriorityManager*> mLRUPool;
uint32_t CalculateLRULevel(uint32_t aLRUPoolIndex);
void AdjustLRUValues(
nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
bool removed);
DISALLOW_EVIL_CONSTRUCTORS(ProcessLRUPool);
};
/**
* This singleton class does the work to implement the process priority manager
* in the main process. This class may not be used in child processes. (You
@ -129,7 +167,7 @@ public:
*/
void SetProcessPriority(ContentParent* aContentParent,
ProcessPriority aPriority,
uint32_t aBackgroundLRU = 0);
uint32_t aLRU = 0);
/**
* If a magic testing-only pref is set, notify the observer service on the
@ -157,9 +195,21 @@ public:
*/
virtual void Notify(const WakeLockInformation& aInfo) MOZ_OVERRIDE;
/**
* Prevents processes from changing priority until unfrozen.
*/
void Freeze();
/**
* Allow process' priorities to change again. This will immediately adjust
* processes whose priority change did not happen because of the freeze.
*/
void Unfreeze();
private:
static bool sPrefListenersRegistered;
static bool sInitialized;
static bool sFrozen;
static StaticRefPtr<ProcessPriorityManagerImpl> sSingleton;
static void PrefChangedCallback(const char* aPref, void* aClosure);
@ -179,8 +229,17 @@ private:
nsDataHashtable<nsUint64HashKey, nsRefPtr<ParticularProcessPriorityManager> >
mParticularManagers;
/** True if the main process is holding a high-priority wakelock */
bool mHighPriority;
/** Contains the PIDs of child processes holding high-priority wakelocks */
nsTHashtable<nsUint64HashKey> mHighPriorityChildIDs;
/** Contains a pseudo-LRU list of background processes */
ProcessLRUPool mBackgroundLRUPool;
/** Contains a pseudo-LRU list of foreground processes */
ProcessLRUPool mForegroundLRUPool;
};
/**
@ -224,7 +283,8 @@ class ParticularProcessPriorityManager MOZ_FINAL
{
~ParticularProcessPriorityManager();
public:
explicit ParticularProcessPriorityManager(ContentParent* aContentParent);
explicit ParticularProcessPriorityManager(ContentParent* aContentParent,
bool aFrozen = false);
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
@ -262,7 +322,9 @@ public:
void ScheduleResetPriority(const char* aTimeoutPref);
void ResetPriority();
void ResetPriorityNow();
void SetPriorityNow(ProcessPriority aPriority, uint32_t aBackgroundLRU = 0);
void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0);
void Freeze();
void Unfreeze();
void ShutDown();
@ -278,8 +340,10 @@ private:
ContentParent* mContentParent;
uint64_t mChildID;
ProcessPriority mPriority;
uint32_t mLRU;
bool mHoldsCPUWakeLock;
bool mHoldsHighPriorityWakeLock;
bool mFrozen;
/**
* Used to implement NameWithComma().
@ -289,48 +353,9 @@ private:
nsCOMPtr<nsITimer> mResetPriorityTimer;
};
class BackgroundProcessLRUPool MOZ_FINAL
{
public:
static BackgroundProcessLRUPool* Singleton();
/**
* Used to remove a ContentParent from background LRU pool when
* it is destroyed or its priority changed from BACKGROUND to others.
*/
void RemoveFromBackgroundLRUPool(ContentParent* aContentParent);
/**
* Used to add a ContentParent into background LRU pool when
* its priority changed to BACKGROUND from others.
*/
void AddIntoBackgroundLRUPool(ContentParent* aContentParent);
private:
static StaticAutoPtr<BackgroundProcessLRUPool> sSingleton;
int32_t mLRUPoolLevels;
int32_t mLRUPoolSize;
int32_t mLRUPoolAvailableIndex;
nsTArray<ContentParent*> mLRUPool;
uint32_t CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex);
nsresult UpdateAvailableIndexInLRUPool(
ContentParent* aContentParent,
int32_t aTargetIndex = -1);
void ShiftLRUPool();
void EnsureLRUPool();
BackgroundProcessLRUPool();
DISALLOW_EVIL_CONSTRUCTORS(BackgroundProcessLRUPool);
};
/* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
/* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
/* static */ bool ProcessPriorityManagerImpl::sFrozen = false;
/* static */ StaticRefPtr<ProcessPriorityManagerImpl>
ProcessPriorityManagerImpl::sSingleton;
@ -399,6 +424,8 @@ ProcessPriorityManagerImpl::GetSingleton()
ProcessPriorityManagerImpl::ProcessPriorityManagerImpl()
: mHighPriority(false)
, mBackgroundLRUPool(PROCESS_PRIORITY_BACKGROUND, 1)
, mForegroundLRUPool(PROCESS_PRIORITY_FOREGROUND, 0)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
RegisterWakeLockObserver(this);
@ -459,7 +486,7 @@ ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
uint64_t cpId = aContentParent->ChildID();
mParticularManagers.Get(cpId, &pppm);
if (!pppm) {
pppm = new ParticularProcessPriorityManager(aContentParent);
pppm = new ParticularProcessPriorityManager(aContentParent, sFrozen);
pppm->Init();
mParticularManagers.Put(cpId, pppm);
@ -473,13 +500,13 @@ ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
void
ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
ProcessPriority aPriority,
uint32_t aBackgroundLRU)
uint32_t aLRU)
{
MOZ_ASSERT(aContentParent);
nsRefPtr<ParticularProcessPriorityManager> pppm =
GetParticularProcessPriorityManager(aContentParent);
if (pppm) {
pppm->SetPriorityNow(aPriority, aBackgroundLRU);
pppm->SetPriorityNow(aPriority, aLRU);
}
}
@ -507,6 +534,10 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
nsRefPtr<ParticularProcessPriorityManager> pppm;
mParticularManagers.Get(childID, &pppm);
if (pppm) {
// Unconditionally remove the manager from the pools
mBackgroundLRUPool.Remove(pppm);
mForegroundLRUPool.Remove(pppm);
pppm->ShutDown();
mParticularManagers.Remove(childID);
@ -528,21 +559,32 @@ ProcessPriorityManagerImpl::NotifyProcessPriorityChanged(
ParticularProcessPriorityManager* aParticularManager,
ProcessPriority aOldPriority)
{
/* We're interested only in changes to/from FOREGROUND_HIGH as we use we
* need to track high priority processes so that we can react to their
* presence. */
ProcessPriority newPriority = aParticularManager->CurrentPriority();
bool isPreallocated = aParticularManager->IsPreallocated();
if (aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
aParticularManager->CurrentPriority() <
PROCESS_PRIORITY_FOREGROUND_HIGH) {
return;
if (newPriority == PROCESS_PRIORITY_BACKGROUND &&
aOldPriority != PROCESS_PRIORITY_BACKGROUND &&
!isPreallocated) {
mBackgroundLRUPool.Add(aParticularManager);
} else if (newPriority != PROCESS_PRIORITY_BACKGROUND &&
aOldPriority == PROCESS_PRIORITY_BACKGROUND &&
!isPreallocated) {
mBackgroundLRUPool.Remove(aParticularManager);
}
if (aParticularManager->CurrentPriority() >=
PROCESS_PRIORITY_FOREGROUND_HIGH) {
if (newPriority == PROCESS_PRIORITY_FOREGROUND &&
aOldPriority != PROCESS_PRIORITY_FOREGROUND) {
mForegroundLRUPool.Add(aParticularManager);
} else if (newPriority != PROCESS_PRIORITY_FOREGROUND &&
aOldPriority == PROCESS_PRIORITY_FOREGROUND) {
mForegroundLRUPool.Remove(aParticularManager);
}
if (newPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH &&
aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH) {
mHighPriorityChildIDs.PutEntry(aParticularManager->ChildID());
} else {
} else if (newPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
aOldPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
mHighPriorityChildIDs.RemoveEntry(aParticularManager->ChildID());
}
}
@ -565,18 +607,56 @@ ProcessPriorityManagerImpl::Notify(const WakeLockInformation& aInfo)
}
}
static PLDHashOperator
FreezeParticularProcessPriorityManagers(
const uint64_t& aKey,
nsRefPtr<ParticularProcessPriorityManager> aValue,
void* aUserData)
{
aValue->Freeze();
return PL_DHASH_NEXT;
}
void
ProcessPriorityManagerImpl::Freeze()
{
sFrozen = true;
mParticularManagers.EnumerateRead(&FreezeParticularProcessPriorityManagers,
nullptr);
}
static PLDHashOperator
UnfreezeParticularProcessPriorityManagers(
const uint64_t& aKey,
nsRefPtr<ParticularProcessPriorityManager> aValue,
void* aUserData)
{
aValue->Unfreeze();
return PL_DHASH_NEXT;
}
void
ProcessPriorityManagerImpl::Unfreeze()
{
sFrozen = false;
mParticularManagers.EnumerateRead(&UnfreezeParticularProcessPriorityManagers,
nullptr);
}
NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
nsIObserver,
nsITimerCallback,
nsISupportsWeakReference);
ParticularProcessPriorityManager::ParticularProcessPriorityManager(
ContentParent* aContentParent)
ContentParent* aContentParent, bool aFrozen)
: mContentParent(aContentParent)
, mChildID(aContentParent->ChildID())
, mPriority(PROCESS_PRIORITY_UNKNOWN)
, mLRU(0)
, mHoldsCPUWakeLock(false)
, mHoldsHighPriorityWakeLock(false)
, mFrozen(aFrozen)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
LOGP("Creating ParticularProcessPriorityManager.");
@ -937,51 +1017,32 @@ ParticularProcessPriorityManager::ComputePriority()
void
ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
uint32_t aBackgroundLRU)
uint32_t aLRU)
{
if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
MOZ_ASSERT(false);
return;
}
if (aBackgroundLRU > 0 &&
aPriority == PROCESS_PRIORITY_BACKGROUND &&
mPriority == PROCESS_PRIORITY_BACKGROUND) {
hal::SetProcessPriority(Pid(), mPriority, aBackgroundLRU);
nsPrintfCString ProcessPriorityWithBackgroundLRU("%s:%d",
ProcessPriorityToString(mPriority), aBackgroundLRU);
FireTestOnlyObserverNotification("process-priority-with-background-LRU-set",
ProcessPriorityWithBackgroundLRU.get());
}
if (!mContentParent ||
!ProcessPriorityManagerImpl::PrefsEnabled() ||
(mPriority == aPriority)) {
if (!ProcessPriorityManagerImpl::PrefsEnabled() ||
!mContentParent ||
mFrozen ||
((mPriority == aPriority) && (mLRU == aLRU))) {
return;
}
// If the prefs were disabled after this ParticularProcessPriorityManager was
// created, we can at least avoid any further calls to
// hal::SetProcessPriority. Supporting dynamic enabling/disabling of the
// ProcessPriorityManager is mostly for testing.
if (!ProcessPriorityManagerImpl::PrefsEnabled()) {
if ((mPriority == aPriority) && (mLRU != aLRU)) {
mLRU = aLRU;
hal::SetProcessPriority(Pid(), mPriority, aLRU);
nsPrintfCString processPriorityWithLRU("%s:%d",
ProcessPriorityToString(mPriority), aLRU);
FireTestOnlyObserverNotification("process-priority-with-LRU-set",
processPriorityWithLRU.get());
return;
}
if (aPriority == PROCESS_PRIORITY_BACKGROUND &&
mPriority != PROCESS_PRIORITY_BACKGROUND &&
!IsPreallocated()) {
ProcessPriorityManager::AddIntoBackgroundLRUPool(mContentParent);
}
if (aPriority != PROCESS_PRIORITY_BACKGROUND &&
mPriority == PROCESS_PRIORITY_BACKGROUND &&
!IsPreallocated()) {
ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
}
LOGP("Changing priority from %s to %s.",
ProcessPriorityToString(mPriority),
ProcessPriorityToString(aPriority));
@ -1006,6 +1067,19 @@ ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
ProcessPriorityToString(mPriority));
}
void
ParticularProcessPriorityManager::Freeze()
{
mFrozen = true;
}
void
ParticularProcessPriorityManager::Unfreeze()
{
mFrozen = false;
ResetPriorityNow();
}
void
ParticularProcessPriorityManager::ShutDown()
{
@ -1018,10 +1092,6 @@ ParticularProcessPriorityManager::ShutDown()
mResetPriorityTimer = nullptr;
}
if (mPriority == PROCESS_PRIORITY_BACKGROUND && !IsPreallocated()) {
ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
}
mContentParent = nullptr;
}
@ -1162,179 +1232,112 @@ ProcessPriorityManagerChild::CurrentProcessIsHighPriority()
mCachedPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH;
}
/* static */ StaticAutoPtr<BackgroundProcessLRUPool>
BackgroundProcessLRUPool::sSingleton;
/* static */ BackgroundProcessLRUPool*
BackgroundProcessLRUPool::Singleton()
ProcessLRUPool::ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias)
: mPriority(aPriority)
, mLRUPoolLevels(1)
, mBias(aBias)
{
if (!sSingleton) {
sSingleton = new BackgroundProcessLRUPool();
ClearOnShutdown(&sSingleton);
}
return sSingleton;
}
BackgroundProcessLRUPool::BackgroundProcessLRUPool()
{
EnsureLRUPool();
}
uint32_t
BackgroundProcessLRUPool::CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex)
{
// Set LRU level of each background process and maintain LRU buffer as below:
// Priority background : LRU0
// Priority background+1: LRU1, LRU2
// Priority background+2: LRU3, LRU4, LRU5, LRU6
// Priority background+3: LRU7, LRU8, LRU9, LRU10, LRU11, LRU12, LRU13, LRU14
// ...
// Priority background+L-1: 2^(number of background LRU pool levels - 1)
// (End of buffer)
return (uint32_t)(log((float)aBackgroundLRUPoolIndex) / log(2.0));
}
void
BackgroundProcessLRUPool::EnsureLRUPool()
{
// We set mBackgroundLRUPoolLevels according to our pref.
// We set mLRUPoolLevels according to our pref.
// This value is used to set background process LRU pool
if (!NS_SUCCEEDED(Preferences::GetInt(
"dom.ipc.processPriorityManager.backgroundLRUPoolLevels",
&mLRUPoolLevels))) {
mLRUPoolLevels = 1;
}
const char* str = ProcessPriorityToString(aPriority);
nsPrintfCString pref("dom.ipc.processPriorityManager.%s.LRUPoolLevels", str);
if (mLRUPoolLevels <= 0) {
MOZ_CRASH();
}
Preferences::GetUint(pref.get(), &mLRUPoolLevels);
// GonkHal defines OOM_ADJUST_MAX is 15 and b2g.js defines
// PROCESS_PRIORITY_BACKGROUND's oom_score_adj is 667 and oom_adj is 10.
// This means we can only have at most (15 -10 + 1) = 6 background LRU levels.
// See bug 822325 comment 49
MOZ_ASSERT(mLRUPoolLevels <= 6);
// Similarly we can have at most 4 foreground LRU levels. We should really be
// getting rid of oom_adj and just rely on oom_score_adj only which would
// lift this constraint.
MOZ_ASSERT(aPriority != PROCESS_PRIORITY_BACKGROUND || mLRUPoolLevels <= 6);
MOZ_ASSERT(aPriority != PROCESS_PRIORITY_FOREGROUND || mLRUPoolLevels <= 4);
// LRU pool size = 2 ^ (number of background LRU pool levels) - 1
mLRUPoolSize = (1 << mLRUPoolLevels) - 1;
mLRUPoolAvailableIndex = 0;
LOG("Making %s LRU pool with size(%d)", str, mLRUPoolSize);
}
LOG("Making background LRU pool with size(%d)", mLRUPoolSize);
uint32_t
ProcessLRUPool::CalculateLRULevel(uint32_t aLRU)
{
// This is used to compute the LRU adjustment for the specified LRU position.
// We use power-of-two groups with increasing adjustments that look like the
// following:
mLRUPool.InsertElementsAt(0, mLRUPoolSize, (ContentParent*)nullptr);
// Priority : LRU0, LRU1
// Priority+1: LRU2, LRU3
// Priority+2: LRU4, LRU5, LRU6, LRU7
// Priority+3: LRU8, LRU9, LRU10, LRU11, LRU12, LRU12, LRU13, LRU14, LRU15
// ...
// Priority+L-1: 2^(number of LRU pool levels - 1)
// (End of buffer)
// Biasing the input can be used to shift the assignment
int exp;
unused << frexp(static_cast<double>(aLRU), &exp);
uint32_t level = std::max(exp - 1, 0);
return std::min(mLRUPoolLevels - 1, level);
}
void
BackgroundProcessLRUPool::RemoveFromBackgroundLRUPool(
ContentParent* aContentParent)
ProcessLRUPool::Remove(ParticularProcessPriorityManager* aParticularManager)
{
for (int32_t i = 0; i < mLRUPoolSize; i++) {
if (mLRUPool[i]) {
if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) {
nsTArray<ParticularProcessPriorityManager*>::index_type index =
mLRUPool.IndexOf(aParticularManager);
mLRUPool[i] = nullptr;
LOG("Remove ChildID(%llu) from LRU pool", aContentParent->ChildID());
// After we remove this ContentParent from LRU pool, we still need to
// update the available index if the index of removed one is less than
// the available index we already have.
UpdateAvailableIndexInLRUPool(aContentParent, i);
break;
}
}
}
}
nsresult
BackgroundProcessLRUPool::UpdateAvailableIndexInLRUPool(
ContentParent* aContentParent,
int32_t aTargetIndex)
{
// If we specify which index we want to assign to mLRUPoolAvailableIndex,
// We have to make sure the index in LRUPool doesn't point to any
// ContentParent.
if (aTargetIndex >= 0 && aTargetIndex < mLRUPoolSize &&
aTargetIndex < mLRUPoolAvailableIndex &&
!mLRUPool[aTargetIndex]) {
mLRUPoolAvailableIndex = aTargetIndex;
return NS_OK;
}
// When we didn't specify any legal aTargetIndex, then we just check
// whether current mLRUPoolAvailableIndex points to any ContentParent or not.
if (mLRUPoolAvailableIndex >= 0 && mLRUPoolAvailableIndex < mLRUPoolSize &&
!(mLRUPool[mLRUPoolAvailableIndex])) {
return NS_OK;
}
// Both above way failed. So now we have to find proper value
// for mLRUPoolAvailableIndex.
// We are looking for an available index. We only shift process with
// LRU less than the available index should have, so we stop update
// mLRUPoolAvailableIndex from the for loop once we got a candidate.
mLRUPoolAvailableIndex = -1;
for (int32_t i = 0; i < mLRUPoolSize; i++) {
if (mLRUPool[i]) {
if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) {
LOG("ChildID(%llu) already in LRU pool", aContentParent->ChildID());
MOZ_ASSERT(false);
return NS_ERROR_UNEXPECTED;
}
continue;
} else {
if (mLRUPoolAvailableIndex == -1) {
mLRUPoolAvailableIndex = i;
}
}
}
// If the LRUPool is already full, mLRUPoolAvailableIndex is still -1 after
// above loop finished. We should set mLRUPoolAvailableIndex
// to mLRUPoolSize - 1 in this case. Here uses the mod operator to do it:
// New mLRUPoolAvailableIndex either equals old mLRUPoolAvailableIndex, or
// mLRUPoolSize - 1 if old mLRUPoolAvailableIndex is -1.
mLRUPoolAvailableIndex =
(mLRUPoolAvailableIndex + mLRUPoolSize) % mLRUPoolSize;
return NS_OK;
}
void
BackgroundProcessLRUPool::ShiftLRUPool()
{
for (int32_t i = mLRUPoolAvailableIndex; i > 0; i--) {
mLRUPool[i] = mLRUPool[i - 1];
// Check whether i+1 is power of Two.
// If so, then it crossed a LRU group boundary and
// we need to assign its new process priority LRU.
if (!((i + 1) & i)) {
ProcessPriorityManagerImpl::GetSingleton()->SetProcessPriority(
mLRUPool[i], PROCESS_PRIORITY_BACKGROUND, CalculateLRULevel(i + 1));
}
}
}
void
BackgroundProcessLRUPool::AddIntoBackgroundLRUPool(
ContentParent* aContentParent)
{
// We have to make sure that we have correct available index in LRU pool
if (!NS_SUCCEEDED(
UpdateAvailableIndexInLRUPool(aContentParent))) {
if (index == nsTArray<ParticularProcessPriorityManager*>::NoIndex) {
return;
}
mLRUPool.RemoveElementAt(index);
AdjustLRUValues(index, /* removed */ true);
LOG("Remove ChildID(%" PRIu64 ") from %s LRU pool",
static_cast<uint64_t>(aParticularManager->ChildID()),
ProcessPriorityToString(mPriority));
}
/*
* Adjust the LRU values of all the processes in an LRU pool. When true the
* `removed` parameter indicates that the processes were shifted left because
* an element was removed; otherwise it means the elements were shifted right
* as an element was added.
*/
void
ProcessLRUPool::AdjustLRUValues(
nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
bool removed)
{
uint32_t adj = (removed ? 1 : 0) + mBias;
for (nsTArray<ParticularProcessPriorityManager*>::index_type i = aStart;
i < mLRUPool.Length();
i++) {
/* Check whether i is a power of two. If so, then it crossed a LRU group
* boundary and we need to assign its new process priority LRU. Note that
* depending on the direction and the bias this test will pick different
* elements. */
if (((i + adj) & (i + adj - 1)) == 0) {
mLRUPool[i]->SetPriorityNow(mPriority, CalculateLRULevel(i + mBias));
}
}
}
void
ProcessLRUPool::Add(ParticularProcessPriorityManager* aParticularManager)
{
// Shift the list in the pool, so we have room at index 0 for the newly added
// ContentParent
ShiftLRUPool();
// manager
mLRUPool.InsertElementAt(0, aParticularManager);
AdjustLRUValues(1, /* removed */ false);
mLRUPool[0] = aContentParent;
LOG("Add ChildID(%llu) into LRU pool", aContentParent->ChildID());
LOG("Add ChildID(%" PRIu64 ") into %s LRU pool",
static_cast<uint64_t>(aParticularManager->ChildID()),
ProcessPriorityToString(mPriority));
}
} // anonymous namespace
@ -1361,31 +1364,6 @@ ProcessPriorityManager::SetProcessPriority(ContentParent* aContentParent,
}
}
/* static */ void
ProcessPriorityManager::RemoveFromBackgroundLRUPool(
ContentParent* aContentParent)
{
MOZ_ASSERT(aContentParent);
BackgroundProcessLRUPool* singleton =
BackgroundProcessLRUPool::Singleton();
if (singleton) {
singleton->RemoveFromBackgroundLRUPool(aContentParent);
}
}
/* static */ void
ProcessPriorityManager::AddIntoBackgroundLRUPool(ContentParent* aContentParent)
{
MOZ_ASSERT(aContentParent);
BackgroundProcessLRUPool* singleton =
BackgroundProcessLRUPool::Singleton();
if (singleton) {
singleton->AddIntoBackgroundLRUPool(aContentParent);
}
}
/* static */ bool
ProcessPriorityManager::CurrentProcessIsForeground()
{
@ -1407,4 +1385,24 @@ ProcessPriorityManager::AnyProcessHasHighPriority()
}
}
/* static */ void
ProcessPriorityManager::Freeze()
{
ProcessPriorityManagerImpl* singleton =
ProcessPriorityManagerImpl::GetSingleton();
if (singleton) {
singleton->Freeze();
}
}
/* static */ void
ProcessPriorityManager::Unfreeze()
{
ProcessPriorityManagerImpl* singleton =
ProcessPriorityManagerImpl::GetSingleton();
if (singleton) {
singleton->Unfreeze();
}
}
} // namespace mozilla

View File

@ -75,16 +75,15 @@ public:
static bool AnyProcessHasHighPriority();
/**
* Used to remove a ContentParent from background LRU pool when
* it is destroyed or its priority changed from BACKGROUND to others.
* Prevents processes from changing priority until unfrozen.
*/
static void RemoveFromBackgroundLRUPool(dom::ContentParent* aContentParent);
static void Freeze();
/**
* Used to add a ContentParent into background LRU pool when
* its priority changed to BACKGROUND from others.
* Allow process' priorities to change again. This will immediately adjust
* processes whose priority change did not happen because of the freeze.
*/
static void AddIntoBackgroundLRUPool(dom::ContentParent* aContentParent);
static void Unfreeze();
private:
ProcessPriorityManager();

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
process_error.xul
process_error_contentscript.js

View File

@ -51,7 +51,7 @@ function setPref(pref, value) {
setPref('dom.ipc.processPriorityManager.testMode', true);
setPref('dom.ipc.processPriorityManager.enabled', true);
setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2);
function runTest()
{

View File

@ -51,7 +51,7 @@ function setPref(pref, value) {
setPref('dom.ipc.processPriorityManager.testMode', true);
setPref('dom.ipc.processPriorityManager.enabled', true);
setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2);
setPref('dom.ipc.processPrelaunch.testMode', true); // For testing deadlock.
function runTest()

View File

@ -956,7 +956,8 @@ public:
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0),
mDroppedFrames(0) {}
mDroppedFrames(0),
mCorruptFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
@ -983,7 +984,13 @@ public:
// Number of frames that have been skipped because they have missed their
// compoisition deadline.
uint32_t GetDroppedFrames() {
return mDroppedFrames;
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDroppedFrames + mCorruptFrames;
}
uint32_t GetCorruptedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mCorruptFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
@ -1005,6 +1012,11 @@ public:
++mPresentedFrames;
}
void NotifyCorruptFrame() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mCorruptFrames;
}
private:
// ReentrantMonitor to protect access of playback statistics.
@ -1023,6 +1035,8 @@ public:
uint32_t mPresentedFrames;
uint32_t mDroppedFrames;
uint32_t mCorruptFrames;
};
// Return the frame decode/paint related statistics.

View File

@ -260,6 +260,8 @@ public:
// decoding.
virtual bool VideoIsHardwareAccelerated() const { return false; }
virtual void DisableHardwareAcceleration() {}
protected:
virtual ~MediaDecoderReader();

View File

@ -239,6 +239,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDecodeToSeekTarget(false),
mCurrentTimeBeforeSeek(0),
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
mCorruptFrames(30),
mDisabledHardwareAcceleration(false),
mDecodingFrozenAtStateDecoding(false),
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false)
@ -2888,6 +2890,23 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
if (container) {
if (aData->mImage && !aData->mImage->IsValid()) {
MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
frameStats.NotifyCorruptFrame();
// If more than 10% of the last 30 frames have been corrupted, then try disabling
// hardware acceleration. We use 10 as the corrupt value because RollingMean<>
// only supports integer types.
mCorruptFrames.insert(10);
if (!mDisabledHardwareAcceleration &&
mReader->VideoIsHardwareAccelerated() &&
frameStats.GetPresentedFrames() > 30 &&
mCorruptFrames.mean() >= 1 /* 10% */) {
DecodeTaskQueue()->Dispatch(NS_NewRunnableMethod(mReader, &MediaDecoderReader::DisableHardwareAcceleration));
mDisabledHardwareAcceleration = true;
}
} else {
mCorruptFrames.insert(0);
}
container->SetCurrentFrame(ThebesIntSize(aData->mDisplay), aData->mImage,
aTarget);
MOZ_ASSERT(container->GetFrameDelay() >= 0 || IsRealTime());

View File

@ -90,6 +90,7 @@ hardware (via AudioStream).
#include "MediaDecoderOwner.h"
#include "MediaMetadataManager.h"
#include "MediaDecoderStateMachineScheduler.h"
#include "mozilla/RollingMean.h"
class nsITimer;
@ -1135,6 +1136,10 @@ protected:
MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
mozilla::RollingMean<uint32_t, uint32_t> mCorruptFrames;
bool mDisabledHardwareAcceleration;
// mDecodingFrozenAtStateDecoding: turn on/off at
// SetDormant/Seek,Play.
bool mDecodingFrozenAtStateDecoding;

View File

@ -35,7 +35,6 @@ public:
virtual bool IsDormantNeeded() MOZ_OVERRIDE;
virtual void AllocateMediaResources() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
private:
@ -44,6 +43,8 @@ private:
// will set mError accordingly.
nsresult CreateDecoder();
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
nsRefPtr<PlatformDecoderModule> mPDM;
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
@ -92,18 +93,21 @@ AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
return NS_ERROR_FAILURE;
}
nsresult rv;
if (!mDecoder) {
// It is not possible to create an AVCC H264 decoder without SPS.
// As such, creation will fail if the extra_data just extracted doesn't
// contain a SPS.
nsresult rv = CreateDecoderAndInit(aSample);
rv = CreateDecoderAndInit(aSample);
if (rv == NS_ERROR_NOT_INITIALIZED) {
// We are missing the required SPS to create the decoder.
// Ignore for the time being, the MP4Sample will be dropped.
return NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = CheckForSPSChange(aSample);
}
NS_ENSURE_SUCCESS(rv, rv);
aSample->extra_data = mCurrentConfig.extra_data;
@ -149,33 +153,21 @@ AVCCMediaDataDecoder::IsWaitingMediaResources()
bool
AVCCMediaDataDecoder::IsDormantNeeded()
{
if (mDecoder) {
return mDecoder->IsDormantNeeded();
}
return MediaDataDecoder::IsDormantNeeded();
return true;
}
void
AVCCMediaDataDecoder::AllocateMediaResources()
{
if (mDecoder) {
mDecoder->AllocateMediaResources();
}
// Nothing to do, decoder will be allocated on the fly when required.
}
void
AVCCMediaDataDecoder::ReleaseMediaResources()
{
if (mDecoder) {
mDecoder->ReleaseMediaResources();
}
}
void
AVCCMediaDataDecoder::ReleaseDecoder()
{
if (mDecoder) {
mDecoder->ReleaseDecoder();
mDecoder->Shutdown();
mDecoder = nullptr;
}
}
@ -186,6 +178,8 @@ AVCCMediaDataDecoder::CreateDecoder()
// nothing found yet, will try again later
return NS_ERROR_NOT_INITIALIZED;
}
UpdateConfigFromExtraData(mCurrentConfig.extra_data);
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
mLayersBackend,
mImageContainer,
@ -206,15 +200,7 @@ AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
return NS_ERROR_NOT_INITIALIZED;
}
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(extra_data, spsdata) &&
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
mCurrentConfig.image_width = spsdata.pic_width;
mCurrentConfig.image_height = spsdata.pic_height;
mCurrentConfig.display_width = spsdata.display_width;
mCurrentConfig.display_height = spsdata.display_height;
}
mCurrentConfig.extra_data = extra_data;
UpdateConfigFromExtraData(extra_data);
nsresult rv = CreateDecoder();
NS_ENSURE_SUCCESS(rv, rv);
@ -230,6 +216,37 @@ AVCCMediaDataDecoder::IsHardwareAccelerated() const
return MediaDataDecoder::IsHardwareAccelerated();
}
nsresult
AVCCMediaDataDecoder::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
{
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
mCurrentConfig.extra_data)) {
return NS_OK;
}
// The SPS has changed, signal to flush the current decoder and create a
// new one.
mDecoder->Flush();
ReleaseMediaResources();
return CreateDecoderAndInit(aSample);
}
void
AVCCMediaDataDecoder::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
{
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
mCurrentConfig.image_width = spsdata.pic_width;
mCurrentConfig.image_height = spsdata.pic_height;
mCurrentConfig.display_width = spsdata.display_width;
mCurrentConfig.display_height = spsdata.display_height;
}
mCurrentConfig.extra_data = aExtraData;
}
// AVCCDecoderModule
AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM)

View File

@ -158,7 +158,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mIsEncrypted(false)
, mIndexReady(false)
, mDemuxerMonitor("MP4 Demuxer")
#if defined(XP_WIN)
#if defined(MP4_READER_DORMANT_HEURISTIC)
, mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
#endif
{
@ -295,18 +295,13 @@ private:
#endif
void MP4Reader::RequestCodecResource() {
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources();
}
#endif
}
bool MP4Reader::IsWaitingOnCodecResource() {
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
#endif
return false;
}
bool MP4Reader::IsWaitingOnCDMResource() {
@ -582,6 +577,26 @@ MP4Reader::GetNextKeyframeTime()
return mVideo.mTrackDemuxer->GetNextKeyframeTime();
}
void
MP4Reader::DisableHardwareAcceleration()
{
if (HasVideo() && !mIsEncrypted && mSharedDecoderManager) {
mPlatform->DisableHardwareAcceleration();
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
if (!mSharedDecoderManager->Recreate(mPlatform, video, mLayersBackendType, mDecoder->GetImageContainer())) {
MonitorAutoLock mon(mVideo.mMonitor);
mVideo.mError = true;
if (mVideo.HasPromise()) {
mVideo.RejectPromise(DECODE_ERROR, __func__);
}
} else {
MonitorAutoLock lock(mVideo.mMonitor);
ScheduleUpdate(kVideo);
}
}
}
bool
MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
{
@ -624,7 +639,9 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
MonitorAutoLock lock(mVideo.mMonitor);
nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
if (eos) {
if (mVideo.mError) {
mVideo.mPromise.Reject(DECODE_ERROR, __func__);
} else if (eos) {
mVideo.mPromise.Reject(END_OF_STREAM, __func__);
} else {
ScheduleUpdate(kVideo);
@ -1059,9 +1076,9 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
bool MP4Reader::IsDormantNeeded()
{
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
#if defined(MP4_READER_DORMANT)
return
#if defined(XP_WIN)
#if defined(MP4_READER_DORMANT_HEURISTIC)
mDormantEnabled &&
#endif
mVideo.mDecoder &&
@ -1072,7 +1089,6 @@ bool MP4Reader::IsDormantNeeded()
void MP4Reader::ReleaseMediaResources()
{
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
// Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline.
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
@ -1082,16 +1098,13 @@ void MP4Reader::ReleaseMediaResources()
if (mVideo.mDecoder) {
mVideo.mDecoder->ReleaseMediaResources();
}
#endif
}
void MP4Reader::NotifyResourcesStatusChanged()
{
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if (mDecoder) {
mDecoder->NotifyWaitingForResourcesStatusChanged();
}
#endif
}
void
@ -1108,7 +1121,7 @@ MP4Reader::SetIdle()
void
MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager)
{
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
#if !defined(MOZ_WIDGET_ANDROID)
mSharedDecoderManager = aManager;
#endif
}

View File

@ -27,6 +27,18 @@ typedef std::deque<MediaSample*> MediaSampleQueue;
class MP4Stream;
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT
#else
#undef MP4_READER_DORMANT
#endif
#if defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT_HEURISTIC
#else
#undef MP4_READER_DORMANT_HEURISTIC
#endif
class MP4Reader MOZ_FINAL : public MediaDecoderReader
{
typedef mp4_demuxer::TrackType TrackType;
@ -84,6 +96,8 @@ public:
virtual bool VideoIsHardwareAccelerated() const MOZ_OVERRIDE;
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE;
private:
bool InitDemuxer();
@ -275,7 +289,7 @@ private:
Monitor mDemuxerMonitor;
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
#if defined(XP_WIN)
#if defined(MP4_READER_DORMANT_HEURISTIC)
const bool mDormantEnabled;
#endif
};

View File

@ -135,6 +135,8 @@ public:
// Indicates if the video decoder requires AVCC format.
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
virtual void DisableHardwareAcceleration() {}
protected:
PlatformDecoderModule() {}
virtual ~PlatformDecoderModule() {}
@ -244,7 +246,6 @@ public:
};
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
virtual void ReleaseDecoder() {}
virtual bool IsHardwareAccelerated() const { return false; }
};

View File

@ -93,6 +93,22 @@ SharedDecoderManager::CreateVideoDecoder(
return proxy.forget();
}
bool
SharedDecoderManager::Recreate(PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer)
{
mDecoder->Flush();
mDecoder->Shutdown();
mDecoder = aPDM->CreateVideoDecoder(aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback);
if (!mDecoder) {
return false;
}
nsresult rv = mDecoder->Init();
return rv == NS_OK;
}
void
SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
{
@ -232,14 +248,6 @@ SharedDecoderProxy::ReleaseMediaResources()
}
}
void
SharedDecoderProxy::ReleaseDecoder()
{
if (mManager->mActiveProxy == this) {
mManager->mDecoder->ReleaseMediaResources();
}
}
bool
SharedDecoderProxy::IsHardwareAccelerated() const
{

View File

@ -40,6 +40,11 @@ public:
friend class SharedDecoderProxy;
friend class SharedDecoderCallback;
bool Recreate(PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer);
private:
virtual ~SharedDecoderManager();
void DrainComplete();
@ -69,7 +74,6 @@ public:
virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
virtual bool IsDormantNeeded() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
friend class SharedDecoderManager;

View File

@ -402,7 +402,7 @@ AppleVDADecoder::InitializeSession()
&mDecoder);
if (rv != noErr) {
NS_ERROR("AppleVDADecoder: Couldn't create decoder!");
NS_WARNING("AppleVDADecoder: Couldn't create hardware VDA decoder");
return NS_ERROR_FAILURE;
}
@ -504,7 +504,6 @@ AppleVDADecoder::CreateVDADecoder(
nsRefPtr<AppleVDADecoder> decoder =
new AppleVDADecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer);
if (NS_FAILED(decoder->Init())) {
NS_ERROR("AppleVDADecoder an error occurred");
return nullptr;
}
return decoder.forget();

View File

@ -37,6 +37,11 @@ public:
bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE;
bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE
{
sDXVAEnabled = false;
}
// Accessors that report whether we have the required MFTs available
// on the system to play various codecs. Windows Vista doesn't have the
// H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"

View File

@ -175,12 +175,6 @@ WMFMediaDataDecoder::ReleaseMediaResources()
#endif
}
void
WMFMediaDataDecoder::ReleaseDecoder()
{
ReleaseMediaResources();
}
bool
WMFMediaDataDecoder::IsHardwareAccelerated() const {
return mMFTManager && mMFTManager->IsHardwareAccelerated();

View File

@ -77,7 +77,6 @@ public:
virtual bool IsDormantNeeded() { return true; };
virtual void AllocateMediaResources() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
private:

View File

@ -84,6 +84,12 @@ public:
void NotifyTimeRangesChanged();
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE {
if (GetVideoReader()) {
GetVideoReader()->DisableHardwareAcceleration();
}
}
// We can't compute a proper start time since we won't necessarily
// have the first frame of the resource available. This does the same
// as chrome/blink and assumes that we always start at t=0.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |bipbop-cenc*|. To
generate the bipbop-cenc files, run the following commands:
Encrypt bipbop-no-edts.mp4 with the keys specified in this file,
and output to |bipbop-cenc-{video,audio}.mp4|
MP4Box -crypt bipbop-frag-cenc.xml -rem 2 -out bipbop-cenc-video.mp4 bipbop-no-edts.mp4
MP4Box -crypt bipbop-frag-cenc.xml -rem 1 -out bipbop-cenc-audio.mp4 bipbop-no-edts.mp4
Fragment |bipbop-cenc-*.mp4| into 500ms segments:
MP4Box -dash 500 -rap -segment-name bipbop-cenc-video -subsegs-per-sidx 5 bipbop-cenc-video.mp4
MP4Box -dash 500 -rap -segment-name bipbop-cenc-audio -subsegs-per-sidx 5 bipbop-cenc-audio.mp4
The above command will generate a set of fragments in |bipbop-cenc-{video,audio}*.m4s
and |bipbop-cenc-{video,audio}init.mp4| containing just the init segment.
To cut down the duration, we throw out all but the first 3 audio & 2 video segments:
rm bipbop-cenc-audio{[^123],[123][^.]}.m4s
rm bipbop-cenc-video{[^12],[12][^.]}.m4s
MP4Box will also have generated some *.mpd files we don't need:
rm bipbop-cenc-*.mpd
Delete intermediate encrypted files:
rm bipbop-cenc-{audio,video}.mp4
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 2 -->
<BS bits="32" value="2" />
<!-- KeyID -->
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d037e571d037e571d037e571d03"
value="0x7e5733337e5733337e5733337e573333" />
</CrypTrack>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d047e571d047e571d047e571d04"
value="0x7e5744447e5744447e5744447e574444" />
</CrypTrack>
</GPACDRM>

Binary file not shown.

View File

@ -1,6 +1,7 @@
#Media chrome tests
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
basic.vtt
seek.webm

View File

@ -73,6 +73,35 @@ function Log(token, msg) {
info(TimeStamp(token) + " " + msg);
}
function TimeRangesToString(trs)
{
var l = trs.length;
if (l === 0) { return "-"; }
var s = "";
var i = 0;
for (;;) {
s += trs.start(i) + "-" + trs.end(i);
if (++i === l) { return s; }
s += ",";
}
}
function SourceBufferToString(sb)
{
return ("SourceBuffer{"
+ "AppendMode=" + (sb.AppendMode || "-")
+ ", updating=" + (sb.updating ? "true" : "false")
+ ", buffered=" + TimeRangesToString(sb.buffered)
+ ", audioTracks=" + (sb.audioTracks ? sb.audioTracks.length : "-")
+ ", videoTracks=" + (sb.videoTracks ? sb.videoTracks.length : "-")
+ "}");
}
function SourceBufferListToString(sbl)
{
return "SourceBufferList[" + sbl.map(SourceBufferToString).join(", ") + "]";
}
function UpdateSessionFunc(test, token, sessionType, resolve, reject) {
return function(ev) {
var msgStr = ArrayBufferToString(ev.message);
@ -186,6 +215,118 @@ function PlayFragmented(test, elem, token)
});
}
function AppendTrack(test, ms, track, token)
{
return new Promise(function(resolve, reject) {
var sb;
var curFragment = 0;
var resolved = false;
var fragmentFile;
function addNextFragment() {
if (curFragment >= track.fragments.length) {
Log(token, track.name + ": end of track");
resolve();
resolved = true;
return;
}
fragmentFile = MaybeCrossOriginURI(test, track.fragments[curFragment++]);
var req = new XMLHttpRequest();
req.open("GET", fragmentFile);
req.responseType = "arraybuffer";
req.addEventListener("load", function() {
Log(token, track.name + ": fetch of " + fragmentFile + " complete, appending");
sb.appendBuffer(new Uint8Array(req.response));
});
req.addEventListener("error", function(){info(token + " error fetching " + fragmentFile);});
req.addEventListener("abort", function(){info(token + " aborted fetching " + fragmentFile);});
Log(token, track.name + ": addNextFragment() fetching next fragment " + fragmentFile);
req.send(null);
}
Log(token, track.name + ": addSourceBuffer(" + track.type + ")");
sb = ms.addSourceBuffer(track.type);
sb.addEventListener("updateend", function() {
if (ms.readyState == "ended") {
/* We can get another updateevent as a result of calling ms.endOfStream() if
the highest end time of our source buffers is different from that of the
media source duration. Due to bug 1065207 this can happen because of
inaccuracies in the frame duration calculations. Check if we are already
"ended" and ignore the update event */
Log(token, track.name + ": updateend when readyState already 'ended'");
if (!resolved) {
// Needed if decoder knows this was the last fragment and ended by itself.
Log(token, track.name + ": but promise not resolved yet -> end of track");
resolve();
resolved = true;
}
return;
}
Log(token, track.name + ": updateend for " + fragmentFile + ", " + SourceBufferToString(sb));
addNextFragment();
});
addNextFragment();
});
}
function PlayMultiTrack(test, elem, token)
{
if (!test.tracks) {
ok(false, token + " test does not have a tracks list");
return Promise.reject();
}
var ms = new MediaSource();
elem.src = URL.createObjectURL(ms);
return new Promise(function (resolve, reject) {
var firstOpen = true;
ms.addEventListener("sourceopen", function () {
if (!firstOpen) {
Log(token, "sourceopen again?");
return;
}
firstOpen = false;
Log(token, "sourceopen");
return Promise.all(test.tracks.map(function(track) {
return AppendTrack(test, ms, track, token);
})).then(function(){
Log(token, "end of stream");
ms.endOfStream();
resolve();
});
})
});
}
// Returns a promise that is resolved when the media element is ready to have
// its play() function called; when it's loaded MSE fragments, or once the load
// has started for non-MSE video.
function LoadTest(test, elem, token)
{
if (test.fragments) {
// A |fragments| array indicates that this is an MSE test case with one track.
return PlayFragmented(test, elem, token);
}
if (test.tracks) {
// A |tracks| array indicates that this is an MSE test case with multiple tracks.
return PlayMultiTrack(test, elem, token);
}
// This file isn't fragmented; won't set the media source normally because
// EME doesn't support non-MSE source.
ok(false, token + " test does not have a fragments or tracks list");
return Promise.reject();
}
function SetupEME(test, token, params)
{
var v = document.createElement("video");
@ -208,12 +349,23 @@ function SetupEME(test, token, params)
? params.onSetKeysFail
: bail(token + " Failed to set MediaKeys on <video> element");
var firstEncrypted = true;
v.addEventListener("encrypted", function(ev) {
Log(token, "got encrypted event");
if (!firstEncrypted) {
// TODO: Better way to handle 'encrypted'?
// Maybe wait for metadataloaded and all expected 'encrypted's?
Log(token, "got encrypted event again, initDataType=" + ev.initDataType);
return;
}
firstEncrypted = false;
Log(token, "got encrypted event, initDataType=" + ev.initDataType);
var options = [
{
initDataType: ev.initDataType,
videoType: test.type,
audioType: test.type,
}
];

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |gizmo-frag-cenc*|. To
generate the gizmo-frag-cenc files, run the following commands:
Encrypt gizmo.mp4 with the keys specified in this file, and output to |gizmo-cenc.mp4|
MP4Box -crypt gizmo-frag-cenc.xml -out gizmo-cenc.mp4 gizmo.mp4
Fragment |gizmo-cenc.mp4| into 1000ms segments:
MP4Box -dash 1000 -rap -segment-name gizmo-frag-cenc -subsegs-per-sidx 5 -rem 2 gizmo-cenc.mp4
The above command will generate a set of fragments in |gizmo-frag-cenc*.m4s|
and a single |gizmo-frag-cencinit.mp4| containing just the init segment.
To cut down the duration, we throw out all but the first two segments:
rm gizmo-frag-cenc[^12].m4s
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 2 -->
<BS bits="32" value="2" />
<!-- KeyID -->
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d037e571d037e571d037e571d03"
value="0x7e5733337e5733337e5733337e573333" />
</CrypTrack>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d047e571d047e571d047e571d04"
value="0x7e5744447e5744447e5744447e574444" />
</CrypTrack>
</GPACDRM>

Binary file not shown.

Binary file not shown.

View File

@ -646,33 +646,100 @@ var gMetadataTests = [
// Test files for Encrypted Media Extensions
var gEMETests = [
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:2.00,
duration:1.60,
},
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:2.00,
crossOrigin:true,
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
tracks: [
{
name:"audio",
type:"audio/mp4; codecs=\"mp4a.40.2\"",
fragments:[ "bipbop-cenc-audioinit.mp4",
"bipbop-cenc-audio1.m4s",
"bipbop-cenc-audio2.m4s",
"bipbop-cenc-audio3.m4s",
],
},
{
name:"video",
type:"video/mp4; codecs=\"avc1.64000d\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
},
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
tracks: [
{
name:"audio",
type:"audio/mp4; codecs=\"mp4a.40.2\"",
fragments:[ "bipbop-cenc-audioinit.mp4",
"bipbop-cenc-audio1.m4s",
"bipbop-cenc-audio2.m4s",
"bipbop-cenc-audio3.m4s",
],
},
{
name:"video",
type:"video/mp4; codecs=\"avc1.64000d\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
},
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
crossOrigin:true,
duration:1.60,
},
];
var gEMENonFragmentedTests = [
var gEMENonMSEFailTests = [
{
name:"short-cenc.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
@ -729,6 +796,10 @@ function getMajorMimeType(mimetype) {
// Force releasing decoder to avoid timeout in waiting for decoding resource.
function removeNodeAndSource(n) {
n.remove();
// Clearing mozSrcObject and/or src will actually set them to some default
// URI that will fail to load, so make sure we don't produce a spurious
// bailing error.
n.onerror = null;
// reset |mozSrcObject| first since it takes precedence over |src|.
n.mozSrcObject = null;
n.src = "";

View File

@ -45,6 +45,13 @@ support-files =
beta-phrasebook.ogg^headers^
big.wav
big.wav^headers^
bipbop-cenc-audio1.m4s
bipbop-cenc-audio2.m4s
bipbop-cenc-audio3.m4s
bipbop-cenc-audioinit.mp4
bipbop-cenc-video1.m4s
bipbop-cenc-video2.m4s
bipbop-cenc-videoinit.mp4
bogus.duh
bogus.ogv
bogus.ogv^headers^
@ -141,9 +148,6 @@ support-files =
dynamic_redirect.sjs
dynamic_resource.sjs
eme.js
gizmo-frag-cenc1.m4s
gizmo-frag-cenc2.m4s
gizmo-frag-cencinit.mp4
file_access_controls.html
fragment_noplay.js
fragment_play.js
@ -369,7 +373,7 @@ skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'go
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || (os == 'win' && !debug) # bug 1043403, bug 1057908, bug 1140675
[test_eme_non_fragmented.html]
[test_eme_non_mse_fails.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
#[test_eme_obs_notification.html]
#skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908

View File

@ -38,7 +38,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -84,7 +84,7 @@ function startTest(test, token)
}
function beginTest() {
manager.runTests(gEMENonFragmentedTests, startTest);
manager.runTests(gEMENonMSEFailTests, startTest);
}
var prefs = [

View File

@ -52,7 +52,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -147,7 +147,7 @@ function startTest(test, token)
}
);
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -88,7 +88,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token)
LoadTest(test, v, token)
.then(function() {
v.play();
}).catch(function() {

View File

@ -32,7 +32,7 @@ function startTest(test, token)
ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail");
});
manager.started(case1token);
PlayFragmented(test, v1, case1token);
LoadTest(test, v1, case1token);
// Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
@ -51,7 +51,7 @@ function startTest(test, token)
manager.finished(case2token);
});
manager.started(case2token);
PlayFragmented(test, v2, case2token);
LoadTest(test, v2, case2token);
// Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
@ -69,7 +69,7 @@ function startTest(test, token)
manager.finished(case3token);
});
manager.started(case3token);
PlayFragmented(test, v3, case3token);
LoadTest(test, v3, case3token);
}
function beginTest() {

View File

@ -21,7 +21,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode, AudioNode,
mThreshold,
mKnee,
mRatio,
mReduction,
mAttack,
mRelease)
@ -173,9 +172,7 @@ private:
node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
}
if (node) {
AudioParam* reduction = node->Reduction();
reduction->CancelAllEvents();
reduction->SetValue(mReduction);
node->SetReduction(mReduction);
}
return NS_OK;
}
@ -207,7 +204,7 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
, mThreshold(new AudioParam(this, SendThresholdToStream, -24.f))
, mKnee(new AudioParam(this, SendKneeToStream, 30.f))
, mRatio(new AudioParam(this, SendRatioToStream, 12.f))
, mReduction(new AudioParam(this, Callback, 0.f))
, mReduction(0)
, mAttack(new AudioParam(this, SendAttackToStream, 0.003f))
, mRelease(new AudioParam(this, SendReleaseToStream, 0.25f))
{

View File

@ -40,11 +40,6 @@ public:
return mRatio;
}
AudioParam* Reduction() const
{
return mReduction;
}
AudioParam* Attack() const
{
return mAttack;
@ -56,6 +51,11 @@ public:
return mRelease;
}
float Reduction() const
{
return mReduction;
}
virtual const char* NodeType() const MOZ_OVERRIDE
{
return "DynamicsCompressorNode";
@ -64,6 +64,12 @@ public:
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
void SetReduction(float aReduction)
{
MOZ_ASSERT(NS_IsMainThread());
mReduction = aReduction;
}
protected:
virtual ~DynamicsCompressorNode();
@ -78,7 +84,7 @@ private:
nsRefPtr<AudioParam> mThreshold;
nsRefPtr<AudioParam> mKnee;
nsRefPtr<AudioParam> mRatio;
nsRefPtr<AudioParam> mReduction;
float mReduction;
nsRefPtr<AudioParam> mAttack;
nsRefPtr<AudioParam> mRelease;
};

View File

@ -1,3 +1,4 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_AudioNodeDevtoolsAPI.html]

View File

@ -16,21 +16,15 @@ function near(a, b, msg) {
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var destination = context.destination;
var source = context.createBufferSource();
var osc = context.createOscillator();
var sp = context.createScriptProcessor();
var compressor = context.createDynamicsCompressor();
source.buffer = buffer;
source.connect(compressor);
compressor.connect(destination);
osc.connect(compressor);
osc.connect(sp);
compressor.connect(context.destination);
is(compressor.channelCount, 2, "compressor node has 2 input channels by default");
is(compressor.channelCountMode, "explicit", "Correct channelCountMode for the compressor node");
@ -38,22 +32,36 @@ addLoadEvent(function() {
// Verify default values
with (compressor) {
ok(threshold instanceof AudioParam, "treshold is an AudioParam");
near(threshold.defaultValue, -24, "Correct default value for threshold");
ok(knee instanceof AudioParam, "knee is an AudioParam");
near(knee.defaultValue, 30, "Correct default value for knee");
ok(ratio instanceof AudioParam, "knee is an AudioParam");
near(ratio.defaultValue, 12, "Correct default value for ratio");
near(reduction.defaultValue, 0, "Correct default value for reduction");
is(typeof reduction, "number", "reduction is a number");
near(reduction, 0, "Correct default value for reduction");
ok(attack instanceof AudioParam, "attack is an AudioParam");
near(attack.defaultValue, 0.003, "Correct default value for attack");
ok(release instanceof AudioParam, "release is an AudioParam");
near(release.defaultValue, 0.25, "Correct default value for release");
}
source.start(0);
SimpleTest.executeSoon(function() {
source.stop(0);
source.disconnect();
compressor.disconnect();
compressor.threshold.value = -80;
SimpleTest.finish();
});
osc.start();
var iteration = 0;
sp.onaudioprocess = function(e) {
if (iteration > 10) {
ok(compressor.reduction < 0,
"Feeding a full-scale sine to a compressor should result in an db" +
"reduction.");
sp.onaudioprocess = null;
osc.stop(0);
SimpleTest.finish();
}
iteration++;
}
});
</script>

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_phonenumber.xul]
[test_phonenumberservice.xul]

View File

@ -1,5 +1,5 @@
[DEFAULT]
skip-if = buildapp == "mulet"
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
support-files =
hang_test.js
privatemode_perwindowpb.xul

View File

@ -9,6 +9,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "jsprf.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIDOMWindow.h"
#include "nsIObserverService.h"
@ -31,6 +32,7 @@ static void LogFunctionAndJSStack(const char* funcname) {
"Call to %s. The JS stack is:\n%s\n",
funcname,
jsstack ? jsstack : "<no JS stack>");
JS_smprintf_free(jsstack);
}
// bug 839452
#define LOG_FUNCTION_AND_JS_STACK() \

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
[test_dependentPromises.html]
[test_on_new_promise.html]

View File

@ -148,11 +148,13 @@ CSPService::ShouldLoad(uint32_t aContentType,
// Cache the app status for this origin.
uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
nsAutoCString contentOrigin;
aContentLocation->GetPrePath(contentOrigin);
if (aRequestPrincipal && !mAppStatusCache.Get(contentOrigin, &status)) {
aRequestPrincipal->GetAppStatus(&status);
mAppStatusCache.Put(contentOrigin, status);
nsAutoCString sourceOrigin;
if (aRequestPrincipal && aRequestOrigin) {
aRequestOrigin->GetPrePath(sourceOrigin);
if (!mAppStatusCache.Get(sourceOrigin, &status)) {
aRequestPrincipal->GetAppStatus(&status);
mAppStatusCache.Put(sourceOrigin, status);
}
}
if (status == nsIPrincipal::APP_STATUS_CERTIFIED) {
@ -170,8 +172,8 @@ CSPService::ShouldLoad(uint32_t aContentType,
{
// Whitelist the theme resources.
auto themeOrigin = Preferences::GetCString("b2g.theme.origin");
nsAutoCString sourceOrigin;
aRequestOrigin->GetPrePath(sourceOrigin);
nsAutoCString contentOrigin;
aContentLocation->GetPrePath(contentOrigin);
if (!(sourceOrigin.Equals(contentOrigin) ||
(themeOrigin && themeOrigin.Equals(contentOrigin)))) {

Some files were not shown because too many files have changed in this diff Show More