Merge autoland to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2017-01-23 18:42:45 -08:00
commit 8a8c8d9816
76 changed files with 912 additions and 360 deletions

View File

@ -547,7 +547,7 @@
</div>
<div id="errorDescriptionsContainer">
<div id="ed_generic">&generic.longDesc;</div>
<div id="ed_captivePortal">&captivePortal.longDesc;</div>
<div id="ed_captivePortal">&captivePortal.longDesc2;</div>
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
<div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
@ -616,7 +616,7 @@
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
<button id="returnButton" class="primary" autocomplete="off" autofocus="true">&returnToPreviousPage.label;</button>
<button id="openPortalLoginPageButton" class="primary" autocomplete="off" autofocus="true">&openPortalLoginPage.label;</button>
<button id="openPortalLoginPageButton" class="primary" autocomplete="off" autofocus="true">&openPortalLoginPage.label2;</button>
<div class="button-spacer"></div>
<button id="advancedButton" autocomplete="off" autofocus="true">&advanced.label;</button>
</div>

View File

@ -192,7 +192,7 @@ var CaptivePortalWatcher = {
_showNotification() {
let buttons = [
{
label: this._browserBundle.GetStringFromName("captivePortal.showLoginPage"),
label: this._browserBundle.GetStringFromName("captivePortal.showLoginPage2"),
callback: () => {
this.ensureCaptivePortalTab();
@ -203,7 +203,7 @@ var CaptivePortalWatcher = {
},
];
let message = this._browserBundle.GetStringFromName("captivePortal.infoMessage2");
let message = this._browserBundle.GetStringFromName("captivePortal.infoMessage3");
let closeHandler = (aEventName) => {
if (aEventName != "removed") {

View File

@ -452,6 +452,19 @@
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/>
</menu>
<menu id="menu_mobileBookmarks"
class="menu-iconic bookmark-item"
label="&mobileBookmarksCmd.label;"
hidden="true"
container="true">
<menupopup id="mobileBookmarksFolderPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS');"/>
</menu>
<menuseparator id="bookmarksMenuItemsSeparator"/>
<!-- Bookmarks menu items -->
</menupopup>

View File

@ -1342,6 +1342,7 @@ var BookmarkingUI = {
return;
}
this._initMobileBookmarks(document.getElementById("BMB_mobileBookmarks"));
this._initRecentBookmarks(document.getElementById("BMB_recentBookmarks"),
"subviewbutton");
@ -1380,6 +1381,28 @@ var BookmarkingUI = {
RECENTLY_BOOKMARKED_PREF: "browser.bookmarks.showRecentlyBookmarked",
// Set by sync after syncing bookmarks successfully once.
MOBILE_BOOKMARKS_PREF: "browser.bookmarks.showMobileBookmarks",
_shouldShowMobileBookmarks() {
try {
return Services.prefs.getBoolPref(this.MOBILE_BOOKMARKS_PREF);
} catch (e) {}
// No pref set (or invalid pref set), look for a mobile bookmarks left pane query.
const organizerQueryAnno = "PlacesOrganizer/OrganizerQuery";
const mobileBookmarksAnno = "MobileBookmarks";
let shouldShow = PlacesUtils.annotations.getItemsWithAnnotation(organizerQueryAnno, {}).filter(
id => PlacesUtils.annotations.getItemAnnotation(id, organizerQueryAnno) == mobileBookmarksAnno
).length > 0;
// Sync will change this pref if/when it adds a mobile bookmarks query.
Services.prefs.setBoolPref(this.MOBILE_BOOKMARKS_PREF, shouldShow);
return shouldShow;
},
_initMobileBookmarks(mobileMenuItem) {
mobileMenuItem.hidden = !this._shouldShowMobileBookmarks();
},
_initRecentBookmarks(aHeaderItem, aExtraCSSClass) {
this._populateRecentBookmarks(aHeaderItem, aExtraCSSClass);
@ -1710,6 +1733,7 @@ var BookmarkingUI = {
this._updateBookmarkPageMenuItem();
PlacesCommandHook.updateBookmarkAllTabsCommand();
this._initMobileBookmarks(document.getElementById("menu_mobileBookmarks"));
this._initRecentBookmarks(document.getElementById("menu_recentBookmarks"));
},

View File

@ -6246,12 +6246,12 @@ var IndexedDBPromptHelper = {
}
];
PopupNotifications.show(browser, topic, message,
this._notificationIcon, mainAction,
secondaryActions, {
persistent: true,
hideClose: true,
});
PopupNotifications.show(
browser, topic, message, this._notificationIcon, mainAction, secondaryActions,
{
persistent: true,
hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
});
}
};

View File

@ -883,6 +883,19 @@
new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS',
PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
</menu>
<menu id="BMB_mobileBookmarks"
class="menu-iconic bookmark-item subviewbutton"
label="&bookmarksMenuButton.mobile.label;"
hidden="true"
container="true">
<menupopup id="BMB_mobileBookmarksPopup"
placespopup="true"
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS',
PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
</menu>
<menuseparator/>
<!-- Bookmarks menu items will go here -->
<menuitem id="BMB_bookmarksShowAll"

View File

@ -198,10 +198,32 @@ var tests = [
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
this.notification.remove();
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
ok(!this.notifyObj.secondaryActionClicked, "secondary action not clicked");
}
},
// Test that notification close button calls secondary action instead of
// dismissal callback if privacy.permissionPrompts.showCloseButton is set.
{ id: "Test#10",
run() {
Preferences.set("privacy.permissionPrompts.showCloseButton", true);
this.notifyObj = new BasicNotification(this.id);
this.notification = showNotification(this.notifyObj);
},
onShown(popup) {
checkPopup(popup, this.notifyObj);
let notification = popup.childNodes[0];
EventUtils.synthesizeMouseAtCenter(notification.closebutton, {});
},
onHidden(popup) {
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback not triggered");
ok(this.notifyObj.secondaryActionClicked, "secondary action clicked");
Preferences.reset("privacy.permissionPrompts.showCloseButton");
this.notification.remove();
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
}
},
// Test notification when chrome is hidden
{ id: "Test#10",
{ id: "Test#11",
run() {
window.locationbar.visible = false;
this.notifyObj = new BasicNotification(this.id);

View File

@ -48,8 +48,10 @@ browser/chrome/devtools/modules/devtools/client/projecteditor/lib/helpers/readdi
browser/chrome/devtools/modules/devtools/client/shared/frame-script-utils.js
browser/chrome/devtools/modules/devtools/client/shared/theme-switching.js
browser/chrome/devtools/modules/devtools/client/themes/common.css
browser/chrome/devtools/modules/devtools/client/themes/toolbars.css
browser/chrome/devtools/modules/devtools/client/themes/variables.css
browser/chrome/devtools/skin/common.css
browser/chrome/devtools/skin/toolbars.css
browser/chrome/devtools/skin/images/command-scratchpad.svg
browser/chrome/devtools/skin/images/controls.png
browser/chrome/devtools/skin/images/controls@2x.png

View File

@ -184,6 +184,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY showAllBookmarks2.label "Show All Bookmarks">
<!ENTITY recentBookmarks.label "Recently Bookmarked">
<!ENTITY otherBookmarksCmd.label "Other Bookmarks">
<!ENTITY mobileBookmarksCmd.label "Mobile Bookmarks">
<!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
<!ENTITY showRecentlyBookmarked.label "Show Recently Bookmarked">
<!ENTITY showRecentlyBookmarked.accesskey "h">
@ -245,6 +246,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarksMenuButton.label "Bookmarks">
<!ENTITY bookmarksMenuButton.other.label "Other Bookmarks">
<!ENTITY bookmarksMenuButton.mobile.label "Mobile Bookmarks">
<!ENTITY viewBookmarksSidebar2.label "View Bookmarks Sidebar">
<!ENTITY viewBookmarksToolbar.label "View Bookmarks Toolbar">

View File

@ -846,14 +846,14 @@ decoder.noHWAcceleration.message = To improve video quality, you may need to ins
decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
# LOCALIZATION NOTE (captivePortal.infoMessage2):
# LOCALIZATION NOTE (captivePortal.infoMessage3):
# Shown in a notification bar when we detect a captive portal is blocking network access
# and requires the user to log in before browsing.
captivePortal.infoMessage2 = This network may require you to log in to use the internet.
# LOCALIZATION NOTE (captivePortal.showLoginPage):
captivePortal.infoMessage3 = You must log in to this network before you can access the Internet.
# LOCALIZATION NOTE (captivePortal.showLoginPage2):
# The label for a button shown in the info bar in all tabs except the login page tab.
# The button shows the portal login page tab when clicked.
captivePortal.showLoginPage = Show Login Page
captivePortal.showLoginPage2 = Open Network Login Page
permissions.remove.tooltip = Clear this permission and ask again

View File

@ -52,11 +52,11 @@
">
<!ENTITY captivePortal.title "Log in to network">
<!ENTITY captivePortal.longDesc "
<p>This network may require you to log in to access the internet.</p>
<!ENTITY captivePortal.longDesc2 "
<p>You must log in to this network before you can access the Internet.</p>
">
<!ENTITY openPortalLoginPage.label "Open Login Page">
<!ENTITY openPortalLoginPage.label2 "Open Network Login Page">
<!ENTITY malformedURI.title "The address isnt valid">
<!ENTITY malformedURI.longDesc "

View File

@ -341,9 +341,9 @@ this.PermissionPromptPrototype = {
if (!options.hasOwnProperty("displayURI") || options.displayURI) {
options.displayURI = this.principal.URI;
}
// Permission prompts are always persistent and don't have a close button.
// Permission prompts are always persistent; the close button is controlled by a pref.
options.persistent = true;
options.hideClose = true;
options.hideClose = !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton");
this.onBeforeShow();
chromeWin.PopupNotifications.show(this.browser,

View File

@ -444,7 +444,7 @@ function prompt(aBrowser, aRequest) {
let options = {
persistent: true,
hideClose: true,
hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
checkbox: {
label: stringBundle.getString("getUserMedia.remember"),
checkedState: reasonForNoPermanentAllow ? {

View File

@ -1195,7 +1195,8 @@ menuitem.panel-subview-footer@menuStateActive@,
#BMB_bookmarksPopup menupopup[placespopup=true][singleitempopup=true] > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
/* These popups never have a footer */
#BMB_bookmarksToolbarPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
#BMB_unsortedBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox {
#BMB_unsortedBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
#BMB_mobileBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox {
/* And so they need some bottom padding: */
padding-bottom: 4px;
}

View File

@ -214,6 +214,7 @@ Converter.prototype = {
let baseUrl = clientBaseUrl + "jsonview/";
let themeVarsUrl = clientBaseUrl + "themes/variables.css";
let commonUrl = clientBaseUrl + "themes/common.css";
let toolbarsUrl = clientBaseUrl + "themes/toolbars.css";
let os;
let platform = Services.appinfo.OS;
@ -238,6 +239,8 @@ Converter.prototype = {
themeVarsUrl + "\">" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
commonUrl + "\">" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
toolbarsUrl + "\">" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\">" +
"<script data-main=\"viewer-config\" src=\"lib/require.js\"></script>" +
"</head><body>" +

View File

@ -202,7 +202,6 @@ webconsole.close.key=CmdOrCtrl+W
webconsole.clear.key=Ctrl+Shift+L
webconsole.clear.keyOSX=Ctrl+L
# LOCALIZATION NOTE (webconsole.menu.copyURL.label)
# Label used for a context-menu item displayed for network message logs. Clicking on it
# copies the URL displayed in the message to the clipboard.
@ -239,3 +238,61 @@ webconsole.menu.copy.accesskey=C
webconsole.menu.selectAll.label=Select all
webconsole.menu.selectAll.accesskey=A
# LOCALIZATION NOTE (webconsole.clearButton.tooltip)
# Label used for the tooltip on the clear logs button in the console top toolbar bar.
# Clicking on it will clear the content of the console.
webconsole.clearButton.tooltip=Clear the Web Console output
# LOCALIZATION NOTE (webconsole.toggleFilterButton.tooltip)
# Label used for the tooltip on the toggle filter bar button in the console top
# toolbar bar. Clicking on it will toggle the visibility of an additional bar which
# contains filter buttons.
webconsole.toggleFilterButton.tooltip=Toggle filter bar
# LOCALIZATION NOTE (webconsole.filterInput.placeholder)
# Label used for for the placeholder on the filter input, in the console top toolbar.
webconsole.filterInput.placeholder=Filter output
# LOCALIZATION NOTE (webconsole.errorsFilterButton.label)
# Label used as the text of the "Errors" button in the additional filter toolbar.
# It shows or hides error messages, either inserted in the page using
# console.error() or as a result of a javascript error..
webconsole.errorsFilterButton.label=Errors
# LOCALIZATION NOTE (webconsole.warningsFilterButton.label)
# Label used as the text of the "Warnings" button in the additional filter toolbar.
# It shows or hides warning messages, inserted in the page using console.warn().
webconsole.warningsFilterButton.label=Warnings
# LOCALIZATION NOTE (webconsole.logsFilterButton.label)
# Label used as the text of the "Logs" button in the additional filter toolbar.
# It shows or hides log messages, inserted in the page using console.log().
webconsole.logsFilterButton.label=Logs
# LOCALIZATION NOTE (webconsole.infoFilterButton.label)
# Label used as the text of the "Info" button in the additional filter toolbar.
# It shows or hides info messages, inserted in the page using console.info().
webconsole.infoFilterButton.label=Info
# LOCALIZATION NOTE (webconsole.debugFilterButton.label)
# Label used as the text of the "Debug" button in the additional filter toolbar.
# It shows or hides debug messages, inserted in the page using console.debug().
webconsole.debugFilterButton.label=Debug
# LOCALIZATION NOTE (webconsole.cssFilterButton.label)
# Label used as the text of the "CSS" button in the additional filter toolbar.
# It shows or hides CSS warning messages, inserted in the page by the browser
# when there are CSS errors in the page.
webconsole.cssFilterButton.label=CSS
# LOCALIZATION NOTE (webconsole.xhrFilterButton.label)
# Label used as the text of the "XHR" button in the additional filter toolbar.
# It shows or hides messages displayed when the page makes an XMLHttpRequest or
# a fetch call.
webconsole.xhrFilterButton.label=XHR
# LOCALIZATION NOTE (webconsole.requestsFilterButton.label)
# Label used as the text of the "Requests" button in the additional filter toolbar.
# It shows or hides messages displayed when the page makes a network call, for example
# when an image or a scripts is requested.
webconsole.requestsFilterButton.label=Requests

View File

@ -29,10 +29,6 @@
height: 28px;
}
.tabs .tabs-menu-item a {
cursor: default;
}
/* The tab takes entire horizontal space and individual tabs
should stretch accordingly. Use flexbox for the behavior.
Use also `overflow: hidden` so, 'overflow' and 'underflow'

View File

@ -30,6 +30,10 @@
white-space: nowrap;
}
.tabs .tabs-menu-item a {
cursor: default;
}
/* Make sure panel content takes entire vertical space.
(minus the height of the tab bar) */
.tabs .panels {

View File

@ -11,5 +11,6 @@ DIRS += [
DevToolsModules(
'common.css',
'splitters.css',
'toolbars.css',
'variables.css',
)

View File

@ -12,9 +12,13 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
const { filterTextSet, filtersClear } = require("devtools/client/webconsole/new-console-output/actions/index");
const { messagesClear } = require("devtools/client/webconsole/new-console-output/actions/index");
const uiActions = require("devtools/client/webconsole/new-console-output/actions/index");
const {
filterTextSet,
filtersClear,
filterBarToggle,
messagesClear
} = require("devtools/client/webconsole/new-console-output/actions/index");
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
const {
MESSAGE_LEVEL
} = require("../constants");
@ -43,7 +47,7 @@ const FilterBar = createClass({
},
onClickFilterBarToggle: function () {
this.props.dispatch(uiActions.filterBarToggle());
this.props.dispatch(filterBarToggle());
},
onClickFiltersClear: function () {
@ -62,20 +66,20 @@ const FilterBar = createClass({
children.push(dom.div({className: "devtools-toolbar webconsole-filterbar-primary"},
dom.button({
className: "devtools-button devtools-clear-icon",
title: "Clear output",
title: l10n.getStr("webconsole.clearButton.tooltip"),
onClick: this.onClickMessagesClear
}),
dom.button({
className: "devtools-button devtools-filter-icon" + (
filterBarVisible ? " checked" : ""),
title: "Toggle filter bar",
title: l10n.getStr("webconsole.toggleFilterButton.tooltip"),
onClick: this.onClickFilterBarToggle
}),
dom.input({
className: "devtools-plaininput text-filter",
type: "search",
value: filter.text,
placeholder: "Filter output",
placeholder: l10n.getStr("webconsole.filterInput.placeholder"),
onInput: this.onSearchInput
})
));
@ -85,31 +89,31 @@ const FilterBar = createClass({
dom.div({className: "devtools-toolbar webconsole-filterbar-secondary"},
FilterButton({
active: filter.error,
label: "Errors",
label: l10n.getStr("webconsole.errorsFilterButton.label"),
filterKey: MESSAGE_LEVEL.ERROR,
dispatch
}),
FilterButton({
active: filter.warn,
label: "Warnings",
label: l10n.getStr("webconsole.warningsFilterButton.label"),
filterKey: MESSAGE_LEVEL.WARN,
dispatch
}),
FilterButton({
active: filter.log,
label: "Logs",
label: l10n.getStr("webconsole.logsFilterButton.label"),
filterKey: MESSAGE_LEVEL.LOG,
dispatch
}),
FilterButton({
active: filter.info,
label: "Info",
label: l10n.getStr("webconsole.infoFilterButton.label"),
filterKey: MESSAGE_LEVEL.INFO,
dispatch
}),
FilterButton({
active: filter.debug,
label: "Debug",
label: l10n.getStr("webconsole.debugFilterButton.label"),
filterKey: MESSAGE_LEVEL.DEBUG,
dispatch
}),
@ -118,19 +122,19 @@ const FilterBar = createClass({
}),
FilterButton({
active: filter.css,
label: "CSS",
label: l10n.getStr("webconsole.cssFilterButton.label"),
filterKey: "css",
dispatch
}),
FilterButton({
active: filter.netxhr,
label: "XHR",
label: l10n.getStr("webconsole.xhrFilterButton.label"),
filterKey: "netxhr",
dispatch
}),
FilterButton({
active: filter.net,
label: "Requests",
label: l10n.getStr("webconsole.requestsFilterButton.label"),
filterKey: "net",
dispatch
})
@ -138,23 +142,6 @@ const FilterBar = createClass({
);
}
if (ui.filteredMessageVisible) {
children.push(
dom.div({className: "devtools-toolbar"},
dom.span({
className: "clear"},
"You have filters set that may hide some results. " +
"Learn more about our filtering syntax ",
dom.a({}, "here"),
"."),
dom.button({
className: "menu-filter-button",
onClick: this.onClickFiltersClear
}, "Remove filters")
)
);
}
return (
dom.div({
className: "webconsole-filteringbar-wrapper",

View File

@ -6,7 +6,7 @@ const expect = require("expect");
const sinon = require("sinon");
const { render, mount } = require("enzyme");
const { createFactory } = require("devtools/client/shared/vendor/react");
const { createFactory, DOM } = require("devtools/client/shared/vendor/react");
const Provider = createFactory(require("react-redux").Provider);
const FilterButton = createFactory(require("devtools/client/webconsole/new-console-output/components/filter-button"));
@ -32,7 +32,7 @@ describe("FilterBar component:", () => {
// Clear button
expect(toolbar.children().eq(0).attr("class"))
.toBe("devtools-button devtools-clear-icon");
expect(toolbar.children().eq(0).attr("title")).toBe("Clear output");
expect(toolbar.children().eq(0).attr("title")).toBe("Clear the Web Console output");
// Filter bar toggle
expect(toolbar.children().eq(1).attr("class"))
@ -58,22 +58,28 @@ describe("FilterBar component:", () => {
expect(getAllUi(store.getState()).filterBarVisible).toBe(true);
// Buttons are displayed
const buttonProps = {
active: true,
dispatch: store.dispatch
};
const logButton = FilterButton(Object.assign({}, buttonProps,
{ label: "Logs", filterKey: MESSAGE_LEVEL.LOG }));
const debugButton = FilterButton(Object.assign({}, buttonProps,
{ label: "Debug", filterKey: MESSAGE_LEVEL.DEBUG }));
const infoButton = FilterButton(Object.assign({}, buttonProps,
{ label: "Info", filterKey: MESSAGE_LEVEL.INFO }));
const warnButton = FilterButton(Object.assign({}, buttonProps,
{ label: "Warnings", filterKey: MESSAGE_LEVEL.WARN }));
const errorButton = FilterButton(Object.assign({}, buttonProps,
{ label: "Errors", filterKey: MESSAGE_LEVEL.ERROR }));
let buttons = [errorButton, warnButton, logButton, infoButton, debugButton];
expect(wrapper.contains(buttons)).toBe(true);
const filterBtn = props => FilterButton(
Object.assign({}, {
active: true,
dispatch: store.dispatch
}, props)
);
let buttons = [
filterBtn({ label: "Errors", filterKey: MESSAGE_LEVEL.ERROR }),
filterBtn({ label: "Warnings", filterKey: MESSAGE_LEVEL.WARN }),
filterBtn({ label: "Logs", filterKey: MESSAGE_LEVEL.LOG }),
filterBtn({ label: "Info", filterKey: MESSAGE_LEVEL.INFO }),
filterBtn({ label: "Debug", filterKey: MESSAGE_LEVEL.DEBUG }),
DOM.span({
className: "devtools-separator",
}),
filterBtn({ label: "CSS", filterKey: "css" }),
filterBtn({ label: "XHR", filterKey: "netxhr", active: false }),
filterBtn({ label: "Requests", filterKey: "net", active: false }),
];
expect(wrapper.containsAllMatchingElements(buttons)).toBe(true);
});
it("fires MESSAGES_CLEAR action when clear button is clicked", () => {

View File

@ -15,6 +15,28 @@ class L10n {
return "XHR";
case "webConsoleMoreInfoLabel":
return "Learn More";
case "webconsole.clearButton.tooltip":
return "Clear the Web Console output";
case "webconsole.toggleFilterButton.tooltip":
return "Toggle filter bar";
case "webconsole.filterInput.placeholder":
return "Filter output";
case "webconsole.errorsFilterButton.label":
return "Errors";
case "webconsole.warningsFilterButton.label":
return "Warnings";
case "webconsole.logsFilterButton.label":
return "Logs";
case "webconsole.infoFilterButton.label":
return "Info";
case "webconsole.debugFilterButton.label":
return "Debug";
case "webconsole.cssFilterButton.label":
return "CSS";
case "webconsole.xhrFilterButton.label":
return "XHR";
case "webconsole.requestsFilterButton.label":
return "Requests";
default:
return str;
}

View File

@ -12,6 +12,8 @@
#include "mozilla/Move.h"
#include "mozilla/Maybe.h"
#include <ostream>
class nsCycleCollectionTraversalCallback;
namespace mozilla {
@ -110,6 +112,11 @@ public:
{
return !Equals(aOtherNullable);
}
friend std::ostream& operator<<(std::ostream& aStream,
const Nullable& aNullable) {
return aStream << aNullable.mValue;
}
};

View File

@ -2651,7 +2651,7 @@ void
TabChild::GetDPI(float* aDPI)
{
*aDPI = -1.0;
if (!mRemoteFrame) {
if (!(mDidFakeShow || mDidSetRealShowInfo)) {
return;
}
@ -2668,7 +2668,7 @@ void
TabChild::GetDefaultScale(double* aScale)
{
*aScale = -1.0;
if (!mRemoteFrame) {
if (!(mDidFakeShow || mDidSetRealShowInfo)) {
return;
}
@ -2685,7 +2685,7 @@ void
TabChild::GetWidgetRounding(int32_t* aRounding)
{
*aRounding = 1;
if (!mRemoteFrame) {
if (!(mDidFakeShow || mDidSetRealShowInfo)) {
return;
}
if (mRounding > 0) {

View File

@ -169,7 +169,7 @@ MediaDecoderOwner*
MediaDecoder::ResourceCallback::GetMediaOwner() const
{
MOZ_ASSERT(NS_IsMainThread());
return mDecoder ? mDecoder->mOwner : nullptr;
return mDecoder ? mDecoder->GetOwner() : nullptr;
}
void
@ -548,10 +548,10 @@ MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
Invalidate();
break;
case MediaEventType::EnterVideoSuspend:
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
break;
case MediaEventType::ExitVideoSuspend:
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
break;
}
}
@ -568,7 +568,7 @@ MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
MOZ_ASSERT(NS_IsMainThread());
// OnDecoderDoctorEvent is disconnected at shutdown time.
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
HTMLMediaElement* element = mOwner->GetMediaElement();
HTMLMediaElement* element = GetOwner()->GetMediaElement();
if (!element) {
return;
}
@ -712,7 +712,7 @@ MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aProm
if (mPlayState == PLAY_STATE_ENDED) {
PinForSeek();
ChangeState(mOwner->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
}
return NS_OK;
}
@ -813,12 +813,12 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
// our new size.
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mFiredMetadataLoaded = true;
mOwner->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget()));
GetOwner()->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget()));
}
// Invalidate() will end up calling mOwner->UpdateMediaSize with the last
// Invalidate() will end up calling GetOwner()->UpdateMediaSize with the last
// dimensions retrieved from the video frame container. The video frame
// container contains more up to date dimensions than aInfo.
// So we call Invalidate() after calling mOwner->MetadataLoaded to ensure
// So we call Invalidate() after calling GetOwner()->MetadataLoaded to ensure
// the media element has the latest dimensions.
Invalidate();
@ -893,10 +893,10 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
// that autoplay should run.
NotifySuspendedStatusChanged();
// mOwner->FirstFrameLoaded() might call us back. Put it at the bottom of
// GetOwner()->FirstFrameLoaded() might call us back. Put it at the bottom of
// this function to avoid unexpected shutdown from reentrant calls.
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mOwner->FirstFrameLoaded();
GetOwner()->FirstFrameLoaded();
}
}
@ -905,7 +905,7 @@ MediaDecoder::NetworkError()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->NetworkError();
GetOwner()->NetworkError();
}
void
@ -913,7 +913,7 @@ MediaDecoder::DecodeError(const MediaResult& aError)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->DecodeError(aError);
GetOwner()->DecodeError(aError);
}
void
@ -935,7 +935,7 @@ MediaDecoder::OwnerHasError() const
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
return mOwner->HasError();
return GetOwner()->HasError();
}
class MediaElementGMPCrashHelper : public GMPCrashHelper
@ -962,8 +962,8 @@ already_AddRefed<GMPCrashHelper>
MediaDecoder::GetCrashHelper()
{
MOZ_ASSERT(NS_IsMainThread());
return mOwner->GetMediaElement() ?
MakeAndAddRef<MediaElementGMPCrashHelper>(mOwner->GetMediaElement()) : nullptr;
return GetOwner()->GetMediaElement() ?
MakeAndAddRef<MediaElementGMPCrashHelper>(GetOwner()->GetMediaElement()) : nullptr;
}
bool
@ -997,9 +997,9 @@ MediaDecoder::PlaybackEnded()
ChangeState(PLAY_STATE_ENDED);
InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
mOwner->PlaybackEnded();
GetOwner()->PlaybackEnded();
// This must be called after |mOwner->PlaybackEnded()| call above, in order
// This must be called after |GetOwner()->PlaybackEnded()| call above, in order
// to fire the required durationchange.
if (IsInfinite()) {
SetInfinite(false);
@ -1069,7 +1069,7 @@ MediaDecoder::NotifySuspendedStatusChanged()
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
if (mResource) {
bool suspended = mResource->IsSuspendedByCache();
mOwner->NotifySuspendedByCache(suspended);
GetOwner()->NotifySuspendedByCache(suspended);
}
}
@ -1079,7 +1079,7 @@ MediaDecoder::NotifyBytesDownloaded()
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
UpdatePlaybackRate();
mOwner->DownloadProgressed();
GetOwner()->DownloadProgressed();
}
void
@ -1092,7 +1092,7 @@ MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
if (aStatus == NS_BINDING_ABORTED) {
// Download has been cancelled by user.
mOwner->LoadAborted();
GetOwner()->LoadAborted();
return;
}
@ -1115,7 +1115,7 @@ MediaDecoder::NotifyPrincipalChanged()
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
mOwner->NotifyDecoderPrincipalChanged();
GetOwner()->NotifyDecoderPrincipalChanged();
}
void
@ -1152,7 +1152,7 @@ MediaDecoder::OnSeekResolved()
// Ensure logical position is updated after seek.
UpdateLogicalPositionInternal();
mOwner->SeekCompleted();
GetOwner()->SeekCompleted();
AsyncResolveSeekDOMPromiseIfExists();
}
@ -1170,7 +1170,7 @@ MediaDecoder::SeekingStarted()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->SeekStarted();
GetOwner()->SeekStarted();
}
void
@ -1245,7 +1245,7 @@ MediaDecoder::DurationChanged()
// of whether we should fire durationchange on explicit infinity.
if (mFiredMetadataLoaded &&
(!mozilla::IsInfinite<double>(mDuration) || mExplicitDuration.Ref().isSome())) {
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
}
if (CurrentPosition() > TimeUnit::FromSeconds(mDuration).ToMicroseconds()) {
@ -1382,7 +1382,7 @@ MediaDecoder::SetPlaybackRate(double aPlaybackRate)
}
if (oldRate == 0 && !mOwner->GetPaused()) {
if (oldRate == 0 && !GetOwner()->GetPaused()) {
// PlaybackRate is no longer null.
// Restart the playback if the media was playing.
Play();
@ -1514,7 +1514,7 @@ MediaDecoder::FireTimeUpdate()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->FireTimeUpdate(true);
GetOwner()->FireTimeUpdate(true);
}
void
@ -1672,7 +1672,7 @@ MediaDecoder::ConstructMediaTracks()
return;
}
HTMLMediaElement* element = mOwner->GetMediaElement();
HTMLMediaElement* element = GetOwner()->GetMediaElement();
if (!element) {
return;
}
@ -1705,7 +1705,7 @@ MediaDecoder::RemoveMediaTracks()
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
HTMLMediaElement* element = mOwner->GetMediaElement();
HTMLMediaElement* element = GetOwner()->GetMediaElement();
if (!element) {
return;
}
@ -1738,32 +1738,71 @@ MediaDecoder::NextFrameBufferedStatus()
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
nsCString
MediaDecoder::GetDebugInfo()
{
return nsPrintfCString(
"channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mdsm=%p",
mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
PlayStateStr(), GetStateMachine());
}
void
MediaDecoder::DumpDebugInfo()
{
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, "
"state: mPlayState=%s mdsm=%p",
mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
PlayStateStr(), GetStateMachine());
nsCString str = GetDebugInfo();
nsAutoCString str;
GetMozDebugReaderData(str);
if (!str.IsEmpty()) {
DUMP_LOG("reader data:\n%s", str.get());
nsAutoCString readerStr;
GetMozDebugReaderData(readerStr);
if (!readerStr.IsEmpty()) {
str += "\nreader data:\n";
str += readerStr;
}
if (GetStateMachine()) {
GetStateMachine()->DumpDebugInfo();
if (!GetStateMachine()) {
DUMP_LOG("%s", str.get());
return;
}
GetStateMachine()->RequestDebugInfo()->Then(
AbstractThread::MainThread(), __func__,
[this, str] (const nsACString& aString) {
DUMP_LOG("%s", str.get());
DUMP_LOG("%s", aString.Data());
},
[this, str] () {
DUMP_LOG("%s", str.get());
});
}
RefPtr<MediaDecoder::DebugInfoPromise>
MediaDecoder::RequestDebugInfo()
{
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
auto str = GetDebugInfo();
if (!GetStateMachine()) {
return DebugInfoPromise::CreateAndResolve(str, __func__);
}
return GetStateMachine()->RequestDebugInfo()->Then(
AbstractThread::MainThread(), __func__,
[str] (const nsACString& aString) {
nsCString result = str + nsCString("\n") + aString;
return DebugInfoPromise::CreateAndResolve(result, __func__);
},
[str] () {
return DebugInfoPromise::CreateAndResolve(str, __func__);
});
}
void
MediaDecoder::NotifyAudibleStateChanged()
{
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->SetAudibleState(mIsAudioDataAudible);
GetOwner()->SetAudibleState(mIsAudioDataAudible);
}
MediaMemoryTracker::MediaMemoryTracker()

View File

@ -473,7 +473,7 @@ private:
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
mOwner->UpdateReadyState();
GetOwner()->UpdateReadyState();
}
virtual MediaDecoderOwner::NextFrameStatus NextFrameStatus() { return mNextFrameStatus; }
@ -485,6 +485,9 @@ private:
virtual void DumpDebugInfo();
using DebugInfoPromise = MozPromise<nsCString, bool, true>;
RefPtr<DebugInfoPromise> RequestDebugInfo();
protected:
virtual ~MediaDecoder();
@ -552,6 +555,8 @@ protected:
static const int DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED = 250000;
private:
nsCString GetDebugInfo();
// Called when the metadata from the media file has been loaded by the
// state machine. Call on the main thread only.
void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,

View File

@ -67,24 +67,20 @@ using namespace mozilla::media;
#undef VERBOSE_LOG
#undef SAMPLE_LOG
#undef DECODER_WARN
#undef DUMP_LOG
#undef SFMT
#undef SLOG
#undef SWARN
#undef SDUMP
#define FMT(x, ...) "Decoder=%p " x, mDecoderID, ##__VA_ARGS__
#define DECODER_LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (FMT(x, ##__VA_ARGS__)))
#define VERBOSE_LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
#define SAMPLE_LOG(x, ...) MOZ_LOG(gMediaSampleLog, LogLevel::Debug, (FMT(x, ##__VA_ARGS__)))
#define DECODER_WARN(x, ...) NS_WARNING(nsPrintfCString(FMT(x, ##__VA_ARGS__)).get())
#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
// Used by StateObject and its sub-classes
#define SFMT(x, ...) "Decoder=%p state=%s " x, mMaster->mDecoderID, ToStateStr(GetState()), ##__VA_ARGS__
#define SLOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (SFMT(x, ##__VA_ARGS__)))
#define SWARN(x, ...) NS_WARNING(nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get())
#define SDUMP(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
// Certain constants get stored as member variables and then adjusted by various
// scale factors on a per-decoder basis. We want to make sure to avoid using these
@ -245,7 +241,7 @@ public:
virtual void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) {}
virtual void DumpDebugInfo() {}
virtual nsCString GetDebugInfo() { return nsCString(); }
private:
template <class S, typename R, typename... As>
@ -744,9 +740,9 @@ public:
}
}
void DumpDebugInfo() override
nsCString GetDebugInfo() override
{
SDUMP("mIsPrerolling=%d", mIsPrerolling);
return nsPrintfCString("mIsPrerolling=%d", mIsPrerolling);
}
private:
@ -3654,33 +3650,32 @@ uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
}
void
MediaDecoderStateMachine::DumpDebugInfo()
nsCString
MediaDecoderStateMachine::GetDebugInfo()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(OnTaskQueue());
return nsPrintfCString(
"GetMediaTime=%lld GetClock=%lld mMediaSink=%p "
"state=%s mPlayState=%d mSentFirstFrameLoadedEvent=%d IsPlaying=%d "
"mAudioStatus=%s mVideoStatus=%s mDecodedAudioEndTime=%lld mDecodedVideoEndTime=%lld "
"mAudioCompleted=%d mVideoCompleted=%d ",
GetMediaTime(), mMediaSink->IsStarted() ? GetClock() : -1, mMediaSink.get(),
ToStateStr(), mPlayState.Ref(), mSentFirstFrameLoadedEvent, IsPlaying(),
AudioRequestStatus(), VideoRequestStatus(), mDecodedAudioEndTime, mDecodedVideoEndTime,
mAudioCompleted, mVideoCompleted)
+ mStateObj->GetDebugInfo() + nsCString("\n")
+ mMediaSink->GetDebugInfo();
}
// It is fine to capture a raw pointer here because MediaDecoder only call
// this function before shutdown begins.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
mMediaSink->DumpDebugInfo();
mStateObj->DumpDebugInfo();
DUMP_LOG(
"GetMediaTime=%lld GetClock=%lld mMediaSink=%p "
"state=%s mPlayState=%d mSentFirstFrameLoadedEvent=%d IsPlaying=%d "
"mAudioStatus=%s mVideoStatus=%s mDecodedAudioEndTime=%lld mDecodedVideoEndTime=%lld "
"mAudioCompleted=%d mVideoCompleted=%d",
GetMediaTime(), mMediaSink->IsStarted() ? GetClock() : -1, mMediaSink.get(),
ToStateStr(), mPlayState.Ref(), mSentFirstFrameLoadedEvent, IsPlaying(),
AudioRequestStatus(), VideoRequestStatus(), mDecodedAudioEndTime, mDecodedVideoEndTime,
mAudioCompleted, mVideoCompleted);
});
// Since the task is run asynchronously, it is possible other tasks get first
// and change the object states before we print them. Therefore we want to
// dispatch this task immediately without waiting for the tail dispatching
// phase so object states are less likely to change before being printed.
OwnerThread()->Dispatch(r.forget(),
AbstractThread::AssertDispatchSuccess, AbstractThread::TailDispatch);
RefPtr<MediaDecoder::DebugInfoPromise>
MediaDecoderStateMachine::RequestDebugInfo()
{
using PromiseType = MediaDecoder::DebugInfoPromise;
RefPtr<PromiseType::Private> p = new PromiseType::Private(__func__);
OwnerThread()->Dispatch(NS_NewRunnableFunction([this, p] () {
p->Resolve(GetDebugInfo(), __func__);
}), AbstractThread::AssertDispatchSuccess, AbstractThread::TailDispatch);
return p.forget();
}
void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,

View File

@ -162,7 +162,7 @@ public:
DECODER_STATE_SHUTDOWN
};
void DumpDebugInfo();
RefPtr<MediaDecoder::DebugInfoPromise> RequestDebugInfo();
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
// Remove an output stream added with AddOutputStream.
@ -240,6 +240,8 @@ private:
static const char* ToStr(NextFrameStatus aStatus);
const char* ToStateStr();
nsCString GetDebugInfo();
// Functions used by assertions to ensure we're calling things
// on the appropriate threads.
bool OnTaskQueue() const;

View File

@ -553,11 +553,15 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
} else {
// SKIP_FRAME
// Extend the duration of the last encoded data in aData
// because this frame will be skip.
// because this frame will be skipped.
VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Skipping a frame.");
RefPtr<EncodedFrame> last = aData.GetEncodedFrames().LastElement();
if (last) {
last->SetDuration(last->GetDuration() + chunk.GetDuration());
CheckedInt64 skippedDuration = FramesToUsecs(chunk.mDuration, mTrackRate);
if (skippedDuration.isValid() && skippedDuration.value() > 0) {
last->SetDuration(last->GetDuration() +
(static_cast<uint64_t>(skippedDuration.value())));
}
}
}

View File

@ -716,9 +716,12 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFile)
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
" but this system can't sandbox it; not loading.\n",
mDisplayName.get());
nsPrintfCString msg(
"GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
" but this system can't sandbox it; not loading.",
mDisplayName.get());
printf_stderr("%s\n", msg.get());
LOGD("%s", msg.get());
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
#endif
@ -771,6 +774,18 @@ GMPParent::ParseChromiumManifest(const nsAString& aJSON)
mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
nsPrintfCString msg(
"GMPParent::ParseChromiumManifest: Plugin \"%s\" is an EME CDM"
" but this system can't sandbox it; not loading.",
mDisplayName.get());
printf_stderr("%s\n", msg.get());
LOGD("%s", msg.get());
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
#endif
nsCString kEMEKeySystem;
// We hard code a few of the settings because they can't be stored in the

View File

@ -429,6 +429,49 @@ TEST(VP8VideoTrackEncoder, NullFrameFirst)
EXPECT_EQ(pointThree, totalDuration);
}
// Test encoding a track that has to skip frames.
TEST(VP8VideoTrackEncoder, SkippedFrames)
{
// Initiate VP8 encoder
TestVP8TrackEncoder encoder;
InitParam param = {true, 640, 480};
encoder.TestInit(param);
YUVBufferGenerator generator;
generator.Init(mozilla::gfx::IntSize(640, 480));
TimeStamp now = TimeStamp::Now();
VideoSegment segment;
// Pass 100 frames of the shortest possible duration where we don't get
// rounding errors between input/output rate.
for (uint32_t i = 0; i < 100; ++i) {
segment.AppendFrame(generator.GenerateI420Image(),
mozilla::StreamTime(90), // 1ms
generator.GetSize(),
PRINCIPAL_HANDLE_NONE,
false,
now + TimeDuration::FromMilliseconds(i));
}
encoder.SetCurrentFrames(segment);
// End the track.
segment.Clear();
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment);
EncodedFrameContainer container;
ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
EXPECT_TRUE(encoder.IsEncodingComplete());
// Verify total duration being 100 * 1ms = 100ms.
uint64_t totalDuration = 0;
for (auto& frame : container.GetEncodedFrames()) {
totalDuration += frame->GetDuration();
}
const uint64_t hundredMillis = PR_USEC_PER_SEC / 10;
EXPECT_EQ(hundredMillis, totalDuration);
}
// EOS test
TEST(VP8VideoTrackEncoder, EncodeComplete)
{

View File

@ -22,9 +22,6 @@
namespace mozilla {
#undef DUMP_LOG
#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(x, ##__VA_ARGS__).get(), nullptr, nullptr, -1)
/*
* A container class to make it easier to pass the playback info all the
* way to DecodedStreamGraphListener from DecodedStream.
@ -136,7 +133,7 @@ public:
void SetPlaying(bool aPlaying);
MediaEventSource<int64_t>& OnOutput();
void Forget();
void DumpDebugInfo();
nsCString GetDebugInfo();
/* The following group of fields are protected by the decoder's monitor
* and can be read or written on any thread.
@ -229,12 +226,12 @@ DecodedStreamData::Forget()
mListener->Forget();
}
void
DecodedStreamData::DumpDebugInfo()
nsCString
DecodedStreamData::GetDebugInfo()
{
DUMP_LOG(
"DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%lld"
"mNextAudioTime=%lld mNextVideoTime=%lld mHaveSentFinish=%d"
return nsPrintfCString(
"DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%lld "
"mNextAudioTime=%lld mNextVideoTime=%lld mHaveSentFinish=%d "
"mHaveSentFinishAudio=%d mHaveSentFinishVideo=%d",
this, mPlaying, mAudioFramesWritten, mNextAudioTime, mNextVideoTime,
mHaveSentFinish, mHaveSentFinishAudio, mHaveSentFinishVideo);
@ -779,16 +776,14 @@ DecodedStream::DisconnectListener()
mVideoFinishListener.Disconnect();
}
void
DecodedStream::DumpDebugInfo()
nsCString
DecodedStream::GetDebugInfo()
{
AssertOwnerThread();
DUMP_LOG(
return nsPrintfCString(
"DecodedStream=%p mStartTime=%lld mLastOutputTime=%lld mPlaying=%d mData=%p",
this, mStartTime.valueOr(-1), mLastOutputTime, mPlaying, mData.get());
if (mData) {
mData->DumpDebugInfo();
}
this, mStartTime.valueOr(-1), mLastOutputTime, mPlaying, mData.get())
+ (mData ? nsCString("\n") + mData->GetDebugInfo() : nsCString());
}
} // namespace mozilla

View File

@ -64,7 +64,7 @@ public:
bool IsStarted() const override;
bool IsPlaying() const override;
void DumpDebugInfo() override;
nsCString GetDebugInfo() override;
protected:
virtual ~DecodedStream();

View File

@ -119,9 +119,9 @@ public:
// Must be called after playback stopped.
virtual void Shutdown() {}
// Dump debugging information to the logs.
// Return a string containing debugging information.
// Can be called in any phase.
virtual void DumpDebugInfo() {}
virtual nsCString GetDebugInfo() { return nsCString(); }
protected:
virtual ~MediaSink() {}

View File

@ -13,12 +13,10 @@ namespace mozilla {
extern LazyLogModule gMediaDecoderLog;
#undef FMT
#undef DUMP_LOG
#define FMT(x, ...) "VideoSink=%p " x, this, ##__VA_ARGS__
#define VSINK_LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (FMT(x, ##__VA_ARGS__)))
#define VSINK_LOG_V(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
using namespace mozilla::layers;
@ -473,17 +471,17 @@ VideoSink::MaybeResolveEndPromise()
}
}
void
VideoSink::DumpDebugInfo()
nsCString
VideoSink::GetDebugInfo()
{
AssertOwnerThread();
DUMP_LOG(
return nsPrintfCString(
"IsStarted=%d IsPlaying=%d, VideoQueue: finished=%d size=%d, "
"mVideoFrameEndTime=%lld mHasVideo=%d mVideoSinkEndRequest.Exists()=%d "
"mEndPromiseHolder.IsEmpty()=%d",
"mEndPromiseHolder.IsEmpty()=%d\n",
IsStarted(), IsPlaying(), VideoQueue().IsFinished(), VideoQueue().GetSize(),
mVideoFrameEndTime, mHasVideo, mVideoSinkEndRequest.Exists(), mEndPromiseHolder.IsEmpty());
mAudioSink->DumpDebugInfo();
mVideoFrameEndTime, mHasVideo, mVideoSinkEndRequest.Exists(), mEndPromiseHolder.IsEmpty())
+ mAudioSink->GetDebugInfo();
}
} // namespace media

View File

@ -68,7 +68,7 @@ public:
void Shutdown() override;
void DumpDebugInfo() override;
nsCString GetDebugInfo() override;
private:
virtual ~VideoSink();

View File

@ -61,7 +61,6 @@ Logger::printf(const char* fmt, ...)
}
LazyLogModule Logger::gChromiumPRLog("chromium");
} // namespace mozilla
mozilla::Logger&
operator<<(mozilla::Logger& log, const char* s)
@ -97,3 +96,5 @@ operator<<(mozilla::Logger& log, void* p)
log.printf("%p", p);
return log;
}
} // namespace mozilla

View File

@ -76,8 +76,6 @@ struct EmptyLog
{
};
} // namespace mozilla
mozilla::Logger& operator<<(mozilla::Logger& log, const char* s);
mozilla::Logger& operator<<(mozilla::Logger& log, const std::string& s);
mozilla::Logger& operator<<(mozilla::Logger& log, int i);
@ -90,6 +88,8 @@ const mozilla::EmptyLog& operator <<(const mozilla::EmptyLog& log, const T&)
return log;
}
} // namespace mozilla
#ifdef NO_CHROMIUM_LOGGING
#define CHROMIUM_LOG(info) std::stringstream()
#define LOG_IF(info, condition) if (!(condition)) std::stringstream()

View File

@ -7,12 +7,14 @@
#ifndef mozilla_mscom_ActivationContext_h
#define mozilla_mscom_ActivationContext_h
#include "mozilla/Attributes.h"
#include <windows.h>
namespace mozilla {
namespace mscom {
class ActivationContext
class MOZ_RAII ActivationContext
{
public:
explicit ActivationContext(HMODULE aLoadFromModule);
@ -23,6 +25,11 @@ public:
return mActCtx != INVALID_HANDLE_VALUE;
}
ActivationContext(const ActivationContext&) = delete;
ActivationContext(ActivationContext&&) = delete;
ActivationContext& operator=(const ActivationContext&) = delete;
ActivationContext& operator=(ActivationContext&&) = delete;
private:
HANDLE mActCtx;
ULONG_PTR mActivationCookie;

View File

@ -32,35 +32,64 @@
/* This code MUST NOT use any non-inlined internal Mozilla APIs, as it will be
compiled into DLLs that COM may load into non-Mozilla processes! */
namespace {
extern "C" {
// This function is defined in generated code for proxy DLLs but is not declared
// in rpcproxy.h, so we need this typedef.
typedef void (RPC_ENTRY *GetProxyDllInfoFnPtr)(const ProxyFileInfo*** aInfo,
const CLSID** aId);
// in rpcproxy.h, so we need this declaration.
void RPC_ENTRY GetProxyDllInfo(const ProxyFileInfo*** aInfo, const CLSID** aId);
} // anonymous namespace
#if defined(_MSC_VER)
extern IMAGE_DOS_HEADER __ImageBase;
#endif
}
namespace mozilla {
namespace mscom {
static HMODULE
GetContainingModule()
{
HMODULE thisModule = nullptr;
#if defined(_MSC_VER)
thisModule = reinterpret_cast<HMODULE>(&__ImageBase);
#else
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCTSTR>(&GetContainingModule),
&thisModule)) {
return nullptr;
}
#endif
return thisModule;
}
static bool
GetContainingLibPath(wchar_t* aBuffer, size_t aBufferLen)
{
HMODULE thisModule = GetContainingModule();
if (!thisModule) {
return false;
}
DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen);
if (!fileNameResult || (fileNameResult == aBufferLen &&
::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
return false;
}
return true;
}
static bool
BuildLibPath(RegistrationFlags aFlags, wchar_t* aBuffer, size_t aBufferLen,
const wchar_t* aLeafName)
{
if (aFlags == RegistrationFlags::eUseBinDirectory) {
HMODULE thisModule = nullptr;
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCTSTR>(&RegisterProxy),
&thisModule)) {
return false;
}
DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen);
if (!fileNameResult || (fileNameResult == aBufferLen &&
::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
if (!GetContainingLibPath(aBuffer, aBufferLen)) {
return false;
}
if (!PathRemoveFileSpec(aBuffer)) {
return false;
}
@ -79,6 +108,74 @@ BuildLibPath(RegistrationFlags aFlags, wchar_t* aBuffer, size_t aBufferLen,
return true;
}
static bool
RegisterPSClsids(const ProxyFileInfo** aProxyInfo, const CLSID* aProxyClsid)
{
while (*aProxyInfo) {
const ProxyFileInfo& curInfo = **aProxyInfo;
for (unsigned short idx = 0, size = curInfo.TableSize; idx < size; ++idx) {
HRESULT hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[idx]->header.piid),
*aProxyClsid);
if (FAILED(hr)) {
return false;
}
}
++aProxyInfo;
}
return true;
}
UniquePtr<RegisteredProxy>
RegisterProxy()
{
const ProxyFileInfo** proxyInfo = nullptr;
const CLSID* proxyClsid = nullptr;
GetProxyDllInfo(&proxyInfo, &proxyClsid);
if (!proxyInfo || !proxyClsid) {
return nullptr;
}
IUnknown* classObject = nullptr;
HRESULT hr = DllGetClassObject(*proxyClsid, IID_IUnknown, (void**)&classObject);
if (FAILED(hr)) {
return nullptr;
}
DWORD regCookie;
hr = CoRegisterClassObject(*proxyClsid, classObject, CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &regCookie);
if (FAILED(hr)) {
classObject->lpVtbl->Release(classObject);
return nullptr;
}
wchar_t modulePathBuf[MAX_PATH + 1] = {0};
if (!GetContainingLibPath(modulePathBuf, ArrayLength(modulePathBuf))) {
CoRevokeClassObject(regCookie);
classObject->lpVtbl->Release(classObject);
return nullptr;
}
ITypeLib* typeLib = nullptr;
hr = LoadTypeLibEx(modulePathBuf, REGKIND_NONE, &typeLib);
MOZ_ASSERT(SUCCEEDED(hr));
if (FAILED(hr)) {
CoRevokeClassObject(regCookie);
classObject->lpVtbl->Release(classObject);
return nullptr;
}
// RegisteredProxy takes ownership of classObject and typeLib references
auto result(MakeUnique<RegisteredProxy>(classObject, regCookie, typeLib));
if (!RegisterPSClsids(proxyInfo, proxyClsid)) {
return nullptr;
}
return result;
}
UniquePtr<RegisteredProxy>
RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags)
{
@ -100,7 +197,7 @@ RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags)
return nullptr;
}
auto GetProxyDllInfoFn = reinterpret_cast<GetProxyDllInfoFnPtr>(
auto GetProxyDllInfoFn = reinterpret_cast<decltype(&GetProxyDllInfo)>(
GetProcAddress(proxyDll, "GetProxyDllInfo"));
if (!GetProxyDllInfoFn) {
return nullptr;
@ -144,16 +241,8 @@ RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags)
auto result(MakeUnique<RegisteredProxy>(reinterpret_cast<uintptr_t>(proxyDll.disown()),
classObject, regCookie, typeLib));
while (*proxyInfo) {
const ProxyFileInfo& curInfo = **proxyInfo;
for (unsigned short i = 0, e = curInfo.TableSize; i < e; ++i) {
hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[i]->header.piid),
*proxyClsid);
if (FAILED(hr)) {
return nullptr;
}
}
++proxyInfo;
if (!RegisterPSClsids(proxyInfo, proxyClsid)) {
return nullptr;
}
return result;
@ -192,6 +281,19 @@ RegisteredProxy::RegisteredProxy(uintptr_t aModule, IUnknown* aClassObject,
AddToRegistry(this);
}
RegisteredProxy::RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie,
ITypeLib* aTypeLib)
: mModule(0)
, mClassObject(aClassObject)
, mRegCookie(aRegCookie)
, mTypeLib(aTypeLib)
, mIsRegisteredInMTA(IsCurrentThreadMTA())
{
MOZ_ASSERT(aClassObject);
MOZ_ASSERT(aTypeLib);
AddToRegistry(this);
}
// If we're initializing from a typelib, it doesn't matter which apartment we
// run in, so mIsRegisteredInMTA may always be set to false in this case.
RegisteredProxy::RegisteredProxy(ITypeLib* aTypeLib)

View File

@ -28,6 +28,8 @@ class RegisteredProxy
public:
RegisteredProxy(uintptr_t aModule, IUnknown* aClassObject,
uint32_t aRegCookie, ITypeLib* aTypeLib);
RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie,
ITypeLib* aTypeLib);
explicit RegisteredProxy(ITypeLib* aTypeLib);
RegisteredProxy(RegisteredProxy&& aOther);
RegisteredProxy& operator=(RegisteredProxy&& aOther);
@ -63,6 +65,10 @@ enum class RegistrationFlags
eUseSystemDirectory
};
// For our own DLL that we are currently executing in (ie, xul).
// Assumes corresponding TLB is embedded in resources.
UniquePtr<RegisteredProxy> RegisterProxy();
// For DLL files. Assumes corresponding TLB is embedded in resources.
UniquePtr<RegisteredProxy> RegisterProxy(const wchar_t* aLeafName,
RegistrationFlags aFlags =

View File

@ -110,9 +110,10 @@ private:
{
nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService();
if (observerService)
if (observerService) {
observerService->RemoveObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
}
};
@ -340,7 +341,7 @@ PeerConnectionCtx::EverySecondTelemetryCallback_m(nsITimer* timer, void *closure
p != ctx->mPeerConnections.end(); ++p) {
if (p->second->HasMedia()) {
if (!queries->append(nsAutoPtr<RTCStatsQuery>(new RTCStatsQuery(true)))) {
return;
return;
}
if (NS_WARN_IF(NS_FAILED(p->second->BuildStatsQuery_m(nullptr, // all tracks
queries->back())))) {

View File

@ -16,6 +16,7 @@
#include "mozilla/TypeTraits.h"
#include <new> // for placement new
#include <ostream>
#include <type_traits>
namespace mozilla {
@ -452,6 +453,17 @@ public:
::new (mStorage.addr()) T(Forward<Args>(aArgs)...);
mIsSome = true;
}
friend std::ostream&
operator<<(std::ostream& aStream, const Maybe<T>& aMaybe)
{
if (aMaybe) {
aStream << aMaybe.ref();
} else {
aStream << "<Nothing>";
}
return aStream;
}
};
/*

View File

@ -16,6 +16,7 @@
<head>
<meta name="viewport" content="width=device-width; user-scalable=0" />
<meta charset="UTF-8" />
<link rel="stylesheet" href="chrome://browser/skin/config.css" type="text/css"/>
<script type="text/javascript;version=1.8" src="chrome://browser/content/config.js"></script>

View File

@ -15,9 +15,9 @@
"unpack": true
},
{
"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
"size": 110451636,
"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
"size": 92947272,
"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
"algorithm": "sha512",
"filename": "rustc.tar.xz",
"unpack": true

View File

@ -48,9 +48,9 @@
"unpack": true
},
{
"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
"size": 110451636,
"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
"size": 92947272,
"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
"algorithm": "sha512",
"filename": "rustc.tar.xz",
"unpack": true

View File

@ -73,9 +73,9 @@
"size": 51753660
},
{
"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
"size": 110451636,
"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
"size": 92947272,
"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
"algorithm": "sha512",
"filename": "rustc.tar.xz",
"unpack": true

View File

@ -54,6 +54,7 @@ chrome.jar:
skin/images/checkbox_unchecked_disabled.png (images/checkbox_unchecked_disabled.png)
skin/images/checkbox_unchecked_pressed.png (images/checkbox_unchecked_pressed.png)
skin/images/chevron.png (images/chevron.png)
skin/images/chevron-rtl.png (images/chevron-rtl.png)
skin/images/dropmarker.svg (images/dropmarker.svg)
skin/images/dropmarker-right.svg (images/dropmarker-right.svg)
skin/images/errorpage-warning.png (images/errorpage-warning.png)

View File

@ -1220,6 +1220,10 @@ pref("privacy.popups.disable_from_plugins", 2);
// send "do not track" HTTP header, disabled by default
pref("privacy.donottrackheader.enabled", false);
// If true, close buton will be shown on permission prompts
// and for all PopupNotifications, the secondary action of
// the popup will be called when the popup is dismissed.
pref("privacy.permissionPrompts.showCloseButton", false);
// Enforce tracking protection in all modes
pref("privacy.trackingprotection.enabled", false);
// Enforce tracking protection in Private Browsing mode

View File

@ -9,6 +9,7 @@
#include <stdint.h>
#include <algorithm> // for std::min, std::max
#include <ostream>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
@ -279,6 +280,11 @@ public:
return mValue != 0;
}
friend std::ostream& operator<<(std::ostream& aStream,
const BaseTimeDuration& aDuration) {
return aStream << aDuration.ToMilliseconds() << " ms";
}
// Return a best guess at the system's current timing resolution,
// which might be variable. BaseTimeDurations below this order of
// magnitude are meaningless, and those at the same order of

View File

@ -439,7 +439,7 @@ class WinArtifactJob(ArtifactJob):
# The values correpsond to a pair of (<package regex>, <test archive regex>).
JOB_DETAILS = {
'android-api-15-opt': (AndroidArtifactJob, (r'(public/build/fennec-(.*)\.android-arm.apk|public/build/target\.apk)',
r'public/build/fennec-(.*)\.common\.tests\.zip|public/build/target-(.*)\.common\.tests\.zip')),
r'public/build/fennec-(.*)\.common\.tests\.zip|public/build/target\.common\.tests\.zip')),
'android-api-15-debug': (AndroidArtifactJob, (r'public/build/target\.apk',
r'public/build/target\.common\.tests\.zip')),
'android-x86-opt': (AndroidArtifactJob, (r'public/build/target\.apk',

View File

@ -1029,6 +1029,7 @@ BookmarksTracker.prototype = {
},
_ensureMobileQuery: function _ensureMobileQuery() {
Services.prefs.setBoolPref("browser.bookmarks.showMobileBookmarks", true);
let find = val =>
PlacesUtils.annotations.getItemsWithAnnotation(ORGANIZERQUERY_ANNO, {}).filter(
id => PlacesUtils.annotations.getItemAnnotation(id, ORGANIZERQUERY_ANNO) == val

View File

@ -106,7 +106,7 @@ android-api-15-nightly/opt:
index:
product: mobile
job-name: android-api-15-opt
type: nightly
type: nightly-with-multi-l10n
treeherder:
platform: android-4-0-armv7-api15/opt
symbol: tc(N)

View File

@ -38,6 +38,7 @@ linux64/opt:
- external-media-tests
- web-platform-tests
- opt-only-tests
- desktop-screenshot-capture
- talos
# TODO: use 'pgo' and 'asan' labels here, instead of -pgo/opt

View File

@ -180,6 +180,9 @@ linux32-opt-tests:
# mochitest-dt is too slow on linux32/debug
- mochitest-devtools-chrome
desktop-screenshot-capture:
- mochitest-browser-screenshots
android-common-tests:
- cppunit
- crashtest

View File

@ -433,6 +433,35 @@ mochitest-browser-chrome:
default: legacy
allow-software-gl-layers: false
mochitest-browser-screenshots:
description: "Mochitest Browser Screenshots"
suite: mochitest/browser-chrome-screenshots
treeherder-symbol: tc-M(ss)
loopback-video: true
run-on-projects:
by-test-platform:
linux64/opt: ['mozilla-central', 'try']
default: []
e10s: true
max-run-time: 3600
mozharness:
script: desktop_unittest.py
no-read-buildbot-config: true
config:
by-test-platform:
windows.*:
- unittests/win_taskcluster_unittest.py
macosx.*:
- remove_executables.py
- unittests/mac_unittest.py
linux.*:
- unittests/linux_unittest.py
- remove_executables.py
extra-options:
- --mochitest-suite=browser-chrome-screenshots
instance-size: legacy
allow-software-gl-layers: false
mochitest-chrome:
description: "Mochitest chrome run"
suite: mochitest/chrome

View File

@ -1 +1 @@
0.4.1
0.4.2

View File

@ -57,6 +57,9 @@ def install(filename, target):
print(' Unpacking %s...' % filename)
subprocess.check_call(['tar', 'xf', filename])
basename = filename.split('.tar')[0]
# Work around bad tarball naming in 1.15 cargo packages.
basename = basename.replace('cargo-beta', 'cargo-nightly')
basename = basename.replace('cargo-0.16', 'cargo-nightly')
print(' Installing %s...' % basename)
install_cmd = [os.path.join(basename, 'install.sh')]
install_cmd += ['--prefix=' + os.path.abspath(target)]
@ -195,4 +198,4 @@ if __name__ == '__main__':
repack(win64, [win64])
repack(linux64, [linux64, linux32])
repack(linux64, [linux64, mac64, mac32], suffix='mac-cross')
repack(linux64, [linux64, android, android_x86], suffix='android-cross')
repack(linux64, [linux64, android, android_x86], channel='beta', suffix='android-cross')

View File

@ -93,7 +93,7 @@ task_description_schema = Schema({
'job-name': basestring,
# Type of gecko v2 index to use
'type': Any('generic', 'nightly', 'l10n'),
'type': Any('generic', 'nightly', 'l10n', 'nightly-with-multi-l10n'),
# The rank that the task will receive in the TaskCluster
# index. A newly completed task supercedes the currently
@ -661,11 +661,21 @@ def add_nightly_index_routes(config, task):
for tpl in V2_NIGHTLY_TEMPLATES:
routes.append(tpl.format(**subs))
# Also add routes for en-US
task = add_l10n_index_routes(config, task, force_locale="en-US")
return task
@index_builder('nightly-with-multi-l10n')
def add_nightly_multi_index_routes(config, task):
task = add_nightly_index_routes(config, task)
task = add_l10n_index_routes(config, task, force_locale="multi")
return task
@index_builder('l10n')
def add_l10n_index_routes(config, task):
def add_l10n_index_routes(config, task, force_locale=None):
index = task.get('index')
routes = task.setdefault('routes', [])
@ -682,6 +692,10 @@ def add_l10n_index_routes(config, task):
locales = task['attributes'].get('chunk_locales',
task['attributes'].get('all_locales'))
if force_locale:
# Used for en-US and multi-locale
locales = [force_locale]
if not locales:
raise Exception("Error: Unable to use l10n index for tasks without locales")

View File

@ -5,7 +5,7 @@
from marionette_driver.by import By
from marionette_driver.errors import MoveTargetOutOfBoundsException
from marionette_harness import MarionetteTestCase, skip
from marionette_harness import MarionetteTestCase, skip, skip_if_mobile
class TestClickScrolling(MarionetteTestCase):
@ -97,6 +97,7 @@ class TestClickScrolling(MarionetteTestCase):
self.marionette.find_element(By.ID, "{}-70".format(s)).click()
self.assertNotEqual(scroll_x, self.marionette.execute_script("return window.scrollX;"))
@skip_if_mobile("Bug 1293855 - Lists differ: [70, 70] != [70, 120]")
def test_should_not_scroll_elements_if_click_point_is_in_view(self):
test_html = self.marionette.absolute_url("element_outside_viewport.html")

View File

@ -5,7 +5,7 @@
from marionette_driver.by import By
from marionette_driver.keys import Keys
from marionette_harness import MarionetteTestCase
from marionette_harness import MarionetteTestCase, skip_if_mobile
class TestText(MarionetteTestCase):
@ -53,7 +53,7 @@ class TestText(MarionetteTestCase):
key_reporter.send_keys("a")
result = self.marionette.find_element(By.ID, "result")
self.assertTrue("press:" in result.text)
self.assertIn("press:", result.text)
def test_should_fire_key_down_events(self):
test_html = self.marionette.absolute_url("javascriptPage.html")
@ -62,7 +62,7 @@ class TestText(MarionetteTestCase):
key_reporter.send_keys("a")
result = self.marionette.find_element(By.ID, "result")
self.assertTrue("down:" in result.text)
self.assertIn("down:", result.text)
def test_should_fire_key_up_events(self):
test_html = self.marionette.absolute_url("javascriptPage.html")
@ -71,7 +71,7 @@ class TestText(MarionetteTestCase):
key_reporter.send_keys("a")
result = self.marionette.find_element(By.ID, "result")
self.assertTrue("up:" in result.text)
self.assertIn("up:", result.text)
def test_should_type_lowercase_characters(self):
test_html = self.marionette.absolute_url("javascriptPage.html")
@ -183,26 +183,27 @@ class TestText(MarionetteTestCase):
# filled, we're a letter short here
self.assertEqual(result.text, "I like chees")
@skip_if_mobile("Bug 1333069 - Assertion: 'down: 40' not found in u''")
def test_should_report_key_code_of_arrow_keys_up_down_events(self):
test_html = self.marionette.absolute_url("javascriptPage.html")
self.marionette.navigate(test_html)
result = self.marionette.find_element(By.ID, "result")
element = self.marionette.find_element(By.ID, "keyReporter")
element.send_keys(Keys.ARROW_DOWN)
self.assertTrue("down: 40" in result.text.strip())
self.assertTrue("up: 40" in result.text.strip())
self.assertIn("down: 40", result.text.strip())
self.assertIn("up: 40", result.text.strip())
element.send_keys(Keys.ARROW_UP)
self.assertTrue("down: 38" in result.text.strip())
self.assertTrue("up: 38" in result.text.strip())
self.assertIn("down: 38", result.text.strip())
self.assertIn("up: 38", result.text.strip())
element.send_keys(Keys.ARROW_LEFT)
self.assertTrue("down: 37" in result.text.strip())
self.assertTrue("up: 37" in result.text.strip())
self.assertIn("down: 37", result.text.strip())
self.assertIn("up: 37", result.text.strip())
element.send_keys(Keys.ARROW_RIGHT)
self.assertTrue("down: 39" in result.text.strip())
self.assertTrue("up: 39" in result.text.strip())
self.assertIn("down: 39", result.text.strip())
self.assertIn("up: 39", result.text.strip())
# And leave no rubbish/printable keys in the "keyReporter"
self.assertEqual("", element.get_property("value"))

View File

@ -322,6 +322,7 @@ def killPid(pid, log):
except Exception as e:
log.info("Failed to kill process %d: %s" % (pid, str(e)))
if mozinfo.isWin:
import ctypes.wintypes
@ -825,7 +826,6 @@ class MochitestDesktop(object):
self.result = {}
self.start_script = os.path.join(here, 'start_desktop.js')
self.disable_leak_checking = False
def update_mozinfo(self):
"""walk up directories to find mozinfo.json update the info"""
@ -1508,8 +1508,7 @@ toolbar#nav-bar {
self.log.error(str(e))
return None
if not self.disable_leak_checking:
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
try:
gmp_path = self.getGMPPluginPath(options)
@ -1952,13 +1951,12 @@ toolbar#nav-bar {
args.append('-foreground')
self.start_script_kwargs['testUrl'] = testUrl or 'about:blank'
if detectShutdownLeaks and not self.disable_leak_checking:
if detectShutdownLeaks:
shutdownLeaks = ShutdownLeaks(self.log)
else:
shutdownLeaks = None
if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac) \
and not self.disable_leak_checking:
if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac):
lsanLeaks = LSANLeaks(self.log)
else:
lsanLeaks = None
@ -2230,28 +2228,6 @@ toolbar#nav-bar {
result = 1 # default value, if no tests are run.
for d in dirs:
print("dir: %s" % d)
# BEGIN LEAKCHECK HACK
# Leak checking was broken in mochitest unnoticed for a length of time. During
# this time, several leaks slipped through. The leak checking was fixed by bug
# 1325148, but it couldn't land until all the regressions were also fixed or
# backed out. Rather than waiting and risking new regressions, in the meantime
# this code will selectively disable leak checking on flavors/directories where
# known regressions exist. At least this way we can prevent further damage while
# they get fixed.
skip_leak_conditions = []
for condition, reason in skip_leak_conditions:
if condition:
self.log.warning('WARNING | disabling leakcheck due to {}'.format(reason))
self.disable_leak_checking = True
break
else:
self.disable_leak_checking = False
# END LEAKCHECK HACK
tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
# If we are using --run-by-dir, we should not use the profile path (if) provided
@ -2358,6 +2334,7 @@ toolbar#nav-bar {
self.browserEnv["MOZ_LOG_FILE"] = "{}/moz-pid=%PID-uid={}.log".format(
self.browserEnv["MOZ_UPLOAD_DIR"], str(uuid.uuid4()))
status = 0
try:
self.startServers(options, debuggerInfo)
@ -2417,23 +2394,25 @@ toolbar#nav-bar {
self.log.info("runtests.py | Running with e10s: {}".format(options.e10s))
self.log.info("runtests.py | Running tests: start.\n")
status = self.runApp(testURL,
self.browserEnv,
options.app,
profile=self.profile,
extraArgs=options.browserArgs,
utilityPath=options.utilityPath,
debuggerInfo=debuggerInfo,
valgrindPath=valgrindPath,
valgrindArgs=valgrindArgs,
valgrindSuppFiles=valgrindSuppFiles,
symbolsPath=options.symbolsPath,
timeout=timeout,
detectShutdownLeaks=detectShutdownLeaks,
screenshotOnFail=options.screenshotOnFail,
bisectChunk=options.bisectChunk,
marionette_args=marionette_args,
)
ret = self.runApp(
testURL,
self.browserEnv,
options.app,
profile=self.profile,
extraArgs=options.browserArgs,
utilityPath=options.utilityPath,
debuggerInfo=debuggerInfo,
valgrindPath=valgrindPath,
valgrindArgs=valgrindArgs,
valgrindSuppFiles=valgrindSuppFiles,
symbolsPath=options.symbolsPath,
timeout=timeout,
detectShutdownLeaks=detectShutdownLeaks,
screenshotOnFail=options.screenshotOnFail,
bisectChunk=options.bisectChunk,
marionette_args=marionette_args,
)
status = ret or status
except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n")
status = -1
@ -2735,5 +2714,6 @@ def cli(args=sys.argv[1:]):
return run_test_harness(parser, options)
if __name__ == "__main__":
sys.exit(cli())

View File

@ -15,7 +15,9 @@ import contextlib
import errno
import functools
import os
import random
import re
import time
from mercurial.i18n import _
from mercurial.node import hex
@ -30,7 +32,7 @@ from mercurial import (
util,
)
testedwith = '3.6 3.7 3.8 3.9'
testedwith = '3.7 3.8 3.9 4.0'
minimumhgversion = '3.7'
cmdtable = {}
@ -116,11 +118,13 @@ def purgewrapper(orig, ui, *args, **kwargs):
('b', 'branch', '', 'Branch to check out'),
('', 'purge', False, 'Whether to purge the working directory'),
('', 'sharebase', '', 'Directory where shared repos should be placed'),
('', 'networkattempts', 3, 'Maximum number of attempts for network '
'operations'),
],
'[OPTION]... URL DEST',
norepo=True)
def robustcheckout(ui, url, dest, upstream=None, revision=None, branch=None,
purge=False, sharebase=None):
purge=False, sharebase=None, networkattempts=None):
"""Ensure a working copy has the specified revision checked out."""
if not revision and not branch:
raise error.Abort('must specify one of --revision or --branch')
@ -156,12 +160,16 @@ def robustcheckout(ui, url, dest, upstream=None, revision=None, branch=None,
sharebase = os.path.realpath(sharebase)
return _docheckout(ui, url, dest, upstream, revision, branch, purge,
sharebase)
sharebase, networkattempts)
def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase,
networkattemptlimit, networkattempts=None):
if not networkattempts:
networkattempts = [1]
def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase):
def callself():
return _docheckout(ui, url, dest, upstream, revision, branch, purge,
sharebase)
sharebase, networkattemptlimit, networkattempts)
ui.write('ensuring %s@%s is available at %s\n' % (url, revision or branch,
dest))
@ -217,6 +225,45 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase):
# At this point we either have an existing working directory using
# shared, pooled storage or we have nothing.
def handlepullabort(e):
"""Handle an error.Abort raised during a pull.
Returns True if caller should call ``callself()`` to retry.
"""
if e.args[0] == _('repository is unrelated'):
ui.warn('(repository is unrelated; deleting)\n')
destvfs.rmtree(forcibly=True)
return True
elif e.args[0].startswith(_('stream ended unexpectedly')):
ui.warn('%s\n' % e.args[0])
if networkattempts[0] < networkattemptlimit:
ui.warn('(retrying after network failure on attempt %d of %d)\n' %
(networkattempts[0], networkattemptlimit))
# Do a backoff on retries to mitigate the thundering herd
# problem. This is an exponential backoff with a multipler
# plus random jitter thrown in for good measure.
# With the default settings, backoffs will be:
# 1) 2.5 - 6.5
# 2) 5.5 - 9.5
# 3) 11.5 - 15.5
backoff = (2 ** networkattempts[0] - 1) * 1.5
jittermin = ui.configint('robustcheckout', 'retryjittermin', 1000)
jittermax = ui.configint('robustcheckout', 'retryjittermax', 5000)
backoff += float(random.randint(jittermin, jittermax)) / 1000.0
ui.warn('(waiting %.2fs before retry)\n' % backoff)
time.sleep(backoff)
networkattempts[0] += 1
return True
else:
raise error.Abort('reached maximum number of network attempts; '
'giving up\n')
return False
created = False
if not destvfs.exists():
@ -237,6 +284,10 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase):
try:
res = hg.clone(ui, {}, cloneurl, dest=dest, update=False,
shareopts={'pool': sharebase, 'mode': 'identity'})
except error.Abort as e:
if handlepullabort(e):
return callself()
raise
except error.RepoError as e:
return handlerepoerror(e)
except error.RevlogError as e:
@ -293,11 +344,8 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase):
if not pullop.rheads:
raise error.Abort('unable to pull requested revision')
except error.Abort as e:
if e.message == _('repository is unrelated'):
ui.warn('(repository is unrelated; deleting)\n')
destvfs.rmtree(forcibly=True)
if handlepullabort(e):
return callself()
raise
except error.RepoError as e:
return handlerepoerror(e)

View File

@ -1013,7 +1013,7 @@ LoginManagerPrompter.prototype = {
timeout: Date.now() + 10000,
persistWhileVisible: true,
passwordNotificationType: type,
hideClose: true,
hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
eventCallback(topic) {
switch (topic) {
case "showing":

View File

@ -468,35 +468,33 @@ Classifier::Check(const nsACString& aSpec,
for (uint32_t i = 0; i < cacheArray.Length(); i++) {
LookupCache *cache = cacheArray[i];
bool has, complete;
bool has, fromCache;
uint32_t matchLength;
rv = cache->Has(lookupHash, &has, &complete, &matchLength);
rv = cache->Has(lookupHash, &has, &matchLength, &fromCache);
NS_ENSURE_SUCCESS(rv, rv);
if (has) {
LookupResult *result = aResults.AppendElement();
if (!result)
return NS_ERROR_OUT_OF_MEMORY;
int64_t age;
bool found = mTableFreshness.Get(cache->TableName(), &age);
if (!found) {
age = 24 * 60 * 60; // just a large number
} else {
int64_t now = (PR_Now() / PR_USEC_PER_SEC);
age = now - age;
// For V2, there is no TTL for caching, so we use table freshness to
// decide if matching a completion should trigger a gethash request or not.
// For V4, this is done by Positive Caching & Negative Caching mechanism.
bool confirmed = false;
if (fromCache) {
cache->IsHashEntryConfirmed(lookupHash, mTableFreshness,
aFreshnessGuarantee, &confirmed);
}
LOG(("Found a result in %s: %s (Age: %Lds)",
LOG(("Found a result in %s: %s",
cache->TableName().get(),
complete ? "complete." : "Not complete.",
age));
confirmed ? "confirmed." : "Not confirmed."));
result->hash.complete = lookupHash;
result->mComplete = complete;
result->mFresh = (age < aFreshnessGuarantee);
result->mConfirmed = confirmed;
result->mTableName.Assign(cache->TableName());
result->mPartialHashLength = matchLength;
result->mPartialHashLength = confirmed ? COMPLETE_SIZE : matchLength;
if (LookupCache::Cast<LookupCacheV4>(cache)) {
matchingStatistics |= PrefixMatch::eMatchV4Prefix;

View File

@ -158,7 +158,7 @@ private:
nsTArray<nsCString> mActiveTablesCache;
uint32_t mHashKey;
// Stores the last time a given table was updated (seconds).
nsDataHashtable<nsCStringHashKey, int64_t> mTableFreshness;
TableFreshnessMap mTableFreshness;
// In-memory cache for the result of TableRequest. See
// nsIUrlClassifierDBService.getTables for the format.

View File

@ -16,6 +16,7 @@
#include "nsNetUtil.h"
#include "nsIOutputStream.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#if DEBUG
#include "plbase64.h"
@ -316,6 +317,8 @@ WriteTArray(nsIOutputStream* aStream, nsTArray_Impl<T, Alloc>& aArray)
typedef nsClassHashtable<nsUint32HashKey, nsCString> PrefixStringMap;
typedef nsDataHashtable<nsCStringHashKey, int64_t> TableFreshnessMap;
} // namespace safebrowsing
} // namespace mozilla

View File

@ -421,10 +421,10 @@ LookupCacheV2::ClearAll()
nsresult
LookupCacheV2::Has(const Completion& aCompletion,
bool* aHas, bool* aComplete,
uint32_t* aMatchLength)
bool* aHas, uint32_t* aMatchLength,
bool* aFromCache)
{
*aHas = *aComplete = false;
*aHas = *aFromCache = false;
*aMatchLength = 0;
uint32_t prefix = aCompletion.ToUint32();
@ -443,7 +443,7 @@ LookupCacheV2::Has(const Completion& aCompletion,
if ((mGetHashCache.BinaryIndexOf(aCompletion) != nsTArray<Completion>::NoIndex) ||
(mUpdateCompletions.BinaryIndexOf(aCompletion) != nsTArray<Completion>::NoIndex)) {
LOG(("Complete in %s", mTableName.get()));
*aComplete = true;
*aFromCache = true;
*aHas = true;
*aMatchLength = COMPLETE_SIZE;
}
@ -451,6 +451,25 @@ LookupCacheV2::Has(const Completion& aCompletion,
return NS_OK;
}
void
LookupCacheV2::IsHashEntryConfirmed(const Completion& aEntry,
const TableFreshnessMap& aTableFreshness,
uint32_t aFreshnessGuarantee,
bool* aConfirmed)
{
int64_t age; // in seconds
bool found = aTableFreshness.Get(mTableName, &age);
if (!found) {
*aConfirmed = false;
} else {
int64_t now = (PR_Now() / PR_USEC_PER_SEC);
MOZ_ASSERT(age <= now);
// Considered completion as unsafe if its table is up-to-date.
*aConfirmed = (now - age) < aFreshnessGuarantee;
}
}
nsresult
LookupCacheV2::Build(AddPrefixArray& aAddPrefixes,
AddCompleteArray& aAddCompletes)

View File

@ -25,9 +25,8 @@ namespace safebrowsing {
class LookupResult {
public:
LookupResult() : mComplete(false), mNoise(false),
mFresh(false), mProtocolConfirmed(false),
mPartialHashLength(0) {}
LookupResult() : mNoise(false), mProtocolConfirmed(false),
mPartialHashLength(0), mConfirmed(false) {}
// The fragment that matched in the LookupCache
union {
@ -53,11 +52,10 @@ public:
return hex;
}
bool Confirmed() const { return (mComplete && mFresh) || mProtocolConfirmed; }
bool Complete() const { return mComplete; }
bool Confirmed() const { return mConfirmed || mProtocolConfirmed; }
// True if we have a complete match for this hash in the table.
bool mComplete;
bool Complete() const { return mPartialHashLength == COMPLETE_SIZE; }
// True if this is a noise entry, i.e. an extra entry
// that is inserted to mask the true URL we are requesting.
@ -66,14 +64,14 @@ public:
// don't know the corresponding full URL.
bool mNoise;
// True if we've updated this table recently-enough.
bool mFresh;
bool mProtocolConfirmed;
nsCString mTableName;
uint32_t mPartialHashLength;
// True as long as this lookup is complete and hasn't expired.
bool mConfirmed;
};
typedef nsTArray<LookupResult> LookupResultArray;
@ -139,8 +137,13 @@ public:
virtual nsresult Init() = 0;
virtual nsresult ClearPrefixes() = 0;
virtual nsresult Has(const Completion& aCompletion,
bool* aHas, bool* aComplete,
uint32_t* aMatchLength) = 0;
bool* aHas, uint32_t* aMatchLength,
bool* aFromCache) = 0;
virtual void IsHashEntryConfirmed(const Completion& aEntry,
const TableFreshnessMap& aTableFreshness,
uint32_t aFreshnessGuarantee,
bool* aConfirmed) = 0;
virtual void ClearAll();
@ -186,8 +189,13 @@ public:
virtual nsresult Open() override;
virtual void ClearAll() override;
virtual nsresult Has(const Completion& aCompletion,
bool* aHas, bool* aComplete,
uint32_t* aMatchLength) override;
bool* aHas, uint32_t* aMatchLength,
bool* aFromCache) override;
virtual void IsHashEntryConfirmed(const Completion& aEntry,
const TableFreshnessMap& aTableFreshness,
uint32_t aFreshnessGuarantee,
bool* aConfirmed) override;
nsresult Build(AddPrefixArray& aAddPrefixes,
AddCompleteArray& aAddCompletes);

View File

@ -80,10 +80,10 @@ LookupCacheV4::Init()
nsresult
LookupCacheV4::Has(const Completion& aCompletion,
bool* aHas, bool* aComplete,
uint32_t* aMatchLength)
bool* aHas, uint32_t* aMatchLength,
bool* aFromCache)
{
*aHas = *aComplete = false;
*aHas = *aFromCache = false;
*aMatchLength = 0;
uint32_t length = 0;
@ -94,18 +94,29 @@ LookupCacheV4::Has(const Completion& aCompletion,
NS_ENSURE_SUCCESS(rv, rv);
*aHas = length >= PREFIX_SIZE;
*aComplete = length == COMPLETE_SIZE;
*aMatchLength = length;
if (LOG_ENABLED()) {
uint32_t prefix = aCompletion.ToUint32();
LOG(("Probe in V4 %s: %X, found %d, complete %d", mTableName.get(),
prefix, *aHas, *aComplete));
prefix, *aHas, length == COMPLETE_SIZE));
}
// TODO : Bug 1311935 - Implement v4 caching
return NS_OK;
}
void
LookupCacheV4::IsHashEntryConfirmed(const Completion& aEntry,
const TableFreshnessMap& aTableFreshness,
uint32_t aFreshnessGuarantee,
bool* aConfirmed)
{
// TODO : Bug 1311935 - Implement v4 caching
*aConfirmed = true;
}
nsresult
LookupCacheV4::Build(PrefixStringMap& aPrefixMap)
{

View File

@ -25,8 +25,13 @@ public:
virtual nsresult Init() override;
virtual nsresult Has(const Completion& aCompletion,
bool* aHas, bool* aComplete,
uint32_t* aMatchLength) override;
bool* aHas, uint32_t* aMatchLength,
bool* aFromCache) override;
virtual void IsHashEntryConfirmed(const Completion& aEntry,
const TableFreshnessMap& aTableFreshness,
uint32_t aFreshnessGuarantee,
bool* aConfirmed) override;
nsresult Build(PrefixStringMap& aPrefixMap);

View File

@ -1012,10 +1012,9 @@ nsUrlClassifierLookupCallback::LookupComplete(nsTArray<LookupResult>* results)
}
} else {
// For tables with no hash completer, a complete hash match is
// good enough, we'll consider it fresh, even if it hasn't been updated
// in 45 minutes.
// good enough, we'll consider it is valid.
if (result.Complete()) {
result.mFresh = true;
result.mConfirmed = true;
LOG(("Skipping completion in a table without a valid completer (%s).",
result.mTableName.get()));
} else {

View File

@ -60,13 +60,13 @@ TestHasPrefix(const _Fragment& aFragment, bool aExpectedHas, bool aExpectedCompl
nsCOMPtr<nsICryptoHash> cryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID);
lookupHash.FromPlaintext(aFragment, cryptoHash);
bool has, complete;
bool has, fromCache;
uint32_t matchLength;
nsresult rv = cache->Has(lookupHash, &has, &complete, &matchLength);
nsresult rv = cache->Has(lookupHash, &has, &matchLength, &fromCache);
EXPECT_EQ(rv, NS_OK);
EXPECT_EQ(has, aExpectedHas);
EXPECT_EQ(complete, aExpectedComplete);
EXPECT_EQ(matchLength == COMPLETE_SIZE, aExpectedComplete);
cache->ClearAll();
});

View File

@ -716,7 +716,11 @@ PopupNotifications.prototype = {
popupnotification.setAttribute("label", n.message);
popupnotification.setAttribute("id", popupnotificationID);
popupnotification.setAttribute("popupid", n.id);
popupnotification.setAttribute("closebuttoncommand", `PopupNotifications._dismiss(event, ${TELEMETRY_STAT_DISMISSAL_CLOSE_BUTTON});`);
if (Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton")) {
popupnotification.setAttribute("closebuttoncommand", "PopupNotifications._onButtonEvent(event, 'secondarybuttoncommand');");
} else {
popupnotification.setAttribute("closebuttoncommand", `PopupNotifications._dismiss(event, ${TELEMETRY_STAT_DISMISSAL_CLOSE_BUTTON});`);
}
if (n.mainAction) {
popupnotification.setAttribute("buttonlabel", n.mainAction.label);
popupnotification.setAttribute("buttonaccesskey", n.mainAction.accessKey);

View File

@ -485,11 +485,6 @@ audio > xul|videocontrols {
background-color: transparent;
}
.controlsSpacer:hover {
background-color: rgb(254,255,255);
opacity: .4;
}
@media (-moz-windows-default-theme) {
.controlsSpacer {
background-color: rgba(255,255,255,.4);

View File

@ -997,7 +997,7 @@ public:
return p.forget();
}
void Resolve(typename PromiseType::ResolveValueType aResolveValue,
void Resolve(const typename PromiseType::ResolveValueType& aResolveValue,
const char* aMethodName)
{
if (mMonitor) {
@ -1007,17 +1007,33 @@ public:
mPromise->Resolve(aResolveValue, aMethodName);
mPromise = nullptr;
}
void Resolve(typename PromiseType::ResolveValueType&& aResolveValue,
const char* aMethodName)
{
if (mMonitor) {
mMonitor->AssertCurrentThreadOwns();
}
MOZ_ASSERT(mPromise);
mPromise->Resolve(Move(aResolveValue), aMethodName);
mPromise = nullptr;
}
void ResolveIfExists(typename PromiseType::ResolveValueType aResolveValue,
void ResolveIfExists(const typename PromiseType::ResolveValueType& aResolveValue,
const char* aMethodName)
{
if (!IsEmpty()) {
Resolve(aResolveValue, aMethodName);
}
}
void ResolveIfExists(typename PromiseType::ResolveValueType&& aResolveValue,
const char* aMethodName)
{
if (!IsEmpty()) {
Resolve(Move(aResolveValue), aMethodName);
}
}
void Reject(typename PromiseType::RejectValueType aRejectValue,
void Reject(const typename PromiseType::RejectValueType& aRejectValue,
const char* aMethodName)
{
if (mMonitor) {
@ -1027,15 +1043,31 @@ public:
mPromise->Reject(aRejectValue, aMethodName);
mPromise = nullptr;
}
void Reject(typename PromiseType::RejectValueType&& aRejectValue,
const char* aMethodName)
{
if (mMonitor) {
mMonitor->AssertCurrentThreadOwns();
}
MOZ_ASSERT(mPromise);
mPromise->Reject(Move(aRejectValue), aMethodName);
mPromise = nullptr;
}
void RejectIfExists(typename PromiseType::RejectValueType aRejectValue,
void RejectIfExists(const typename PromiseType::RejectValueType& aRejectValue,
const char* aMethodName)
{
if (!IsEmpty()) {
Reject(aRejectValue, aMethodName);
}
}
void RejectIfExists(typename PromiseType::RejectValueType&& aRejectValue,
const char* aMethodName)
{
if (!IsEmpty()) {
Reject(Move(aRejectValue), aMethodName);
}
}
private:
Monitor* mMonitor;