mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
ee67ad0d8d
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -1,3 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_aboutCrashed.xul]
|
||||
|
@ -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]
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files = sample_feed.atom
|
||||
|
||||
[test_423060.xul]
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files = head.js
|
||||
|
||||
[test_0_bug510634.xul]
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
hosted_app.manifest
|
||||
validator/*
|
||||
|
@ -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) => {
|
||||
|
@ -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();
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
app/index.html
|
||||
app/manifest.webapp
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
file_disableScript.html
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
662200a.html
|
||||
662200b.html
|
||||
|
@ -1 +1,2 @@
|
||||
[chrome/test_running_on_compositor.html]
|
||||
skip-if = buildapp == 'b2g'
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
asmjs/*
|
||||
file_bug_945152.html
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
file_url.jsm
|
||||
file_empty.html
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
blockNoPlugins.xml
|
||||
blockPluginHard.xml
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_csp_bug768029.html]
|
||||
[test_csp_bug773891.html]
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_bug707564-chrome.html]
|
||||
[test_bug775543.html]
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
});
|
||||
|
||||
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{ }
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files = nonchrome_webgl_debug_renderer_info.html
|
||||
|
||||
[test_webgl_debug_renderer_info.html]
|
||||
|
@ -1,5 +1,6 @@
|
||||
[DEFAULT]
|
||||
skip-if = os == "android"
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_contacts_shutdown.xul]
|
||||
[test_contacts_upgrade.xul]
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'mulet'
|
||||
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
|
||||
|
||||
[test_app_permissions.html]
|
||||
[test_fs_app_permissions.html]
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files = file_stringencoding.jsm
|
||||
|
||||
[test_stringencoding.xul]
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
bug415498-doc1.html
|
||||
bug415498-doc2.html
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
file_anchor_ping.html
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
submit_invalid_file.sjs
|
||||
[test_autocompleteinfo.html]
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
support-files=
|
||||
file_browserid_rp_ok.html
|
||||
|
@ -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) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files = chromeHelpers.js
|
||||
|
||||
[test_globalObjects_chrome.xul]
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
process_error.xul
|
||||
process_error_contentscript.js
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -260,6 +260,8 @@ public:
|
||||
// decoding.
|
||||
virtual bool VideoIsHardwareAccelerated() const { return false; }
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
protected:
|
||||
virtual ~MediaDecoderReader();
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -175,12 +175,6 @@ WMFMediaDataDecoder::ReleaseMediaResources()
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::ReleaseDecoder()
|
||||
{
|
||||
ReleaseMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
WMFMediaDataDecoder::IsHardwareAccelerated() const {
|
||||
return mMFTManager && mMFTManager->IsHardwareAccelerated();
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
BIN
dom/media/test/bipbop-cenc-audio1.m4s
Normal file
BIN
dom/media/test/bipbop-cenc-audio1.m4s
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-audio2.m4s
Normal file
BIN
dom/media/test/bipbop-cenc-audio2.m4s
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-audio3.m4s
Normal file
BIN
dom/media/test/bipbop-cenc-audio3.m4s
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-audioinit.mp4
Normal file
BIN
dom/media/test/bipbop-cenc-audioinit.mp4
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-video1.m4s
Normal file
BIN
dom/media/test/bipbop-cenc-video1.m4s
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-video2.m4s
Normal file
BIN
dom/media/test/bipbop-cenc-video2.m4s
Normal file
Binary file not shown.
BIN
dom/media/test/bipbop-cenc-videoinit.mp4
Normal file
BIN
dom/media/test/bipbop-cenc-videoinit.mp4
Normal file
Binary file not shown.
57
dom/media/test/bipbop-frag-cenc.xml
Normal file
57
dom/media/test/bipbop-frag-cenc.xml
Normal 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>
|
BIN
dom/media/test/bipbop-no-edts.mp4
Normal file
BIN
dom/media/test/bipbop-no-edts.mp4
Normal file
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
#Media chrome tests
|
||||
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
basic.vtt
|
||||
seek.webm
|
||||
|
@ -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,
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -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.
Binary file not shown.
@ -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 = "";
|
||||
|
@ -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
|
||||
|
@ -38,7 +38,7 @@ function startTest(test, token)
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
PlayFragmented(test, v, token);
|
||||
LoadTest(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
@ -84,7 +84,7 @@ function startTest(test, token)
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(gEMENonFragmentedTests, startTest);
|
||||
manager.runTests(gEMENonMSEFailTests, startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
@ -52,7 +52,7 @@ function startTest(test, token)
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
PlayFragmented(test, v, token);
|
||||
LoadTest(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
@ -147,7 +147,7 @@ function startTest(test, token)
|
||||
}
|
||||
);
|
||||
|
||||
PlayFragmented(test, v, token);
|
||||
LoadTest(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -1,3 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_AudioNodeDevtoolsAPI.html]
|
||||
|
@ -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>
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_phonenumber.xul]
|
||||
[test_phonenumberservice.xul]
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == "mulet"
|
||||
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
|
||||
support-files =
|
||||
hang_test.js
|
||||
privatemode_perwindowpb.xul
|
||||
|
@ -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() \
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_dependentPromises.html]
|
||||
[test_on_new_promise.html]
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user