This commit is contained in:
Ryan VanderMeulen 2014-02-18 15:25:07 -05:00
Родитель 482f700272 8a4698657b
Коммит 6735b2344d
55 изменённых файлов: 728 добавлений и 511 удалений

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

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
@ -91,7 +91,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/> <project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things --> <!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="4e236e65a5d652a66ac32590f69f2123d17cb4ad"/> <project name="android-development" path="development" remote="b2g" revision="4e236e65a5d652a66ac32590f69f2123d17cb4ad"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="5be0a9c4b3c6c004786917fdb5bee248960d045b"/> <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="e7e8734fdd8bf41e48a56c1c85e0f7dac60aaa9f"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/> <project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/> <project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/> <project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

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

@ -11,7 +11,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/> <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

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

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
@ -91,7 +91,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/> <project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things --> <!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="4e236e65a5d652a66ac32590f69f2123d17cb4ad"/> <project name="android-development" path="development" remote="b2g" revision="4e236e65a5d652a66ac32590f69f2123d17cb4ad"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="5be0a9c4b3c6c004786917fdb5bee248960d045b"/> <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="e7e8734fdd8bf41e48a56c1c85e0f7dac60aaa9f"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/> <project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/> <project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/> <project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

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

@ -1,4 +1,4 @@
{ {
"revision": "8d15cd3ac0d07cde9ff36ce611ae47e6ef30d9b0", "revision": "a8b221aeef715c5d8159faa5b31f3ee15e5c3c5a",
"repo_path": "/integration/gaia-central" "repo_path": "/integration/gaia-central"
} }

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

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

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

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

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

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

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

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

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

@ -11,7 +11,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/> <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

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

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="258ae6472bd0e87ae074a6b9b464273dc9cfc8d6"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac06cfbd2baf6494ffbb668cc599e3892cd5e17b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

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

@ -468,7 +468,6 @@ pref("browser.tabs.closeButtons", 1);
pref("browser.tabs.selectOwnerOnClose", true); pref("browser.tabs.selectOwnerOnClose", true);
pref("browser.ctrlTab.previews", false); pref("browser.ctrlTab.previews", false);
pref("browser.ctrlTab.recentlyUsedLimit", 7);
// By default, do not export HTML at shutdown. // By default, do not export HTML at shutdown.
// If true, at shutdown the bookmarks in your menu and toolbar will // If true, at shutdown the bookmarks in your menu and toolbar will
@ -1371,6 +1370,9 @@ pref("identity.fxaccounts.remote.uri", "https://accounts.firefox.com/?service=sy
// should be fetched. Must use HTTPS. // should be fetched. Must use HTTPS.
pref("identity.fxaccounts.remote.force_auth.uri", "https://accounts.firefox.com/force_auth?service=sync&context=fx_desktop_v1"); pref("identity.fxaccounts.remote.force_auth.uri", "https://accounts.firefox.com/force_auth?service=sync&context=fx_desktop_v1");
// The remote content URL shown for signin in. Must use HTTPS.
pref("identity.fxaccounts.remote.signin.uri", "https://accounts.firefox.com/signin?service=sync&context=fx_desktop_v1");
// The URL we take the user to when they opt to "manage" their Firefox Account. // The URL we take the user to when they opt to "manage" their Firefox Account.
// Note that this will always need to be in the same TLD as the // Note that this will always need to be in the same TLD as the
// "identity.fxaccounts.remote.uri" pref. // "identity.fxaccounts.remote.uri" pref.

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

@ -250,6 +250,9 @@ function openPrefs() {
function init() { function init() {
if (window.location.href.contains("action=signin")) { if (window.location.href.contains("action=signin")) {
show("remote");
wrapper.init(fxAccounts.getAccountsSignInURI());
} else if (window.location.href.contains("action=signup")) {
show("remote"); show("remote");
wrapper.init(); wrapper.init();
} else if (window.location.href.contains("action=reauth")) { } else if (window.location.href.contains("action=reauth")) {

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

@ -161,10 +161,6 @@ var ctrlTab = {
delete this.previews; delete this.previews;
return this.previews = this.panel.getElementsByClassName("ctrlTab-preview"); return this.previews = this.panel.getElementsByClassName("ctrlTab-preview");
}, },
get recentlyUsedLimit () {
delete this.recentlyUsedLimit;
return this.recentlyUsedLimit = gPrefService.getIntPref("browser.ctrlTab.recentlyUsedLimit");
},
get keys () { get keys () {
var keys = {}; var keys = {};
["close", "find", "selectAll"].forEach(function (key) { ["close", "find", "selectAll"].forEach(function (key) {
@ -187,31 +183,7 @@ var ctrlTab = {
get canvasHeight () Math.round(this.canvasWidth * tabPreviews.aspectRatio), get canvasHeight () Math.round(this.canvasWidth * tabPreviews.aspectRatio),
get tabList () { get tabList () {
if (this._tabList) return this._recentlyUsedTabs;
return this._tabList;
// Using gBrowser.tabs instead of gBrowser.visibleTabs, as the latter
// exlcudes closing tabs, breaking the following loop in case the the
// selected tab is closing.
let list = Array.filter(gBrowser.tabs, function (tab) !tab.hidden);
// Rotate the list until the selected tab is first
while (!list[0].selected)
list.push(list.shift());
list = list.filter(function (tab) !tab.closing);
if (this.recentlyUsedLimit != 0) {
let recentlyUsedTabs = this._recentlyUsedTabs;
if (this.recentlyUsedLimit > 0)
recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
list.unshift(recentlyUsedTabs[i]);
}
}
return this._tabList = list;
}, },
init: function ctrlTab_init() { init: function ctrlTab_init() {
@ -340,6 +312,9 @@ var ctrlTab = {
}, },
attachTab: function ctrlTab_attachTab(aTab, aPos) { attachTab: function ctrlTab_attachTab(aTab, aPos) {
if (aTab.closing)
return;
if (aPos == 0) if (aPos == 0)
this._recentlyUsedTabs.unshift(aTab); this._recentlyUsedTabs.unshift(aTab);
else if (aPos) else if (aPos)
@ -347,6 +322,7 @@ var ctrlTab = {
else else
this._recentlyUsedTabs.push(aTab); this._recentlyUsedTabs.push(aTab);
}, },
detachTab: function ctrlTab_detachTab(aTab) { detachTab: function ctrlTab_detachTab(aTab) {
var i = this._recentlyUsedTabs.indexOf(aTab); var i = this._recentlyUsedTabs.indexOf(aTab);
if (i >= 0) if (i >= 0)
@ -417,8 +393,6 @@ var ctrlTab = {
Array.forEach(this.previews, function (preview) { Array.forEach(this.previews, function (preview) {
this.updatePreview(preview, null); this.updatePreview(preview, null);
}, this); }, this);
this._tabList = null;
}, },
onKeyPress: function ctrlTab_onKeyPress(event) { onKeyPress: function ctrlTab_onKeyPress(event) {
@ -472,7 +446,6 @@ var ctrlTab = {
return; return;
} }
this._tabList = null;
this.updatePreviews(); this.updatePreviews();
if (this.selected.hidden) if (this.selected.hidden)

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

@ -46,7 +46,7 @@ var gConnectionsDialog = {
proxyTypeChanged: function () proxyTypeChanged: function ()
{ {
var proxyTypePref = document.getElementById("network.proxy.type"); var proxyTypePref = document.getElementById("network.proxy.type");
// Update http // Update http
var httpProxyURLPref = document.getElementById("network.proxy.http"); var httpProxyURLPref = document.getElementById("network.proxy.http");
httpProxyURLPref.disabled = proxyTypePref.value != 1; httpProxyURLPref.disabled = proxyTypePref.value != 1;
@ -58,10 +58,11 @@ var gConnectionsDialog = {
var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings"); var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
shareProxiesPref.disabled = proxyTypePref.value != 1; shareProxiesPref.disabled = proxyTypePref.value != 1;
var autologinProxyPref = document.getElementById("signon.autologin.proxy");
autologinProxyPref.disabled = proxyTypePref.value == 0;
var noProxiesPref = document.getElementById("network.proxy.no_proxies_on"); var noProxiesPref = document.getElementById("network.proxy.no_proxies_on");
noProxiesPref.disabled = proxyTypePref.value != 1; noProxiesPref.disabled = proxyTypePref.value != 1;
var autoconfigURLPref = document.getElementById("network.proxy.autoconfig_url"); var autoconfigURLPref = document.getElementById("network.proxy.autoconfig_url");
autoconfigURLPref.disabled = proxyTypePref.value != 2; autoconfigURLPref.disabled = proxyTypePref.value != 2;

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

@ -44,7 +44,10 @@
<preference id="network.proxy.share_proxy_settings" <preference id="network.proxy.share_proxy_settings"
name="network.proxy.share_proxy_settings" name="network.proxy.share_proxy_settings"
type="bool"/> type="bool"/>
<preference id="signon.autologin.proxy"
name="signon.autologin.proxy"
type="bool"/>
<preference id="pref.advanced.proxies.disable_button.reload" <preference id="pref.advanced.proxies.disable_button.reload"
name="pref.advanced.proxies.disable_button.reload" name="pref.advanced.proxies.disable_button.reload"
type="bool"/> type="bool"/>
@ -159,6 +162,13 @@
</hbox> </hbox>
</radiogroup> </radiogroup>
</groupbox> </groupbox>
<separator class="thin"/>
<checkbox id="autologinProxy"
label="&autologinproxy.label;"
accesskey="&autologinproxy.accesskey;"
preference="signon.autologin.proxy"
tooltiptext="&autologinproxy.tooltip;"/>
<separator/>
</prefpane> </prefpane>
</prefwindow> </prefwindow>

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

@ -256,6 +256,10 @@ let gSyncPane = {
window.close(); window.close();
}, },
signUp: function() {
this.openContentInBrowser("about:accounts?action=signup");
},
signIn: function() { signIn: function() {
this.openContentInBrowser("about:accounts?action=signin"); this.openContentInBrowser("about:accounts?action=signin");
}, },

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

@ -188,7 +188,7 @@
<vbox id="noFxaAccount"> <vbox id="noFxaAccount">
<description>&welcome.description;</description> <description>&welcome.description;</description>
<label class="text-link" <label class="text-link"
onclick="gSyncPane.signIn(); return false;" onclick="gSyncPane.signUp(); return false;"
value="&welcome.createAccount.label;"/> value="&welcome.createAccount.label;"/>
<label class="text-link" <label class="text-link"
onclick="gSyncPane.signIn(); return false;" onclick="gSyncPane.signIn(); return false;"
@ -207,7 +207,7 @@
<deck id="fxaLoginStatus"> <deck id="fxaLoginStatus">
<!-- logged in and verified and all is good --> <!-- logged in and verified and all is good -->
<hbox flex="1"> <hbox>
<label id="fxaEmailAddress1"/> <label id="fxaEmailAddress1"/>
<label class="text-link" <label class="text-link"
onclick="gSyncPane.manageFirefoxAccount();" onclick="gSyncPane.manageFirefoxAccount();"

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

@ -67,7 +67,10 @@
<p class="project-validation valid">&projects.valid;</p> <p class="project-validation valid">&projects.valid;</p>
<p class="project-validation warning">&projects.warning;</p> <p class="project-validation warning">&projects.warning;</p>
<p class="project-validation error">&projects.error;</p> <p class="project-validation error">&projects.error;</p>
<p class="project-type" template='{"type":"textContent","path":"type"}'></p> </div>
<div class="project-status" template='{"type":"attribute","path":"type","name":"type"}'>
<p class="project-type hosted">&projects.hosted;</p>
<p class="project-type packaged">&projects.packaged;</p>
</div> </div>
</div> </div>
<span template='{"type":"textContent","path":"manifest.developer.name"}'></span> <span template='{"type":"textContent","path":"manifest.developer.name"}'></span>

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

@ -133,10 +133,11 @@ Spectrum.rgbToHsv = function(r, g, b, a) {
Spectrum.getOffset = function(el) { Spectrum.getOffset = function(el) {
let curleft = 0, curtop = 0; let curleft = 0, curtop = 0;
if (el.offsetParent) { if (el.offsetParent) {
do { while (el) {
curleft += el.offsetLeft; curleft += el.offsetLeft;
curtop += el.offsetTop; curtop += el.offsetTop;
} while (el = el.offsetParent); el = el.offsetParent;
}
} }
return { return {
left: curleft, left: curleft,

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

@ -83,6 +83,8 @@
<!ENTITY projects.valid "Valid"> <!ENTITY projects.valid "Valid">
<!ENTITY projects.error "Error"> <!ENTITY projects.error "Error">
<!ENTITY projects.warning "Warning"> <!ENTITY projects.warning "Warning">
<!ENTITY projects.hosted "Hosted">
<!ENTITY projects.packaged "Packaged">
<!ENTITY help.title "App Manager"> <!ENTITY help.title "App Manager">
<!ENTITY help.close "Close"> <!ENTITY help.close "Close">

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

@ -44,3 +44,6 @@
<!ENTITY noproxyExplain.label "Example: .mozilla.org, .net.nz, 192.168.1.0/24"> <!ENTITY noproxyExplain.label "Example: .mozilla.org, .net.nz, 192.168.1.0/24">
<!ENTITY shareproxy.label "Use this proxy server for all protocols"> <!ENTITY shareproxy.label "Use this proxy server for all protocols">
<!ENTITY shareproxy.accesskey "s"> <!ENTITY shareproxy.accesskey "s">
<!ENTITY autologinproxy.label "Do not prompt for authentication if password is saved">
<!ENTITY autologinproxy.accesskey "a">
<!ENTITY autologinproxy.tooltip "This option silently authenticates you to proxies when you have saved credentials for them. You will be prompted if authentication fails.">

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

@ -15,15 +15,32 @@
<content> <content>
<xul:stack> <xul:stack>
<xul:toolbarbutton anonid="progressButton" class="circularprogressindicator-progressButton"/> <xul:toolbarbutton anonid="progressButton"
<html:div anonid="progressTrack" xbl:inherits="progress" class="circularprogressindicator-progressTrack"></html:div> class="circularprogressindicator-progressButton"/>
<html:canvas anonid="progressRing" xbl:inherits="progress" class="circularprogressindicator-progressRing" width="40" height="40"></html:canvas> <html:div anonid="progressTrack"
xbl:inherits="progress"
class="circularprogressindicator-progressTrack">
</html:div>
<html:canvas anonid="progressRing"
xbl:inherits="progress"
class="circularprogressindicator-progressRing"
width="40"
height="40">
</html:canvas>
<html:div anonid="progressNotification"
xbl:inherits="progress"
class="circularprogressindicator-progressNotification">
</html:div>
</xul:stack> </xul:stack>
</content> </content>
<implementation> <implementation>
<field name="_progressCanvas"> <field name="_progressCanvas">
document.getAnonymousElementByAttribute(this, "anonid", "progressRing"); document.getAnonymousElementByAttribute(this, "anonid", "progressRing");
</field>
<field name="_progressNotification">
document.getAnonymousElementByAttribute(this, "anonid",
"progressNotification");
</field> </field>
<field name="_progressCircleCtx">null</field> <field name="_progressCircleCtx">null</field>
<field name="_img">null</field> <field name="_img">null</field>
@ -92,6 +109,26 @@
]]> ]]>
</body> </body>
</method> </method>
<method name="notify">
<body>
<![CDATA[
this.addEventListener("transitionend", this._onNotificationEnd);
this._progressNotification.classList.add(
"progressNotification-active");
]]>
</body>
</method>
<method name="_onNotificationEnd">
<body>
<![CDATA[
this.removeEventListener("transitionend", this._onNotificationEnd);
this._progressNotification.classList.remove(
"progressNotification-active");
]]>
</body>
</method>
</implementation> </implementation>
</binding> </binding>
</bindings> </bindings>

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

@ -532,7 +532,11 @@ var MetroDownloadsView = {
let notn = this._progressNotification; let notn = this._progressNotification;
if (notn) if (notn)
this._notificationBox.removeNotification(notn); this._notificationBox.removeNotification(notn);
ContextUI.displayNavbar();
} }
this._downloadProgressIndicator.notify();
break; break;
case "dl-failed": case "dl-failed":
download = aSubject.QueryInterface(Ci.nsIDownload); download = aSubject.QueryInterface(Ci.nsIDownload);

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

@ -7,7 +7,8 @@
.circularprogressindicator-progressButton, .circularprogressindicator-progressButton,
.circularprogressindicator-progressRing, .circularprogressindicator-progressRing,
.circularprogressindicator-progressTrack { .circularprogressindicator-progressTrack,
.circularprogressindicator-progressNotification {
margin: 0 @toolbar_horizontal_spacing@; margin: 0 @toolbar_horizontal_spacing@;
} }
@ -25,6 +26,21 @@
background-image: url(chrome://browser/skin/images/progresscircle-bg.png); background-image: url(chrome://browser/skin/images/progresscircle-bg.png);
} }
.circularprogressindicator-progressNotification {
width: 40px;
height: 40px;
background-image: url(chrome://browser/skin/images/navbar-download-finished.png);
visibility: hidden;
}
.circularprogressindicator-progressNotification.progressNotification-active {
visibility: visible;
opacity: 0;
transform: scale(2);
transition: opacity @metro_animation_duration@,
transform @metro_animation_duration@;
}
.circularprogressindicator-progressRing:not([progress]), .circularprogressindicator-progressRing:not([progress]),
.circularprogressindicator-progressRing[progress="100"], .circularprogressindicator-progressRing[progress="100"],
.circularprogressindicator-progressTrack:not([progress]), .circularprogressindicator-progressTrack:not([progress]),

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

@ -360,10 +360,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
width: 0; /* Fancy cropping solution for flexbox. */ width: 0; /* Fancy cropping solution for flexbox. */
} }
#PanelUI-fxa-status[signedin] {
font-weight: bold;
}
#PanelUI-help, #PanelUI-help,
#PanelUI-quit { #PanelUI-quit {
min-width: 46px; min-width: 46px;

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

@ -337,6 +337,14 @@ strong {
display: inline; display: inline;
} }
.project-type {
display: none;
margin-left: 10px;
}
[type="hosted"] > .project-type.hosted,
[type="packaged"] > .project-type.packaged {
display: inline;
}
/********* PROJECT BUTTONS ***********/ /********* PROJECT BUTTONS ***********/

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

@ -33,8 +33,8 @@
/* We want a 4px gap between the TabsToolbar and the toolbar-menubar when the /* We want a 4px gap between the TabsToolbar and the toolbar-menubar when the
toolbar-menu is displayed, and a 16px gap when it is not. 1px is taken care toolbar-menu is displayed, and a 16px gap when it is not. 1px is taken care
of by the (light) outer shadow of the tab, the remaining 3/15 are these margins. */ of by the (light) outer shadow of the tab, the remaining 3/15 are these margins. */
#toolbar-menubar:not([autohide="true"]) ~ #TabsToolbar, #toolbar-menubar:not([moz-collapsed=true]):not([autohide=true]) ~ #TabsToolbar,
#toolbar-menubar[autohide="true"]:not([inactive]) ~ #TabsToolbar { #toolbar-menubar:not([moz-collapsed=true])[autohide=true]:not([inactive]) ~ #TabsToolbar {
margin-top: 3px; margin-top: 3px;
} }

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

@ -42,7 +42,7 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
aPlane.mStride > 0; aPlane.mStride > 0;
} }
#if 0 #ifdef MOZ_WIDGET_GONK
static bool static bool
IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane, IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
const VideoData::YCbCrBuffer::Plane& aCbPlane, const VideoData::YCbCrBuffer::Plane& aCbPlane,
@ -103,6 +103,45 @@ VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
return v; return v;
} }
/* static */
void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,
bool aCopyData)
{
if (!aVideoImage) {
return;
}
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
PlanarYCbCrData data;
data.mYChannel = Y.mData + Y.mOffset;
data.mYSize = IntSize(Y.mWidth, Y.mHeight);
data.mYStride = Y.mStride;
data.mYSkip = Y.mSkip;
data.mCbChannel = Cb.mData + Cb.mOffset;
data.mCrChannel = Cr.mData + Cr.mOffset;
data.mCbCrSize = IntSize(Cb.mWidth, Cb.mHeight);
data.mCbCrStride = Cb.mStride;
data.mCbSkip = Cb.mSkip;
data.mCrSkip = Cr.mSkip;
data.mPicX = aPicture.x;
data.mPicY = aPicture.y;
data.mPicSize = aPicture.Size();
data.mStereoMode = aInfo.mStereoMode;
aVideoImage->SetDelayedConversion(true);
if (aCopyData) {
aVideoImage->SetData(data);
} else {
aVideoImage->SetDataNoCopy(data);
}
}
/* static */
VideoData* VideoData::Create(VideoInfo& aInfo, VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer, ImageContainer* aContainer,
Image* aImage, Image* aImage,
@ -164,14 +203,16 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
aKeyframe, aKeyframe,
aTimecode, aTimecode,
aInfo.mDisplay.ToIntSize())); aInfo.mDisplay.ToIntSize()));
#ifdef MOZ_WIDGET_GONK
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0]; const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1]; const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2]; const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
#endif
if (!aImage) { if (!aImage) {
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR // Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
// format. // format.
#if 0 #ifdef MOZ_WIDGET_GONK
if (IsYV12Format(Y, Cb, Cr)) { if (IsYV12Format(Y, Cb, Cr)) {
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR); v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
} }
@ -191,32 +232,30 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
"Wrong format?"); "Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get()); PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
PlanarYCbCrData data;
data.mYChannel = Y.mData + Y.mOffset;
data.mYSize = IntSize(Y.mWidth, Y.mHeight);
data.mYStride = Y.mStride;
data.mYSkip = Y.mSkip;
data.mCbChannel = Cb.mData + Cb.mOffset;
data.mCrChannel = Cr.mData + Cr.mOffset;
data.mCbCrSize = IntSize(Cb.mWidth, Cb.mHeight);
data.mCbCrStride = Cb.mStride;
data.mCbSkip = Cb.mSkip;
data.mCrSkip = Cr.mSkip;
data.mPicX = aPicture.x;
data.mPicY = aPicture.y;
data.mPicSize = aPicture.Size();
data.mStereoMode = aInfo.mStereoMode;
videoImage->SetDelayedConversion(true);
if (!aImage) { if (!aImage) {
videoImage->SetData(data); VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
true /* aCopyData */);
} else { } else {
videoImage->SetDataNoCopy(data); VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
false /* aCopyData */);
} }
#ifdef MOZ_WIDGET_GONK
if (!videoImage->IsValid() && !aImage && IsYV12Format(Y, Cb, Cr)) {
// Failed to allocate gralloc. Try fallback.
v->mImage = aContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
if (!v->mImage) {
return nullptr;
}
videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
true /* aCopyData */);
}
#endif
return v.forget(); return v.forget();
} }
/* static */
VideoData* VideoData::Create(VideoInfo& aInfo, VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer, ImageContainer* aContainer,
int64_t aOffset, int64_t aOffset,
@ -231,6 +270,7 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
aKeyframe, aTimecode, aPicture); aKeyframe, aTimecode, aPicture);
} }
/* static */
VideoData* VideoData::Create(VideoInfo& aInfo, VideoData* VideoData::Create(VideoInfo& aInfo,
Image* aImage, Image* aImage,
int64_t aOffset, int64_t aOffset,
@ -245,6 +285,7 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
aKeyframe, aTimecode, aPicture); aKeyframe, aTimecode, aPicture);
} }
/* static */
VideoData* VideoData::CreateFromImage(VideoInfo& aInfo, VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
ImageContainer* aContainer, ImageContainer* aContainer,
int64_t aOffset, int64_t aOffset,
@ -266,6 +307,7 @@ VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
} }
#ifdef MOZ_OMX_DECODER #ifdef MOZ_OMX_DECODER
/* static */
VideoData* VideoData::Create(VideoInfo& aInfo, VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer, ImageContainer* aContainer,
int64_t aOffset, int64_t aOffset,

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

@ -102,6 +102,7 @@ public:
namespace layers { namespace layers {
class GraphicBufferLocked; class GraphicBufferLocked;
class PlanarYCbCrImage;
} }
class VideoInfo; class VideoInfo;
@ -113,6 +114,7 @@ public:
typedef gfx::IntSize IntSize; typedef gfx::IntSize IntSize;
typedef layers::ImageContainer ImageContainer; typedef layers::ImageContainer ImageContainer;
typedef layers::Image Image; typedef layers::Image Image;
typedef layers::PlanarYCbCrImage PlanarYCbCrImage;
// YCbCr data obtained from decoding the video. The index's are: // YCbCr data obtained from decoding the video. The index's are:
// 0 = Y // 0 = Y
@ -202,6 +204,14 @@ public:
static VideoData* ShallowCopyUpdateDuration(VideoData* aOther, static VideoData* ShallowCopyUpdateDuration(VideoData* aOther,
int64_t aDuration); int64_t aDuration);
// Initialize PlanarYCbCrImage. Only When aCopyData is true,
// video data is copied to PlanarYCbCrImage.
static void SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,
bool aCopyData);
// Constructs a duplicate VideoData object. This intrinsically tells the // Constructs a duplicate VideoData object. This intrinsically tells the
// player that it does not need to update the displayed frame when this // player that it does not need to update the displayed frame when this
// frame is played; this frame is identical to the previous. // frame is played; this frame is identical to the previous.

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

@ -112,12 +112,16 @@ OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
// Send the EOS signal to OMXCodecWrapper. // Send the EOS signal to OMXCodecWrapper.
if (mEndOfStream && iter.IsEnded() && !mEosSetInEncoder) { if (mEndOfStream && iter.IsEnded() && !mEosSetInEncoder) {
mEosSetInEncoder = true;
uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate; uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate;
layers::Image* img = (!mLastFrame.GetImage() || mLastFrame.GetForceBlack()) layers::Image* img = (!mLastFrame.GetImage() || mLastFrame.GetForceBlack())
? nullptr : mLastFrame.GetImage(); ? nullptr : mLastFrame.GetImage();
mEncoder->Encode(img, mFrameWidth, mFrameHeight, totalDurationUs, nsresult result = mEncoder->Encode(img, mFrameWidth, mFrameHeight,
OMXCodecWrapper::BUFFER_EOS); totalDurationUs,
OMXCodecWrapper::BUFFER_EOS);
// Keep sending EOS signal until OMXVideoEncoder gets it.
if (result == NS_OK) {
mEosSetInEncoder = true;
}
} }
// Dequeue an encoded frame from the output buffers of OMXCodecWrapper. // Dequeue an encoded frame from the output buffers of OMXCodecWrapper.

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

@ -8,6 +8,7 @@
#include "TrackEncoder.h" #include "TrackEncoder.h"
#include <binder/ProcessState.h> #include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <media/ICrypto.h> #include <media/ICrypto.h>
#include <media/IOMX.h> #include <media/IOMX.h>
#include <OMX_Component.h> #include <OMX_Component.h>
@ -110,6 +111,15 @@ OMXCodecWrapper::Stop()
return result; return result;
} }
// Check system property to see if we're running on emulator.
static
bool IsRunningOnEmulator()
{
char qemu[PROPERTY_VALUE_MAX];
property_get("ro.kernel.qemu", qemu, "");
return strncmp(qemu, "1", 1) == 0;
}
nsresult nsresult
OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate) OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate)
{ {
@ -118,6 +128,19 @@ OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate)
NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0, NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0,
NS_ERROR_INVALID_ARG); NS_ERROR_INVALID_ARG);
OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3;
OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstant;
// Limitation of soft AVC/H.264 encoder running on emulator in stagefright.
static bool emu = IsRunningOnEmulator();
if (emu) {
if (aWidth > 352 || aHeight > 288) {
CODEC_ERROR("SoftAVCEncoder doesn't support resolution larger than CIF");
return NS_ERROR_INVALID_ARG;
}
level = OMX_VIDEO_AVCLevel2;
bitrateMode = OMX_Video_ControlRateVariable;
}
// Set up configuration parameters for AVC/H.264 encoder. // Set up configuration parameters for AVC/H.264 encoder.
sp<AMessage> format = new AMessage; sp<AMessage> format = new AMessage;
// Fixed values // Fixed values
@ -128,8 +151,8 @@ OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate)
// height is half that of Y // height is half that of Y
format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar); format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar);
format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline); format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline);
format->setInt32("level", OMX_VIDEO_AVCLevel3); format->setInt32("level", level);
format->setInt32("bitrate-mode", OMX_Video_ControlRateConstant); format->setInt32("bitrate-mode", bitrateMode);
format->setInt32("store-metadata-in-buffers", 0); format->setInt32("store-metadata-in-buffers", 0);
format->setInt32("prepend-sps-pps-to-idr-frames", 0); format->setInt32("prepend-sps-pps-to-idr-frames", 0);
// Input values. // Input values.

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

@ -448,7 +448,7 @@ AudioChannelService::SendAudioChannelChangedNotification(uint64_t aChildID)
} }
// Calculating the most important active channel. // Calculating the most important active channel.
AudioChannelType higher = AUDIO_CHANNEL_LAST; AudioChannelType higher = AUDIO_CHANNEL_DEFAULT;
// Top-Down in the hierarchy for visible elements // Top-Down in the hierarchy for visible elements
if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION].IsEmpty()) { if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION].IsEmpty()) {
@ -482,30 +482,19 @@ AudioChannelService::SendAudioChannelChangedNotification(uint64_t aChildID)
AudioChannelType visibleHigher = higher; AudioChannelType visibleHigher = higher;
// Top-Down in the hierarchy for non-visible elements // Top-Down in the hierarchy for non-visible elements
if (higher == AUDIO_CHANNEL_LAST) { // And we can ignore normal channel because it can't play in the background.
if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN].IsEmpty()) { for (int i = AUDIO_CHANNEL_LAST - 1;
higher = AUDIO_CHANNEL_PUBLICNOTIFICATION; i > higher && i > AUDIO_CHANNEL_NORMAL; i--) {
if (i == AUDIO_CHANNEL_CONTENT &&
mPlayableHiddenContentChildID != CONTENT_PROCESS_ID_UNKNOWN) {
higher = static_cast<AudioChannelType>(i);
} }
else if (!mChannelCounters[AUDIO_CHANNEL_INT_RINGER_HIDDEN].IsEmpty()) { // Each channel type will be split to fg and bg for recording the state,
higher = AUDIO_CHANNEL_RINGER; // so here need to do a translation.
} if (!mChannelCounters[i * 2 + 1].IsEmpty()) {
higher = static_cast<AudioChannelType>(i);
else if (!mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].IsEmpty()) { break;
higher = AUDIO_CHANNEL_TELEPHONY;
}
else if (!mChannelCounters[AUDIO_CHANNEL_INT_ALARM_HIDDEN].IsEmpty()) {
higher = AUDIO_CHANNEL_ALARM;
}
else if (!mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN].IsEmpty()) {
higher = AUDIO_CHANNEL_NOTIFICATION;
}
// Check whether there is any playable hidden content channel or not.
else if (mPlayableHiddenContentChildID != CONTENT_PROCESS_ID_UNKNOWN) {
higher = AUDIO_CHANNEL_CONTENT;
} }
} }
@ -513,7 +502,7 @@ AudioChannelService::SendAudioChannelChangedNotification(uint64_t aChildID)
mCurrentHigherChannel = higher; mCurrentHigherChannel = higher;
nsString channelName; nsString channelName;
if (mCurrentHigherChannel != AUDIO_CHANNEL_LAST) { if (mCurrentHigherChannel != AUDIO_CHANNEL_DEFAULT) {
channelName.AssignASCII(ChannelName(mCurrentHigherChannel)); channelName.AssignASCII(ChannelName(mCurrentHigherChannel));
} else { } else {
channelName.AssignLiteral("none"); channelName.AssignLiteral("none");
@ -528,7 +517,7 @@ AudioChannelService::SendAudioChannelChangedNotification(uint64_t aChildID)
mCurrentVisibleHigherChannel = visibleHigher; mCurrentVisibleHigherChannel = visibleHigher;
nsString channelName; nsString channelName;
if (mCurrentVisibleHigherChannel != AUDIO_CHANNEL_LAST) { if (mCurrentVisibleHigherChannel != AUDIO_CHANNEL_DEFAULT) {
channelName.AssignASCII(ChannelName(mCurrentVisibleHigherChannel)); channelName.AssignASCII(ChannelName(mCurrentVisibleHigherChannel));
} else { } else {
channelName.AssignLiteral("none"); channelName.AssignLiteral("none");

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

@ -134,6 +134,7 @@
#include "AudioChannelService.h" #include "AudioChannelService.h"
#include "JavaScriptChild.h" #include "JavaScriptChild.h"
#include "mozilla/dom/telephony/PTelephonyChild.h" #include "mozilla/dom/telephony/PTelephonyChild.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/net/NeckoMessageUtils.h" #include "mozilla/net/NeckoMessageUtils.h"
using namespace base; using namespace base;
@ -311,6 +312,15 @@ NS_IMPL_ISUPPORTS1(SystemMessageHandledObserver, nsIObserver)
ContentChild* ContentChild::sSingleton; ContentChild* ContentChild::sSingleton;
// Performs initialization that is not fork-safe, i.e. that must be done after
// forking from the Nuwa process.
static void
InitOnContentProcessCreated()
{
// This will register cross-process observer.
mozilla::dom::time::InitializeDateCacheCleaner();
}
ContentChild::ContentChild() ContentChild::ContentChild()
: mID(uint64_t(-1)) : mID(uint64_t(-1))
#ifdef ANDROID #ifdef ANDROID
@ -462,6 +472,10 @@ ContentChild::InitXPCOM()
nsRefPtr<SystemMessageHandledObserver> sysMsgObserver = nsRefPtr<SystemMessageHandledObserver> sysMsgObserver =
new SystemMessageHandledObserver(); new SystemMessageHandledObserver();
sysMsgObserver->Init(); sysMsgObserver->Init();
#ifndef MOZ_NUWA_PROCESS
InitOnContentProcessCreated();
#endif
} }
PMemoryReportRequestChild* PMemoryReportRequestChild*
@ -1623,6 +1637,10 @@ public:
toplevel = toplevel->getNext(); toplevel = toplevel->getNext();
} }
// Perform other after-fork initializations.
InitOnContentProcessCreated();
return NS_OK; return NS_OK;
} }
}; };

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

@ -66,7 +66,7 @@ CrashReporterParent::CrashReporterParent()
#ifdef MOZ_CRASHREPORTER #ifdef MOZ_CRASHREPORTER
mNotes(4), mNotes(4),
#endif #endif
mStartTime(time(nullptr)) mStartTime(::time(nullptr))
, mInitialized(false) , mInitialized(false)
{ {
MOZ_COUNT_CTOR(CrashReporterParent); MOZ_COUNT_CTOR(CrashReporterParent);

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

@ -79,7 +79,15 @@ NetworkStatsDB.prototype = {
// to modify the keyPath is mandatory to delete the object store // to modify the keyPath is mandatory to delete the object store
// and create it again. Old data is going to be deleted because the // and create it again. Old data is going to be deleted because the
// networkId for each sample can not be set. // networkId for each sample can not be set.
db.deleteObjectStore(DEPRECATED_STORE_NAME);
// In version 1.2 objectStore name was 'net_stats_v2', to avoid errors when
// upgrading from 1.2 to 1.3 objectStore name should be checked.
let stores = db.objectStoreNames;
if(stores.contains("net_stats_v2")) {
db.deleteObjectStore("net_stats_v2");
} else {
db.deleteObjectStore(DEPRECATED_STORE_NAME);
}
objectStore = db.createObjectStore(DEPRECATED_STORE_NAME, { keyPath: ["appId", "network", "timestamp"] }); objectStore = db.createObjectStore(DEPRECATED_STORE_NAME, { keyPath: ["appId", "network", "timestamp"] });
objectStore.createIndex("appId", "appId", { unique: false }); objectStore.createIndex("appId", "appId", { unique: false });

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

@ -22,6 +22,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Sntp.jsm"); Cu.import("resource://gre/modules/Sntp.jsm");
Cu.import("resource://gre/modules/systemlibs.js"); Cu.import("resource://gre/modules/systemlibs.js");
Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
var RIL = {}; var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL); Cu.import("resource://gre/modules/ril_consts.js", RIL);
@ -3299,6 +3300,16 @@ RadioInterface.prototype = {
// Or refresh the SNTP. // Or refresh the SNTP.
this._sntp.request(); this._sntp.request();
} }
} else {
// Set a sane minimum time.
let buildTime = libcutils.property_get("ro.build.date.utc", "0") * 1000;
let file = FileUtils.File("/system/b2g/b2g");
if (file.lastModifiedTime > buildTime) {
buildTime = file.lastModifiedTime;
}
if (buildTime > Date.now()) {
gTimeService.set(buildTime);
}
} }
break; break;
case kSettingsTimezoneAutoUpdateEnabled: case kSettingsTimezoneAutoUpdateEnabled:

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

@ -80,7 +80,7 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
gfxImageFormat format gfxImageFormat format
= gfxPlatform::GetPlatform()->OptimalFormatForContent(type); = gfxPlatform::GetPlatform()->OptimalFormatForContent(type);
GrallocTextureClientOGL* grallocTC = RefPtr<GrallocTextureClientOGL> grallocTC =
new GrallocTextureClientOGL( new GrallocTextureClientOGL(
allocator, allocator,
gfx::ImageFormatToSurfaceFormat(format), gfx::ImageFormatToSurfaceFormat(format),
@ -102,7 +102,6 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
LOCAL_EGL_NATIVE_BUFFER_ANDROID, LOCAL_EGL_NATIVE_BUFFER_ANDROID,
clientBuffer, attrs); clientBuffer, attrs);
if (!image) { if (!image) {
grallocTC->DropTextureData()->DeallocateSharedData(allocator);
return nullptr; return nullptr;
} }

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

@ -92,6 +92,9 @@ GrallocImage::SetData(const Data& aData)
GraphicBuffer::USAGE_SW_WRITE_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN |
GraphicBuffer::USAGE_HW_TEXTURE, GraphicBuffer::USAGE_HW_TEXTURE,
&desc); &desc);
if (desc.type() == SurfaceDescriptor::T__None) {
return;
}
mBufferAllocated = true; mBufferAllocated = true;
mGraphicBufferLocked = new GraphicBufferLocked(desc); mGraphicBufferLocked = new GraphicBufferLocked(desc);
} }

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

@ -132,7 +132,7 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf); SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
GrallocTextureClientOGL* grallocTextureClient = RefPtr<GrallocTextureClientOGL> grallocTextureClient =
static_cast<GrallocTextureClientOGL*>(grallocSurf->GetTextureClient()); static_cast<GrallocTextureClientOGL*>(grallocSurf->GetTextureClient());
// If IPDLActor is null means this TextureClient didn't AddTextureClient yet // If IPDLActor is null means this TextureClient didn't AddTextureClient yet

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

@ -130,7 +130,6 @@ using namespace mozilla;
using namespace mozilla::net; using namespace mozilla::net;
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::dom::ipc; using namespace mozilla::dom::ipc;
using namespace mozilla::dom::time;
nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0; nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
@ -280,8 +279,6 @@ nsLayoutStatics::Initialize()
nsCookieService::AppClearDataObserverInit(); nsCookieService::AppClearDataObserverInit();
nsApplicationCacheService::AppClearDataObserverInit(); nsApplicationCacheService::AppClearDataObserverInit();
InitializeDateCacheCleaner();
HTMLVideoElement::Init(); HTMLVideoElement::Init();
CacheObserver::Init(); CacheObserver::Init();

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

@ -29,7 +29,7 @@ bool VolatileBuffer::Init(size_t aSize, size_t aAlignment)
#if defined(MOZ_MEMORY) #if defined(MOZ_MEMORY)
posix_memalign(&mBuf, aAlignment, aSize); posix_memalign(&mBuf, aAlignment, aSize);
#elif defined(HAVE_POSIX_MEMALIGN) #elif defined(HAVE_POSIX_MEMALIGN)
moz_posix_memalign(&mBuf, aAlignment, aSize); (void)moz_posix_memalign(&mBuf, aAlignment, aSize);
#else #else
#error "No memalign implementation found" #error "No memalign implementation found"
#endif #endif

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

@ -46,7 +46,7 @@ VolatileBuffer::Init(size_t aSize, size_t aAlignment)
} }
heap_alloc: heap_alloc:
moz_posix_memalign(&mBuf, aAlignment, aSize); (void)moz_posix_memalign(&mBuf, aAlignment, aSize);
mHeap = true; mHeap = true;
return !!mBuf; return !!mBuf;
} }

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

@ -79,6 +79,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
@ -890,6 +891,12 @@ abstract public class BrowserApp extends GeckoApp
// Intercept key events for gamepad shortcuts // Intercept key events for gamepad shortcuts
mLayerView.setOnKeyListener(this); mLayerView.setOnKeyListener(this);
// Initialize the actionbar menu items on startup for both large and small tablets
if (HardwareUtils.isTablet()) {
onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, null);
invalidateOptionsMenu();
}
} }
private void shareCurrentUrl() { private void shareCurrentUrl() {

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

@ -44,6 +44,13 @@ var ContextMenus = {
init: function() { init: function() {
document.addEventListener("contextmenu", this, false); document.addEventListener("contextmenu", this, false);
document.getElementById("contextmenu-open").addEventListener("click", this.open.bind(this), false);
document.getElementById("contextmenu-retry").addEventListener("click", this.retry.bind(this), false);
document.getElementById("contextmenu-remove").addEventListener("click", this.remove.bind(this), false);
document.getElementById("contextmenu-pause").addEventListener("click", this.pause.bind(this), false);
document.getElementById("contextmenu-resume").addEventListener("click", this.resume.bind(this), false);
document.getElementById("contextmenu-cancel").addEventListener("click", this.cancel.bind(this), false);
document.getElementById("contextmenu-removeall").addEventListener("click", this.removeAll.bind(this), false);
this.items = [ this.items = [
{ name: "open", states: [Downloads._dlmgr.DOWNLOAD_FINISHED] }, { name: "open", states: [Downloads._dlmgr.DOWNLOAD_FINISHED] },
{ name: "retry", states: [Downloads._dlmgr.DOWNLOAD_FAILED, Downloads._dlmgr.DOWNLOAD_CANCELED] }, { name: "retry", states: [Downloads._dlmgr.DOWNLOAD_FAILED, Downloads._dlmgr.DOWNLOAD_CANCELED] },
@ -599,3 +606,8 @@ let Downloads = {
return this; return this;
} }
} }
document.addEventListener("DOMContentLoaded", Downloads.init.bind(Downloads), true);
window.addEventListener("unload", Downloads.uninit.bind(Downloads), false);

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

@ -24,15 +24,15 @@
<link rel="stylesheet" href="chrome://browser/skin/aboutDownloads.css" type="text/css"/> <link rel="stylesheet" href="chrome://browser/skin/aboutDownloads.css" type="text/css"/>
</head> </head>
<body dir="&locale.dir;" onload="Downloads.init();" onunload="Downloads.uninit();"> <body dir="&locale.dir;">
<menu type="context" id="downloadmenu"> <menu type="context" id="downloadmenu">
<menuitem id="contextmenu-open" label="&aboutDownloads.open;" onclick="ContextMenus.open();"></menuitem> <menuitem id="contextmenu-open" label="&aboutDownloads.open;"></menuitem>
<menuitem id="contextmenu-retry" label="&aboutDownloads.retry;" onclick="ContextMenus.retry();"></menuitem> <menuitem id="contextmenu-retry" label="&aboutDownloads.retry;"></menuitem>
<menuitem id="contextmenu-remove" label="&aboutDownloads.remove;" onclick="ContextMenus.remove();"></menuitem> <menuitem id="contextmenu-remove" label="&aboutDownloads.remove;"></menuitem>
<menuitem id="contextmenu-pause" label="&aboutDownloads.pause;" onclick="ContextMenus.pause();"></menuitem> <menuitem id="contextmenu-pause" label="&aboutDownloads.pause;"></menuitem>
<menuitem id="contextmenu-resume" label="&aboutDownloads.resume;" onclick="ContextMenus.resume();"></menuitem> <menuitem id="contextmenu-resume" label="&aboutDownloads.resume;"></menuitem>
<menuitem id="contextmenu-cancel" label="&aboutDownloads.cancel;" onclick="ContextMenus.cancel();"></menuitem> <menuitem id="contextmenu-cancel" label="&aboutDownloads.cancel;"></menuitem>
<menuitem id="contextmenu-removeall" label="&aboutDownloads.removeAll;" onclick="ContextMenus.removeAll();"></menuitem> <menuitem id="contextmenu-removeall" label="&aboutDownloads.removeAll;"></menuitem>
</menu> </menu>
<div class="header"> <div class="header">

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

@ -24,6 +24,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
// All properties exposed by the public FxAccounts API. // All properties exposed by the public FxAccounts API.
let publicProperties = [ let publicProperties = [
"getAccountsSignInURI",
"getAccountsURI", "getAccountsURI",
"getAssertion", "getAssertion",
"getKeys", "getKeys",
@ -615,6 +616,15 @@ FxAccountsInternal.prototype = {
return url; return url;
}, },
// Return the URI of the remote UI flows.
getAccountsSignInURI: function() {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.signin.uri");
if (!/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
return url;
},
// Returns a promise that resolves with the URL to use to force a re-signin // Returns a promise that resolves with the URL to use to force a re-signin
// of the current account. // of the current account.
promiseAccountsForceSigninURI: function() { promiseAccountsForceSigninURI: function() {

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

@ -64,14 +64,20 @@ this.TelemetryFile = {
* *
* @param {object} ping The content of the ping to save. * @param {object} ping The content of the ping to save.
* @param {string} file The destination file. * @param {string} file The destination file.
* @param {bool} overwrite If |true|, the file will be overwritten * @param {bool} overwrite If |true|, the file will be overwritten if it exists,
* if it exists. * if |false| the file will not be overwritten and no error will be reported if
* the file exists.
* @returns {promise} * @returns {promise}
*/ */
savePingToFile: function(ping, file, overwrite) { savePingToFile: function(ping, file, overwrite) {
let pingString = JSON.stringify(ping); return Task.spawn(function*() {
return OS.File.writeAtomic(file, pingString, {tmpPath: file + ".tmp", try {
noOverwrite: !overwrite}); let pingString = JSON.stringify(ping);
yield OS.File.writeAtomic(file, pingString, {tmpPath: file + ".tmp",
noOverwrite: !overwrite});
} catch(e if e.becauseExists) {
}
})
}, },
/** /**
@ -86,7 +92,7 @@ this.TelemetryFile = {
return Task.spawn(function*() { return Task.spawn(function*() {
yield getPingDirectory(); yield getPingDirectory();
let file = pingFilePath(ping); let file = pingFilePath(ping);
return this.savePingToFile(ping, file, overwrite); yield this.savePingToFile(ping, file, overwrite);
}.bind(this)); }.bind(this));
}, },
@ -98,6 +104,8 @@ this.TelemetryFile = {
*/ */
savePendingPings: function(sessionPing) { savePendingPings: function(sessionPing) {
let p = pendingPings.reduce((p, ping) => { let p = pendingPings.reduce((p, ping) => {
// Restore the files with the previous pings if for some reason they have
// been deleted, don't overwrite them otherwise.
p.push(this.savePing(ping, false)); p.push(this.savePing(ping, false));
return p;}, [this.savePing(sessionPing, true)]); return p;}, [this.savePing(sessionPing, true)]);

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

@ -789,13 +789,13 @@ let Impl = {
function handler(success) { function handler(success) {
return function(event) { return function(event) {
this.finishPingRequest(success, startTime, ping); this.finishPingRequest(success, startTime, ping).then(() => {
if (success) {
if (success) { deferred.resolve();
deferred.resolve(); } else {
} else { deferred.reject(event);
deferred.reject(event); }
} });
}; };
} }
request.addEventListener("error", handler(false).bind(this), false); request.addEventListener("error", handler(false).bind(this), false);

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

@ -18,6 +18,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this); Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://gre/modules/TelemetryPing.jsm", this); Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this); Cu.import("resource://gre/modules/Task.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this); Cu.import("resource://gre/modules/Promise.jsm", this);
@ -399,6 +400,14 @@ function actualTest() {
run_next_test(); run_next_test();
} }
// Ensure that not overwriting an existing file fails silently
add_task(function* test_overwritePing() {
let ping = {slug: "foo"}
yield TelemetryFile.savePing(ping, true);
yield TelemetryFile.savePing(ping, false);
yield TelemetryFile.cleanupPingFile(ping);
});
// Ensures that expired histograms are not part of the payload. // Ensures that expired histograms are not part of the payload.
add_task(function* test_expiredHistogram() { add_task(function* test_expiredHistogram() {
let histogram_id = "FOOBAR"; let histogram_id = "FOOBAR";

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

@ -91,6 +91,9 @@
testQuickFindText(); testQuickFindText();
gFindBar.close(); gFindBar.close();
ok(gFindBar.hidden, "Failed to close findbar after testQuickFindText"); ok(gFindBar.hidden, "Failed to close findbar after testQuickFindText");
testFindWithHighlight();
gFindBar.close();
ok(gFindBar.hidden, "Failed to close findbar after testFindWithHighlight");
testFindbarSelection(); testFindbarSelection();
testDrop(); testDrop();
testQuickFindLink(); testQuickFindLink();
@ -304,6 +307,52 @@
"testQuickFindLink: failed to find sample link"); "testQuickFindLink: failed to find sample link");
} }
// See bug 963925 for more details on this test.
function testFindWithHighlight() {
//clearFocus();
gFindBar._findField.value = "";
let findCommand = document.getElementById("cmd_find");
findCommand.doCommand();
let searchStr = "e";
enterStringIntoFindField(searchStr);
let a = gFindBar._findField.value;
let b = gFindBar._browser.finder._fastFind.searchString;
let c = gFindBar._browser.finder.searchString;
ok(a == b && b == c, "testFindWithHighlight: " + a + ", " + b + ", " + c + ".");
let oldGetInitialSelection = gFindBar._getInitialSelection;
let searchStr = "t";
gFindBar._getInitialSelection = () => searchStr;
findCommand.doCommand();
gFindBar._getInitialSelection = oldGetInitialSelection;
a = gFindBar._findField.value;
b = gFindBar._browser.finder._fastFind.searchString;
c = gFindBar._browser.finder.searchString;
ok(a == searchStr && b == c, "testFindWithHighlight: " + a + ", " + b + ", " + c + ".");
let highlightButton = gFindBar.getElement("highlight");
highlightButton.click();
ok(highlightButton.checked, "testFindWithHighlight: Highlight All should be checked.");
a = gFindBar._findField.value;
b = gFindBar._browser.finder._fastFind.searchString;
c = gFindBar._browser.finder.searchString;
ok(a == searchStr && b == c, "testFindWithHighlight: " + a + ", " + b + ", " + c + ".");
gFindBar.onFindAgainCommand();
a = gFindBar._findField.value;
b = gFindBar._browser.finder._fastFind.searchString;
c = gFindBar._browser.finder.searchString;
ok(a == b && b == c, "testFindWithHighlight: " + a + ", " + b + ", " + c + ".");
highlightButton.click();
ok(!highlightButton.checked, "testFindWithHighlight: Highlight All should be unchecked.");
}
function testQuickFindText() { function testQuickFindText() {
clearFocus(); clearFocus();

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

@ -123,8 +123,7 @@
<handler event="compositionend"><![CDATA[ <handler event="compositionend"><![CDATA[
let findbar = this.findbar; let findbar = this.findbar;
findbar._isIMEComposing = false; findbar._isIMEComposing = false;
if (findbar._findMode != findbar.FIND_NORMAL && if (findbar._findMode != findbar.FIND_NORMAL)
!findbar.hidden)
findbar._setFindCloseTimeout(); findbar._setFindCloseTimeout();
]]></handler> ]]></handler>
@ -410,17 +409,18 @@
if (this._quickFindTimeout) if (this._quickFindTimeout)
clearTimeout(this._quickFindTimeout); clearTimeout(this._quickFindTimeout);
// Don't close the find toolbar while IME is composing. // Don't close the find toolbar while IME is composing OR when the
if (this._isIMEComposing) { // findbar is already hidden.
if (this._isIMEComposing || this.hidden) {
this._quickFindTimeout = null; this._quickFindTimeout = null;
return; return;
} }
this._quickFindTimeout = this._quickFindTimeout = setTimeout(() => {
setTimeout(function(aSelf) { if (this._findMode != this.FIND_NORMAL)
if (aSelf._findMode != aSelf.FIND_NORMAL) this.close();
aSelf.close(); this._quickFindTimeout = null;
}, this._quickFindTimeoutLength, this); }, this._quickFindTimeoutLength);
]]></body> ]]></body>
</method> </method>
@ -1127,7 +1127,7 @@
else else
this._findFailedString = null; this._findFailedString = null;
if (this._findMode != this.FIND_NORMAL && !this.hidden) if (this._findMode != this.FIND_NORMAL)
this._setFindCloseTimeout(); this._setFindCloseTimeout();
]]></body> ]]></body>
</method> </method>

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

@ -11,6 +11,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
Cu.import("resource://gre/modules/Task.jsm");
const promise = require("sdk/core/promise"); const promise = require("sdk/core/promise");
const events = require("sdk/event/core"); const events = require("sdk/event/core");
@ -94,18 +95,7 @@ let StyleSheetsActor = protocol.ActorClass({
let window = this.window; let window = this.window;
var domReady = () => { var domReady = () => {
window.removeEventListener("DOMContentLoaded", domReady, true); window.removeEventListener("DOMContentLoaded", domReady, true);
this._addAllStyleSheets().then(deferred.resolve, Cu.reportError);
let documents = [this.document];
let actors = [];
for (let doc of documents) {
let sheets = this._addStyleSheets(doc.styleSheets);
actors = actors.concat(sheets);
// Recursively handle style sheets of the documents in iframes.
for (let iframe of doc.getElementsByTagName("iframe")) {
documents.push(iframe.contentDocument);
}
}
deferred.resolve(actors);
}; };
if (window.document.readyState === "loading") { if (window.document.readyState === "loading") {
@ -120,29 +110,55 @@ let StyleSheetsActor = protocol.ActorClass({
response: { styleSheets: RetVal("array:stylesheet") } response: { styleSheets: RetVal("array:stylesheet") }
}), }),
/**
* Add all the stylesheets in this document and its subframes.
* Assumes the document is loaded.
*
* @return {Promise}
* Promise that resolves with an array of StyleSheetActors
*/
_addAllStyleSheets: function() {
return Task.spawn(function() {
let documents = [this.document];
let actors = [];
for (let doc of documents) {
let sheets = yield this._addStyleSheets(doc.styleSheets);
actors = actors.concat(sheets);
// Recursively handle style sheets of the documents in iframes.
for (let iframe of doc.getElementsByTagName("iframe")) {
documents.push(iframe.contentDocument);
}
}
throw new Task.Result(actors);
}.bind(this));
},
/** /**
* Add all the stylesheets to the map and create an actor for each one * Add all the stylesheets to the map and create an actor for each one
* if not already created. Send event that there are new stylesheets. * if not already created.
* *
* @param {[DOMStyleSheet]} styleSheets * @param {[DOMStyleSheet]} styleSheets
* Stylesheets to add * Stylesheets to add
* @return {[object]} *
* Array of actors for each StyleSheetActor created * @return {Promise}
* Promise that resolves to an array of StyleSheetActors
*/ */
_addStyleSheets: function(styleSheets) _addStyleSheets: function(styleSheets)
{ {
let sheets = []; return Task.spawn(function() {
for (let i = 0; i < styleSheets.length; i++) { let actors = [];
let styleSheet = styleSheets[i]; for (let i = 0; i < styleSheets.length; i++) {
sheets.push(styleSheet); let actor = this._createStyleSheetActor(styleSheets[i]);
actors.push(actor);
// Get all sheets, including imported ones // Get all sheets, including imported ones
let imports = this._getImported(styleSheet); let imports = yield this._getImported(actor);
sheets = sheets.concat(imports); actors = actors.concat(imports);
} }
let actors = sheets.map(this._createStyleSheetActor.bind(this)); throw new Task.Result(actors);
}.bind(this));
return actors;
}, },
/** /**
@ -150,31 +166,37 @@ let StyleSheetsActor = protocol.ActorClass({
* *
* @param {DOMStyleSheet} styleSheet * @param {DOMStyleSheet} styleSheet
* Style sheet to search * Style sheet to search
* @return {array} * @return {Promise}
* All the imported stylesheets * A promise that resolves with an array of StyleSheetActors
*/ */
_getImported: function(styleSheet) { _getImported: function(styleSheet) {
let imported = []; return Task.spawn(function() {
let rules = yield styleSheet.getCSSRules();
let imported = [];
for (let i = 0; i < styleSheet.cssRules.length; i++) { for (let i = 0; i < rules.length; i++) {
let rule = styleSheet.cssRules[i]; let rule = rules[i];
if (rule.type == Ci.nsIDOMCSSRule.IMPORT_RULE) { if (rule.type == Ci.nsIDOMCSSRule.IMPORT_RULE) {
// Associated styleSheet may be null if it has already been seen due to // Associated styleSheet may be null if it has already been seen due
// duplicate @imports for the same URL. // to duplicate @imports for the same URL.
if (!rule.styleSheet) { if (!rule.styleSheet) {
continue; continue;
}
let actor = this._createStyleSheetActor(rule.styleSheet);
imported.push(actor);
// recurse imports in this stylesheet as well
let children = yield this._getImported(actor);
imported = imported.concat(children);
} }
imported.push(rule.styleSheet); else if (rule.type != Ci.nsIDOMCSSRule.CHARSET_RULE) {
// @import rules must precede all others except @charset
break;
}
}
// recurse imports in this stylesheet as well throw new Task.Result(imported);
imported = imported.concat(this._getImported(rule.styleSheet)); }.bind(this));
}
else if (rule.type != Ci.nsIDOMCSSRule.CHARSET_RULE) {
// @import rules must precede all others except @charset
break;
}
}
return imported;
}, },
/** /**
@ -319,17 +341,50 @@ let StyleSheetActor = protocol.ActorClass({
this._styleSheetIndex = -1; this._styleSheetIndex = -1;
this._transitionRefCount = 0; this._transitionRefCount = 0;
},
// if this sheet has an @import, then it's rules are loaded async /**
let ownerNode = this.rawSheet.ownerNode; * Get the raw stylesheet's cssRules once the sheet has been loaded.
if (ownerNode) { *
let onSheetLoaded = function(event) { * @return {Promise}
ownerNode.removeEventListener("load", onSheetLoaded, false); * Promise that resolves with a CSSRuleList
this._notifyPropertyChanged("ruleCount"); */
}.bind(this); getCSSRules: function() {
let rules;
ownerNode.addEventListener("load", onSheetLoaded, false); try {
rules = this.rawSheet.cssRules;
} }
catch (e) {
// sheet isn't loaded yet
}
if (rules) {
return promise.resolve(rules);
}
let ownerNode = this.rawSheet.ownerNode;
if (!ownerNode) {
return promise.resolve([]);
}
if (this._cssRules) {
return this._cssRules;
}
let deferred = promise.defer();
let onSheetLoaded = function(event) {
ownerNode.removeEventListener("load", onSheetLoaded, false);
deferred.resolve(this.rawSheet.cssRules);
}.bind(this);
ownerNode.addEventListener("load", onSheetLoaded, false);
// cache so we don't add many listeners if this is called multiple times.
this._cssRules = deferred.promise;
return this._cssRules;
}, },
/** /**
@ -369,6 +424,9 @@ let StyleSheetActor = protocol.ActorClass({
} }
catch(e) { catch(e) {
// stylesheet had an @import rule that wasn't loaded yet // stylesheet had an @import rule that wasn't loaded yet
this.getCSSRules().then(() => {
this._notifyPropertyChanged("ruleCount");
});
} }
return form; return form;
}, },

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

@ -111,11 +111,12 @@ function safeGetState(state) {
if (!state) { if (!state) {
return "(none)"; return "(none)";
} }
let data, string;
try { try {
// Evaluate state(), normalize the result into something that we can // Evaluate state(), normalize the result into something that we can
// safely stringify or upload. // safely stringify or upload.
let string = JSON.stringify(state()); string = JSON.stringify(state());
let data = JSON.parse(string); data = JSON.parse(string);
// Simplify the rest of the code by ensuring that we can simply // Simplify the rest of the code by ensuring that we can simply
// concatenate the result to a message. // concatenate the result to a message.
if (data && typeof data == "object") { if (data && typeof data == "object") {
@ -125,6 +126,9 @@ function safeGetState(state) {
} }
return data; return data;
} catch (ex) { } catch (ex) {
if (string) {
return string;
}
try { try {
return "Error getting state: " + ex + " at " + ex.stack; return "Error getting state: " + ex + " at " + ex.stack;
} catch (ex2) { } catch (ex2) {

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

@ -36,8 +36,9 @@ Finder.prototype = {
this._listeners = this._listeners.filter(l => l != aListener); this._listeners = this._listeners.filter(l => l != aListener);
}, },
_notify: function (aSearchString, aResult, aFindBackwards, aDrawOutline) { _notify: function (aSearchString, aResult, aFindBackwards, aDrawOutline, aStoreResult = true) {
this._searchString = aSearchString; if (aStoreResult)
this._searchString = aSearchString;
this._outlineLink(aDrawOutline); this._outlineLink(aDrawOutline);
let foundLink = this._fastFind.foundLink; let foundLink = this._fastFind.foundLink;
@ -62,6 +63,7 @@ Finder.prototype = {
linkURL: linkURL, linkURL: linkURL,
rect: this._getResultRect(), rect: this._getResultRect(),
searchString: this._searchString, searchString: this._searchString,
storeResult: aStoreResult
}; };
for (let l of this._listeners) { for (let l of this._listeners) {
@ -110,7 +112,7 @@ Finder.prototype = {
if (aHighlight) { if (aHighlight) {
let result = found ? Ci.nsITypeAheadFind.FIND_FOUND let result = found ? Ci.nsITypeAheadFind.FIND_FOUND
: Ci.nsITypeAheadFind.FIND_NOTFOUND; : Ci.nsITypeAheadFind.FIND_NOTFOUND;
this._notify(aWord, result, false, false); this._notify(aWord, result, false, false, false);
} }
}, },

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

@ -5,213 +5,213 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GonkMemoryPressureMonitoring.h" #include "GonkMemoryPressureMonitoring.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsMemoryPressure.h" #include "nsMemoryPressure.h"
#include "nsXULAppAPI.h" #include "nsThreadUtils.h"
#include "base/message_loop.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h>
#include <android/log.h> #include <android/log.h>
#define LOG(args...) \ #define LOG(args...) \
__android_log_print(ANDROID_LOG_INFO, "GonkMemoryPressure" , ## args) __android_log_print(ANDROID_LOG_INFO, "GonkMemoryPressure" , ## args)
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
using namespace mozilla; using namespace mozilla;
namespace { namespace {
// /**
// MemoryPressureWatcher watches on the I/O thread for changes to the * MemoryPressureWatcher watches sysfs from its own thread to notice when the
// lowmemkiller's sysfs interface. If the system runs low on memory, * system is under memory pressure. When we observe memory pressure, we use
// MemoryPressureWatcher sends a MemoryPressureEvent, removes itself * MemoryPressureRunnable to notify observers that they should release memory.
// from the I/O loop, and schedules a PollTask to re-start polling *
// after a timeout has been reached. * When the system is under memory pressure, we don't want to constantly fire
// * memory-pressure events. So instead, we try to detect when sysfs indicates
// The PollTask is allocated by MemoryPressureWatcher and handed over * that we're no longer under memory pressure, and only then start firing events
// to the I/O loop, which then owns the object and deletes it after it * again.
// ran. We cannot allocate the object dynamically, because the system *
// is already low on memory. Instead we overload the new and delete * (This is a bit problematic because we can't poll() to detect when we're no
// operators for PollTask to hand-out statically allocated memory. * longer under memory pressure; instead we have to periodically read the sysfs
// There can only be at most one instance of PollTask at a time, so * node. If we remain under memory pressure for a long time, this means we'll
// we can re-use the same memory on each allocation. * continue waking up to read from the node for a long time, potentially wasting
// * battery life. Hopefully we don't hit this case in practice! We write to
// There is a separate observer for shutdown events. When the system * logcat each time we go around this loop so it's at least noticable.)
// shuts down, it sends a task to the I/O thread for removing the *
// watcher. If a PollTask is pending, it gets canceled. We cannot * Shutting down safely is a bit of a chore. XPCOM won't shut down until all
// delete it at this point, because it's owned by the I/O loop. * threads exit, so we need to exit the Run() method below on shutdown. But our
// * thread might be blocked in one of two situations: We might be poll()'ing the
class MemoryPressureWatcher : public MessageLoopForIO::Watcher * sysfs node waiting for memory pressure to occur, or we might be asleep
* waiting to read() the sysfs node to see if we're no longer under memory
* pressure.
*
* To let us wake up from the poll(), we poll() not just the sysfs node but also
* a pipe, which we write to on shutdown. To let us wake up from sleeping
* between read()s, we sleep by Wait()'ing on a monitor, which we notify on
* shutdown.
*/
class MemoryPressureWatcher
: public nsIRunnable
, public nsIObserver
{ {
public: public:
class PollTask : public CancelableTask MemoryPressureWatcher()
: mMonitor("MemoryPressureWatcher")
, mShuttingDown(false)
{ {
public:
PollTask(MemoryPressureWatcher* aWatcher)
: mWatcher(aWatcher)
{
MOZ_ASSERT(mWatcher);
}
static void* operator new(size_t aSize);
static void operator delete(void* aMem, size_t aSize);
void Run() MOZ_OVERRIDE
{
MOZ_ASSERT(MessageLoopForIO::current());
if (mWatcher) {
MOZ_ASSERT(MessageLoopForIO::current() == mWatcher->GetIOLoop());
mWatcher->StartWatching();
}
}
void Cancel() MOZ_OVERRIDE
{
mWatcher = nullptr;
}
private:
MemoryPressureWatcher* mWatcher;
};
template <size_t Size> class PollTaskAllocator
{
public:
void* Alloc()
{
MOZ_ASSERT(!sAllocated);
sAllocated = true;
return mMem;
}
void Release(void* aMem)
{
MOZ_ASSERT(mMem == aMem);
MOZ_ASSERT(sAllocated);
sAllocated = false;
}
private:
static bool sAllocated;
unsigned char mMem[Size];
};
MemoryPressureWatcher(MessageLoop* aIOLoop, uint32_t aPollMS)
: mFd(-1)
, mIOLoop(aIOLoop)
, mPollTask(nullptr)
, mPollMS(aPollMS)
, mMemoryPressure(false)
{
MOZ_ASSERT(mIOLoop);
} }
virtual ~MemoryPressureWatcher() NS_DECL_THREADSAFE_ISUPPORTS
nsresult Init()
{ {
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop); nsCOMPtr<nsIObserverService> os = services::GetObserverService();
MOZ_ASSERT(mFd == -1); NS_ENSURE_STATE(os);
// The observer service holds us alive.
os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, /* holdsWeak */ false);
// While we're under memory pressure, we periodically read()
// notify_trigger_active to try and see when we're no longer under memory
// pressure. mPollMS indicates how many milliseconds we wait between those
// read()s.
mPollMS = Preferences::GetUint("gonk.systemMemoryPressureRecoveryPollMS",
/* default */ 5000);
int pipes[2];
NS_ENSURE_STATE(!pipe(pipes));
mShutdownPipeRead = pipes[0];
mShutdownPipeWrite = pipes[1];
return NS_OK;
} }
MessageLoop* GetIOLoop () const NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{ {
return mIOLoop; MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
} LOG("Observed XPCOM shutdown.");
nsresult Open() MonitorAutoLock lock(mMonitor);
{ mShuttingDown = true;
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop); mMonitor.Notify();
int fd;
int rv;
do { do {
fd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active", // Write something to the pipe; doesn't matter what.
O_RDONLY | O_CLOEXEC); uint32_t dummy = 0;
} while (fd == -1 && errno == EINTR); rv = write(mShutdownPipeWrite, &dummy, sizeof(dummy));
} while(rv == -1 && errno == EINTR);
if (NS_WARN_IF(fd == -1)) {
return NS_ERROR_NOT_AVAILABLE;
}
mFd = fd;
return NS_OK; return NS_OK;
} }
void Close() NS_IMETHOD Run()
{ {
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop); MOZ_ASSERT(!NS_IsMainThread());
if (NS_WARN_IF(mFd == -1)) { #ifdef MOZ_NUWA_PROCESS
return; if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
"NuwaMarkCurrentThread is undefined!");
NuwaMarkCurrentThread(nullptr, nullptr);
} }
#endif
int res; int lowMemFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active",
O_RDONLY | O_CLOEXEC);
NS_ENSURE_STATE(lowMemFd != -1);
ScopedClose autoClose(lowMemFd);
do { nsresult rv = CheckForMemoryPressure(lowMemFd, nullptr);
res = close(mFd); NS_ENSURE_SUCCESS(rv, rv);
} while (res == -1 && errno == EINTR);
NS_WARN_IF(res == -1); while (true) {
mFd = -1; // Wait for a notification on lowMemFd or for data to be written to
} // mShutdownPipeWrite. (poll(lowMemFd, POLLPRI) blocks until we're under
// memory pressure.)
struct pollfd pollfds[2];
pollfds[0].fd = lowMemFd;
pollfds[0].events = POLLPRI;
pollfds[1].fd = mShutdownPipeRead;
pollfds[1].events = POLLIN;
void StartWatching() int pollRv;
{ do {
MessageLoopForIO* ioLoop = MessageLoopForIO::current(); pollRv = poll(pollfds, ArrayLength(pollfds), /* timeout */ -1);
MOZ_ASSERT(ioLoop == mIOLoop); } while (pollRv == -1 && errno == EINTR);
ioLoop->WatchFileDescriptor(mFd, true, MessageLoopForIO::WATCH_READ,
&mReadWatcher, this);
mPollTask = nullptr;
}
void StopWatching() if (pollfds[1].revents) {
{ // Something was written to our shutdown pipe; we're outta here.
if (mPollTask) { LOG("shutting down (1)");
mPollTask->Cancel(); return NS_OK;
}
mReadWatcher.StopWatchingFileDescriptor();
}
virtual void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
NS_WARNING("Must not write to memory monitor");
}
virtual void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
bool memoryPressure;
nsresult rv = CheckForMemoryPressure(memoryPressure);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (memoryPressure) {
LOG("Memory pressure detected.");
StopWatching();
if (mMemoryPressure) {
rv = NS_DispatchMemoryPressure(MemPressure_Ongoing);
} else {
rv = NS_DispatchMemoryPressure(MemPressure_New);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
} }
// While we're under memory pressure, we periodically read() // If pollfds[1] isn't happening, pollfds[0] ought to be!
// notify_trigger_active to try and see when we're no longer under if (!(pollfds[0].revents & POLLPRI)) {
// memory pressure. mPollMS indicates how many milliseconds we wait LOG("Unexpected revents value after poll(): %d. "
// between those read()s. "Shutting down GonkMemoryPressureMonitoring.", pollfds[0].revents);
mPollTask = new PollTask(this); return NS_ERROR_FAILURE;
mIOLoop->PostDelayedTask(FROM_HERE, mPollTask, mPollMS); }
} else if (mMemoryPressure) {
// POLLPRI on lowMemFd indicates that we're in a low-memory situation. We
// could read lowMemFd to double-check, but we've observed that the read
// sometimes completes after the memory-pressure event is over, so let's
// just believe the result of poll().
// We use low-memory-no-forward because each process has its own watcher
// and thus there is no need for the main process to forward this event.
rv = NS_DispatchMemoryPressure(MemPressure_New);
NS_ENSURE_SUCCESS(rv, rv);
// Manually check lowMemFd until we observe that memory pressure is over.
// We won't fire any more low-memory events until we observe that
// we're no longer under pressure. Instead, we fire low-memory-ongoing
// events, which cause processes to keep flushing caches but will not
// trigger expensive GCs and other attempts to save memory that are
// likely futile at this point.
bool memoryPressure;
do {
{
MonitorAutoLock lock(mMonitor);
// We need to check mShuttingDown before we wait here, in order to
// catch a shutdown signal sent after we poll()'ed mShutdownPipeRead
// above but before we started waiting on the monitor. But we don't
// need to check after we wait, because we'll either do another
// iteration of this inner loop, in which case we'll check
// mShuttingDown, or we'll exit this loop and do another iteration
// of the outer loop, in which case we'll check the shutdown pipe.
if (mShuttingDown) {
LOG("shutting down (2)");
return NS_OK;
}
mMonitor.Wait(PR_MillisecondsToInterval(mPollMS));
}
LOG("Checking to see if memory pressure is over.");
rv = CheckForMemoryPressure(lowMemFd, &memoryPressure);
NS_ENSURE_SUCCESS(rv, rv);
if (memoryPressure) {
rv = NS_DispatchMemoryPressure(MemPressure_Ongoing);
NS_ENSURE_SUCCESS(rv, rv);
continue;
}
} while (false);
LOG("Memory pressure is over."); LOG("Memory pressure is over.");
} }
mMemoryPressure = memoryPressure;
return NS_OK;
} }
private: private:
@ -222,138 +222,38 @@ private:
* *
* We don't expect this method to block. * We don't expect this method to block.
*/ */
nsresult CheckForMemoryPressure(bool& aOut) nsresult CheckForMemoryPressure(int aLowMemFd, bool* aOut)
{ {
aOut = false; if (aOut) {
*aOut = false;
off_t off = lseek(mFd, 0, SEEK_SET);
if (NS_WARN_IF(off)) {
return NS_ERROR_UNEXPECTED;
} }
lseek(aLowMemFd, 0, SEEK_SET);
char buf[2]; char buf[2];
int nread; int nread;
do { do {
nread = read(mFd, buf, sizeof(buf)); nread = read(aLowMemFd, buf, sizeof(buf));
} while(nread == -1 && errno == EINTR); } while(nread == -1 && errno == EINTR);
if (NS_WARN_IF(nread != 2)) { NS_ENSURE_STATE(nread == 2);
return NS_ERROR_UNEXPECTED;
}
// The notify_trigger_active sysfs node should contain either "0\n" or // The notify_trigger_active sysfs node should contain either "0\n" or
// "1\n". The latter indicates memory pressure. // "1\n". The latter indicates memory pressure.
aOut = buf[0] == '1' && buf[1] == '\n'; if (aOut) {
*aOut = buf[0] == '1' && buf[1] == '\n';
return NS_OK;
}
int mFd;
MessageLoop* mIOLoop;
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
PollTask* mPollTask;
uint32_t mPollMS;
bool mMemoryPressure;
};
static
MemoryPressureWatcher::PollTaskAllocator<sizeof(MemoryPressureWatcher::PollTask)>
sPollTaskAllocator;
template<>
bool
MemoryPressureWatcher::PollTaskAllocator<sizeof(MemoryPressureWatcher::PollTask)>::sAllocated(false);
void*
MemoryPressureWatcher::PollTask::operator new(size_t aSize)
{
return sPollTaskAllocator.Alloc();
}
void
MemoryPressureWatcher::PollTask::operator delete(void* aMem, size_t aSize)
{
sPollTaskAllocator.Release(aMem);
}
// Initializes MemoryPressureWatcher on I/O thread
//
class InitMemoryPressureWatcherTask : public Task
{
public:
InitMemoryPressureWatcherTask(MemoryPressureWatcher* aWatcher)
: mWatcher(aWatcher)
{
MOZ_ASSERT(mWatcher);
}
void Run() MOZ_OVERRIDE
{
MOZ_ASSERT(MessageLoopForIO::current() == mWatcher->GetIOLoop());
nsresult rv = mWatcher->Open();
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
} }
mWatcher->StartWatching();
}
private:
MemoryPressureWatcher* mWatcher;
};
// Releases MemoryPressureWatcher on I/O thread
//
class ShutdownMemoryPressureWatcherTask : public Task
{
public:
ShutdownMemoryPressureWatcherTask(MemoryPressureWatcher* aWatcher)
: mWatcher(aWatcher)
{
MOZ_ASSERT(mWatcher);
}
void Run() MOZ_OVERRIDE
{
MOZ_ASSERT(MessageLoopForIO::current() == mWatcher->GetIOLoop());
mWatcher->StopWatching();
mWatcher->Close();
}
private:
nsAutoPtr<MemoryPressureWatcher> mWatcher;
};
// Closes MemoryPressureWatcher on shutdown
//
class ShutdownObserver : public nsIObserver
{
public:
ShutdownObserver(MemoryPressureWatcher* aWatcher)
: mWatcher(aWatcher)
{
MOZ_ASSERT(mWatcher);
}
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
LOG("Observed XPCOM shutdown.");
Task* task = new ShutdownMemoryPressureWatcherTask(mWatcher);
mWatcher->GetIOLoop()->PostTask(FROM_HERE, task);
return NS_OK; return NS_OK;
} }
private: Monitor mMonitor;
MemoryPressureWatcher* mWatcher; uint32_t mPollMS;
bool mShuttingDown;
ScopedClose mShutdownPipeRead;
ScopedClose mShutdownPipeWrite;
}; };
NS_IMPL_ISUPPORTS1(ShutdownObserver, nsIObserver); NS_IMPL_ISUPPORTS2(MemoryPressureWatcher, nsIRunnable, nsIObserver);
} // anonymous namespace } // anonymous namespace
@ -362,22 +262,13 @@ namespace mozilla {
void void
InitGonkMemoryPressureMonitoring() InitGonkMemoryPressureMonitoring()
{ {
MessageLoop* ioLoop = XRE_GetIOMessageLoop(); // memoryPressureWatcher is held alive by the observer service.
uint32_t pollMS = nsRefPtr<MemoryPressureWatcher> memoryPressureWatcher =
Preferences::GetUint("gonk.systemMemoryPressureRecoveryPollMS", 5000); new MemoryPressureWatcher();
MemoryPressureWatcher* watcher = new MemoryPressureWatcher(ioLoop, pollMS); NS_ENSURE_SUCCESS_VOID(memoryPressureWatcher->Init());
// Start watcher on I/O thread nsCOMPtr<nsIThread> thread;
Task* task = new InitMemoryPressureWatcherTask(watcher); NS_NewThread(getter_AddRefs(thread), memoryPressureWatcher);
watcher->GetIOLoop()->PostTask(FROM_HERE, task);
// Install shutdown observer
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (NS_WARN_IF(!os)) {
return;
}
nsRefPtr<ShutdownObserver> observer = new ShutdownObserver(watcher);
os->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
} }
} // namespace mozilla } // namespace mozilla