mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge m-c to inbound, a=merge
MozReview-Commit-ID: Aas4kEyBseh
This commit is contained in:
commit
c65b052530
@ -346,48 +346,10 @@ pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240"
|
||||
pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240"
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
pref("browser.safebrowsing.enabled", true);
|
||||
// Prevent loading of pages identified as malware
|
||||
pref("browser.safebrowsing.malware.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.remote.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
|
||||
pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous_host", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
|
||||
pref("browser.safebrowsing.downloads.remote.block_uncommon", false);
|
||||
pref("browser.safebrowsing.debug", false);
|
||||
|
||||
pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
|
||||
pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
|
||||
pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
||||
pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportMalwareMistakeURL", "https://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
|
||||
pref("browser.safebrowsing.id", "Firefox");
|
||||
|
||||
// Tables for application reputation.
|
||||
pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
|
||||
|
||||
// The number of random entries to send with a gethash request.
|
||||
pref("urlclassifier.gethashnoise", 4);
|
||||
|
||||
// Gethash timeout for Safebrowsing.
|
||||
pref("urlclassifier.gethash.timeout_ms", 5000);
|
||||
|
||||
// If an urlclassifier table has not been updated in this number of seconds,
|
||||
// a gethash request will be forced to check that the result is still in
|
||||
// the database.
|
||||
pref("urlclassifier.max-complete-age", 2700);
|
||||
|
||||
// Tracking protection
|
||||
pref("privacy.trackingprotection.enabled", false);
|
||||
pref("privacy.trackingprotection.pbmode.enabled", true);
|
||||
|
||||
#endif
|
||||
|
||||
// True if this is the first time we are showing about:firstrun
|
||||
|
@ -780,26 +780,8 @@ pref("gecko.handlerService.schemes.ircs.3.uriTemplate", "chrome://browser-region
|
||||
pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
pref("browser.safebrowsing.enabled", true);
|
||||
pref("browser.safebrowsing.malware.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.remote.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
|
||||
pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous_host", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
|
||||
pref("browser.safebrowsing.downloads.remote.block_uncommon", false);
|
||||
pref("browser.safebrowsing.debug", false);
|
||||
|
||||
pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
|
||||
pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
|
||||
pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
||||
pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportMalwareMistakeURL", "https://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
|
||||
#ifdef MOZILLA_OFFICIAL
|
||||
// Normally the "client ID" sent in updates is appinfo.name, but for
|
||||
@ -811,18 +793,6 @@ pref("browser.safebrowsing.id", "navclient-auto-ffox");
|
||||
// pages on phishing/malware hits. (bug 399233)
|
||||
pref("urlclassifier.alternate_error_page", "blocked");
|
||||
|
||||
// The number of random entries to send with a gethash request.
|
||||
pref("urlclassifier.gethashnoise", 4);
|
||||
|
||||
// Gethash timeout for Safebrowsing.
|
||||
pref("urlclassifier.gethash.timeout_ms", 5000);
|
||||
|
||||
// If an urlclassifier table has not been updated in this number of seconds,
|
||||
// a gethash request will be forced to check that the result is still in
|
||||
// the database.
|
||||
pref("urlclassifier.max-complete-age", 2700);
|
||||
// Tables for application reputation.
|
||||
pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
|
||||
#ifdef XP_WIN
|
||||
// Only download the whitelist on Windows, since the whitelist is
|
||||
// only useful for suppressing remote lookups for signed binaries which we can
|
||||
|
@ -468,13 +468,20 @@
|
||||
onpopupshowing="if (!this.parentNode._placesView)
|
||||
new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
|
||||
</menu>
|
||||
<menu id="menu_unsortedBookmarks"
|
||||
class="menu-iconic bookmark-item"
|
||||
label="&otherBookmarksCmd.label;"
|
||||
container="true">
|
||||
<menupopup id="otherBookmarksFolderPopup"
|
||||
#ifndef XP_MACOSX
|
||||
placespopup="true"
|
||||
#endif
|
||||
context="placesContext"
|
||||
onpopupshowing="if (!this.parentNode._placesView)
|
||||
new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/>
|
||||
</menu>
|
||||
<menuseparator id="bookmarksMenuItemsSeparator"/>
|
||||
<!-- Bookmarks menu items -->
|
||||
<menuseparator builder="end"
|
||||
class="hide-if-empty-places-result"/>
|
||||
<menuitem id="menu_unsortedBookmarks"
|
||||
label="&otherBookmarksCmd.label;"
|
||||
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
|
@ -528,29 +528,36 @@ this.DownloadsCommon = {
|
||||
* @param aOwnerWindow
|
||||
* The window with which this action is associated.
|
||||
*
|
||||
* @return True to unblock the file, false to keep the user safe and
|
||||
* cancel the operation.
|
||||
* @return {Promise}
|
||||
* @resolves String representing the action that should be executed:
|
||||
* - "unblock" to allow the download without opening the file.
|
||||
* - "confirmBlock" to delete the blocked data permanently.
|
||||
* - "cancel" to do nothing and cancel the operation.
|
||||
*/
|
||||
confirmUnblockDownload: Task.async(function* (aVerdict, aOwnerWindow) {
|
||||
let s = DownloadsCommon.strings;
|
||||
let title = s.unblockHeader;
|
||||
let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
|
||||
(Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1) +
|
||||
Ci.nsIPrompt.BUTTON_POS_1_DEFAULT;
|
||||
(Ci.nsIPrompt.BUTTON_TITLE_CANCEL * Ci.nsIPrompt.BUTTON_POS_1);
|
||||
let type = "";
|
||||
let message = s.unblockTip;
|
||||
let okButton = s.unblockButtonContinue;
|
||||
let cancelButton = s.unblockButtonCancel;
|
||||
let unblockButton = s.unblockButtonContinue;
|
||||
let confirmBlockButton = s.unblockButtonCancel;
|
||||
|
||||
switch (aVerdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
type = s.unblockTypeUncommon;
|
||||
buttonFlags += (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
|
||||
Ci.nsIPrompt.BUTTON_POS_0_DEFAULT;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
type = s.unblockTypePotentiallyUnwanted;
|
||||
buttonFlags += (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
|
||||
Ci.nsIPrompt.BUTTON_POS_2_DEFAULT;
|
||||
break;
|
||||
default: // Assume Downloads.Error.BLOCK_VERDICT_MALWARE
|
||||
type = s.unblockTypeMalware;
|
||||
buttonFlags += Ci.nsIPrompt.BUTTON_POS_1_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -580,8 +587,9 @@ this.DownloadsCommon = {
|
||||
// The ordering of the ok/cancel buttons is used this way to allow "cancel"
|
||||
// to have the same result as hitting the ESC or Close button (see bug 345067).
|
||||
let rv = Services.prompt.confirmEx(aOwnerWindow, title, message, buttonFlags,
|
||||
okButton, cancelButton, null, null, {});
|
||||
return (rv == 0);
|
||||
unblockButton, null, confirmBlockButton,
|
||||
null, {});
|
||||
return ["unblock", "cancel", "confirmBlock"][rv];
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
|
||||
"resource://gre/modules/DownloadUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
@ -112,6 +114,14 @@ this.DownloadsViewUI.DownloadElementShell.prototype = {
|
||||
this.element.setAttribute("state",
|
||||
DownloadsCommon.stateOfDownload(this.download));
|
||||
|
||||
if (this.download.error &&
|
||||
this.download.error.becauseBlockedByReputationCheck) {
|
||||
this.element.setAttribute("verdict",
|
||||
this.download.error.reputationCheckVerdict);
|
||||
} else {
|
||||
this.element.removeAttribute("verdict");
|
||||
}
|
||||
|
||||
// Since state changed, reset the time left estimation.
|
||||
this.lastEstimatedSecondsLeft = Infinity;
|
||||
|
||||
@ -132,6 +142,11 @@ this.DownloadsViewUI.DownloadElementShell.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// When a block is confirmed, the removal of blocked data will not trigger a
|
||||
// state change for the download, so this class must be updated here.
|
||||
this.element.classList.toggle("temporary-block",
|
||||
!!this.download.hasBlockedData);
|
||||
|
||||
// The progress bar is only displayed for in-progress downloads.
|
||||
if (this.download.hasProgress) {
|
||||
this.element.setAttribute("progressmode", "normal");
|
||||
@ -220,7 +235,17 @@ this.DownloadsViewUI.DownloadElementShell.prototype = {
|
||||
} else if (this.download.error.becauseBlockedByParentalControls) {
|
||||
stateLabel = s.stateBlockedParentalControls;
|
||||
} else if (this.download.error.becauseBlockedByReputationCheck) {
|
||||
stateLabel = s.stateDirty;
|
||||
switch (this.download.error.reputationCheckVerdict) {
|
||||
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
|
||||
stateLabel = s.blockedUncommon;
|
||||
break;
|
||||
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
|
||||
stateLabel = s.blockedPotentiallyUnwanted;
|
||||
break;
|
||||
default: // Assume Downloads.Error.BLOCK_VERDICT_MALWARE
|
||||
stateLabel = s.blockedMalware;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
stateLabel = s.stateFailed;
|
||||
}
|
||||
@ -239,6 +264,25 @@ this.DownloadsViewUI.DownloadElementShell.prototype = {
|
||||
return { text, tip: tip || text };
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the appropriate unblock dialog based on the verdict, and executes the
|
||||
* action selected by the user in the dialog, which may involve unblocking,
|
||||
* opening or removing the file.
|
||||
*
|
||||
* @param window
|
||||
* The window to which the dialog should be anchored.
|
||||
*/
|
||||
confirmUnblock(window) {
|
||||
let verdict = this.download.error.reputationCheckVerdict;
|
||||
DownloadsCommon.confirmUnblockDownload(verdict, window).then(action => {
|
||||
if (action == "unblock") {
|
||||
return this.download.unblock();
|
||||
} else if (action == "confirmBlock") {
|
||||
return this.download.confirmBlock();
|
||||
}
|
||||
}).catch(Cu.reportError);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the name of the default command to use for the current state of the
|
||||
* download, when there is a double click or another default interaction. If
|
||||
|
@ -298,9 +298,7 @@ HistoryDownloadElementShell.prototype = {
|
||||
},
|
||||
|
||||
onStateChanged() {
|
||||
this.element.setAttribute("image", this.image);
|
||||
this.element.setAttribute("state",
|
||||
DownloadsCommon.stateOfDownload(this.download));
|
||||
this._updateState();
|
||||
|
||||
if (this.element.selected) {
|
||||
goUpdateDownloadCommands();
|
||||
@ -379,12 +377,7 @@ HistoryDownloadElementShell.prototype = {
|
||||
},
|
||||
|
||||
downloadsCmd_unblock() {
|
||||
let verdict = this.download.error.reputationCheckVerdict;
|
||||
DownloadsCommon.confirmUnblockDownload(verdict, window).then(confirmed => {
|
||||
if (confirmed) {
|
||||
return this.download.unblock();
|
||||
}
|
||||
}).catch(Cu.reportError);
|
||||
this.confirmUnblock(window);
|
||||
},
|
||||
|
||||
// Returns whether or not the download handled by this shell should
|
||||
|
@ -47,22 +47,25 @@
|
||||
xbl:inherits="value=status,tooltiptext=statusTip"/>
|
||||
</xul:vbox>
|
||||
<xul:stack>
|
||||
<xul:button class="downloadButton downloadCancel"
|
||||
<xul:button class="downloadButton downloadCancel downloadIconCancel"
|
||||
tooltiptext="&cmd.cancel.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
|
||||
<xul:button class="downloadButton downloadRetry"
|
||||
<xul:button class="downloadButton downloadRetry downloadIconRetry"
|
||||
tooltiptext="&cmd.retry.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
|
||||
<xul:button class="downloadButton downloadShow"
|
||||
<xul:button class="downloadButton downloadShow downloadIconShow"
|
||||
#ifdef XP_MACOSX
|
||||
tooltiptext="&cmd.showMac.label;"
|
||||
#else
|
||||
tooltiptext="&cmd.show.label;"
|
||||
#endif
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
|
||||
<xul:button class="downloadButton downloadConfirmBlock"
|
||||
<xul:button class="downloadButton downloadConfirmBlock downloadIconCancel"
|
||||
tooltiptext="&cmd.removeFile.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_confirmBlock');"/>
|
||||
<xul:button class="downloadButton downloadUnblock downloadIconShow"
|
||||
tooltiptext="&cmd.unblock.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_unblock');"/>
|
||||
</xul:stack>
|
||||
</content>
|
||||
</binding>
|
||||
|
@ -118,11 +118,22 @@ richlistitem.download button {
|
||||
.downloadCancel,
|
||||
|
||||
/* Blocked (dirty) downloads that have not been confirmed and
|
||||
have temporary data. */
|
||||
have temporary data, for the Malware case. */
|
||||
.download-state:not( [state="8"] /* Blocked (dirty) */)
|
||||
.downloadConfirmBlock,
|
||||
.download-state[state="8"]:not(.temporary-block)
|
||||
.downloadConfirmBlock,
|
||||
.download-state[state="8"].temporary-block:not([verdict="Malware"])
|
||||
.downloadConfirmBlock,
|
||||
|
||||
/* Blocked (dirty) downloads that have not been confirmed and
|
||||
have temporary data, for cases other than Malware. */
|
||||
.download-state:not( [state="8"] /* Blocked (dirty) */)
|
||||
.downloadUnblock,
|
||||
.download-state[state="8"]:not(.temporary-block)
|
||||
.downloadUnblock,
|
||||
.download-state[state="8"].temporary-block[verdict="Malware"]
|
||||
.downloadUnblock,
|
||||
|
||||
.download-state:not(:-moz-any([state="2"], /* Failed */
|
||||
[state="3"]) /* Canceled */)
|
||||
|
@ -1035,17 +1035,10 @@ DownloadsViewItem.prototype = {
|
||||
_element: null,
|
||||
|
||||
onStateChanged() {
|
||||
this.element.setAttribute("image", this.image);
|
||||
this.element.setAttribute("state",
|
||||
DownloadsCommon.stateOfDownload(this.download));
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
onChanged() {
|
||||
// This cannot be placed within onStateChanged because
|
||||
// when a download goes from hasBlockedData to !hasBlockedData
|
||||
// it will still remain in the same state.
|
||||
this.element.classList.toggle("temporary-block",
|
||||
!!this.download.hasBlockedData);
|
||||
this._updateProgress();
|
||||
},
|
||||
|
||||
@ -1099,12 +1092,7 @@ DownloadsViewItem.prototype = {
|
||||
|
||||
downloadsCmd_unblock() {
|
||||
DownloadsPanel.hidePanel();
|
||||
let verdict = this.download.error.reputationCheckVerdict;
|
||||
DownloadsCommon.confirmUnblockDownload(verdict, window).then(confirmed => {
|
||||
if (confirmed) {
|
||||
return this.download.unblock();
|
||||
}
|
||||
}).catch(Cu.reportError);
|
||||
this.confirmUnblock(window);
|
||||
},
|
||||
|
||||
downloadsCmd_open() {
|
||||
|
@ -35,12 +35,12 @@ add_task(function* test_confirm_unblock_dialog_unblock() {
|
||||
addDialogOpenObserver("accept");
|
||||
let result = yield DownloadsCommon.confirmUnblockDownload(Downloads.Error.BLOCK_VERDICT_MALWARE,
|
||||
window);
|
||||
ok(result, "Should return true when the user clicks on `Unblock` button.");
|
||||
is(result, "unblock");
|
||||
});
|
||||
|
||||
add_task(function* test_confirm_unblock_dialog_keep_safe() {
|
||||
addDialogOpenObserver("cancel");
|
||||
let result = yield DownloadsCommon.confirmUnblockDownload(Downloads.Error.BLOCK_VERDICT_MALWARE,
|
||||
window);
|
||||
ok(!result, "Should return false when the user clicks on `Keep me safe` button.");
|
||||
is(result, "cancel");
|
||||
});
|
||||
|
@ -11,90 +11,90 @@
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-error?size=dialog");
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-error?size=32");
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-warning?size=32");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-info?size=32");
|
||||
}
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@ .downloadButton.downloadCancel {
|
||||
@itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow {
|
||||
@item@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:hover {
|
||||
@item@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:active {
|
||||
@item@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadShow {
|
||||
@itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadRetry {
|
||||
@itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
|
@ -37,7 +37,15 @@
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-error?size=dialog");
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-error?size=32");
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-warning?size=32");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("moz-icon://stock/gtk-dialog-info?size=32");
|
||||
}
|
||||
|
||||
.downloadButton:focus > .button-box {
|
||||
@ -63,45 +71,50 @@
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow {
|
||||
@itemNotFinished@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@itemNotFinished@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@itemNotFinished@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
|
@ -10,88 +10,88 @@
|
||||
--downloads-item-height: 6em;
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/warning-32.png");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/information-32.png");
|
||||
}
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@ .downloadButton.downloadCancel {
|
||||
@itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow {
|
||||
@item@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:hover {
|
||||
@item@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:active {
|
||||
@item@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadShow {
|
||||
@itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadRetry {
|
||||
@itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
|
||||
@ -104,86 +104,78 @@
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 64px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 96px, 32px, 64px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 32px, 96px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@ .downloadButton.downloadCancel {
|
||||
@itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 160px, 32px, 128px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 224px, 32px, 192px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 256px, 32px, 224px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 32px, 64px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow {
|
||||
@item@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 64px, 64px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:hover {
|
||||
@item@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(32px, 96px, 64px, 64px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:active {
|
||||
@item@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(32px, 128px, 64px, 96px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadShow {
|
||||
@itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 160px, 64px, 128px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 192px, 64px, 160px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(32px, 224px, 64px, 192px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(32px, 256px, 64px, 224px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 32px, 96px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 64px, 96px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(64px, 96px, 96px, 64px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(64px, 128px, 96px, 96px);
|
||||
}
|
||||
@itemFocused@ .downloadButton.downloadRetry {
|
||||
@itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 160px, 96px, 128px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 192px, 96px, 160px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(64px, 224px, 96px, 192px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(64px, 256px, 96px, 224px);
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,14 @@
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/warning-32.png");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/information-32.png");
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
@keyfocus@ @itemFocused@,
|
||||
@ -64,89 +72,84 @@
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadCancel {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow:hover,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow:active,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadShow {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadRetry {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
|
||||
@ -159,89 +162,84 @@
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 64px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 96px, 32px, 64px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 32px, 96px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadCancel {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 160px, 32px, 128px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 224px, 32px, 192px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 256px, 32px, 224px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 32px, 64px, 0px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 64px, 64px, 32px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow:hover,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(32px, 96px, 64px, 64px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemNotFinished@:hover .downloadButton.downloadIconShow:active,
|
||||
@keyfocus@ @itemFinished@:hover:not([selected]) .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(32px, 128px, 64px, 96px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadShow {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 160px, 64px, 128px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(32px, 192px, 64px, 160px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:hover,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(32px, 224px, 64px, 192px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:active,
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(32px, 256px, 64px, 224px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 32px, 96px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 64px, 96px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(64px, 96px, 96px, 64px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(64px, 128px, 96px, 96px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadRetry {
|
||||
@keyfocus@ @itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 160px, 96px, 128px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(64px, 192px, 96px, 160px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(64px, 224px, 96px, 192px);
|
||||
}
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@keyfocus@ @itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(64px, 256px, 96px, 224px);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
%define notKeyfocus #downloadsPanel:not([keyfocus])
|
||||
%define item richlistitem[type="download"]
|
||||
%define itemFinished @item@[state="1"]
|
||||
%define itemNotFinished @item@:not([state="1"])
|
||||
%define itemFocused #downloadsListBox:focus > @item@[selected]
|
||||
|
||||
/*** Panel and outer controls ***/
|
||||
|
@ -10,6 +10,14 @@
|
||||
--downloads-item-height: 6em;
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Warning.png");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/information-32.png");
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@ -44,90 +52,82 @@
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow {
|
||||
@item@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:hover {
|
||||
@item@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:active {
|
||||
@item@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
@itemFocused@ .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@ .downloadButton.downloadCancel {
|
||||
@itemFocused@ .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@itemFocused@:hover .downloadButton.downloadCancel:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
}
|
||||
|
||||
@itemFocused@ .downloadButton.downloadShow {
|
||||
@itemFocused@ .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadShow:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
@itemFocused@ .downloadButton.downloadRetry {
|
||||
@itemFocused@ .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:hover {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
@itemFocused@:hover .downloadButton.downloadRetry:active {
|
||||
@itemFocused@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,14 @@
|
||||
border: 1px dotted ThreeDDarkShadow;
|
||||
}
|
||||
|
||||
@item@[verdict="PotentiallyUnwanted"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Warning.png");
|
||||
}
|
||||
|
||||
@item@[verdict="Uncommon"] .blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/information-32.png");
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
@keyfocus@ @itemFocused@ {
|
||||
@ -148,65 +156,61 @@
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadConfirmBlock,
|
||||
.downloadButton.downloadCancel {
|
||||
.downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock,
|
||||
@item@:hover .downloadButton.downloadCancel {
|
||||
@item@:hover .downloadButton.downloadIconCancel {
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:hover,
|
||||
@item@:hover .downloadButton.downloadCancel:hover {
|
||||
@item@:hover .downloadButton.downloadIconCancel:hover {
|
||||
-moz-image-region: rect(0px, 48px, 16px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadConfirmBlock:active,
|
||||
@item@:hover .downloadButton.downloadCancel:active {
|
||||
@item@:hover .downloadButton.downloadIconCancel:active {
|
||||
-moz-image-region: rect(0px, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
.downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow {
|
||||
@item@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:hover {
|
||||
@item@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadShow:active {
|
||||
@item@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadShow {
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadShow:hover {
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadShow:active {
|
||||
@keyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:hover {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadShow:active {
|
||||
@notKeyfocus@ @itemFinished@:hover .downloadButton.downloadIconShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
.downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry {
|
||||
@item@:hover .downloadButton.downloadIconRetry {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:hover {
|
||||
@item@:hover .downloadButton.downloadIconRetry:hover {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
@item@:hover .downloadButton.downloadRetry:active {
|
||||
@item@:hover .downloadButton.downloadIconRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||
* const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
|
||||
* let s = new Spectrum(containerElement, [255, 126, 255, 1]);
|
||||
* s.on("changed", (event, rgba, color) => {
|
||||
* console.log("rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " + rgba[3] + ")");
|
||||
* console.log("rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " +
|
||||
* rgba[3] + ")");
|
||||
* });
|
||||
* s.show();
|
||||
* s.destroy();
|
||||
@ -31,32 +32,32 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||
function Spectrum(parentEl, rgb) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.element = parentEl.ownerDocument.createElement('div');
|
||||
this.element = parentEl.ownerDocument.createElement("div");
|
||||
this.parentEl = parentEl;
|
||||
|
||||
this.element.className = "spectrum-container";
|
||||
this.element.innerHTML = [
|
||||
"<div class='spectrum-top'>",
|
||||
"<div class='spectrum-fill'></div>",
|
||||
"<div class='spectrum-top-inner'>",
|
||||
"<div class='spectrum-color spectrum-box'>",
|
||||
"<div class='spectrum-sat'>",
|
||||
"<div class='spectrum-val'>",
|
||||
"<div class='spectrum-dragger'></div>",
|
||||
"</div>",
|
||||
"</div>",
|
||||
"</div>",
|
||||
"<div class='spectrum-hue spectrum-box'>",
|
||||
"<div class='spectrum-slider spectrum-slider-control'></div>",
|
||||
"</div>",
|
||||
"</div>",
|
||||
"</div>",
|
||||
"<div class='spectrum-alpha spectrum-checker spectrum-box'>",
|
||||
"<div class='spectrum-alpha-inner'>",
|
||||
"<div class='spectrum-alpha-handle spectrum-slider-control'></div>",
|
||||
"</div>",
|
||||
"</div>",
|
||||
].join("");
|
||||
this.element.innerHTML = `
|
||||
<div class="spectrum-top">
|
||||
<div class="spectrum-fill"></div>
|
||||
<div class="spectrum-top-inner">
|
||||
<div class="spectrum-color spectrum-box">
|
||||
<div class="spectrum-sat">
|
||||
<div class="spectrum-val">
|
||||
<div class="spectrum-dragger"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spectrum-hue spectrum-box">
|
||||
<div class="spectrum-slider spectrum-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spectrum-alpha spectrum-checker spectrum-box">
|
||||
<div class="spectrum-alpha-inner">
|
||||
<div class="spectrum-alpha-handle spectrum-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.onElementClick = this.onElementClick.bind(this);
|
||||
this.element.addEventListener("click", this.onElementClick, false);
|
||||
@ -94,12 +95,12 @@ Spectrum.hsvToRgb = function(h, s, v, a) {
|
||||
let t = v * (1 - (1 - f) * s);
|
||||
|
||||
switch(i % 6) {
|
||||
case 0: r = v, g = t, b = p; break;
|
||||
case 1: r = q, g = v, b = p; break;
|
||||
case 2: r = p, g = v, b = t; break;
|
||||
case 3: r = p, g = q, b = v; break;
|
||||
case 4: r = t, g = p, b = v; break;
|
||||
case 5: r = v, g = p, b = q; break;
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
|
||||
return [r * 255, g * 255, b * 255, a];
|
||||
@ -116,10 +117,10 @@ Spectrum.rgbToHsv = function(r, g, b, a) {
|
||||
let d = max - min;
|
||||
s = max == 0 ? 0 : d / max;
|
||||
|
||||
if(max == min) {
|
||||
h = 0; // achromatic
|
||||
}
|
||||
else {
|
||||
if (max == min) {
|
||||
// achromatic
|
||||
h = 0;
|
||||
} else {
|
||||
switch(max) {
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
@ -220,8 +221,10 @@ Spectrum.prototype = {
|
||||
},
|
||||
|
||||
get rgb() {
|
||||
let rgb = Spectrum.hsvToRgb(this.hsv[0], this.hsv[1], this.hsv[2], this.hsv[3]);
|
||||
return [Math.round(rgb[0]), Math.round(rgb[1]), Math.round(rgb[2]), Math.round(rgb[3]*100)/100];
|
||||
let rgb = Spectrum.hsvToRgb(this.hsv[0], this.hsv[1], this.hsv[2],
|
||||
this.hsv[3]);
|
||||
return [Math.round(rgb[0]), Math.round(rgb[1]), Math.round(rgb[2]),
|
||||
Math.round(rgb[3] * 100) / 100];
|
||||
},
|
||||
|
||||
get rgbNoSatVal() {
|
||||
@ -231,11 +234,12 @@ Spectrum.prototype = {
|
||||
|
||||
get rgbCssString() {
|
||||
let rgb = this.rgb;
|
||||
return "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")";
|
||||
return "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " +
|
||||
rgb[3] + ")";
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this.element.classList.add('spectrum-show');
|
||||
this.element.classList.add("spectrum-show");
|
||||
|
||||
this.slideHeight = this.slider.offsetHeight;
|
||||
this.dragWidth = this.dragger.offsetWidth;
|
||||
@ -276,9 +280,11 @@ Spectrum.prototype = {
|
||||
},
|
||||
|
||||
updateHelperLocations: function() {
|
||||
// If the UI hasn't been shown yet then none of the dimensions will be correct
|
||||
if (!this.element.classList.contains('spectrum-show'))
|
||||
// If the UI hasn't been shown yet then none of the dimensions will be
|
||||
// correct
|
||||
if (!this.element.classList.contains("spectrum-show")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let h = this.hsv[0];
|
||||
let s = this.hsv[1];
|
||||
@ -287,7 +293,7 @@ Spectrum.prototype = {
|
||||
// Placing the color dragger
|
||||
let dragX = s * this.dragWidth;
|
||||
let dragY = this.dragHeight - (v * this.dragHeight);
|
||||
let helperDim = this.dragHelperHeight/2;
|
||||
let helperDim = this.dragHelperHeight / 2;
|
||||
|
||||
dragX = Math.max(
|
||||
-helperDim,
|
||||
@ -302,11 +308,12 @@ Spectrum.prototype = {
|
||||
this.dragHelper.style.left = dragX + "px";
|
||||
|
||||
// Placing the hue slider
|
||||
let slideY = (h * this.slideHeight) - this.slideHelperHeight/2;
|
||||
let slideY = (h * this.slideHeight) - this.slideHelperHeight / 2;
|
||||
this.slideHelper.style.top = slideY + "px";
|
||||
|
||||
// Placing the alpha slider
|
||||
let alphaSliderX = (this.hsv[3] * this.alphaSliderWidth) - (this.alphaSliderHelperWidth / 2);
|
||||
let alphaSliderX = (this.hsv[3] * this.alphaSliderWidth) -
|
||||
(this.alphaSliderHelperWidth / 2);
|
||||
this.alphaSliderHelper.style.left = alphaSliderX + "px";
|
||||
},
|
||||
|
||||
@ -316,14 +323,15 @@ Spectrum.prototype = {
|
||||
let rgb = this.rgb;
|
||||
let rgbNoSatVal = this.rgbNoSatVal;
|
||||
|
||||
let flatColor = "rgb(" + rgbNoSatVal[0] + ", " + rgbNoSatVal[1] + ", " + rgbNoSatVal[2] + ")";
|
||||
let fullColor = "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")";
|
||||
let flatColor = "rgb(" + rgbNoSatVal[0] + ", " + rgbNoSatVal[1] + ", " +
|
||||
rgbNoSatVal[2] + ")";
|
||||
|
||||
this.dragger.style.backgroundColor = flatColor;
|
||||
|
||||
var rgbNoAlpha = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
|
||||
var rgbAlpha0 = "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ", 0)";
|
||||
var alphaGradient = "linear-gradient(to right, " + rgbAlpha0 + ", " + rgbNoAlpha + ")";
|
||||
let rgbNoAlpha = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
|
||||
let rgbAlpha0 = "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ", 0)";
|
||||
let alphaGradient = "linear-gradient(to right, " + rgbAlpha0 + ", " +
|
||||
rgbNoAlpha + ")";
|
||||
this.alphaSliderInner.style.background = alphaGradient;
|
||||
},
|
||||
|
||||
|
@ -109,7 +109,6 @@
|
||||
.theme-firebug .netInfoBody > .tabs .tabs-menu-item.is-active a:focus {
|
||||
border: 1px solid var(--net-border);
|
||||
border-bottom-color: transparent;
|
||||
border-color: var(--net-border);
|
||||
}
|
||||
|
||||
.theme-firebug .netInfoBody > .tabs .tabs-menu-item:hover a {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "AudioConverter.h"
|
||||
#include <string.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include <cmath>
|
||||
|
||||
/*
|
||||
* Parts derived from MythTV AudioConvert Class
|
||||
@ -27,13 +26,25 @@ AudioConverter::AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut)
|
||||
MOZ_DIAGNOSTIC_ASSERT(aIn.Format() == aOut.Format() &&
|
||||
aIn.Interleaved() == aOut.Interleaved(),
|
||||
"No format or rate conversion is supported at this stage");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aOut.Channels() <= 2 ||
|
||||
MOZ_DIAGNOSTIC_ASSERT((aIn.Channels() > aOut.Channels() && aOut.Channels() <= 2) ||
|
||||
aIn.Channels() == aOut.Channels(),
|
||||
"Only down/upmixing to mono or stereo is supported at this stage");
|
||||
"Only downmixing to mono or stereo is supported at this stage");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aOut.Interleaved(), "planar audio format not supported");
|
||||
mIn.Layout().MappingTable(mOut.Layout(), mChannelOrderMap);
|
||||
if (aIn.Rate() != aOut.Rate()) {
|
||||
RecreateResampler();
|
||||
int error;
|
||||
mResampler = speex_resampler_init(aOut.Channels(),
|
||||
aIn.Rate(),
|
||||
aOut.Rate(),
|
||||
SPEEX_RESAMPLER_QUALITY_DEFAULT,
|
||||
&error);
|
||||
|
||||
if (error == RESAMPLER_ERR_SUCCESS) {
|
||||
speex_resampler_skip_zeros(mResampler);
|
||||
} else {
|
||||
NS_WARNING("Failed to initialize resampler.");
|
||||
mResampler = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +60,6 @@ bool
|
||||
AudioConverter::CanWorkInPlace() const
|
||||
{
|
||||
bool needDownmix = mIn.Channels() > mOut.Channels();
|
||||
bool needUpmix = mIn.Channels() < mOut.Channels();
|
||||
bool canDownmixInPlace =
|
||||
mIn.Channels() * AudioConfig::SampleSize(mIn.Format()) >=
|
||||
mOut.Channels() * AudioConfig::SampleSize(mOut.Format());
|
||||
@ -58,7 +68,7 @@ AudioConverter::CanWorkInPlace() const
|
||||
// We should be able to work in place if 1s of audio input takes less space
|
||||
// than 1s of audio output. However, as we downmix before resampling we can't
|
||||
// perform any upsampling in place (e.g. if incoming rate >= outgoing rate)
|
||||
return !needUpmix && (!needDownmix || canDownmixInPlace) &&
|
||||
return (!needDownmix || canDownmixInPlace) &&
|
||||
(!needResample || canResampleInPlace);
|
||||
}
|
||||
|
||||
@ -67,9 +77,8 @@ AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aFrames)
|
||||
{
|
||||
if (mIn.Channels() > mOut.Channels()) {
|
||||
return DownmixAudio(aOut, aIn, aFrames);
|
||||
} else if (mIn.Channels() < mOut.Channels()) {
|
||||
return UpmixAudio(aOut, aIn, aFrames);
|
||||
} else if (mIn.Layout() != mOut.Layout() && CanReorderAudio()) {
|
||||
} else if (mIn.Layout() != mOut.Layout() &&
|
||||
CanReorderAudio()) {
|
||||
ReOrderInterleavedChannels(aOut, aIn, aFrames);
|
||||
} else if (aIn != aOut) {
|
||||
memmove(aOut, aIn, FramesOutToBytes(aFrames));
|
||||
@ -105,7 +114,10 @@ AudioConverter::ReOrderInterleavedChannels(void* aOut, const void* aIn,
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() == mOut.Channels());
|
||||
|
||||
if (mOut.Channels() == 1 || mOut.Layout() == mIn.Layout()) {
|
||||
if (mOut.Layout() == mIn.Layout()) {
|
||||
return;
|
||||
}
|
||||
if (mOut.Channels() == 1) {
|
||||
// If channel count is 1, planar and non-planar formats are the same and
|
||||
// there's nothing to reorder.
|
||||
if (aOut != aIn) {
|
||||
@ -219,7 +231,7 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
|
||||
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
|
||||
const float* in = static_cast<const float*>(aIn);
|
||||
float* out = static_cast<float*>(aOut);
|
||||
for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
float sample = 0.0;
|
||||
// The sample of the buffer would be interleaved.
|
||||
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
|
||||
@ -228,7 +240,7 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
|
||||
} else if (mIn.Format() == AudioConfig::FORMAT_S16) {
|
||||
const int16_t* in = static_cast<const int16_t*>(aIn);
|
||||
int16_t* out = static_cast<int16_t*>(aOut);
|
||||
for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
int32_t sample = 0.0;
|
||||
// The sample of the buffer would be interleaved.
|
||||
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
|
||||
@ -250,126 +262,27 @@ AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
|
||||
uint32_t outframes = ResampleRecipientFrames(aFrames);
|
||||
uint32_t inframes = aFrames;
|
||||
|
||||
int error;
|
||||
if (mOut.Format() == AudioConfig::FORMAT_FLT) {
|
||||
const float* in = reinterpret_cast<const float*>(aIn);
|
||||
float* out = reinterpret_cast<float*>(aOut);
|
||||
error =
|
||||
speex_resampler_process_interleaved_float(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
speex_resampler_process_interleaved_float(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
} else if (mOut.Format() == AudioConfig::FORMAT_S16) {
|
||||
const int16_t* in = reinterpret_cast<const int16_t*>(aIn);
|
||||
int16_t* out = reinterpret_cast<int16_t*>(aOut);
|
||||
error =
|
||||
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
} else {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
|
||||
}
|
||||
MOZ_ASSERT(error == RESAMPLER_ERR_SUCCESS);
|
||||
if (error != RESAMPLER_ERR_SUCCESS) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
mResampler = nullptr;
|
||||
return 0;
|
||||
}
|
||||
MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
|
||||
return outframes;
|
||||
}
|
||||
|
||||
void
|
||||
AudioConverter::RecreateResampler()
|
||||
{
|
||||
if (mResampler) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
}
|
||||
int error;
|
||||
mResampler = speex_resampler_init(mOut.Channels(),
|
||||
mIn.Rate(),
|
||||
mOut.Rate(),
|
||||
SPEEX_RESAMPLER_QUALITY_DEFAULT,
|
||||
&error);
|
||||
|
||||
if (error == RESAMPLER_ERR_SUCCESS) {
|
||||
speex_resampler_skip_zeros(mResampler);
|
||||
} else {
|
||||
NS_WARNING("Failed to initialize resampler.");
|
||||
mResampler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioConverter::DrainResampler(void* aOut)
|
||||
{
|
||||
if (!mResampler) {
|
||||
return 0;
|
||||
}
|
||||
int frames = speex_resampler_get_input_latency(mResampler);
|
||||
AlignedByteBuffer buffer(FramesOutToBytes(frames));
|
||||
if (!buffer) {
|
||||
// OOM
|
||||
return 0;
|
||||
}
|
||||
frames = ResampleAudio(aOut, buffer.Data(), frames);
|
||||
// Tore down the resampler as it's easier than handling follow-up.
|
||||
RecreateResampler();
|
||||
return frames;
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioConverter::UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const
|
||||
{
|
||||
MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
|
||||
mIn.Format() == AudioConfig::FORMAT_FLT);
|
||||
MOZ_ASSERT(mIn.Channels() < mOut.Channels());
|
||||
MOZ_ASSERT(mIn.Channels() == 1, "Can only upmix mono for now");
|
||||
MOZ_ASSERT(mOut.Channels() == 2, "Can only upmix to stereo for now");
|
||||
|
||||
if (mOut.Channels() != 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Upmix mono to stereo.
|
||||
// This is a very dumb mono to stereo upmixing, power levels are preserved
|
||||
// following the calculation: left = right = -3dB*mono.
|
||||
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
|
||||
const float m3db = std::sqrt(0.5); // -3dB = sqrt(1/2)
|
||||
const float* in = static_cast<const float*>(aIn);
|
||||
float* out = static_cast<float*>(aOut);
|
||||
for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
float sample = in[fIdx] * m3db;
|
||||
// The samples of the buffer would be interleaved.
|
||||
*out++ = sample;
|
||||
*out++ = sample;
|
||||
}
|
||||
} else if (mIn.Format() == AudioConfig::FORMAT_S16) {
|
||||
const int16_t* in = static_cast<const int16_t*>(aIn);
|
||||
int16_t* out = static_cast<int16_t*>(aOut);
|
||||
for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
|
||||
int16_t sample = ((int32_t)in[fIdx] * 11585) >> 14; // close enough to i*sqrt(0.5)
|
||||
// The samples of the buffer would be interleaved.
|
||||
*out++ = sample;
|
||||
*out++ = sample;
|
||||
}
|
||||
} else {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
|
||||
}
|
||||
|
||||
return aFrames;
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioConverter::ResampleRecipientFrames(size_t aFrames) const
|
||||
{
|
||||
if (!aFrames && mIn.Rate() != mOut.Rate()) {
|
||||
// The resampler will be drained, account for frames currently buffered
|
||||
// in the resampler.
|
||||
if (!mResampler) {
|
||||
return 0;
|
||||
}
|
||||
return speex_resampler_get_output_latency(mResampler);
|
||||
} else {
|
||||
return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
|
||||
}
|
||||
return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -123,8 +123,6 @@ public:
|
||||
// Convert the AudioDataBuffer.
|
||||
// Conversion will be done in place if possible. Otherwise a new buffer will
|
||||
// be returned.
|
||||
// Providing an empty buffer and resampling is expected, the resampler
|
||||
// will be drained.
|
||||
template <AudioConfig::SampleFormat Format, typename Value>
|
||||
AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
|
||||
{
|
||||
@ -154,7 +152,7 @@ public:
|
||||
return AudioDataBuffer<Format, Value>(Move(temp1));
|
||||
}
|
||||
frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
|
||||
if (mIn.Rate() == mOut.Rate()) {
|
||||
if (!frames || mIn.Rate() == mOut.Rate()) {
|
||||
temp1.SetLength(FramesOutToSamples(frames));
|
||||
return AudioDataBuffer<Format, Value>(Move(temp1));
|
||||
}
|
||||
@ -163,17 +161,13 @@ public:
|
||||
// If we are downsampling we can re-use it.
|
||||
AlignedBuffer<Value>* outputBuffer = &temp1;
|
||||
AlignedBuffer<Value> temp2;
|
||||
if (!frames || mOut.Rate() > mIn.Rate()) {
|
||||
// We are upsampling or about to drain, we can't work in place.
|
||||
// Allocate another temporary buffer where the upsampling will occur.
|
||||
if (mOut.Rate() > mIn.Rate()) {
|
||||
// We are upsampling, we can't work in place. Allocate another temporary
|
||||
// buffer where the upsampling will occur.
|
||||
temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)));
|
||||
outputBuffer = &temp2;
|
||||
}
|
||||
if (!frames) {
|
||||
frames = DrainResampler(outputBuffer->Data());
|
||||
} else {
|
||||
frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
|
||||
}
|
||||
frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
|
||||
outputBuffer->SetLength(FramesOutToSamples(frames));
|
||||
return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
|
||||
}
|
||||
@ -219,7 +213,6 @@ private:
|
||||
size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
|
||||
void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
|
||||
size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
|
||||
size_t UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
|
||||
|
||||
size_t FramesOutToSamples(size_t aFrames) const;
|
||||
size_t SamplesInToFrames(size_t aSamples) const;
|
||||
@ -229,8 +222,6 @@ private:
|
||||
SpeexResamplerState* mResampler;
|
||||
size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
|
||||
size_t ResampleRecipientFrames(size_t aFrames) const;
|
||||
void RecreateResampler();
|
||||
size_t DrainResampler(void* aOut);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -129,6 +129,7 @@ AudioStream::AudioStream(DataSource& aSource)
|
||||
, mTimeStretcher(nullptr)
|
||||
, mDumpFile(nullptr)
|
||||
, mState(INITIALIZED)
|
||||
, mIsMonoAudioEnabled(gfxPrefs::MonoAudio())
|
||||
, mDataSource(aSource)
|
||||
{
|
||||
}
|
||||
@ -330,7 +331,7 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
("%s channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
|
||||
mInRate = mOutRate = aRate;
|
||||
mChannels = aNumChannels;
|
||||
mOutChannels = aNumChannels;
|
||||
mOutChannels = mIsMonoAudioEnabled ? 1 : aNumChannels;
|
||||
|
||||
mDumpFile = OpenDumpFile(this);
|
||||
|
||||
@ -352,6 +353,11 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
|
||||
mAudioClock.Init();
|
||||
|
||||
if (mIsMonoAudioEnabled) {
|
||||
AudioConfig inConfig(mChannels, mInRate);
|
||||
AudioConfig outConfig(mOutChannels, mOutRate);
|
||||
mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
|
||||
}
|
||||
return OpenCubeb(params);
|
||||
}
|
||||
|
||||
@ -546,7 +552,7 @@ AudioStream::IsPaused()
|
||||
}
|
||||
|
||||
bool
|
||||
AudioStream::IsValidAudioFormat(Chunk* aChunk)
|
||||
AudioStream::Downmix(Chunk* aChunk)
|
||||
{
|
||||
if (aChunk->Rate() != mInRate) {
|
||||
LOGW("mismatched sample %u, mInRate=%u", aChunk->Rate(), mInRate);
|
||||
@ -557,6 +563,10 @@ AudioStream::IsValidAudioFormat(Chunk* aChunk)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mAudioConverter) {
|
||||
mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -585,10 +595,10 @@ AudioStream::GetUnprocessed(AudioBufferWriter& aWriter)
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(c->Frames() <= aWriter.Available());
|
||||
if (IsValidAudioFormat(c.get())) {
|
||||
if (Downmix(c.get())) {
|
||||
aWriter.Write(c->Data(), c->Frames());
|
||||
} else {
|
||||
// Write silence if invalid format.
|
||||
// Write silence if downmixing fails.
|
||||
aWriter.WriteZeros(c->Frames());
|
||||
}
|
||||
}
|
||||
@ -613,10 +623,10 @@ AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(c->Frames() <= toPopFrames);
|
||||
if (IsValidAudioFormat(c.get())) {
|
||||
if (Downmix(c.get())) {
|
||||
mTimeStretcher->putSamples(c->Data(), c->Frames());
|
||||
} else {
|
||||
// Write silence if invalid format.
|
||||
// Write silence if downmixing fails.
|
||||
AutoTArray<AudioDataValue, 1000> buf;
|
||||
buf.SetLength(mOutChannels * c->Frames());
|
||||
memset(buf.Elements(), 0, buf.Length() * sizeof(AudioDataValue));
|
||||
|
@ -286,11 +286,6 @@ public:
|
||||
// Returns true when the audio stream is paused.
|
||||
bool IsPaused();
|
||||
|
||||
static uint32_t GetPreferredRate()
|
||||
{
|
||||
CubebUtils::InitPreferredSampleRate();
|
||||
return CubebUtils::PreferredSampleRate();
|
||||
}
|
||||
uint32_t GetRate() { return mOutRate; }
|
||||
uint32_t GetChannels() { return mChannels; }
|
||||
uint32_t GetOutChannels() { return mOutChannels; }
|
||||
@ -333,9 +328,8 @@ private:
|
||||
|
||||
nsresult EnsureTimeStretcherInitializedUnlocked();
|
||||
|
||||
// Return true if audio frames are valid (correct sampling rate and valid
|
||||
// channel count) otherwise false.
|
||||
bool IsValidAudioFormat(Chunk* aChunk);
|
||||
// Return true if downmixing succeeds otherwise false.
|
||||
bool Downmix(Chunk* aChunk);
|
||||
|
||||
void GetUnprocessed(AudioBufferWriter& aWriter);
|
||||
void GetTimeStretched(AudioBufferWriter& aWriter);
|
||||
@ -375,8 +369,12 @@ private:
|
||||
|
||||
StreamState mState;
|
||||
bool mIsFirst;
|
||||
// Get this value from the preference, if true, we would downmix the stereo.
|
||||
bool mIsMonoAudioEnabled;
|
||||
|
||||
DataSource& mDataSource;
|
||||
|
||||
UniquePtr<AudioConverter> mAudioConverter;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -361,7 +361,7 @@ MediaDecoderStateMachine::CreateAudioSink()
|
||||
auto audioSinkCreator = [self] () {
|
||||
MOZ_ASSERT(self->OnTaskQueue());
|
||||
return new DecodedAudioDataSink(
|
||||
self->mTaskQueue, self->mAudioQueue, self->GetMediaTime(),
|
||||
self->mAudioQueue, self->GetMediaTime(),
|
||||
self->mInfo.mAudio, self->mAudioChannel);
|
||||
};
|
||||
return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
|
||||
|
@ -29,8 +29,7 @@ namespace media {
|
||||
// The amount of audio frames that is used to fuzz rounding errors.
|
||||
static const int64_t AUDIO_FUZZ_FRAMES = 1;
|
||||
|
||||
DecodedAudioDataSink::DecodedAudioDataSink(AbstractThread* aThread,
|
||||
MediaQueue<MediaData>& aAudioQueue,
|
||||
DecodedAudioDataSink::DecodedAudioDataSink(MediaQueue<MediaData>& aAudioQueue,
|
||||
int64_t aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel)
|
||||
@ -41,32 +40,16 @@ DecodedAudioDataSink::DecodedAudioDataSink(AbstractThread* aThread,
|
||||
, mInfo(aInfo)
|
||||
, mChannel(aChannel)
|
||||
, mPlaying(true)
|
||||
, mErrored(false)
|
||||
, mPlaybackComplete(false)
|
||||
, mOwnerThread(aThread)
|
||||
, mFramesParsed(0)
|
||||
, mLastEndTime(0)
|
||||
{
|
||||
bool resampling = gfxPrefs::AudioSinkResampling();
|
||||
|
||||
if (resampling) {
|
||||
mOutputRate = gfxPrefs::AudioSinkResampleRate();
|
||||
} else if (mInfo.mRate == 44100 || mInfo.mRate == 48000) {
|
||||
// The original rate is of good quality and we want to minimize unecessary
|
||||
// resampling. The common scenario being that the sampling rate is one or
|
||||
// the other, this allows to minimize audio quality regression and hoping
|
||||
// content provider want change from those rates mid-stream.
|
||||
mOutputRate = mInfo.mRate;
|
||||
} else {
|
||||
// We will resample all data to match cubeb's preferred sampling rate.
|
||||
mOutputRate = AudioStream::GetPreferredRate();
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(mOutputRate, "output rate can't be 0.");
|
||||
|
||||
bool monoAudioEnabled = gfxPrefs::MonoAudio();
|
||||
|
||||
mOutputChannels = monoAudioEnabled
|
||||
? 1 : (gfxPrefs::AudioSinkForceStereo() ? 2 : mInfo.mChannels);
|
||||
uint32_t resamplingRate = gfxPrefs::AudioSinkResampleRate();
|
||||
mConverter =
|
||||
MakeUnique<AudioConverter>(
|
||||
AudioConfig(mInfo.mChannels, mInfo.mRate),
|
||||
AudioConfig(mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
|
||||
? 2 : mInfo.mChannels,
|
||||
resampling ? resamplingRate : mInfo.mRate));
|
||||
}
|
||||
|
||||
DecodedAudioDataSink::~DecodedAudioDataSink()
|
||||
@ -76,16 +59,6 @@ DecodedAudioDataSink::~DecodedAudioDataSink()
|
||||
RefPtr<GenericPromise>
|
||||
DecodedAudioDataSink::Init(const PlaybackParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
||||
mAudioQueueListener = mAudioQueue.PushEvent().Connect(
|
||||
mOwnerThread, this, &DecodedAudioDataSink::OnAudioPushed);
|
||||
mProcessedQueueListener = mProcessedQueue.PopEvent().Connect(
|
||||
mOwnerThread, this, &DecodedAudioDataSink::OnAudioPopped);
|
||||
|
||||
// To ensure at least one audio packet will be popped from AudioQueue and
|
||||
// ready to be played.
|
||||
NotifyAudioNeeded();
|
||||
RefPtr<GenericPromise> p = mEndPromise.Ensure(__func__);
|
||||
nsresult rv = InitializeAudioStream(aParams);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -122,16 +95,10 @@ DecodedAudioDataSink::HasUnplayedFrames()
|
||||
void
|
||||
DecodedAudioDataSink::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
||||
mAudioQueueListener.Disconnect();
|
||||
mProcessedQueueListener.Disconnect();
|
||||
|
||||
if (mAudioStream) {
|
||||
mAudioStream->Shutdown();
|
||||
mAudioStream = nullptr;
|
||||
}
|
||||
mProcessedQueue.Reset();
|
||||
mEndPromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
|
||||
@ -179,7 +146,9 @@ nsresult
|
||||
DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
|
||||
{
|
||||
mAudioStream = new AudioStream(*this);
|
||||
nsresult rv = mAudioStream->Init(mOutputChannels, mOutputRate, mChannel);
|
||||
nsresult rv = mAudioStream->Init(mConverter->OutputConfig().Channels(),
|
||||
mConverter->OutputConfig().Rate(),
|
||||
mChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
mAudioStream->Shutdown();
|
||||
mAudioStream = nullptr;
|
||||
@ -199,14 +168,13 @@ DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
|
||||
int64_t
|
||||
DecodedAudioDataSink::GetEndTime() const
|
||||
{
|
||||
CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mOutputRate) + mStartTime;
|
||||
CheckedInt64 playedUsecs =
|
||||
FramesToUsecs(mWritten, mConverter->OutputConfig().Rate()) + mStartTime;
|
||||
if (!playedUsecs.isValid()) {
|
||||
NS_WARNING("Int overflow calculating audio end time");
|
||||
return -1;
|
||||
}
|
||||
// As we may be resampling, rounding errors may occur. Ensure we never get
|
||||
// past the original end time.
|
||||
return std::min<int64_t>(mLastEndTime, playedUsecs.value());
|
||||
return playedUsecs.value();
|
||||
}
|
||||
|
||||
UniquePtr<AudioStream::Chunk>
|
||||
@ -249,13 +217,78 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
UniquePtr<AudioDataValue[]> mData;
|
||||
};
|
||||
|
||||
if (!mCurrentData) {
|
||||
while (!mCurrentData) {
|
||||
// No data in the queue. Return an empty chunk.
|
||||
if (!mProcessedQueue.GetSize()) {
|
||||
if (AudioQueue().GetSize() == 0) {
|
||||
return MakeUnique<Chunk>();
|
||||
}
|
||||
|
||||
mCurrentData = dont_AddRef(mProcessedQueue.PopFront().take());
|
||||
AudioData* a = AudioQueue().PeekFront()->As<AudioData>();
|
||||
|
||||
// Ignore the element with 0 frames and try next.
|
||||
if (a->mFrames == 0) {
|
||||
RefPtr<MediaData> releaseMe = AudioQueue().PopFront();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore invalid samples.
|
||||
if (a->mRate != mInfo.mRate || a->mChannels != mInfo.mChannels) {
|
||||
NS_WARNING(nsPrintfCString(
|
||||
"mismatched sample format, data=%p rate=%u channels=%u frames=%u",
|
||||
a->mAudioData.get(), a->mRate, a->mChannels, a->mFrames).get());
|
||||
RefPtr<MediaData> releaseMe = AudioQueue().PopFront();
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if there's a gap in the audio. If there is, push silence into the
|
||||
// audio hardware, so we can play across the gap.
|
||||
// Calculate the timestamp of the next chunk of audio in numbers of
|
||||
// samples.
|
||||
CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime,
|
||||
mConverter->OutputConfig().Rate());
|
||||
// Calculate the number of frames that have been pushed onto the audio hardware.
|
||||
CheckedInt64 playedFrames = UsecsToFrames(mStartTime,
|
||||
mConverter->OutputConfig().Rate()) +
|
||||
static_cast<int64_t>(mWritten);
|
||||
CheckedInt64 missingFrames = sampleTime - playedFrames;
|
||||
|
||||
if (!missingFrames.isValid() || !sampleTime.isValid()) {
|
||||
NS_WARNING("Int overflow in DecodedAudioDataSink");
|
||||
mErrored = true;
|
||||
return MakeUnique<Chunk>();
|
||||
}
|
||||
|
||||
const uint32_t rate = mConverter->OutputConfig().Rate();
|
||||
const uint32_t channels = mConverter->OutputConfig().Channels();
|
||||
|
||||
if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
|
||||
// The next audio chunk begins some time after the end of the last chunk
|
||||
// we pushed to the audio hardware. We must push silence into the audio
|
||||
// hardware so that the next audio chunk begins playback at the correct
|
||||
// time.
|
||||
missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
|
||||
auto framesToPop = std::min<uint32_t>(missingFrames.value(), aFrames);
|
||||
mWritten += framesToPop;
|
||||
return MakeUnique<SilentChunk>(framesToPop, channels, rate);
|
||||
}
|
||||
|
||||
RefPtr<AudioData> data =
|
||||
dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
|
||||
if (mConverter->InputConfig() != mConverter->OutputConfig()) {
|
||||
AlignedAudioBuffer convertedData =
|
||||
mConverter->Process(AudioSampleBuffer(Move(data->mAudioData))).Forget();
|
||||
mCurrentData =
|
||||
new AudioData(data->mOffset,
|
||||
data->mTime,
|
||||
data->mDuration,
|
||||
convertedData.Length() / channels,
|
||||
Move(convertedData),
|
||||
channels,
|
||||
rate);
|
||||
} else {
|
||||
mCurrentData = Move(data);
|
||||
}
|
||||
|
||||
mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
|
||||
mCurrentData->mChannels,
|
||||
mCurrentData->mFrames);
|
||||
@ -275,7 +308,7 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
|
||||
// All frames are popped. Reset mCurrentData so we can pop new elements from
|
||||
// the audio queue in next calls to PopFrames().
|
||||
if (!mCursor->Available()) {
|
||||
if (mCursor->Available() == 0) {
|
||||
mCurrentData = nullptr;
|
||||
}
|
||||
|
||||
@ -297,189 +330,5 @@ DecodedAudioDataSink::Drained()
|
||||
mEndPromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
DecodedAudioDataSink::OnAudioPopped(const RefPtr<MediaData>& aSample)
|
||||
{
|
||||
SINK_LOG_V("AudioStream has used an audio packet.");
|
||||
NotifyAudioNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedAudioDataSink::OnAudioPushed(const RefPtr<MediaData>& aSample)
|
||||
{
|
||||
SINK_LOG_V("One new audio packet available.");
|
||||
NotifyAudioNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedAudioDataSink::NotifyAudioNeeded()
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn(),
|
||||
"Not called from the owner's thread");
|
||||
|
||||
if (AudioQueue().IsFinished() && !AudioQueue().GetSize()) {
|
||||
// We have reached the end of the data, drain the resampler.
|
||||
DrainConverter();
|
||||
return;
|
||||
}
|
||||
|
||||
// Always ensure we have two processed frames pending to allow for processing
|
||||
// latency.
|
||||
while (AudioQueue().GetSize() && mProcessedQueue.GetSize() < 2) {
|
||||
RefPtr<AudioData> data =
|
||||
dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
|
||||
|
||||
// Ignore the element with 0 frames and try next.
|
||||
if (!data->mFrames) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mConverter ||
|
||||
(data->mRate != mConverter->InputConfig().Rate() ||
|
||||
data->mChannels != mConverter->InputConfig().Channels())) {
|
||||
SINK_LOG_V("Audio format changed from %u@%uHz to %u@%uHz",
|
||||
mConverter? mConverter->InputConfig().Channels() : 0,
|
||||
mConverter ? mConverter->InputConfig().Rate() : 0,
|
||||
data->mChannels, data->mRate);
|
||||
|
||||
DrainConverter();
|
||||
|
||||
// mFramesParsed indicates the current playtime in frames at the current
|
||||
// input sampling rate. Recalculate it per the new sampling rate.
|
||||
if (mFramesParsed) {
|
||||
// We minimize overflow.
|
||||
uint32_t oldRate = mConverter->InputConfig().Rate();
|
||||
uint32_t newRate = data->mRate;
|
||||
int64_t major = mFramesParsed / oldRate;
|
||||
int64_t remainder = mFramesParsed % oldRate;
|
||||
CheckedInt64 result =
|
||||
CheckedInt64(remainder) * newRate / oldRate + major * oldRate;
|
||||
if (!result.isValid()) {
|
||||
NS_WARNING("Int overflow in DecodedAudioDataSink");
|
||||
mErrored = true;
|
||||
return;
|
||||
}
|
||||
mFramesParsed = result.value();
|
||||
}
|
||||
|
||||
mConverter =
|
||||
MakeUnique<AudioConverter>(
|
||||
AudioConfig(data->mChannels, data->mRate),
|
||||
AudioConfig(mOutputChannels, mOutputRate));
|
||||
}
|
||||
|
||||
// See if there's a gap in the audio. If there is, push silence into the
|
||||
// audio hardware, so we can play across the gap.
|
||||
// Calculate the timestamp of the next chunk of audio in numbers of
|
||||
// samples.
|
||||
CheckedInt64 sampleTime = UsecsToFrames(data->mTime - mStartTime,
|
||||
data->mRate);
|
||||
// Calculate the number of frames that have been pushed onto the audio hardware.
|
||||
CheckedInt64 missingFrames = sampleTime - mFramesParsed;
|
||||
|
||||
if (!missingFrames.isValid()) {
|
||||
NS_WARNING("Int overflow in DecodedAudioDataSink");
|
||||
mErrored = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
|
||||
// The next audio packet begins some time after the end of the last packet
|
||||
// we pushed to the audio hardware. We must push silence into the audio
|
||||
// hardware so that the next audio packet begins playback at the correct
|
||||
// time.
|
||||
missingFrames = std::min<int64_t>(INT32_MAX, missingFrames.value());
|
||||
mFramesParsed += missingFrames.value();
|
||||
// We need to insert silence, first use drained frames if any.
|
||||
missingFrames -= DrainConverter(missingFrames.value());
|
||||
// Insert silence is still needed.
|
||||
if (missingFrames.value()) {
|
||||
AlignedAudioBuffer silenceData(missingFrames.value() * mOutputChannels);
|
||||
if (!silenceData) {
|
||||
NS_WARNING("OOM in DecodedAudioDataSink");
|
||||
mErrored = true;
|
||||
return;
|
||||
}
|
||||
RefPtr<AudioData> silence = CreateAudioFromBuffer(Move(silenceData), data);
|
||||
if (silence) {
|
||||
mProcessedQueue.Push(silence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLastEndTime = data->GetEndTime();
|
||||
mFramesParsed += data->mFrames;
|
||||
|
||||
if (mConverter->InputConfig() != mConverter->OutputConfig()) {
|
||||
AlignedAudioBuffer convertedData =
|
||||
mConverter->Process(AudioSampleBuffer(Move(data->mAudioData))).Forget();
|
||||
data = CreateAudioFromBuffer(Move(convertedData), data);
|
||||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
mProcessedQueue.Push(data);
|
||||
mLastProcessedPacket = Some(data);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<AudioData>
|
||||
DecodedAudioDataSink::CreateAudioFromBuffer(AlignedAudioBuffer&& aBuffer,
|
||||
AudioData* aReference)
|
||||
{
|
||||
uint32_t frames = aBuffer.Length() / mOutputChannels;
|
||||
if (!frames) {
|
||||
return nullptr;
|
||||
}
|
||||
CheckedInt64 duration = FramesToUsecs(frames, mOutputRate);
|
||||
if (!duration.isValid()) {
|
||||
NS_WARNING("Int overflow in DecodedAudioDataSink");
|
||||
mErrored = true;
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<AudioData> data =
|
||||
new AudioData(aReference->mOffset,
|
||||
aReference->mTime,
|
||||
duration.value(),
|
||||
frames,
|
||||
Move(aBuffer),
|
||||
mOutputChannels,
|
||||
mOutputRate);
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DecodedAudioDataSink::DrainConverter(uint32_t aMaxFrames)
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
||||
if (!mConverter || !mLastProcessedPacket) {
|
||||
// nothing to drain.
|
||||
return 0;
|
||||
}
|
||||
|
||||
RefPtr<AudioData> lastPacket = mLastProcessedPacket.ref();
|
||||
mLastProcessedPacket.reset();
|
||||
|
||||
// To drain we simply provide an empty packet to the audio converter.
|
||||
AlignedAudioBuffer convertedData =
|
||||
mConverter->Process(AudioSampleBuffer(AlignedAudioBuffer())).Forget();
|
||||
|
||||
uint32_t frames = convertedData.Length() / mOutputChannels;
|
||||
if (!convertedData.SetLength(std::min(frames, aMaxFrames) * mOutputChannels)) {
|
||||
// This can never happen as we were reducing the length of convertData.
|
||||
mErrored = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
RefPtr<AudioData> data =
|
||||
CreateAudioFromBuffer(Move(convertedData), lastPacket);
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
mProcessedQueue.Push(data);
|
||||
return data->mFrames;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace mozilla
|
||||
|
@ -28,8 +28,7 @@ namespace media {
|
||||
class DecodedAudioDataSink : public AudioSink,
|
||||
private AudioStream::DataSource {
|
||||
public:
|
||||
DecodedAudioDataSink(AbstractThread* aThread,
|
||||
MediaQueue<MediaData>& aAudioQueue,
|
||||
DecodedAudioDataSink(MediaQueue<MediaData>& aAudioQueue,
|
||||
int64_t aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel);
|
||||
@ -103,35 +102,12 @@ private:
|
||||
// Keep track of the read position of mCurrentData.
|
||||
UniquePtr<AudioBufferCursor> mCursor;
|
||||
// True if there is any error in processing audio data like overflow.
|
||||
Atomic<bool> mErrored;
|
||||
bool mErrored = false;
|
||||
|
||||
// Set on the callback thread of cubeb once the stream has drained.
|
||||
Atomic<bool> mPlaybackComplete;
|
||||
|
||||
const RefPtr<AbstractThread> mOwnerThread;
|
||||
|
||||
// Audio Processing objects and methods
|
||||
void OnAudioPopped(const RefPtr<MediaData>& aSample);
|
||||
void OnAudioPushed(const RefPtr<MediaData>& aSample);
|
||||
void NotifyAudioNeeded();
|
||||
// Drain the converter and add the output to the processed audio queue.
|
||||
// A maximum of aMaxFrames will be added.
|
||||
uint32_t DrainConverter(uint32_t aMaxFrames = UINT32_MAX);
|
||||
already_AddRefed<AudioData> CreateAudioFromBuffer(AlignedAudioBuffer&& aBuffer,
|
||||
AudioData* aReference);
|
||||
UniquePtr<AudioConverter> mConverter;
|
||||
MediaQueue<AudioData> mProcessedQueue;
|
||||
MediaEventListener mAudioQueueListener;
|
||||
MediaEventListener mProcessedQueueListener;
|
||||
// Number of frames processed from AudioQueue(). Used to determine gaps in
|
||||
// the input stream. It indicates the time in frames since playback started
|
||||
// at the current input framerate.
|
||||
int64_t mFramesParsed;
|
||||
Maybe<RefPtr<AudioData>> mLastProcessedPacket;
|
||||
int64_t mLastEndTime;
|
||||
// Never modifed after construction.
|
||||
uint32_t mOutputRate;
|
||||
uint32_t mOutputChannels;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
@ -1094,6 +1094,14 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult)
|
||||
// 6. Set first initialization segment received flag to true.
|
||||
mFirstInitializationSegmentReceived = true;
|
||||
} else {
|
||||
// Check that audio configuration hasn't changed as this is something
|
||||
// we do not support yet (bug 1185827).
|
||||
if (mAudioTracks.mNumTracks &&
|
||||
(info.mAudio.mChannels != mAudioTracks.mInfo->GetAsAudioInfo()->mChannels ||
|
||||
info.mAudio.mRate != mAudioTracks.mInfo->GetAsAudioInfo()->mRate)) {
|
||||
RejectAppend(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
mAudioTracks.mLastInfo = new SharedTrackInfo(info.mAudio, streamID);
|
||||
mVideoTracks.mLastInfo = new SharedTrackInfo(info.mVideo, streamID);
|
||||
}
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Cache-Control: no-store
|
@ -34,15 +34,7 @@ support-files =
|
||||
bipbop/bipbop11.m4s^headers^ bipbop/bipbop_audio11.m4s^headers^ bipbop/bipbop_video11.m4s^headers^
|
||||
bipbop/bipbop12.m4s^headers^ bipbop/bipbop_video12.m4s^headers^
|
||||
bipbop/bipbop13.m4s^headers^ bipbop/bipbop_video13.m4s^headers^
|
||||
aac20-48000-64000-init.mp4 aac20-48000-64000-init.mp4^headers^
|
||||
aac20-48000-64000-1.m4s aac20-48000-64000-1.m4s^headers^
|
||||
aac20-48000-64000-2.m4s aac20-48000-64000-2.m4s^headers^
|
||||
aac51-48000-128000-init.mp4 aac51-48000-128000-init.mp4^headers^
|
||||
aac51-48000-128000-1.m4s aac51-48000-128000-1.m4s^headers^
|
||||
aac51-48000-128000-2.m4s aac51-48000-128000-2.m4s^headers^
|
||||
|
||||
[test_AudioChange_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
|
||||
[test_BufferedSeek.html]
|
||||
[test_BufferedSeek_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
|
||||
|
@ -1,72 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>MSE: basic functionality</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// This test checks loading a stereo segment, followed by a 5.1 segment plays without error.
|
||||
|
||||
runWithMSE(function(ms, el) {
|
||||
el.controls = true;
|
||||
once(ms, 'sourceopen').then(function() {
|
||||
// Log events for debugging.
|
||||
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
|
||||
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
|
||||
"waiting", "pause", "durationchange", "seeking", "seeked"];
|
||||
function logEvent(e) {
|
||||
var v = e.target;
|
||||
info("got " + e.type + " event");
|
||||
}
|
||||
events.forEach(function(e) {
|
||||
el.addEventListener(e, logEvent, false);
|
||||
});
|
||||
|
||||
ok(true, "Receive a sourceopen event");
|
||||
var audiosb = ms.addSourceBuffer("audio/mp4");
|
||||
el.addEventListener("error", function(e) {
|
||||
ok(false, "should not fire '" + e.type + "' event");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
|
||||
fetchAndLoad(audiosb, 'aac20-48000-64000-', ['init'], '.mp4')
|
||||
.then(once.bind(null, el, 'loadedmetadata'))
|
||||
.then(function() {
|
||||
ok(true, "got loadedmetadata event");
|
||||
var promises = [];
|
||||
promises.push(once(el, 'loadeddata'));
|
||||
promises.push(once(el, 'canplay'));
|
||||
promises.push(fetchAndLoad(audiosb, 'aac20-48000-64000-', ['1'], '.m4s'));
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function() {
|
||||
ok(true, "got canplay event");
|
||||
el.play();
|
||||
return fetchAndLoad(audiosb, 'aac51-48000-128000-', ['init'], '.mp4');
|
||||
})
|
||||
.then(fetchAndLoad.bind(null, audiosb, 'aac51-48000-128000-', ['2'], '.m4s'))
|
||||
.then(function() {
|
||||
var promises = [];
|
||||
ms.endOfStream();
|
||||
promises.push(once(el, 'ended'));
|
||||
promises.push(once(audiosb, 'updateend'));
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function() {
|
||||
ok(el.currentTime >= 6, "played to the end");
|
||||
SimpleTest.finish();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,46 +0,0 @@
|
||||
diff --git a/media/libspeex_resampler/src/resample.c b/media/libspeex_resampler/src/resample.c
|
||||
index 83ad119..a3859e3 100644
|
||||
--- a/media/libspeex_resampler/src/resample.c
|
||||
+++ b/media/libspeex_resampler/src/resample.c
|
||||
@@ -811,6 +811,12 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
return NULL;
|
||||
}
|
||||
st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
|
||||
+ if (!st)
|
||||
+ {
|
||||
+ if (err)
|
||||
+ *err = RESAMPLER_ERR_ALLOC_FAILED;
|
||||
+ return NULL;
|
||||
+ }
|
||||
st->initialised = 0;
|
||||
st->started = 0;
|
||||
st->in_rate = 0;
|
||||
@@ -832,9 +838,12 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
st->buffer_size = 160;
|
||||
|
||||
/* Per channel data */
|
||||
- st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t));
|
||||
- st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
- st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
+ if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t))))
|
||||
+ goto fail;
|
||||
+ if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))
|
||||
+ goto fail;
|
||||
+ if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))
|
||||
+ goto fail;
|
||||
for (i=0;i<nb_channels;i++)
|
||||
{
|
||||
st->last_sample[i] = 0;
|
||||
@@ -857,6 +866,12 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
*err = filter_err;
|
||||
|
||||
return st;
|
||||
+
|
||||
+fail:
|
||||
+ if (err)
|
||||
+ *err = RESAMPLER_ERR_ALLOC_FAILED;
|
||||
+ speex_resampler_destroy(st);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
|
@ -811,12 +811,6 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
return NULL;
|
||||
}
|
||||
st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
|
||||
if (!st)
|
||||
{
|
||||
if (err)
|
||||
*err = RESAMPLER_ERR_ALLOC_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
st->initialised = 0;
|
||||
st->started = 0;
|
||||
st->in_rate = 0;
|
||||
@ -838,12 +832,9 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
st->buffer_size = 160;
|
||||
|
||||
/* Per channel data */
|
||||
if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t))))
|
||||
goto fail;
|
||||
if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))
|
||||
goto fail;
|
||||
if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t))))
|
||||
goto fail;
|
||||
st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t));
|
||||
st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
for (i=0;i<nb_channels;i++)
|
||||
{
|
||||
st->last_sample[i] = 0;
|
||||
@ -866,12 +857,6 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
*err = filter_err;
|
||||
|
||||
return st;
|
||||
|
||||
fail:
|
||||
if (err)
|
||||
*err = RESAMPLER_ERR_ALLOC_FAILED;
|
||||
speex_resampler_destroy(st);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
|
||||
|
@ -25,4 +25,3 @@ patch -p3 < simd-detect-runtime.patch
|
||||
patch -p3 < set-skip-frac.patch
|
||||
patch -p3 < hugemem.patch
|
||||
patch -p3 < remove-empty-asm-clobber.patch
|
||||
patch -p3 < handle-memory-error.patch
|
||||
|
@ -305,9 +305,6 @@ pref("browser.search.order.US.3", "chrome://browser/locale/region.properties");
|
||||
// disable updating
|
||||
pref("browser.search.update", false);
|
||||
|
||||
// enable tracking protection for private browsing
|
||||
pref("privacy.trackingprotection.pbmode.enabled", true);
|
||||
|
||||
// disable search suggestions by default
|
||||
pref("browser.search.suggest.enabled", false);
|
||||
pref("browser.search.suggest.prompted", false);
|
||||
@ -649,46 +646,14 @@ pref("media.mediasource.enabled", true);
|
||||
pref("image.downscale-during-decode.enabled", true);
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
pref("browser.safebrowsing.enabled", true);
|
||||
pref("browser.safebrowsing.malware.enabled", true);
|
||||
pref("browser.safebrowsing.downloads.enabled", false);
|
||||
pref("browser.safebrowsing.downloads.remote.enabled", false);
|
||||
pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
|
||||
pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous_host", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
|
||||
pref("browser.safebrowsing.downloads.remote.block_uncommon", false);
|
||||
pref("browser.safebrowsing.debug", false);
|
||||
|
||||
pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
|
||||
pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
|
||||
pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
||||
pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportMalwareMistakeURL", "https://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
|
||||
pref("browser.safebrowsing.id", @MOZ_APP_UA_NAME@);
|
||||
|
||||
// Name of the about: page contributed by safebrowsing to handle display of error
|
||||
// pages on phishing/malware hits. (bug 399233)
|
||||
pref("urlclassifier.alternate_error_page", "blocked");
|
||||
|
||||
// The number of random entries to send with a gethash request.
|
||||
pref("urlclassifier.gethashnoise", 4);
|
||||
|
||||
// Gethash timeout for Safebrowsing.
|
||||
pref("urlclassifier.gethash.timeout_ms", 5000);
|
||||
|
||||
// If an urlclassifier table has not been updated in this number of seconds,
|
||||
// a gethash request will be forced to check that the result is still in
|
||||
// the database.
|
||||
pref("urlclassifier.max-complete-age", 2700);
|
||||
|
||||
// Tables for application reputation.
|
||||
pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
|
||||
#endif
|
||||
|
||||
// True if this is the first time we are showing about:firstrun
|
||||
|
@ -47,6 +47,11 @@ import java.util.ArrayList;
|
||||
* * Note: when the application starts for testing, it may need to upgrade the database from your existing version. If
|
||||
* this fails, the application will crash and the test may fail to start.
|
||||
*
|
||||
* IMPORTANT:
|
||||
* Test DBs must be created on the oldest version of Android that is currently supported. SQLite
|
||||
* is not forwards compatible. E.g. uploading a DB created on a 6.0 device will cause failures
|
||||
* when robocop tests running on 4.3 are unable to load it.
|
||||
*
|
||||
* Implementation inspired by:
|
||||
* http://riggaroo.co.za/automated-testing-sqlite-database-upgrades-android/
|
||||
*/
|
||||
|
@ -4957,6 +4957,7 @@ pref("dom.inter-app-communication-api.enabled", false);
|
||||
// Disable mapped array buffer by default.
|
||||
pref("dom.mapped_arraybuffer.enabled", false);
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
// The tables used for Safebrowsing phishing and malware checks.
|
||||
pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,test-malware-simple,test-unwanted-simple");
|
||||
pref("urlclassifier.phishTable", "goog-phish-shavar,test-phish-simple");
|
||||
@ -4969,6 +4970,41 @@ pref("urlclassifier.disallow_completions", "test-malware-simple,test-phish-simpl
|
||||
pref("urlclassifier.trackingTable", "test-track-simple,mozstd-track-digest256");
|
||||
pref("urlclassifier.trackingWhitelistTable", "test-trackwhite-simple,mozstd-trackwhite-digest256");
|
||||
|
||||
// Tables for application reputation.
|
||||
pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
|
||||
|
||||
// The number of random entries to send with a gethash request.
|
||||
pref("urlclassifier.gethashnoise", 4);
|
||||
|
||||
// Gethash timeout for Safebrowsing.
|
||||
pref("urlclassifier.gethash.timeout_ms", 5000);
|
||||
|
||||
// If an urlclassifier table has not been updated in this number of seconds,
|
||||
// a gethash request will be forced to check that the result is still in
|
||||
// the database.
|
||||
pref("urlclassifier.max-complete-age", 2700);
|
||||
|
||||
pref("browser.safebrowsing.enabled", true);
|
||||
pref("browser.safebrowsing.malware.enabled", true);
|
||||
|
||||
pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
|
||||
pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_dangerous_host", true);
|
||||
pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
|
||||
pref("browser.safebrowsing.downloads.remote.block_uncommon", false);
|
||||
pref("browser.safebrowsing.debug", false);
|
||||
|
||||
pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
|
||||
pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
|
||||
pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
||||
pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
|
||||
pref("browser.safebrowsing.reportMalwareMistakeURL", "https://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%&url=");
|
||||
|
||||
|
||||
// The table and global pref for blocking access to sites forbidden by policy
|
||||
pref("browser.safebrowsing.forbiddenURIs.enabled", false);
|
||||
pref("urlclassifier.forbiddenTable", "test-forbid-simple");
|
||||
@ -4991,6 +5027,7 @@ pref("browser.safebrowsing.provider.mozilla.lists.mozfull.description", "mozfull
|
||||
|
||||
// Allow users to ignore Safe Browsing warnings.
|
||||
pref("browser.safebrowsing.allowOverride", true);
|
||||
#endif
|
||||
|
||||
// Turn off Spatial navigation by default.
|
||||
pref("snav.enabled", false);
|
||||
|
@ -5,6 +5,12 @@
|
||||
/*** =================== SAVED SIGNONS CODE =================== ***/
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
var kSignonBundle;
|
||||
var showingPasswords = false;
|
||||
@ -44,16 +50,46 @@ function setFilter(aFilterString) {
|
||||
}
|
||||
|
||||
var signonsTreeView = {
|
||||
_filterSet : [],
|
||||
_lastSelectedRanges : [],
|
||||
// Keep track of which favicons we've fetched or started fetching.
|
||||
// Maps a login origin to a favicon URL.
|
||||
_faviconMap: new Map(),
|
||||
_filterSet: [],
|
||||
// Coalesce invalidations to avoid repeated flickering.
|
||||
_invalidateTask: new DeferredTask(() => {
|
||||
signonsTree.treeBoxObject.invalidateColumn(signonsTree.columns.siteCol);
|
||||
}, 10),
|
||||
_lastSelectedRanges: [],
|
||||
selection: null,
|
||||
|
||||
rowCount : 0,
|
||||
setTree : function(tree) {},
|
||||
getImageSrc : function(row,column) {},
|
||||
getProgressMode : function(row,column) {},
|
||||
getCellValue : function(row,column) {},
|
||||
getCellText : function(row,column) {
|
||||
rowCount: 0,
|
||||
setTree(tree) {},
|
||||
getImageSrc(row, column) {
|
||||
if (column.element.getAttribute("id") !== "siteCol") {
|
||||
return "";
|
||||
}
|
||||
|
||||
const signon = this._filterSet.length ? this._filterSet[row] : signons[row];
|
||||
|
||||
// We already have the favicon URL or we started to fetch (value is null).
|
||||
if (this._faviconMap.has(signon.hostname)) {
|
||||
return this._faviconMap.get(signon.hostname);
|
||||
}
|
||||
|
||||
// Record the fact that we already starting fetching a favicon for this
|
||||
// origin in order to avoid multiple requests for the same origin.
|
||||
this._faviconMap.set(signon.hostname, null);
|
||||
|
||||
PlacesUtils.promiseFaviconLinkUrl(signon.hostname)
|
||||
.then(faviconURI => {
|
||||
this._faviconMap.set(signon.hostname, faviconURI.spec);
|
||||
this._invalidateTask.arm();
|
||||
}).catch(Cu.reportError);
|
||||
|
||||
return "";
|
||||
},
|
||||
getProgressMode(row, column) {},
|
||||
getCellValue(row, column) {},
|
||||
getCellText(row, column) {
|
||||
var time;
|
||||
var signon = this._filterSet.length ? this._filterSet[row] : signons[row];
|
||||
switch (column.id) {
|
||||
@ -80,25 +116,25 @@ var signonsTreeView = {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
isEditable : function(row, col) {
|
||||
isEditable(row, col) {
|
||||
if (col.id == "userCol" || col.id == "passwordCol") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
isSeparator : function(index) { return false; },
|
||||
isSorted : function() { return false; },
|
||||
isContainer : function(index) { return false; },
|
||||
cycleHeader : function(column) {},
|
||||
getRowProperties : function(row) { return ""; },
|
||||
getColumnProperties : function(column) { return ""; },
|
||||
getCellProperties : function(row,column) {
|
||||
isSeparator(index) { return false; },
|
||||
isSorted() { return false; },
|
||||
isContainer(index) { return false; },
|
||||
cycleHeader(column) {},
|
||||
getRowProperties(row) { return ""; },
|
||||
getColumnProperties(column) { return ""; },
|
||||
getCellProperties(row, column) {
|
||||
if (column.element.getAttribute("id") == "siteCol")
|
||||
return "ltr";
|
||||
|
||||
return "";
|
||||
},
|
||||
setCellText : function(row, col, value) {
|
||||
setCellText(row, col, value) {
|
||||
// If there is a filter, _filterSet needs to be used, otherwise signons is used.
|
||||
let table = signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons;
|
||||
function _editLogin(field) {
|
||||
@ -224,7 +260,7 @@ function AskUserShowPasswords() {
|
||||
}
|
||||
|
||||
function FinalizeSignonDeletions(syncNeeded) {
|
||||
for (var s=0; s<deletedSignons.length; s++) {
|
||||
for (var s = 0; s < deletedSignons.length; s++) {
|
||||
passwordmanager.removeLogin(deletedSignons[s]);
|
||||
Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED").add(1);
|
||||
}
|
||||
@ -360,8 +396,7 @@ function SignonSaveState() {
|
||||
}
|
||||
}
|
||||
|
||||
function _filterPasswords()
|
||||
{
|
||||
function _filterPasswords() {
|
||||
var filter = document.getElementById("filter").value;
|
||||
if (filter == "") {
|
||||
SignonClearFilter();
|
||||
|
@ -29,7 +29,6 @@ toolkit.jar:
|
||||
* skin/classic/global/notification.css
|
||||
skin/classic/global/netError.css
|
||||
skin/classic/global/numberbox.css
|
||||
skin/classic/global/passwordmgr.css
|
||||
skin/classic/global/popup.css
|
||||
skin/classic/global/preferences.css
|
||||
skin/classic/global/progressmeter.css
|
||||
|
@ -46,6 +46,7 @@ toolkit.jar:
|
||||
skin/classic/global/in-content/dropdown.svg (../../shared/in-content/dropdown.svg)
|
||||
skin/classic/global/in-content/help-glyph.svg (../../shared/in-content/help-glyph.svg)
|
||||
skin/classic/global/in-content/radio.svg (../../shared/in-content/radio.svg)
|
||||
skin/classic/global/passwordmgr.css (../../shared/passwordmgr.css)
|
||||
skin/classic/global/reader/RM-Close-24x24.svg (../../shared/reader/RM-Close-24x24.svg)
|
||||
skin/classic/global/reader/RM-Minus-24x24.svg (../../shared/reader/RM-Minus-24x24.svg)
|
||||
skin/classic/global/reader/RM-Plus-24x24.svg (../../shared/reader/RM-Plus-24x24.svg)
|
||||
|
@ -18,7 +18,6 @@
|
||||
skin/classic/global/filefield.css (../../windows/global/filefield.css)
|
||||
skin/classic/global/globalBindings.xml (../../windows/global/globalBindings.xml)
|
||||
skin/classic/global/linkTree.css (../../windows/global/linkTree.css)
|
||||
skin/classic/global/passwordmgr.css (../../windows/global/passwordmgr.css)
|
||||
skin/classic/global/progressmeter.css (../../windows/global/progressmeter.css)
|
||||
skin/classic/global/resizer.css (../../windows/global/resizer.css)
|
||||
skin/classic/global/richlistbox.css (../../windows/global/richlistbox.css)
|
||||
|
@ -11,3 +11,16 @@
|
||||
.actionButtons {
|
||||
margin: 0px 3px 6px 3px !important;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(siteCol) {
|
||||
list-style-image: url(chrome://mozapps/skin/places/defaultFavicon.png);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
treechildren::-moz-tree-image(siteCol) {
|
||||
list-style-image: url(chrome://mozapps/skin/places/defaultFavicon@2x.png);
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
.contentPane {
|
||||
margin: 9px 8px 5px 8px;
|
||||
}
|
||||
|
||||
.actionButtons {
|
||||
margin: 0px 3px 6px 3px !important;
|
||||
}
|
Loading…
Reference in New Issue
Block a user