Merge mozilla-central to mozilla-inbound on a CLOSED TREE

--HG--
extra : amend_source : bfda8e6ef1895166a8cbe1942b205c8b76884722
This commit is contained in:
Carsten "Tomcat" Book 2014-02-05 14:28:46 +01:00
Родитель fd4b17df41 b377b7d2b5
Коммит aeff978984
62 изменённых файлов: 806 добавлений и 263 удалений

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

@ -12,13 +12,13 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>

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

@ -11,10 +11,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
<!-- Stock Android things -->

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

@ -12,13 +12,13 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>

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

@ -1,4 +1,4 @@
{
"revision": "a4d9c73e176e7dfc9a32d362f0f5e5cb5c21e323",
"revision": "cea79abbb7a97c0bd67051087bcdf40d25611930",
"repo_path": "/integration/gaia-central"
}

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

@ -11,12 +11,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>

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

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

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

@ -12,12 +12,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>

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

@ -11,12 +11,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>

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

@ -11,10 +11,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
<!-- Stock Android things -->

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

@ -11,12 +11,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac94739a01d64e86890f54f1795ff8e82b8e7939"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="fd67604d5932cce3617ff7ce725a0a686d129905"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>

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

@ -213,7 +213,6 @@ let gFxAccounts = {
},
openSignInAgainPage: function () {
// FIXME: This should actually show the pre-filled username version of about:accounts?
switchToTabHavingURI("about:accounts?signin=true", true);
switchToTabHavingURI("about:accounts?action=reauth", true);
}
};

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

@ -173,6 +173,7 @@ toolbar[customizing] > .overflow-button {
}
%ifdef CAN_DRAW_IN_TITLEBAR
#main-window:not([chromemargin]) > #titlebar,
#main-window[inFullscreen] > #titlebar,
#main-window[inFullscreen] .titlebar-placeholder,
#main-window:not([tabsintitlebar]) .titlebar-placeholder {

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

@ -4481,6 +4481,9 @@ var TabsInTitlebar = {
// Try to avoid reflows in this code by calculating dimensions first and
// then later set the properties affecting layout together in a batch.
// Get the full height of the tabs toolbar:
let tabsToolbar = $("TabsToolbar");
let fullTabsHeight = rect(tabsToolbar).height;
// Buttons first:
let captionButtonsBoxWidth = rect($("titlebar-buttonbox")).width;
#ifdef XP_MACOSX
@ -4495,11 +4498,9 @@ var TabsInTitlebar = {
let menuHeight = rect(menubar).height;
let menuStyles = window.getComputedStyle(menubar);
let fullMenuHeight = verticalMargins(menuStyles) + menuHeight;
#endif
// Get the full height of the tabs toolbar:
let tabsToolbar = $("TabsToolbar");
let tabsStyles = window.getComputedStyle(tabsToolbar);
let fullTabsHeight = rect(tabsToolbar).height + verticalMargins(tabsStyles);
fullTabsHeight += verticalMargins(tabsStyles);
#endif
// If the navbar overlaps the tabbar using negative margins, we need to take those into
// account so we don't overlap it
@ -4509,16 +4510,6 @@ var TabsInTitlebar = {
// And get the height of what's in the titlebar:
let titlebarContentHeight = rect(titlebarContent).height;
// Padding surrounds the tab-view-deck when we are in customization mode,
// so take that into account:
let areCustomizing = document.documentElement.hasAttribute("customizing") ||
document.documentElement.hasAttribute("customize-exiting");
let customizePadding = 0;
if (areCustomizing) {
let deckStyle = window.getComputedStyle($("tab-view-deck"));
customizePadding = parseFloat(deckStyle.paddingTop);
}
// Begin setting CSS properties which will cause a reflow
// If the menubar is around (menuHeight is non-zero), try to adjust
@ -4551,10 +4542,6 @@ var TabsInTitlebar = {
// Next, we calculate how much we need to stretch the titlebar down to
// go all the way to the bottom of the tab strip, if necessary.
let tabAndMenuHeight = fullTabsHeight + fullMenuHeight;
// Oh, and don't forget customization mode:
if (areCustomizing) {
tabAndMenuHeight += customizePadding;
}
if (tabAndMenuHeight > titlebarContentHeight) {
// We need to increase the titlebar content's outer height (ie including margins)
@ -4566,12 +4553,6 @@ var TabsInTitlebar = {
// On non-OSX, we can just use bottom margin:
#ifndef XP_MACOSX
titlebarContent.style.marginBottom = extraMargin + "px";
#else
// Otherwise, center the content. This means taking the titlebar's
// padding into account:
let halfMargin = (extraMargin - titlebarPadding) / 2;
titlebarContent.style.marginTop = halfMargin + "px";
titlebarContent.style.marginBottom = (titlebarPadding + halfMargin) + "px";
#endif
titlebarContentHeight += extraMargin;
}
@ -4606,6 +4587,7 @@ var TabsInTitlebar = {
updateTitlebarDisplay();
// Reset the margins and padding that might have been modified:
titlebarContent.style.marginTop = "";
titlebarContent.style.marginBottom = "";
titlebar.style.marginBottom = "";
menubar.style.paddingBottom = "";
@ -4630,16 +4612,37 @@ var TabsInTitlebar = {
#ifdef CAN_DRAW_IN_TITLEBAR
function updateTitlebarDisplay() {
document.getElementById("titlebar").hidden = !TabsInTitlebar.enabled;
#ifdef XP_MACOSX
// OS X and the other platforms differ enough to necessitate this kind of
// special-casing. Like the other platforms where we CAN_DRAW_IN_TITLEBAR,
// we draw in the OS X titlebar when putting the tabs up there. However, OS X
// also draws in the titlebar when a lightweight theme is applied, regardless
// of whether or not the tabs are drawn in the titlebar.
if (TabsInTitlebar.enabled) {
document.documentElement.setAttribute("chromemargin-nonlwtheme", "0,-1,-1,-1");
document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
document.documentElement.removeAttribute("drawtitle");
} else {
// We set chromemargin-nonlwtheme to "" instead of removing it as a way of
// making sure that LightweightThemeConsumer doesn't take it upon itself to
// detect this value again if and when we do a lwtheme state change.
document.documentElement.setAttribute("chromemargin-nonlwtheme", "");
let isCustomizing = document.documentElement.hasAttribute("customizing");
let hasLWTheme = document.documentElement.hasAttribute("lwtheme");
if (!hasLWTheme || isCustomizing) {
document.documentElement.removeAttribute("chromemargin");
}
document.documentElement.setAttribute("drawtitle", "true");
}
#else
if (TabsInTitlebar.enabled)
#ifdef XP_WIN
document.documentElement.setAttribute("chromemargin", "0,2,2,2");
#else
document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
#endif
else
document.documentElement.removeAttribute("chromemargin");
#endif
}
#endif

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

@ -65,7 +65,7 @@
frame1.docShell.chromeEventHandler.removeAttribute("crashedPageTitle");
SimpleTest.is(frame1.contentDocument.documentURI,
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/1&c=UTF-8&d=pageTitle&f=regular",
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/1&c=UTF-8&f=regular&d=pageTitle",
"Correct about:tabcrashed displayed for page with title.");
errorPageReady = waitForErrorPage(frame2);
@ -74,7 +74,7 @@
yield errorPageReady;
SimpleTest.is(frame2.contentDocument.documentURI,
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/2&c=UTF-8&d=%20&f=regular",
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/2&c=UTF-8&f=regular&d=%20",
"Correct about:tabcrashed displayed for page with no title.");
SimpleTest.finish();

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

@ -313,7 +313,8 @@ skip-if = true # disabled until the tree view is added
[browser_tab_dragdrop.js]
[browser_tab_dragdrop2.js]
[browser_tabbar_big_widgets.js]
skip-if = os == "linux" # No tabs in titlebar on linux
skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
# Disabled on OS X because of bug 967917
[browser_tabfocus.js]
[browser_tabopen_reflows.js]
[browser_tabs_isActive.js]

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

@ -123,9 +123,6 @@ const CustomizableWidgets = [{
item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri);
item.setAttribute("class", "subviewbutton");
item.addEventListener("command", function (aEvent) {
onHistoryVisit(uri, aEvent, item);
});
item.addEventListener("click", function (aEvent) {
onHistoryVisit(uri, aEvent, item);
});

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

@ -13,6 +13,8 @@ support-files =
# Bug 916763 - too many intermittent failures
skip-if = true
[browser_inspector_markup_edit.js]
# Bug 904953 - too many intermittent failures on Linux
skip-if = os == "linux"
[browser_inspector_markup_edit_outerhtml.js]
[browser_inspector_markup_edit_outerhtml2.js]
[browser_inspector_markup_mutation.js]

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

@ -1143,8 +1143,7 @@ var BrowserUI = {
confirmSanitizeDialog: function () {
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let title = bundle.GetStringFromName("clearPrivateData.title2");
let options = bundle.GetStringFromName("optionsCharm");
let message = bundle.GetStringFromName("clearPrivateData.message2").replace("#1", options);
let message = bundle.GetStringFromName("clearPrivateData.message3");
let clearbutton = bundle.GetStringFromName("clearPrivateData.clearButton");
let prefsClearButton = document.getElementById("prefs-clear-data");

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

@ -9,16 +9,18 @@ function test() {
runTests();
}
function getSimpleMeasurementsFromTelemetryPing() {
function getTelemetryPayload() {
return Cu.import("resource://gre/modules/TelemetryPing.jsm", {}).
TelemetryPing.getPayload().simpleMeasurements;
TelemetryPing.getPayload();
}
gTests.push({
desc: "Test browser-ui telemetry",
run: function testBrowserUITelemetry() {
// startup should have registered simple measures function
let simpleMeasurements = getSimpleMeasurementsFromTelemetryPing();
is(getTelemetryPayload().info.appName, "MetroFirefox");
let simpleMeasurements = getTelemetryPayload().simpleMeasurements;
ok(simpleMeasurements, "simpleMeasurements are truthy");
ok(simpleMeasurements.UITelemetry["metro-ui"]["window-width"], "window-width measurement was captured");
ok(simpleMeasurements.UITelemetry["metro-ui"]["window-height"], "window-height measurement was captured");

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

@ -39,8 +39,8 @@ contextAppbar2.clear=Clear selection
# Clear private data
clearPrivateData.clearButton=Clear
clearPrivateData.title2=Clear private data
# LOCALIZATION NOTE (clearPrivateData.message2): #1 is optionsCharm
clearPrivateData.message2=This will permanently delete the private data you have selected in #1
# LOCALIZATION NOTE (clearPrivateData.message3): "Options" is the optionsCharm.
clearPrivateData.message3=This will permanently delete the private data you have selected in "Options".
# Settings Charms
aboutCharm1=About

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

@ -73,6 +73,7 @@ browser.jar:
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)

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

@ -59,7 +59,7 @@
}
}
#main-window[chromehidden~="toolbar"] > #titlebar {
#main-window[chromehidden~="toolbar"]:not(:-moz-lwtheme) > #titlebar {
padding-top: 22px;
}
@ -2669,7 +2669,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
box-shadow: @focusRingShadow@;
}
#titlebar {
#main-window:not(:-moz-lwtheme) > #titlebar {
padding-top: @spaceAboveTabbar@;
min-height: @tabHeight@;
}
@ -4104,13 +4104,26 @@ window > chatbox {
%include ../shared/customizableui/customizeMode.inc.css
#main-window[customize-entered] #titlebar {
#main-window[customize-entered] > #titlebar {
padding-top: 0;
}
#main-window[tabsintitlebar][customize-entered] #titlebar-content {
margin-bottom: 0px !important;
margin-top: 11px !important;
#main-window[tabsintitlebar]:not([customizing]):not(:-moz-lwtheme) > #titlebar > #titlebar-content,
#main-window[tabsintitlebar][customize-entering] > #titlebar > #titlebar-content,
#main-window[tabsintitlebar][customize-exiting] > #titlebar > #titlebar-content {
margin-top: 2px;
margin-bottom: 11px;
}
#main-window[tabsintitlebar][customize-entered] > #titlebar > #titlebar-content,
#main-window:not([tabsintitlebar]):not(:-moz-lwtheme) > #titlebar > #titlebar-content {
margin-top: 11px;
margin-bottom: 0px;
}
#main-window[tabsintitlebar]:-moz-lwtheme > #titlebar > #titlebar-content {
margin-top: 11px;
margin-bottom: 11px;
}
#main-window[customize-entered] #tab-view-deck {
@ -4135,8 +4148,11 @@ window > chatbox {
border-bottom-width: 0;
}
#main-window[customize-entered] #TabsToolbar {
#main-window[tabsintitlebar][customize-entered] #TabsToolbar {
margin-top: 9px;
}
#main-window[customize-entered] #TabsToolbar {
background-clip: padding-box;
border-right: 3px solid transparent;
border-left: 3px solid transparent;

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

@ -15,6 +15,10 @@
list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
}
#main-window[customize-entered] #PanelUI-customize {
list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish@2x.png);
}
#PanelUI-help {
list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
}

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

@ -120,6 +120,8 @@ browser.jar:
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png (../shared/customizableui/menuPanel-customizeFinish@2x.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png (../shared/customizableui/subView-arrow-back-inverted@2x.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)

Двоичные данные
browser/themes/shared/customizableui/menuPanel-customizeFinish.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 236 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 399 B

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

@ -322,6 +322,10 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
list-style-image: url(chrome://browser/skin/menuPanel-customize.png);
}
#customization-panelHolder #PanelUI-customize {
list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish.png);
}
#PanelUI-help {
list-style-image: url(chrome://browser/skin/menuPanel-help.png);
}
@ -378,16 +382,15 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
background-color: #ad3434;
}
#main-window[customize-entered] #PanelUI-customize {
#customization-panelHolder #PanelUI-customize {
color: white;
background-image: linear-gradient(rgb(41,123,204), rgb(40,133,203));
box-shadow: inset 0 1px 1px rgba(0,0,0,0.5), 0 2px rgba(255,255,255,0.2);
text-shadow: 0 1px 0 rgba(0,0,0,0.4);
background-color: rgb(116,191,67);
text-shadow: none;
}
#main-window[customize-entered] #PanelUI-customize:hover,
#main-window[customize-entered] #PanelUI-customize:hover:active {
background-image: linear-gradient(rgb(38,115,191), rgb(38,125,191));
#customization-panelHolder #PanelUI-customize:hover,
#customization-panelHolder #PanelUI-customize:hover:active {
background-color: rgb(105,173,61);
}
#customization-palette .toolbarbutton-multiline-text,

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

@ -92,6 +92,7 @@ browser.jar:
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
* skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
@ -404,6 +405,7 @@ browser.jar:
skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/aero/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
* skin/classic/aero/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/aero/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
* skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)

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

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioCompactor.h"
#if defined(MOZ_MEMORY)
# include "mozmemory.h"
#endif
namespace mozilla {
static size_t
MallocGoodSize(size_t aSize)
{
# if defined(MOZ_MEMORY)
return malloc_good_size(aSize);
# else
return aSize;
# endif
}
static size_t
TooMuchSlop(size_t aSize, size_t aAllocSize, size_t aMaxSlop)
{
// If the allocated size is less then our target size, then we
// are chunking. This means it will be completely filled with
// zero slop.
size_t slop = (aAllocSize > aSize) ? (aAllocSize - aSize) : 0;
return slop > aMaxSlop;
}
uint32_t
AudioCompactor::GetChunkSamples(uint32_t aFrames, uint32_t aChannels,
size_t aMaxSlop)
{
size_t size = AudioDataSize(aFrames, aChannels);
size_t chunkSize = MallocGoodSize(size);
// Reduce the chunk size until we meet our slop goal or the chunk
// approaches an unreasonably small size.
while (chunkSize > 64 && TooMuchSlop(size, chunkSize, aMaxSlop)) {
chunkSize = MallocGoodSize(chunkSize / 2);
}
// Calculate the number of samples based on expected malloc size
// in order to allow as many frames as possible to be packed.
return chunkSize / sizeof(AudioDataValue);
}
uint32_t
AudioCompactor::NativeCopy::operator()(AudioDataValue *aBuffer, size_t aSamples)
{
NS_ASSERTION(aBuffer, "cannot copy to null buffer pointer");
NS_ASSERTION(aSamples, "cannot copy zero values");
size_t bufferBytes = aSamples * sizeof(AudioDataValue);
size_t maxBytes = std::min(bufferBytes, mSourceBytes - mNextByte);
uint32_t frames = maxBytes / BytesPerFrame(mChannels);
size_t bytes = frames * BytesPerFrame(mChannels);
NS_ASSERTION((mNextByte + bytes) <= mSourceBytes,
"tried to copy beyond source buffer");
NS_ASSERTION(bytes <= bufferBytes, "tried to copy beyond destination buffer");
memcpy(aBuffer, mSource + mNextByte, bytes);
mNextByte += bytes;
return frames;
}
} // namespace mozilla

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

@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(AudioCompactor_h)
#define AudioCompactor_h
#include "MediaQueue.h"
#include "MediaData.h"
#include "VideoUtils.h"
namespace mozilla {
class AudioCompactor
{
public:
AudioCompactor(MediaQueue<AudioData>& aQueue)
: mQueue(aQueue)
{ }
// Push audio data into the underlying queue with minimal heap allocation
// slop. This method is responsible for allocating AudioDataValue[] buffers.
// The caller must provide a functor to copy the data into the buffers. The
// functor must provide the following signature:
//
// uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples);
//
// The functor must copy as many complete frames as possible to the provided
// buffer given its length (in AudioDataValue elements). The number of frames
// copied must be returned. This copy functor must support being called
// multiple times in order to copy the audio data fully. The copy functor
// must copy full frames as partial frames will be ignored.
template<typename CopyFunc>
bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc)
{
// If we are losing more than a reasonable amount to padding, try to chunk
// the data.
size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
while (aFrames > 0) {
uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[samples]);
// Copy audio data to buffer using caller-provided functor.
uint32_t framesCopied = aCopyFunc(buffer, samples);
NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
CheckedInt64 duration = FramesToUsecs(framesCopied, aSampleRate);
if (!duration.isValid()) {
return false;
}
mQueue.Push(new AudioData(aOffset,
aTime,
duration.value(),
framesCopied,
buffer.forget(),
aChannels));
// Remove the frames we just pushed into the queue and loop if there is
// more to be done.
aTime += duration.value();
aFrames -= framesCopied;
// NOTE: No need to update aOffset as its only an approximation anyway.
}
return true;
}
// Copy functor suitable for copying audio samples already in the
// AudioDataValue format/layout expected by AudioStream on this platform.
class NativeCopy
{
public:
NativeCopy(const uint8_t* aSource, size_t aSourceBytes,
uint32_t aChannels)
: mSource(aSource)
, mSourceBytes(aSourceBytes)
, mChannels(aChannels)
, mNextByte(0)
{ }
uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples);
private:
const uint8_t* const mSource;
const size_t mSourceBytes;
const uint32_t mChannels;
size_t mNextByte;
};
// Allow 12.5% slop before chunking kicks in. Public so that the gtest can
// access it.
static const size_t MAX_SLOP_DIVISOR = 8;
private:
// Compute the number of AudioDataValue samples that will be fit the most
// frames while keeping heap allocation slop less than the given threshold.
static uint32_t
GetChunkSamples(uint32_t aFrames, uint32_t aChannels, size_t aMaxSlop);
static size_t BytesPerFrame(uint32_t aChannels)
{
return sizeof(AudioDataValue) * aChannels;
}
static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels)
{
return aFrames * BytesPerFrame(aChannels);
}
MediaQueue<AudioData> &mQueue;
};
} // namespace mozilla
#endif // AudioCompactor_h

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

@ -45,7 +45,8 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
}
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mDecoder(aDecoder),
: mAudioCompactor(mAudioQueue),
mDecoder(aDecoder),
mIgnoreAudioOutputFormat(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
@ -280,4 +281,3 @@ MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
}
} // namespace mozilla

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

@ -10,6 +10,7 @@
#include "MediaInfo.h"
#include "MediaData.h"
#include "MediaQueue.h"
#include "AudioCompactor.h"
namespace mozilla {
@ -105,6 +106,12 @@ protected:
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// An adapter to the audio queue which first copies data to buffers with
// minimal allocation slop and then pushes them to the queue. This is
// useful for decoders working with formats that give awkward numbers of
// frames such as mp3.
AudioCompactor mAudioCompactor;
public:
// Populates aBuffered with the time ranges which are buffered. aStartTime
// must be the presentation time of the first frame in the media, e.g.

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

@ -45,6 +45,13 @@ extern PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(type, msg)
#endif
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
// implementation. With unified builds, putting this in headers is not enough.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
// Wait this number of seconds when buffering, then leave and play
// as best as we can if the required amount of data hasn't been
// retrieved.

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

@ -92,6 +92,13 @@ namespace mozilla {
class AudioSegment;
class VideoSegment;
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
// implementation.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
/*
The state machine class. This manages the decoding and seeking in the
MediaDecoderReader on the decode thread, and A/V sync on the shared

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

@ -12,8 +12,12 @@
#define AUDIO_READ_BYTES 4096
// Maximum number of audio frames we will accept from the audio decoder in one
// go.
#define MAX_AUDIO_FRAMES 4096
// go. Carefully select this to work well with both the mp3 1152 max frames
// per block and power-of-2 allocation sizes. Since we must pre-allocate the
// buffer we cannot use AudioCompactor without paying for an additional
// allocation and copy. Therefore, choosing a value that divides exactly into
// 1152 is most memory efficient.
#define MAX_AUDIO_FRAMES 128
namespace mozilla {
@ -201,7 +205,8 @@ AppleMP3Reader::AudioSampleCallback(UInt32 aNumBytes,
LOGD("got %u bytes, %u packets\n", aNumBytes, aNumPackets);
// 1 frame per packet * num channels * 32-bit float
uint32_t decodedSize = MAX_AUDIO_FRAMES * mAudioChannels * 4;
uint32_t decodedSize = MAX_AUDIO_FRAMES * mAudioChannels *
sizeof(AudioDataValue);
// descriptions for _decompressed_ audio packets. ignored.
nsAutoArrayPtr<AudioStreamPacketDescription>
@ -238,6 +243,14 @@ AppleMP3Reader::AudioSampleCallback(UInt32 aNumBytes,
break;
}
// If we decoded zero frames then AudiOConverterFillComplexBuffer is out
// of data to provide. We drained its internal buffer completely on the
// last pass.
if (numFrames == 0 && rv == kNeedMoreData) {
LOGD("FillComplexBuffer out of data exactly\n");
break;
}
int64_t time = FramesToUsecs(mCurrentAudioFrame, mAudioSampleRate).value();
int64_t duration = FramesToUsecs(numFrames, mAudioSampleRate).value();

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

@ -1,4 +1,5 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -247,6 +248,48 @@ DirectShowReader::Finish(HRESULT aStatus)
return false;
}
class DirectShowCopy
{
public:
DirectShowCopy(uint8_t *aSource, uint32_t aBytesPerSample,
uint32_t aSamples, uint32_t aChannels)
: mSource(aSource)
, mBytesPerSample(aBytesPerSample)
, mSamples(aSamples)
, mChannels(aChannels)
, mNextSample(0)
{ }
uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples)
{
size_t maxSamples = std::min(aSamples, mSamples - mNextSample);
uint32_t frames = maxSamples / mChannels;
size_t byteOffset = mNextSample * mBytesPerSample;
if (mBytesPerSample == 1) {
for (uint32_t i = 0; i < maxSamples; ++i) {
uint8_t *sample = mSource + byteOffset;
aBuffer[i] = UnsignedByteToAudioSample(*sample);
byteOffset += mBytesPerSample;
}
} else if (mBytesPerSample == 2) {
for (uint32_t i = 0; i < maxSamples; ++i) {
int16_t *sample = reinterpret_cast<int16_t *>(mSource + byteOffset);
aBuffer[i] = AudioSampleToFloat(*sample);
byteOffset += mBytesPerSample;
}
}
mNextSample = maxSamples;
return frames;
}
private:
uint8_t * const mSource;
const uint32_t mBytesPerSample;
const uint32_t mSamples;
const uint32_t mChannels;
uint32_t mNextSample;
};
bool
DirectShowReader::DecodeAudioData()
{
@ -281,26 +324,15 @@ DirectShowReader::DecodeAudioData()
hr = sample->GetPointer(&data);
NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr));
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[numSamples]);
AudioDataValue* dst = buffer.get();
if (mBytesPerSample == 1) {
uint8_t* src = reinterpret_cast<uint8_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = UnsignedByteToAudioSample(src[i]);
}
} else if (mBytesPerSample == 2) {
int16_t* src = reinterpret_cast<int16_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = AudioSampleToFloat(src[i]);
}
}
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
RefTimeToUsecs(start),
RefTimeToUsecs(end - start),
numFrames,
buffer.forget(),
mNumChannels));
mAudioCompactor.Push(mDecoder->GetResource()->Tell(),
RefTimeToUsecs(start),
mInfo.mAudio.mRate,
numFrames,
mNumChannels,
DirectShowCopy(reinterpret_cast<uint8_t *>(data),
mBytesPerSample,
numSamples,
mNumChannels));
return true;
}

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

@ -532,20 +532,20 @@ bool GStreamerReader::DecodeAudioData()
timestamp = gst_segment_to_stream_time(&mAudioSegment,
GST_FORMAT_TIME, timestamp);
timestamp = GST_TIME_AS_USECONDS(timestamp);
int64_t duration = 0;
if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
int64_t offset = GST_BUFFER_OFFSET(buffer);
unsigned int size = GST_BUFFER_SIZE(buffer);
int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels;
ssize_t outSize = static_cast<size_t>(size / sizeof(AudioDataValue));
nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outSize]);
memcpy(data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
AudioData* audio = new AudioData(offset, timestamp, duration,
frames, data.forget(), mInfo.mAudio.mChannels);
mAudioQueue.Push(audio);
typedef AudioCompactor::NativeCopy GstCopy;
mAudioCompactor.Push(offset,
timestamp,
mInfo.mAudio.mRate,
frames,
mInfo.mAudio.mChannels,
GstCopy(GST_BUFFER_DATA(buffer),
size,
mInfo.mAudio.mChannels));
gst_buffer_unref(buffer);
return true;

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

@ -0,0 +1,131 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "AudioCompactor.h"
#include "MediaDecoderReader.h"
using mozilla::AudioCompactor;
using mozilla::AudioData;
using mozilla::AudioDataValue;
using mozilla::MediaDecoderReader;
using mozilla::MediaQueue;
class TestCopy
{
public:
TestCopy(uint32_t aFrames, uint32_t aChannels,
uint32_t &aCallCount, uint32_t &aFrameCount)
: mFrames(aFrames)
, mChannels(aChannels)
, mCallCount(aCallCount)
, mFrameCount(aFrameCount)
{ }
uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples)
{
mCallCount += 1;
uint32_t frames = std::min(mFrames - mFrameCount, aSamples / mChannels);
mFrameCount += frames;
return frames;
}
private:
const uint32_t mFrames;
const uint32_t mChannels;
uint32_t &mCallCount;
uint32_t &mFrameCount;
};
static void TestAudioCompactor(size_t aBytes)
{
MediaQueue<AudioData> queue;
AudioCompactor compactor(queue);
uint64_t offset = 0;
uint64_t time = 0;
uint32_t sampleRate = 44000;
uint32_t channels = 2;
uint32_t frames = aBytes / (channels * sizeof(AudioDataValue));
size_t maxSlop = aBytes / AudioCompactor::MAX_SLOP_DIVISOR;
uint32_t callCount = 0;
uint32_t frameCount = 0;
compactor.Push(offset, time, sampleRate, frames, channels,
TestCopy(frames, channels, callCount, frameCount));
EXPECT_GT(callCount, 0U) << "copy functor never called";
EXPECT_EQ(frames, frameCount) << "incorrect number of frames copied";
MediaDecoderReader::AudioQueueMemoryFunctor memoryFunc;
queue.LockedForEach(memoryFunc);
size_t allocSize = memoryFunc.mSize - (callCount * sizeof(AudioData));
size_t slop = allocSize - aBytes;
EXPECT_LE(slop, maxSlop) << "allowed too much allocation slop";
}
TEST(Media, AudioCompactor_4000)
{
TestAudioCompactor(4000);
}
TEST(Media, AudioCompactor_4096)
{
TestAudioCompactor(4096);
}
TEST(Media, AudioCompactor_5000)
{
TestAudioCompactor(5000);
}
TEST(Media, AudioCompactor_5256)
{
TestAudioCompactor(5256);
}
TEST(Media, AudioCompactor_NativeCopy)
{
const uint32_t channels = 2;
const size_t srcBytes = 32;
const uint32_t srcSamples = srcBytes / sizeof(AudioDataValue);
const uint32_t srcFrames = srcSamples / channels;
uint8_t src[srcBytes];
for (uint32_t i = 0; i < srcBytes; ++i) {
src[i] = i;
}
AudioCompactor::NativeCopy copy(src, srcBytes, channels);
const uint32_t dstSamples = srcSamples * 2;
AudioDataValue dst[dstSamples];
const AudioDataValue notCopied = 0xffff;
for (uint32_t i = 0; i < dstSamples; ++i) {
dst[i] = notCopied;
}
const uint32_t copyCount = 8;
uint32_t copiedFrames = 0;
uint32_t nextSample = 0;
for (uint32_t i = 0; i < copyCount; ++i) {
uint32_t copySamples = dstSamples / copyCount;
copiedFrames += copy(dst + nextSample, copySamples);
nextSample += copySamples;
}
EXPECT_EQ(srcFrames, copiedFrames) << "copy exact number of source frames";
// Verify that the only the correct bytes were copied.
for (uint32_t i = 0; i < dstSamples; ++i) {
if (i < srcSamples) {
EXPECT_NE(notCopied, dst[i]) << "should have copied over these bytes";
} else {
EXPECT_EQ(notCopied, dst[i]) << "should not have copied over these bytes";
}
}
}

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

@ -7,6 +7,7 @@
LIBRARY_NAME = 'media_gtest'
UNIFIED_SOURCES += [
'TestAudioCompactor.cpp',
'TestTrackEncoder.cpp',
]

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

@ -58,6 +58,7 @@ EXPORTS += [
'AbstractMediaDecoder.h',
'AudioAvailableEventManager.h',
'AudioChannelFormat.h',
'AudioCompactor.h',
'AudioEventTimeline.h',
'AudioNodeEngine.h',
'AudioNodeExternalInputStream.h',
@ -115,6 +116,7 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
'AudioAvailableEventManager.cpp',
'AudioChannelFormat.cpp',
'AudioCompactor.cpp',
'AudioNodeEngine.cpp',
'AudioNodeExternalInputStream.cpp',
'AudioNodeStream.cpp',

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

@ -312,33 +312,29 @@ bool MediaOmxReader::DecodeAudioData()
int64_t pos = mDecoder->GetResource()->Tell();
// Read next frame
MPAPI::AudioFrame frame;
if (!mOmxDecoder->ReadAudio(&frame, mAudioSeekTimeUs)) {
MPAPI::AudioFrame source;
if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) {
return false;
}
mAudioSeekTimeUs = -1;
// Ignore empty buffer which stagefright media read will sporadically return
if (frame.mSize == 0) {
if (source.mSize == 0) {
return true;
}
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frame.mSize/2] );
memcpy(buffer.get(), frame.mData, frame.mSize);
uint32_t frames = source.mSize / (source.mAudioChannels *
sizeof(AudioDataValue));
uint32_t frames = frame.mSize / (2 * frame.mAudioChannels);
CheckedInt64 duration = FramesToUsecs(frames, frame.mAudioSampleRate);
if (!duration.isValid()) {
return false;
}
mAudioQueue.Push(new AudioData(pos,
frame.mTimeUs,
duration.value(),
frames,
buffer.forget(),
frame.mAudioChannels));
return true;
typedef AudioCompactor::NativeCopy OmxCopy;
return mAudioCompactor.Push(pos,
source.mTimeUs,
source.mAudioSampleRate,
frames,
source.mAudioChannels,
OmxCopy(static_cast<uint8_t *>(source.mData),
source.mSize,
source.mAudioChannels));
}
nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)

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

@ -4776,8 +4776,10 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL,
}
errorPageUrl.AppendLiteral("&c=");
errorPageUrl.AppendASCII(escapedCharset.get());
errorPageUrl.AppendLiteral("&d=");
errorPageUrl.AppendASCII(escapedDescription.get());
nsAutoCString frameType(FrameTypeToString(mFrameType));
errorPageUrl.AppendLiteral("&f=");
errorPageUrl.AppendASCII(frameType.get());
// Append the manifest URL if the error comes from an app.
nsString manifestURL;
@ -4791,9 +4793,10 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL,
errorPageUrl.AppendASCII(manifestParam.get());
}
nsAutoCString frameType(FrameTypeToString(mFrameType));
errorPageUrl.AppendLiteral("&f=");
errorPageUrl.AppendASCII(frameType.get());
// netError.xhtml's getDescription only handles the "d" parameter at the
// end of the URL, so append it last.
errorPageUrl.AppendLiteral("&d=");
errorPageUrl.AppendASCII(escapedDescription.get());
nsCOMPtr<nsIURI> errorPageURI;
rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);

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

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.LayerView;
@ -771,51 +772,67 @@ public class GeckoAppShell
createShortcut(aTitle, aURI, aURI, aIconData, aType);
}
// for non-webapps
// For non-webapps.
public static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
createShortcut(aTitle, aURI, aURI, aBitmap, aType);
}
// internal, for webapps
static void createShortcut(String aTitle, String aURI, String aUniqueURI, String aIconData, String aType) {
createShortcut(aTitle, aURI, aUniqueURI, BitmapUtils.getBitmapFromDataURI(aIconData), aType);
}
public static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI,
final Bitmap aIcon, final String aType)
{
// Internal, for webapps.
static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI, final String aIconData, final String aType) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// the intent to be launched by the shortcut
Intent shortcutIntent;
if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
shortcutIntent = getWebAppIntent(aURI, aUniqueURI, aTitle, aIcon);
} else {
shortcutIntent = new Intent();
shortcutIntent.setAction(GeckoApp.ACTION_BOOKMARK);
shortcutIntent.setData(Uri.parse(aURI));
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.BROWSER_INTENT_CLASS);
}
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
if (aTitle != null)
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
else
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon, aType));
// Do not allow duplicate items
intent.putExtra("duplicate", false);
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
getContext().sendBroadcast(intent);
// TODO: use the cache. Bug 961600.
Bitmap icon = FaviconDecoder.getMostSuitableBitmapFromDataURI(aIconData, getPreferredIconSize());
GeckoAppShell.doCreateShortcut(aTitle, aURI, aURI, icon, aType);
}
});
}
public static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI,
final Bitmap aIcon, final String aType) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
GeckoAppShell.doCreateShortcut(aTitle, aURI, aUniqueURI, aIcon, aType);
}
});
}
/**
* Call this method only on the background thread.
*/
private static void doCreateShortcut(final String aTitle, final String aURI, final String aUniqueURI,
final Bitmap aIcon, final String aType) {
// The intent to be launched by the shortcut.
Intent shortcutIntent;
if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
shortcutIntent = getWebAppIntent(aURI, aUniqueURI, aTitle, aIcon);
} else {
shortcutIntent = new Intent();
shortcutIntent.setAction(GeckoApp.ACTION_BOOKMARK);
shortcutIntent.setData(Uri.parse(aURI));
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.BROWSER_INTENT_CLASS);
}
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon, aType));
if (aTitle != null) {
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
} else {
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
}
// Do not allow duplicate items.
intent.putExtra("duplicate", false);
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
getContext().sendBroadcast(intent);
}
public static void removeShortcut(final String aTitle, final String aURI, final String aType) {
removeShortcut(aTitle, aURI, null, aType);
}

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

@ -538,7 +538,7 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
this.fieldID = integerQuery("named_fields", "field_id",
"measurement_name = ? AND measurement_version = ? AND field_name = ?",
new String[] {measurementName, measurementVersion, fieldName},
-1);
UNKNOWN_TYPE_OR_FIELD_ID);
if (this.fieldID == UNKNOWN_TYPE_OR_FIELD_ID) {
throw new IllegalStateException("No field with name " + fieldName +
" (" + measurementName + ", " + measurementVersion + ")");
@ -552,7 +552,9 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
// store differently stable kinds of data, hence type difference.
// Note that we don't pre-populate the environment cache. We'll typically only
// handle one per session.
private final ConcurrentHashMap<String, Integer> envs = new ConcurrentHashMap<String, Integer>();
//
// protected for testing purposes only.
protected final ConcurrentHashMap<String, Integer> envs = new ConcurrentHashMap<String, Integer>();
/**
* An {@link Environment} that knows how to persist to and from our database.
@ -855,6 +857,12 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
private HashMap<String, Field> fields = new HashMap<String, Field>();
private boolean fieldsCacheUpdated = false;
private void invalidateFieldsCache() {
synchronized (this.fields) {
fieldsCacheUpdated = false;
}
}
private String getFieldKey(String mName, int mVersion, String fieldName) {
return mVersion + "." + mName + "/" + fieldName;
}
@ -1014,9 +1022,7 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
notifyMeasurementVersionUpdated(measurement, version);
// Let's be easy for now.
synchronized (fields) {
fieldsCacheUpdated = false;
}
invalidateFieldsCache();
}
/**
@ -1152,10 +1158,16 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
final SQLiteDatabase db = this.helper.getWritableDatabase();
putValue(v, value);
try {
db.insertOrThrow(table, null, v);
} catch (SQLiteConstraintException e) {
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
// Using SQLiteDatabase.insertOrThrow throws SQLiteConstraintException we cannot catch for
// unknown reasons (bug 961526 comment 13). We believe these are thrown because we attempt to
// record events using environment IDs removed from the database by the prune service. We
// invalidate the currentEnvironment ID after pruning, preventing further propagation,
// however, any event recording waiting for the prune service to complete on the background
// thread may carry an invalid ID: we expect an insertion failure and drop these events here.
final long res = db.insert(table, null, v);
if (res == -1) {
Logger.error(LOG_TAG, "Unable to record daily discrete event. Ignoring.");
}
}
@ -1516,6 +1528,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
try {
// Cascade will clear the rest.
db.delete("measurements", null, null);
// Clear measurements and fields cache, because some of their IDs are now invalid.
invalidateFieldsCache(); // Let it repopulate on its own.
populateMeasurementVersionsCache(db); // Performed at Storage init so repopulate now.
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@ -1524,7 +1541,7 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
/**
* Prunes the given number of least-recently used environments. Note that orphaned environments
* are not removed.
* are not removed and the environment cache is cleared.
*/
public void pruneEnvironments(final int numToPrune) {
final SQLiteDatabase db = this.helper.getWritableDatabase();
@ -1538,6 +1555,9 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
" LIMIT " + numToPrune + ")",
null);
db.setTransactionSuccessful();
// Clear environment cache, because some of their IDs are now invalid.
this.envs.clear();
} finally {
db.endTransaction();
}

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

@ -43,6 +43,11 @@ public class PrunePolicyDatabaseStorage implements PrunePolicyStorage {
public void pruneEnvironments(final int count) {
getStorage().pruneEnvironments(count);
// Re-populate the DB and environment cache with the current environment in the unlikely event
// that it was deleted.
this.currentEnvironmentID = -1;
getCurrentEnvironmentID();
}
/**

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

@ -7,6 +7,7 @@ package org.mozilla.gecko.favicons;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
@ -465,15 +466,19 @@ public class Favicons {
}
/**
* Sidestep the cache and get, from either the database or the internet, the largest available
* Favicon for the given page URL. Useful for creating homescreen shortcuts without being limited
* by possibly low-resolution values in the cache.
* Deduces the favicon URL from the history database and, ultimately, guesses.
* Sidestep the cache and get, from either the database or the internet, a favicon
* suitable for use as an app icon for the provided URL.
*
* @param url Page URL to get a large favicon image fro.
* @param onFaviconLoadedListener Listener to call back with the result.
* Useful for creating homescreen shortcuts without being limited
* by possibly low-resolution values in the cache.
*
* Deduces the favicon URL from the browser database, guessing if necessary.
*
* @param url page URL to get a large favicon image for.
* @param onFaviconLoadedListener listener to call back with the result.
*/
public static void getLargestFaviconForPage(String url, OnFaviconLoadedListener onFaviconLoadedListener) {
loadUncachedFavicon(url, null, 0, -1, onFaviconLoadedListener);
public static void getPreferredSizeFaviconForPage(String url, OnFaviconLoadedListener onFaviconLoadedListener) {
int preferredSize = GeckoAppShell.getPreferredIconSize();
loadUncachedFavicon(url, null, 0, preferredSize, onFaviconLoadedListener);
}
}

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

@ -474,7 +474,6 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
private void processResult(Bitmap image) {
Favicons.removeLoadTask(mId);
Bitmap scaled = image;
// Notify listeners, scaling if required.

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

@ -332,7 +332,8 @@ public class FaviconCache {
FaviconCacheElement cacheElement;
int cacheElementIndex = container.getNextHighestIndex(targetSize);
// If targetSize is -1, it means we want the largest possible icon.
int cacheElementIndex = (targetSize == -1) ? -1 : container.getNextHighestIndex(targetSize);
// cacheElementIndex now holds either the index of the next least largest bitmap from
// targetSize, or -1 if targetSize > all bitmaps.
@ -362,12 +363,16 @@ public class FaviconCache {
// If there is no such primary, we'll upscale the next least smaller one instead.
cacheElement = container.getNextPrimary(cacheElementIndex);
if (cacheElement == null) {
// The primary has been invalidated! Fail! Need to get it back from the database.
return null;
}
if (targetSize == -1) {
// We got the biggest primary, so that's what we'll return.
return cacheElement.mFaviconPayload;
}
// Having got this far, we'll be needing to write the new secondary to the cache, which
// involves us falling through to the next try block. This flag lets us do this (Other
// paths prior to this end in returns.)

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

@ -145,6 +145,50 @@ public class FaviconDecoder {
return decodeFavicon(buffer, 0, buffer.length);
}
/**
* Returns the smallest bitmap in the icon represented by the provided
* data: URI that's larger than the desired width, or the largest if
* there is no larger icon.
*
* Returns null if no bitmap could be extracted.
*
* Bug 961600: we shouldn't be doing all of this work. The favicon cache
* should be used, and will give us the right size icon.
*/
public static Bitmap getMostSuitableBitmapFromDataURI(String iconURI, int desiredWidth) {
LoadFaviconResult result = FaviconDecoder.decodeDataURI(iconURI);
if (result == null) {
// Nothing we can do.
Log.w(LOG_TAG, "Unable to decode icon URI.");
return null;
}
final Iterator<Bitmap> bitmaps = result.getBitmaps();
if (!bitmaps.hasNext()) {
Log.w(LOG_TAG, "No bitmaps in decoded icon.");
return null;
}
Bitmap bitmap = bitmaps.next();
if (!bitmaps.hasNext()) {
// We're done! There was only one, so this is as big as it gets.
return bitmap;
}
// Find a bitmap of the most suitable size.
int currentWidth = bitmap.getWidth();
while ((currentWidth < desiredWidth) &&
bitmaps.hasNext()) {
final Bitmap b = bitmaps.next();
if (b.getWidth() > currentWidth) {
currentWidth = b.getWidth();
bitmap = b;
}
}
return bitmap;
}
/**
* Iterator to hold a single bitmap.
*/

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

@ -37,9 +37,13 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -758,11 +762,11 @@ public class BrowserHealthRecorder implements GeckoEventListener {
public static final String MEASUREMENT_NAME_SEARCH_COUNTS = "org.mozilla.searches.counts";
public static final int MEASUREMENT_VERSION_SEARCH_COUNTS = 5;
public static final String[] SEARCH_LOCATIONS = {
public static final Set<String> SEARCH_LOCATIONS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] {
"barkeyword",
"barsuggest",
"bartext",
};
})));
private void initializeSearchProvider() {
this.storage.ensureMeasurementInitialized(
@ -771,7 +775,7 @@ public class BrowserHealthRecorder implements GeckoEventListener {
new MeasurementFields() {
@Override
public Iterable<FieldSpec> getFields() {
ArrayList<FieldSpec> out = new ArrayList<FieldSpec>(SEARCH_LOCATIONS.length);
ArrayList<FieldSpec> out = new ArrayList<FieldSpec>(SEARCH_LOCATIONS.size());
for (String location : SEARCH_LOCATIONS) {
// We're not using a counter, because the set of engine
// identifiers is potentially unbounded, and thus our
@ -803,19 +807,31 @@ public class BrowserHealthRecorder implements GeckoEventListener {
return;
}
final int env = this.env;
if (env == -1) {
Log.d(LOG_TAG, "No environment: not recording search.");
return;
}
if (location == null) {
throw new IllegalArgumentException("location must be provided for search.");
}
// Ensure that we don't throw when trying to look up the field for an
// unknown location. If you add a search location, you must extend the
// list of search locations *and update the measurement version*.
if (!SEARCH_LOCATIONS.contains(location)) {
throw new IllegalArgumentException("Unexpected location: " + location);
}
final int day = storage.getDay();
final int env = this.env;
final String key = (engineID == null) ? "other" : engineID;
final BrowserHealthRecorder self = this;
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final HealthReportDatabaseStorage storage = self.storage;
final HealthReportDatabaseStorage storage = BrowserHealthRecorder.this.storage;
if (storage == null) {
Log.d(LOG_TAG, "No storage: not recording search. Shutting down?");
return;

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

@ -137,8 +137,8 @@ abstract class HomeFragment extends Fragment {
return false;
}
// Fetch the largest cacheable icon size.
Favicons.getLargestFaviconForPage(info.url, new GeckoAppShell.CreateShortcutFaviconLoadedListener(info.url, info.getDisplayTitle()));
// Fetch an icon big enough for use as a home screen icon.
Favicons.getPreferredSizeFaviconForPage(info.url, new GeckoAppShell.CreateShortcutFaviconLoadedListener(info.url, info.getDisplayTitle()));
return true;
}

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

@ -381,8 +381,8 @@ public class TopSitesPanel extends HomeFragment {
return false;
}
// Fetch the largest cacheable icon size.
Favicons.getLargestFaviconForPage(info.url, new GeckoAppShell.CreateShortcutFaviconLoadedListener(info.url, info.getDisplayTitle()));
// Fetch an icon big enough for use as a home screen icon.
Favicons.getPreferredSizeFaviconForPage(info.url, new GeckoAppShell.CreateShortcutFaviconLoadedListener(info.url, info.getDisplayTitle()));
return true;
}

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

@ -135,31 +135,6 @@ public class SearchEnginePreference extends CustomListPreference {
final String iconURI = geckoEngineJSON.getString("iconURI");
// Keep a reference to the bitmap - we'll need it later in onBindView.
try {
// Bug 961600: we shouldn't be doing all of this work. The favicon cache
// should be used, and will give us the right size icon.
LoadFaviconResult result = FaviconDecoder.decodeDataURI(iconURI);
if (result == null) {
// Nothing we can do.
Log.w(LOGTAG, "Unable to decode icon URI.");
return;
}
Iterator<Bitmap> bitmaps = result.getBitmaps();
if (!bitmaps.hasNext()) {
Log.w(LOGTAG, "No bitmaps in decoded icon.");
return;
}
mIconBitmap = bitmaps.next();
if (!bitmaps.hasNext()) {
// We're done! There was only one, so this is as big as it gets.
return;
}
// Find a bitmap of a more suitable size.
final int desiredWidth;
if (mFaviconView != null) {
desiredWidth = mFaviconView.getWidth();
@ -174,15 +149,8 @@ public class SearchEnginePreference extends CustomListPreference {
}
}
int currentWidth = mIconBitmap.getWidth();
while ((currentWidth < desiredWidth) &&
bitmaps.hasNext()) {
Bitmap b = bitmaps.next();
if (b.getWidth() > currentWidth) {
currentWidth = b.getWidth();
mIconBitmap = b;
}
}
// TODO: use the cache. Bug 961600.
mIconBitmap = FaviconDecoder.getMostSuitableBitmapFromDataURI(iconURI, desiredWidth);
} catch (IllegalArgumentException e) {
Log.e(LOGTAG, "IllegalArgumentException creating Bitmap. Most likely a zero-length bitmap.", e);

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

@ -8,6 +8,7 @@ package org.mozilla.gecko.webapp;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.EventDispatcher;
@ -114,7 +115,9 @@ public class EventListener implements GeckoEventListener {
int index = allocator.getIndexForApp(aOriginalOrigin);
assert aIconURL != null;
Bitmap icon = BitmapUtils.getBitmapFromDataURI(aIconURL);
final int preferredSize = GeckoAppShell.getPreferredIconSize();
Bitmap icon = FaviconDecoder.getMostSuitableBitmapFromDataURI(aIconURL, preferredSize);
assert aOrigin != null && index != -1;
allocator.updateAppAllocation(aOrigin, index, icon);

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

@ -19,7 +19,7 @@ interface nsIShellService : nsISupports
*
* @param aTitle the user-friendly name of the shortcut.
* @param aURI the URI to open.
* @param aIconData a base64 encoded representation of the shortcut's icon.
* @param aIconData a base64-encoded data: URI representation of the shortcut's icon, as accepted by the favicon decoder.
* @param aIntent how the URI should be opened. Examples: "default", "bookmark" and "webapp"
*/
void createShortcut(in AString aTitle, in AString aURI, in AString aIconData, in AString aIntent);

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

@ -5,6 +5,7 @@ package org.mozilla.gecko.background.healthreport;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import org.json.JSONObject;
import org.mozilla.gecko.background.common.GlobalConstants;
@ -42,6 +43,10 @@ public class MockHealthReportDatabaseStorage extends HealthReportDatabaseStorage
return now - numDays * GlobalConstants.MILLISECONDS_PER_DAY;
}
public ConcurrentHashMap<String, Integer> getEnvironmentCache() {
return this.envs;
}
public MockHealthReportDatabaseStorage(Context context, File fakeProfileDirectory) {
super(context, fakeProfileDirectory);
}

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

@ -326,10 +326,6 @@ public class TestHealthReportDatabaseStorage extends FakeProfileTestCase {
storage.incrementDailyCount(nonExistentEnvID, storage.getToday(), counterFieldID);
fail("Should throw - event_integer(env) references environments(id), which is given as a non-existent value.");
} catch (IllegalStateException e) { }
try {
storage.recordDailyDiscrete(nonExistentEnvID, storage.getToday(), discreteFieldID, "iu");
fail("Should throw - event_textual(env) references environments(id), which is given as a non-existent value.");
} catch (IllegalStateException e) { }
try {
storage.recordDailyLast(nonExistentEnvID, storage.getToday(), discreteFieldID, "iu");
fail("Should throw - event_textual(env) references environments(id), which is given as a non-existent value.");
@ -339,14 +335,30 @@ public class TestHealthReportDatabaseStorage extends FakeProfileTestCase {
storage.incrementDailyCount(envID, storage.getToday(), nonExistentFieldID);
fail("Should throw - event_integer(field) references fields(id), which is given as a non-existent value.");
} catch (IllegalStateException e) { }
try {
storage.recordDailyDiscrete(envID, storage.getToday(), nonExistentFieldID, "iu");
fail("Should throw - event_textual(field) references fields(id), which is given as a non-existent value.");
} catch (IllegalStateException e) { }
try {
storage.recordDailyLast(envID, storage.getToday(), nonExistentFieldID, "iu");
fail("Should throw - event_textual(field) references fields(id), which is given as a non-existent value.");
} catch (IllegalStateException e) { }
// Test dropped events due to constraint violations that do not throw (see bug 961526).
final String eventValue = "a value not in the database";
assertFalse(isEventInDB(db, eventValue)); // Better safe than sorry.
storage.recordDailyDiscrete(nonExistentEnvID, storage.getToday(), discreteFieldID, eventValue);
assertFalse(isEventInDB(db, eventValue));
storage.recordDailyDiscrete(envID, storage.getToday(), nonExistentFieldID, "iu");
assertFalse(isEventInDB(db, eventValue));
}
private static boolean isEventInDB(final SQLiteDatabase db, final String value) {
final Cursor c = db.query("events_textual", new String[] {"value"}, "value = ?",
new String[] {value}, null, null, null);
try {
return c.getCount() > 0;
} finally {
c.close();
}
}
// Largely taken from testDeleteEnvAndEventsBefore and testDeleteOrphanedAddons.
@ -553,7 +565,10 @@ public class TestHealthReportDatabaseStorage extends FakeProfileTestCase {
new PrepopulatedMockHealthReportDatabaseStorage(context, fakeProfileDirectory, 2);
final SQLiteDatabase db = storage.getDB();
assertEquals(5, DBHelpers.getRowCount(db, "environments"));
assertEquals(5, storage.getEnvironmentCache().size());
storage.pruneEnvironments(1);
assertEquals(0, storage.getEnvironmentCache().size());
assertTrue(!getEnvAppVersions(db).contains("v3"));
storage.pruneEnvironments(2);
assertTrue(!getEnvAppVersions(db).contains("v2"));

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

@ -45,7 +45,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
* @param host
* The url of the host
*/
function HawkClient(host) {
this.HawkClient = function(host) {
this.host = host;
// Clock offset in milliseconds between our client's clock and the date
@ -53,7 +53,7 @@ function HawkClient(host) {
this._localtimeOffsetMsec = 0;
}
HawkClient.prototype = {
this.HawkClient.prototype = {
/*
* Construct an error message for a response. Private.

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

@ -381,6 +381,7 @@
"dom/tests/mochitest/localstorage/test_localStorageReplace.html":"",
"dom/tests/mochitest/sessionstorage/test_cookieSession.html":"",
"dom/tests/mochitest/sessionstorage/test_sessionStorageBaseSessionOnly.html":"",
"dom/tests/mochitest/sessionstorage/test_sessionStorageClone.html":"bug 968051",
"dom/tests/mochitest/pointerlock/test_pointerlock-api.html":"window.open focus issues (using fullscreen)",
"dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html":"",

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

@ -358,6 +358,7 @@
"dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html":"needs https support",
"dom/tests/mochitest/sessionstorage/test_cookieSession.html":"4 failures",
"dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html":"no storage chrome event received",
"dom/tests/mochitest/sessionstorage/test_sessionStorageBaseSessionOnly.html":"bug 967737",
"dom/tests/mochitest/sessionstorage/test_sessionStorageHttpHttps.html":"needs https to work",
"dom/tests/mochitest/pointerlock/test_pointerlock-api.html":"window.open focus issues (using fullscreen)",

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

@ -457,6 +457,14 @@ let Impl = {
revision: HISTOGRAMS_FILE_VERSION,
locale: getLocale()
};
// In order to share profile data, the appName used for Metro Firefox is "Firefox",
// (the same as desktop Firefox). We set it to "MetroFirefox" here in order to
// differentiate telemetry pings sent by desktop vs. metro Firefox.
if(Services.metro && Services.metro.immersive) {
ret.appName = "MetroFirefox";
}
if (this._previousBuildID) {
ret.previousBuildID = this._previousBuildID;
}

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

@ -42,9 +42,7 @@ LightweightThemeConsumer.prototype = {
_lastScreenWidth: null,
_lastScreenHeight: null,
_enabled: true,
#ifdef XP_MACOSX
_chromemarginDefault: undefined,
#endif
_active: false,
enable: function() {
this._enabled = true;
@ -100,8 +98,9 @@ LightweightThemeConsumer.prototype = {
if (!this._enabled)
return;
var root = this._doc.documentElement;
var active = !!aData.headerURL;
let root = this._doc.documentElement;
let active = !!aData.headerURL;
let stateChanging = (active != this._active);
if (active) {
root.style.color = aData.textcolor || "black";
@ -117,6 +116,8 @@ LightweightThemeConsumer.prototype = {
root.removeAttribute("lwtheme");
}
this._active = active;
_setImage(root, active, aData.headerURL);
if (this._footerId) {
let footer = this._doc.getElementById(this._footerId);
@ -129,20 +130,26 @@ LightweightThemeConsumer.prototype = {
}
#ifdef XP_MACOSX
// Sample whether or not we draw in the titlebar by default the first time we update.
// If the root has no chromemargin attribute, getAttribute will return null, and
// we'll remove the attribute when the lw-theme is deactivated.
if (this._chromemarginDefault === undefined)
this._chromemarginDefault = root.getAttribute("chromemargin");
// On OS X, we extend the lightweight theme into the titlebar, which means setting
// the chromemargin attribute. Some XUL applications already draw in the titlebar,
// so we need to save the chromemargin value before we overwrite it with the value
// that lets us draw in the titlebar. We stash this value on the root attribute so
// that XUL applications have the ability to invalidate the saved value.
if (stateChanging) {
if (!root.hasAttribute("chromemargin-nonlwtheme")) {
root.setAttribute("chromemargin-nonlwtheme", root.getAttribute("chromemargin"));
}
if (active) {
root.setAttribute("chromemargin", "0,-1,-1,-1");
}
else {
if (this._chromemarginDefault)
root.setAttribute("chromemargin", this._chromemarginDefault);
else
root.removeAttribute("chromemargin");
if (active) {
root.setAttribute("chromemargin", "0,-1,-1,-1");
} else {
let defaultChromemargin = root.getAttribute("chromemargin-nonlwtheme");
if (defaultChromemargin) {
root.setAttribute("chromemargin", defaultChromemargin);
} else {
root.removeAttribute("chromemargin");
}
}
}
#endif
}