Merge mozilla-central to inbound. a=merge

This commit is contained in:
Cosmin Sabou 2018-07-18 20:23:16 +03:00
commit 8cd0e59ac5
95 changed files with 1211 additions and 425 deletions

View File

@ -1230,26 +1230,34 @@ BrowserPageActions.shareURL = {
let shareProviders = sharingService.getSharingProviders(currentURI);
let fragment = document.createDocumentFragment();
let onCommand = event => {
let shareName = event.target.getAttribute("share-name");
if (shareName) {
sharingService.shareUrl(shareName,
currentURI,
gBrowser.selectedBrowser.contentTitle);
} else if (event.target.classList.contains("share-more-button")) {
sharingService.openSharingPreferences();
}
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
};
shareProviders.forEach(function(share) {
let item = document.createElement("toolbarbutton");
item.setAttribute("label", share.menuItemTitle);
item.setAttribute("share-name", share.name);
item.setAttribute("image", share.image);
item.classList.add("subviewbutton", "subviewbutton-iconic");
item.addEventListener("command", event => {
let shareName = event.target.getAttribute("share-name");
if (shareName) {
sharingService.shareUrl(shareName,
currentURI,
gBrowser.selectedBrowser.contentTitle);
}
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
});
item.addEventListener("command", onCommand);
fragment.appendChild(item);
});
let item = document.createElement("toolbarbutton");
item.setAttribute("label", BrowserPageActions.panelNode.getAttribute("shareMore-label"));
item.classList.add("subviewbutton", "subviewbutton-iconic", "share-more-button");
item.addEventListener("command", onCommand);
fragment.appendChild(item);
while (bodyNode.firstChild) {
bodyNode.firstChild.remove();
}

View File

@ -474,7 +474,8 @@
emailLink-title="&emailPageCmd.label;"
sendToDevice-title="&pageAction.sendTabToDevice.label;"
sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;"
shareURL-title="&pageAction.shareUrl.label;">
shareURL-title="&pageAction.shareUrl.label;"
shareMore-label="&pageAction.shareMore.label;">
<panelmultiview id="pageActionPanelMultiView"
mainViewId="pageActionPanelMainView"
viewCacheId="appMenu-viewCache">

View File

@ -2642,6 +2642,13 @@ window._gBrowser = {
}
var isLastTab = (this.tabs.length - this._removingTabs.length == 1);
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// We have to sample the tab width now, since _beginRemoveTab might
// end up modifying the DOM in such a way that aTab gets a new
// frame created for it (for example, by updating the visually selected
// state).
let tabWidth = windowUtils.getBoundsWithoutFlushing(aTab).width;
if (!this._beginRemoveTab(aTab, null, null, true, skipPermitUnload)) {
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);
@ -2650,7 +2657,7 @@ window._gBrowser = {
}
if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse)
this.tabContainer._lockTabSizing(aTab);
this.tabContainer._lockTabSizing(aTab, tabWidth);
else
this.tabContainer._unlockTabSizing();

View File

@ -400,6 +400,7 @@
<!-- Try to keep the active tab's close button under the mouse cursor -->
<method name="_lockTabSizing">
<parameter name="aTab"/>
<parameter name="aTabWidth"/>
<body><![CDATA[
let tabs = this._getVisibleTabs();
if (!tabs.length) {
@ -407,7 +408,6 @@
}
var isEndTab = (aTab._tPos > tabs[tabs.length - 1]._tPos);
var tabWidth = aTab.getBoundingClientRect().width;
if (!this._tabDefaultMaxWidth) {
this._tabDefaultMaxWidth =
@ -427,7 +427,7 @@
if (aTab.owner) {
return;
}
this._expandSpacerBy(tabWidth);
this._expandSpacerBy(aTabWidth);
} else { // non-overflow mode
// Locking is neither in effect nor needed, so let tabs expand normally.
if (isEndTab && !this._hasTabTempMaxWidth) {
@ -439,18 +439,18 @@
// tabbar width is the same.
if (isEndTab) {
let numNormalTabs = tabs.length - numPinned;
tabWidth = tabWidth * (numNormalTabs + 1) / numNormalTabs;
if (tabWidth > this._tabDefaultMaxWidth) {
tabWidth = this._tabDefaultMaxWidth;
aTabWidth = aTabWidth * (numNormalTabs + 1) / numNormalTabs;
if (aTabWidth > this._tabDefaultMaxWidth) {
aTabWidth = this._tabDefaultMaxWidth;
}
}
tabWidth += "px";
aTabWidth += "px";
for (let i = numPinned; i < tabs.length; i++) {
let tab = tabs[i];
tab.style.setProperty("max-width", tabWidth, "important");
tab.style.setProperty("max-width", aTabWidth, "important");
if (!isEndTab) { // keep tabs the same width
tab.style.transition = "none";
tab.clientTop; // flush styles to skip animation; see bug 649247
window.getComputedStyle(tab); // flush styles to skip animation; see bug 649247
tab.style.transition = "";
}
}

View File

@ -44,7 +44,7 @@ add_task(async function() {
await withPerfObserver(async function() {
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
let tab = gBrowser.tabs[gBrowser.tabs.length - 1];
gBrowser.removeTab(tab, { animate: true });
gBrowser.removeTab(tab, { animate: true, byMouse: true });
await BrowserTestUtils.waitForEvent(tab, "transitionend",
false, e => e.propertyName === "max-width");
await switchDone;

View File

@ -10,9 +10,8 @@ Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
const URL = "http://example.org/";
// Keep track of title of service we chose to share with
let serviceName;
let sharedUrl;
let sharedTitle;
let serviceName, sharedUrl, sharedTitle;
let sharingPreferencesCalled = false;
let mockShareData = [{
name: "NSA",
@ -30,6 +29,9 @@ let stub = sinon.stub(BrowserPageActions.shareURL, "_sharingService").get(() =>
serviceName = name;
sharedUrl = url;
sharedTitle = title;
},
openSharingPreferences() {
sharingPreferencesCalled = true;
}
};
});
@ -54,7 +56,8 @@ add_task(async function shareURL() {
let view = await viewPromise;
let body = document.getElementById(view.id + "-body");
Assert.equal(body.childNodes.length, 1, "Has correct share receivers");
// We should see 1 receiver and one extra node for the "More..." button
Assert.equal(body.childNodes.length, 2, "Has correct share receivers");
let shareButton = body.childNodes[0];
Assert.equal(shareButton.label, mockShareData[0].menuItemTitle);
let hiddenPromise = promisePageActionPanelHidden();
@ -107,7 +110,8 @@ add_task(async function shareURLAddressBar() {
// Ensure we have share providers
let panel = document.getElementById("pageAction-urlbar-shareURL-subview-body");
Assert.equal(panel.childNodes.length, 1, "Has correct share receivers");
// We should see 1 receiver and one extra node for the "More..." button
Assert.equal(panel.childNodes.length, 2, "Has correct share receivers");
// Remove the Share URL button from the Address bar so we dont interfere
// with future tests
@ -125,3 +129,30 @@ add_task(async function shareURLAddressBar() {
await contextMenuPromise;
});
});
add_task(async function openSharingPreferences() {
await BrowserTestUtils.withNewTab(URL, async () => {
// Open the panel.
await promisePageActionPanelOpen();
// Click Share URL.
let shareURLButton = document.getElementById("pageAction-panel-shareURL");
let viewPromise = promisePageActionViewShown();
EventUtils.synthesizeMouseAtCenter(shareURLButton, {});
let view = await viewPromise;
let body = document.getElementById(view.id + "-body");
// We should see 1 receiver and one extra node for the "More..." button
Assert.equal(body.childNodes.length, 2, "Has correct share receivers");
let moreButton = body.childNodes[1];
let hiddenPromise = promisePageActionPanelHidden();
// Click on the "more" button, panel should hide and we should call
// the sharingService function to open preferences
EventUtils.synthesizeMouseAtCenter(moreButton, {});
await hiddenPromise;
Assert.equal(sharingPreferencesCalled, true,
"We called openSharingPreferences");
});
});

View File

@ -77,7 +77,8 @@ Preferences.addAll([
{ id: "privacy.donottrackheader.enabled", type: "bool" },
// Media
{ id: "media.autoplay.enabled", type: "bool" },
{ id: "media.autoplay.default", type: "int" },
{ id: "media.autoplay.enabled.ask-permission", type: "bool" },
{ id: "media.autoplay.enabled.user-gestures-needed", type: "bool" },
// Popups
@ -258,7 +259,6 @@ var gPrivacyPane = {
this._updateSanitizeSettingsButton();
this.initializeHistoryMode();
this.updateAutoplayMediaControls();
this.updateAutoplayMediaControlsVisibility();
this.updateHistoryModePane();
this.updatePrivacyMicroControls();
@ -276,8 +276,8 @@ var gPrivacyPane = {
gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
Preferences.get("privacy.trackingprotection.pbmode.enabled").on("change",
gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
Preferences.get("media.autoplay.enabled").on("change",
gPrivacyPane.updateAutoplayMediaControls.bind(gPrivacyPane));
Preferences.get("media.autoplay.enabled.ask-permission").on("change",
gPrivacyPane.updateAutoplayMediaControlsVisibility.bind(gPrivacyPane));
Preferences.get("media.autoplay.enabled.user-gestures-needed").on("change",
gPrivacyPane.updateAutoplayMediaControlsVisibility.bind(gPrivacyPane));
setEventListener("historyMode", "command", function() {
@ -342,10 +342,12 @@ var gPrivacyPane = {
gPrivacyPane.showMicrophoneExceptions);
setEventListener("popupPolicyButton", "command",
gPrivacyPane.showPopupExceptions);
setEventListener("autoplayMediaPolicy", "command",
setEventListener("autoplayMediaCheckbox", "command",
gPrivacyPane.toggleAutoplayMedia);
setEventListener("autoplayMediaPolicyButton", "command",
gPrivacyPane.showAutoplayMediaExceptions);
setEventListener("autoplayMediaPolicyComboboxButton", "command",
gPrivacyPane.showAutoplayMediaExceptions);
setEventListener("notificationsDoNotDisturb", "command",
gPrivacyPane.toggleDoNotDisturbNotifications);
@ -988,25 +990,34 @@ var gPrivacyPane = {
// MEDIA
/**
* media.autoplay.enabled works the opposite to most of the other preferences.
* The checkbox enabled sets the pref to false
* The checkbox enabled sets the pref to BLOCKED
*/
toggleAutoplayMedia(event) {
Services.prefs.setBoolPref("media.autoplay.enabled", !event.target.checked);
},
updateAutoplayMediaControls() {
let autoPlayEnabled = Preferences.get("media.autoplay.enabled").value;
document.getElementById("autoplayMediaPolicy").checked = !autoPlayEnabled;
document.getElementById("autoplayMediaPolicyButton").disabled = autoPlayEnabled;
let blocked = event.target.checked ? Ci.nsIAutoplay.BLOCKED : Ci.nsIAutoplay.ALLOWED;
Services.prefs.setIntPref("media.autoplay.default", blocked);
},
/**
* Show the controls for the new media autoplay behaviour behind a pref for now
* If user-gestures-needed is false we do not show any UI for configuring autoplay,
* if user-gestures-needed is false and ask-permission is false we show a checkbox
* which only allows the user to block autoplay
* if user-gestures-needed and ask-permission are true we show a combobox that
* allows the user to block / allow or prompt for autoplay
* We will be performing a shield study to determine the behaviour to be
* shipped, at which point we can remove these pref switches.
* https://bugzilla.mozilla.org/show_bug.cgi?id=1475099
*/
updateAutoplayMediaControlsVisibility() {
document.getElementById("autoplayMediaBox").hidden =
!Services.prefs.getBoolPref("media.autoplay.enabled.user-gestures-needed", false);
let askPermission =
Services.prefs.getBoolPref("media.autoplay.ask-permission", false);
let userGestures =
Services.prefs.getBoolPref("media.autoplay.enabled.user-gestures-needed", false);
// Hide the combobox if we don't let the user ask for permission.
document.getElementById("autoplayMediaComboboxWrapper").hidden =
!userGestures || !askPermission;
// If the user may ask for permission, hide the checkbox instead.
document.getElementById("autoplayMediaCheckboxWrapper").hidden =
!userGestures || askPermission;
},
/**
@ -1015,7 +1026,7 @@ var gPrivacyPane = {
*/
showAutoplayMediaExceptions() {
var params = {
blockVisible: false, sessionVisible: false, allowVisible: true,
blockVisible: true, sessionVisible: false, allowVisible: true,
prefilledHost: "", permissionType: "autoplay-media"
};

View File

@ -496,8 +496,8 @@
<separator flex="1"/>
<hbox align="start" id="autoplayMediaBox" hidden="true">
<checkbox id="autoplayMediaPolicy"
<hbox align="start" id="autoplayMediaCheckboxWrapper" hidden="true">
<checkbox id="autoplayMediaCheckbox"
data-l10n-id="permissions-block-autoplay-media"
flex="1" />
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
@ -568,6 +568,37 @@
data-l10n-id="permissions-a11y-privacy-link"/>
</hbox>
</vbox>
<hbox align="center" id="autoplayMediaComboboxWrapper" hidden="true">
<hbox align="center" flex="1">
<label id="autoplayMediaPolicy"
control="autoplayMediaPolicyMenu"
data-l10n-id="permissions-block-autoplay-media-menu"/>
<menulist id="autoplayMediaPolicyMenu"
sizetopopup="always"
preference="media.autoplay.default">
<menupopup>
<!-- Defined in dom/media/nsIAutoplay.idl -->
<menuitem data-l10n-id="autoplay-option-allow" value="0"/>
<menuitem data-l10n-id="autoplay-option-ask" value="2"/>
<menuitem data-l10n-id="autoplay-option-block" value="1"/>
</menupopup>
</menulist>
</hbox>
<hbox pack="end">
<button id="autoplayMediaPolicyComboboxButton"
class="accessory-button"
data-l10n-id="permissions-block-autoplay-media-exceptions"
search-l10n-ids="permissions-address,
permissions-button-cancel.label,
permissions-button-ok.label,
permissions-exceptions-autoplay-media-window.title,
permissions-exceptions-autoplay-media-desc
" />
</hbox>
</hbox>
</groupbox>
<!-- Firefox Data Collection and Use -->

View File

@ -80,6 +80,7 @@ run-if = nightly_build
[browser_spotlight.js]
[browser_site_login_exceptions.js]
[browser_site_autoplay_media_exceptions.js]
[browser_site_autoplay_media_prompt.js]
[browser_permissions_dialog.js]
[browser_subdialogs.js]
support-files =

View File

@ -7,13 +7,15 @@ const PRINCIPAL = Services.scriptSecurityManager
.createCodebasePrincipal(Services.io.newURI(URL), {});
const PERMISSIONS_URL = "chrome://browser/content/preferences/permissions.xul";
const AUTOPLAY_ENABLED_KEY = "media.autoplay.enabled";
const AUTOPLAY_ENABLED_KEY = "media.autoplay.default";
const GESTURES_NEEDED_KEY = "media.autoplay.enabled.user-gestures-needed";
const ASK_PERMISSIONS_KEY = "media.autoplay.enabled.ask-permissions";
var exceptionsDialog;
Services.prefs.setBoolPref(AUTOPLAY_ENABLED_KEY, true);
Services.prefs.setIntPref(AUTOPLAY_ENABLED_KEY, Ci.nsIAutoplay.ALLOWED);
Services.prefs.setBoolPref(GESTURES_NEEDED_KEY, false);
Services.prefs.setBoolPref(ASK_PERMISSIONS_KEY, true);
async function openExceptionsDialog() {
let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
@ -29,6 +31,7 @@ add_task(async function ensureCheckboxHidden() {
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(AUTOPLAY_ENABLED_KEY);
Services.prefs.clearUserPref(GESTURES_NEEDED_KEY);
Services.prefs.clearUserPref(ASK_PERMISSIONS_KEY);
gBrowser.removeCurrentTab();
});
@ -44,11 +47,12 @@ add_task(async function enableBlockingAutoplay() {
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
let doc = content.document;
let autoplayCheckBox = doc.getElementById("autoplayMediaPolicy");
let autoplayCheckBox = doc.getElementById("autoplayMediaCheckbox");
autoplayCheckBox.click();
});
Assert.equal(Services.prefs.getBoolPref(AUTOPLAY_ENABLED_KEY), false,
Assert.equal(Services.prefs.getIntPref(AUTOPLAY_ENABLED_KEY),
Ci.nsIAutoplay.BLOCKED,
"Ensure we have set autoplay to false");
});

View File

@ -0,0 +1,114 @@
"use strict";
ChromeUtils.import("resource:///modules/SitePermissions.jsm");
const URL = "http://www.example.com";
const PRINCIPAL = Services.scriptSecurityManager
.createCodebasePrincipal(Services.io.newURI(URL), {});
const PERMISSIONS_URL = "chrome://browser/content/preferences/permissions.xul";
const AUTOPLAY_ENABLED_KEY = "media.autoplay.default";
const GESTURES_NEEDED_KEY = "media.autoplay.enabled.user-gestures-needed";
const ASK_PERMISSIONS_KEY = "media.autoplay.enabled.ask-permissions";
var exceptionsDialog;
Services.prefs.setIntPref(AUTOPLAY_ENABLED_KEY, Ci.nsIAutoplay.ALLOWED);
Services.prefs.setBoolPref(GESTURES_NEEDED_KEY, false);
Services.prefs.setBoolPref(ASK_PERMISSIONS_KEY, true);
async function openExceptionsDialog() {
let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
let exceptionsButton = content.document.getElementById("autoplayMediaPolicyButton");
exceptionsButton.click();
});
exceptionsDialog = await dialogOpened;
}
add_task(async function ensureMenuHidden() {
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(AUTOPLAY_ENABLED_KEY);
Services.prefs.clearUserPref(GESTURES_NEEDED_KEY);
Services.prefs.clearUserPref(ASK_PERMISSIONS_KEY);
gBrowser.removeCurrentTab();
});
await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
let win = gBrowser.selectedBrowser.contentWindow;
is_element_hidden(win.document.getElementById("autoplayMediaPolicy"),
"Ensure checkbox is hidden when preffed off");
});
add_task(async function enableBlockingAutoplay() {
Services.prefs.setBoolPref(GESTURES_NEEDED_KEY, true);
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
let doc = content.document;
let autoplayMenu = doc.getElementById("autoplayMediaPolicyMenu");
autoplayMenu.click();
let askMenuItem = autoplayMenu.childNodes[0].childNodes[1];
askMenuItem.click();
});
Assert.equal(Services.prefs.getIntPref(AUTOPLAY_ENABLED_KEY),
Ci.nsIAutoplay.PROMPT,
"Ensure we have set autoplay to false");
});
add_task(async function addException() {
await openExceptionsDialog();
let doc = exceptionsDialog.document;
let richlistbox = doc.getElementById("permissionsBox");
Assert.equal(richlistbox.itemCount, 0, "Row count should initially be 0");
let inputBox = doc.getElementById("url");
inputBox.focus();
EventUtils.sendString(URL, exceptionsDialog);
let btnAllow = doc.getElementById("btnAllow");
btnAllow.click();
await TestUtils.waitForCondition(() => richlistbox.itemCount == 1);
Assert.equal(richlistbox.getItemAtIndex(0).getAttribute("origin"), URL);
let permChanged = TestUtils.topicObserved("perm-changed");
let btnApplyChanges = doc.getElementById("btnApplyChanges");
btnApplyChanges.click();
await permChanged;
is(Services.perms.testPermissionFromPrincipal(PRINCIPAL, "autoplay-media"),
Ci.nsIPermissionManager.ALLOW_ACTION, "Correctly added the exception");
});
add_task(async function deleteException() {
await openExceptionsDialog();
let doc = exceptionsDialog.document;
let richlistbox = doc.getElementById("permissionsBox");
Assert.equal(richlistbox.itemCount, 1, "Row count should initially be 1");
richlistbox.focus();
richlistbox.selectedIndex = 0;
if (AppConstants.platform == "macosx") {
EventUtils.synthesizeKey("KEY_Backspace");
} else {
EventUtils.synthesizeKey("KEY_Delete");
}
await TestUtils.waitForCondition(() => richlistbox.itemCount == 0);
is_element_visible(content.gSubDialog._dialogs[0]._box,
"Subdialog is visible after deleting an element");
let permChanged = TestUtils.topicObserved("perm-changed");
let btnApplyChanges = doc.getElementById("btnApplyChanges");
btnApplyChanges.click();
await permChanged;
is(Services.perms.testPermissionFromPrincipal(PRINCIPAL, "autoplay-media"),
Ci.nsIPermissionManager.UNKNOWN_ACTION, "Correctly removed the exception");
});

View File

@ -367,7 +367,6 @@ var SessionFileInternal = {
this._initializationStarted = false;
// Reset the counter and report to telemetry.
this._workerHealth.failures = 0;
Telemetry.scalarAdd("browser.session.restore.worker_restart_count", 1);
}
},

View File

@ -1,39 +0,0 @@
/*
* The primary purpose of this test is to ensure that the sessionstore component
* records information about erroneous workers into a scalar.
*/
"use strict";
const Telemetry = Services.telemetry;
const ScalarId = "browser.session.restore.worker_restart_count";
// Prepare the session file.
var profd = do_get_profile();
ChromeUtils.import("resource:///modules/sessionstore/SessionFile.jsm", this);
/**
* In order to use browser.session.restore.worker_restart_count scalar, it has
* to be registered in "toolkit/components/telemetry/Scalars.yaml".
* This test ensures that the scalar is registered and empty.
*/
add_task(async function test_ensure_scalar_is_empty() {
const scalars = Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT, false).parent || {};
Assert.ok(!(ScalarId in scalars), "Sanity check; no scalars should be there yet.");
});
/**
* Makes sure that the scalar is positively updated when amount of failures
* becomes higher than the threshold.
*/
add_task(async function test_worker_restart() {
let backstagePass = ChromeUtils.import("resource:///modules/sessionstore/SessionFile.jsm", {});
backstagePass.SessionFileInternal._workerHealth.failures = backstagePass.kMaxWriteFailures + 1;
backstagePass.SessionFileInternal._checkWorkerHealth();
Assert.equal(backstagePass.SessionFileInternal._workerHealth.failures, 0,
"Worker failure count should've been reset.");
// Checking if the scalar is positively updated.
const scalars = Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT, false).parent;
Assert.equal(scalars[ScalarId], 1, "Should be increased with one hit.");
});

View File

@ -10,7 +10,6 @@ support-files =
[test_backup_once.js]
[test_histogram_corrupt_files.js]
[test_migration_lz4compression.js]
[test_scalar_worker_restarts.js]
[test_shutdown_cleanup.js]
[test_startup_nosession_async.js]
[test_startup_session_async.js]

View File

@ -47,6 +47,7 @@
[@AB_CD@]
@RESPATH@/dictionaries/*
@RESPATH@/browser/localization/*
@RESPATH@/localization/*
#if defined(XP_WIN) || defined(XP_LINUX)
@RESPATH@/fonts/*
#endif

View File

@ -849,10 +849,19 @@ permissions-block-autoplay-media =
.label = Block websites from automatically playing media with sound
.accesskey = B
permissions-block-autoplay-media-menu = For websites that autoplay sound
permissions-block-autoplay-media-exceptions =
.label = Exceptions…
.accesskey = E
autoplay-option-ask =
.label = Always Ask
autoplay-option-allow =
.label = Allow Autoplay
autoplay-option-block =
.label = Block Autoplay
permissions-block-popups =
.label = Block pop-up windows
.accesskey = B

View File

@ -1031,6 +1031,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
<!ENTITY pageAction.shareUrl.label "Share">
<!ENTITY pageAction.shareMore.label "More…">
<!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more">

View File

@ -608,8 +608,12 @@ var gPermissionObject = {
"autoplay-media": {
exactHostMatch: true,
getDefault() {
if (Services.prefs.getBoolPref("media.autoplay.enabled")) {
let state = Services.prefs.getIntPref("media.autoplay.default",
Ci.nsIAutoplay.PROMPT);
if (state == Ci.nsIAutoplay.ALLOW) {
return SitePermissions.ALLOW;
} if (state == Ci.nsIAutoplay.BLOCK) {
return SitePermissions.DENY;
}
return SitePermissions.UNKNOWN;
},

View File

@ -32,9 +32,9 @@ add_task(async function test_midi_permission_prompt() {
// Tests that AutoplayPermissionPrompt works as expected
add_task(async function test_autoplay_permission_prompt() {
Services.prefs.setBoolPref("media.autoplay.enabled", false);
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.PROMPT);
await testPrompt(PermissionUI.AutoplayPermissionPrompt);
Services.prefs.clearUserPref("media.autoplay.enabled");
Services.prefs.clearUserPref("media.autoplay.default");
});
async function testPrompt(Prompt) {

View File

@ -298,7 +298,7 @@
opacity: 0;
}
#pageActionButton {
#pageActionButton, .share-more-button {
list-style-image: url("chrome://browser/skin/page-action.svg");
}

View File

@ -21,6 +21,7 @@ skip-if = !e10s # too slow on !e10s, logging fully serialized actors (Bug 144659
subsuite = clipboard
[browser_fontinspector_edit-previews.js]
[browser_fontinspector_editor-font-size-conversion.js]
skip-if = true # Bug 1476535
[browser_fontinspector_editor-values.js]
[browser_fontinspector_editor-keywords.js]
[browser_fontinspector_expand-css-code.js]

View File

@ -102,7 +102,6 @@ support-files =
test-insecure-passwords-web-console-warning.html
test-inspect-cross-domain-objects-frame.html
test-inspect-cross-domain-objects-top.html
test-jsterm-dollar.html
test_jsterm_screenshot_command.html
test-local-session-storage.html
test-location-debugger-link-console-log.js
@ -200,12 +199,12 @@ skip-if = verify
[browser_jsterm_autocomplete_return_key.js]
[browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js]
[browser_jsterm_completion.js]
[browser_jsterm_content_defined_helpers.js]
[browser_jsterm_copy_command.js]
[browser_jsterm_ctrl_a_select_all.js]
[browser_jsterm_ctrl_key_nav.js]
skip-if = os != 'mac' # The tested ctrl+key shortcuts are OSX only
[browser_jsterm_document_no_xray.js]
[browser_jsterm_dollar.js]
[browser_jsterm_error_docs.js]
[browser_jsterm_error_outside_valid_range.js]
[browser_jsterm_helper_clear.js]

View File

@ -0,0 +1,63 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that using helper functions in jsterm call the global content functions
// if they are defined.
const PREFIX = "content-";
const HELPERS = [
"$_",
"$",
"$$",
"$0",
"$x",
"cd",
"clear",
"clearHistory",
"copy",
"help",
"inspect",
"keys",
"pprint",
"screenshot",
"values",
];
// The page script sets a global function for each known helper (except print).
const TEST_URI = `data:text/html,<meta charset=utf8>
<script>
const helpers = ${JSON.stringify(HELPERS)};
for (const helper of helpers) {
window[helper] = () => "${PREFIX}" + helper;
}
</script>`;
add_task(async function() {
// Run test with legacy JsTerm
await performTests();
// And then run it with the CodeMirror-powered one.
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
await performTests();
});
async function performTests() {
const {jsterm} = await openNewTabAndConsole(TEST_URI);
const {autocompletePopup} = jsterm;
for (const helper of HELPERS) {
await jstermSetValueAndComplete(jsterm, helper);
const autocompleteItems = getPopupLabels(autocompletePopup).filter(l => l === helper);
is(autocompleteItems.length, 1,
`There's no duplicated "${helper}" item in the autocomplete popup`);
const msg = await jsterm.execute(`${helper}()`);
ok(msg.textContent.includes(PREFIX + helper), `output is correct for ${helper}()`);
}
}
function getPopupLabels(popup) {
return popup.getItems().map(item => item.label);
}

View File

@ -1,39 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that using `$` and `$$` in jsterm call the global content functions
// if they are defined. See Bug 621644.
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/mochitest/test-jsterm-dollar.html";
add_task(async function() {
// Run test with legacy JsTerm
await performTests();
// And then run it with the CodeMirror-powered one.
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
await performTests();
});
async function performTests() {
const hud = await openNewTabAndConsole(TEST_URI);
await test$(hud);
await test$$(hud);
}
async function test$(hud) {
hud.ui.clearOutput();
const msg = await hud.jsterm.execute("$(document.body)");
ok(msg.textContent.includes("<p>"), "jsterm output is correct for $()");
}
async function test$$(hud) {
hud.ui.clearOutput();
hud.jsterm.setInputValue();
const msg = await hud.jsterm.execute("$$(document)");
ok(msg.textContent.includes("621644"), "jsterm output is correct for $$()");
}

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html dir="ltr" xml:lang="en-US" lang="en-US">
<head>
<meta charset="utf-8">
<title>Web Console test for bug 621644</title>
<script>
/* eslint-disable */
function $(elem) {
return elem.innerHTML;
}
function $$(doc) {
return doc.title;
}
</script>
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<h1>Web Console test for bug 621644</h1>
<p>hello world!</p>
</body>
</html>

View File

@ -27,6 +27,7 @@ loader.lazyRequireGetter(this, "StackTraceCollector", "devtools/shared/webconsol
loader.lazyRequireGetter(this, "JSPropertyProvider", "devtools/shared/webconsole/js-property-provider", true);
loader.lazyRequireGetter(this, "Parser", "resource://devtools/shared/Parser.jsm", true);
loader.lazyRequireGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm", true);
loader.lazyRequireGetter(this, "WebConsoleCommands", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "addWebConsoleCommands", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "formatCommand", "devtools/server/actors/webconsole/commands", true);
loader.lazyRequireGetter(this, "isCommand", "devtools/server/actors/webconsole/commands", true);
@ -1134,9 +1135,14 @@ WebConsoleActor.prototype =
));
}
// Make sure we return an array with unique items, since `matches` can hold twice
// the same function name if it was defined in the content page and match an helper
// function (e.g. $, keys, …).
matches = [...new Set(matches)].sort();
return {
from: this.actorID,
matches: matches.sort(),
matches,
matchProp: result.matchProp,
};
},
@ -1418,39 +1424,35 @@ WebConsoleActor.prototype =
}
}
// Check if the Debugger.Frame or Debugger.Object for the global include
// $ or $$. We will not overwrite these functions with the Web Console
// commands.
let found$ = false, found$$ = false, disableScreenshot = false;
// Check if the Debugger.Frame or Debugger.Object for the global include any of the
// helper function we set. We will not overwrite these functions with the Web Console
// commands. The exception being "print" which should exist everywhere as
// `window.print`, and that we don't want to trigger from the console.
const availableHelpers = [...WebConsoleCommands._originalCommands.keys()]
.filter(h => h !== "print");
let helpersToDisable = [];
const helperCache = {};
// do not override command functions if we are using the command key `:`
// before the command string
if (!isCmd) {
// if we do not have the command key as a prefix, screenshot is disabled by default
disableScreenshot = true;
if (frame) {
const env = frame.environment;
if (env) {
found$ = !!env.find("$");
found$$ = !!env.find("$$");
helpersToDisable = availableHelpers.filter(name => !!env.find(name));
}
} else {
found$ = !!dbgWindow.getOwnPropertyDescriptor("$");
found$$ = !!dbgWindow.getOwnPropertyDescriptor("$$");
helpersToDisable = availableHelpers.filter(name =>
!!dbgWindow.getOwnPropertyDescriptor(name));
}
// if we do not have the command key as a prefix, screenshot is disabled by default
helpersToDisable.push("screenshot");
}
let $ = null, $$ = null, screenshot = null;
if (found$) {
$ = bindings.$;
delete bindings.$;
}
if (found$$) {
$$ = bindings.$$;
delete bindings.$$;
}
if (disableScreenshot) {
screenshot = bindings.screenshot;
delete bindings.screenshot;
for (const helper of helpersToDisable) {
helperCache[helper] = bindings[helper];
delete bindings[helper];
}
// Ready to evaluate the string.
@ -1547,14 +1549,8 @@ WebConsoleActor.prototype =
delete helpers.helperResult;
delete helpers.selectedNode;
if ($) {
bindings.$ = $;
}
if ($$) {
bindings.$$ = $$;
}
if (screenshot) {
bindings.screenshot = screenshot;
for (const [helperName, helper] of Object.entries(helperCache)) {
bindings[helperName] = helper;
}
if (bindings._self) {

View File

@ -87,6 +87,7 @@
#include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIAutoplay.h"
#include "nsICachingChannel.h"
#include "nsICategoryManager.h"
#include "nsIClassOfService.h"
@ -1998,7 +1999,7 @@ HTMLMediaElement::Load()
HasSourceChildren(this),
EventStateManager::IsHandlingUserInput(),
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay),
AutoplayPolicy::IsAllowedToPlay(*this) == Authorization::Allowed,
AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED,
OwnerDoc(),
DocumentOrigin(OwnerDoc()).get(),
OwnerDoc() ? OwnerDoc()->HasBeenUserGestureActivated() : 0,
@ -2520,7 +2521,7 @@ HTMLMediaElement::UpdatePreloadAction()
PreloadAction nextAction = PRELOAD_UNDEFINED;
// If autoplay is set, or we're playing, we should always preload data,
// as we'll need it to play.
if ((AutoplayPolicy::IsAllowedToPlay(*this) == Authorization::Allowed &&
if ((AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
!mPaused) {
nextAction = HTMLMediaElement::PRELOAD_ENOUGH;
@ -3053,7 +3054,7 @@ HTMLMediaElement::PauseIfShouldNotBePlaying()
if (GetPaused()) {
return;
}
if (AutoplayPolicy::IsAllowedToPlay(*this) != Authorization::Allowed) {
if (AutoplayPolicy::IsAllowedToPlay(*this) != nsIAutoplay::ALLOWED) {
ErrorResult rv;
Pause(rv);
}
@ -4064,13 +4065,13 @@ HTMLMediaElement::Play(ErrorResult& aRv)
const bool handlingUserInput = EventStateManager::IsHandlingUserInput();
switch (AutoplayPolicy::IsAllowedToPlay(*this)) {
case Authorization::Allowed: {
case nsIAutoplay::ALLOWED: {
mPendingPlayPromises.AppendElement(promise);
PlayInternal(handlingUserInput);
UpdateCustomPolicyAfterPlayed();
break;
}
case Authorization::Blocked: {
case nsIAutoplay::BLOCKED: {
LOG(LogLevel::Debug, ("%p play not blocked.", this));
promise->MaybeReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR);
if (StaticPrefs::MediaBlockEventEnabled()) {
@ -4078,7 +4079,7 @@ HTMLMediaElement::Play(ErrorResult& aRv)
}
break;
}
case Authorization::Prompt: {
case nsIAutoplay::PROMPT: {
// Prompt the user for permission to play.
mPendingPlayPromises.AppendElement(promise);
EnsureAutoplayRequested(handlingUserInput);
@ -6127,7 +6128,7 @@ HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
if (!mPaused) {
if (mDecoder && !mPausedForInactiveDocumentOrChannel) {
MOZ_ASSERT(AutoplayPolicy::IsAllowedToPlay(*this) ==
Authorization::Allowed);
nsIAutoplay::ALLOWED);
mDecoder->Play();
}
NotifyAboutPlaying();
@ -6239,12 +6240,12 @@ HTMLMediaElement::CheckAutoplayDataReady()
}
switch (AutoplayPolicy::IsAllowedToPlay(*this)) {
case Authorization::Blocked:
case nsIAutoplay::BLOCKED:
return;
case Authorization::Prompt:
case nsIAutoplay::PROMPT:
EnsureAutoplayRequested(false);
return;
case Authorization::Allowed:
case nsIAutoplay::ALLOWED:
break;
}

View File

@ -12,6 +12,7 @@
#include "mozilla/AutoplayPermissionManager.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLMediaElementBinding.h"
#include "nsIAutoplay.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
#include "MediaManager.h"
@ -88,42 +89,47 @@ AutoplayPolicy::RequestFor(const nsIDocument& aDocument)
return window->GetAutoplayPermissionManager();
}
/* static */ Authorization
static uint32_t
DefaultAutoplayBehaviour()
{
int prefValue = Preferences::GetInt("media.autoplay.default", nsIAutoplay::ALLOWED);
if (prefValue < nsIAutoplay::ALLOWED || prefValue > nsIAutoplay::PROMPT) {
// Invalid pref values are just converted to ALLOWED.
return nsIAutoplay::ALLOWED;
}
return prefValue;
}
/* static */ uint32_t
AutoplayPolicy::IsAllowedToPlay(const HTMLMediaElement& aElement)
{
if (Preferences::GetBool("media.autoplay.enabled")) {
return Authorization::Allowed;
}
const uint32_t autoplayDefault = DefaultAutoplayBehaviour();
// TODO : this old way would be removed when user-gestures-needed becomes
// as a default option to block autoplay.
if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed", false)) {
// If element is blessed, it would always be allowed to play().
return (aElement.IsBlessed() || EventStateManager::IsHandlingUserInput())
? Authorization::Allowed
: Authorization::Blocked;
return (autoplayDefault == nsIAutoplay::ALLOWED ||
aElement.IsBlessed() ||
EventStateManager::IsHandlingUserInput())
? nsIAutoplay::ALLOWED : nsIAutoplay::BLOCKED;
}
// Muted content
if (aElement.Volume() == 0.0 || aElement.Muted()) {
return Authorization::Allowed;
return nsIAutoplay::ALLOWED;
}
if (IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow())) {
return Authorization::Allowed;
return nsIAutoplay::ALLOWED;
}
if (Preferences::GetBool("media.autoplay.ask-permission", false)) {
return Authorization::Prompt;
}
return Authorization::Blocked;
return autoplayDefault;
}
/* static */ bool
AutoplayPolicy::IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext)
{
if (Preferences::GetBool("media.autoplay.enabled")) {
if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED) {
return true;
}

View File

@ -20,20 +20,13 @@ namespace dom {
class HTMLMediaElement;
class AudioContext;
enum class Authorization
{
Allowed,
Blocked,
Prompt
};
/**
* AutoplayPolicy is used to manage autoplay logic for all kinds of media,
* including MediaElement, Web Audio and Web Speech.
*
* Autoplay could be disable by turn off the pref "media.autoplay.enabled".
* Once user disable autoplay, media could only be played if one of following
* conditions is true.
* Autoplay could be disable by setting the pref "media.autoplay.default"
* to anything but nsIAutoplay::Allowed. Once user disables autoplay, media
* could only be played if one of following conditions is true.
* 1) Owner document is activated by user gestures
* We restrict user gestures to "mouse click", "keyboard press" and "touch".
* 2) Muted media content or video without audio content.
@ -43,7 +36,7 @@ class AutoplayPolicy
{
public:
// Returns whether a given media element is allowed to play.
static Authorization IsAllowedToPlay(const HTMLMediaElement& aElement);
static uint32_t IsAllowedToPlay(const HTMLMediaElement& aElement);
// Returns whether a given AudioContext is allowed to play.
static bool IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext);

View File

@ -14,6 +14,7 @@
#include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
#include "mozilla/gfx/2D.h"
#include "nsContentUtils.h"
#include "Tracing.h"
using namespace mozilla::layers;
using namespace mozilla::gfx;
@ -51,6 +52,8 @@ public:
void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
{
// Called on the MediaStreamGraph thread.
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
mSourceStream.get(), mTrackId);
MOZ_ASSERT(mSourceStream);
StreamTime delta = aDesiredTime - mSourceStream->GetEndOfAppendedData(mTrackId);
if (delta > 0) {

View File

@ -2764,7 +2764,7 @@ SourceMediaStream::SetPullEnabled(bool aEnabled)
bool
SourceMediaStream::PullNewData(StreamTime aDesiredUpToTime)
{
TRACE_AUDIO_CALLBACK();
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p", this);
MutexAutoLock lock(mMutex);
if (!mPullEnabled || mFinished) {
return false;

View File

@ -7,9 +7,7 @@
#include "Tracing.h"
#include <inttypes.h>
#include <cstdio>
#include "AsyncLogger.h"
#include "mozilla/TimeStamp.h"
using namespace mozilla;
@ -40,16 +38,16 @@ AutoTracer::PrintEvent(const char* aName,
void
AutoTracer::PrintBudget(const char* aName,
const char* aCategory,
const char* aComment,
uint64_t aDuration,
uint64_t aPID,
uint64_t aThread,
uint64_t aFrames)
uint64_t aFrames,
uint64_t aSampleRate)
{
mLogger.Log("{\"name\": \"%s\", \"cat\": \"%s\", \"ph\": \"X\","
"\"ts\": %" PRIu64 ", \"dur\": %" PRIu64 ", \"pid\": %" PRIu64 ","
"\"tid\": %" PRIu64 ", \"args\": { \"comment\": %" PRIu64 "}},",
aName, aCategory, NowInUs(), aDuration, aPID, aThread, aFrames);
"\"tid\": %" PRIu64 ", \"args\": { \"comment\": \"%" PRIu64 "/%" PRIu64 "\"}},",
aName, aCategory, NowInUs(), aDuration, aPID, aThread, aFrames, aSampleRate);
}
AutoTracer::AutoTracer(AsyncLogger& aLogger,
@ -70,7 +68,7 @@ AutoTracer::AutoTracer(AsyncLogger& aLogger,
if (aLogger.Enabled()) {
float durationUS = (static_cast<float>(aFrames) / aSampleRate) * 1e6;
PrintBudget(aLocation, "perf", mComment, durationUS, mPID, mTID, aFrames);
PrintBudget(aLocation, "perf", durationUS, mPID, mTID, aFrames, aSampleRate);
}
}

View File

@ -7,11 +7,14 @@
#ifndef TRACING_H
#define TRACING_H
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include "AsyncLogger.h"
#include <mozilla/Attributes.h>
#include "mozilla/Attributes.h"
#include "mozilla/UniquePtr.h"
#if defined(_WIN32)
#include <process.h>
@ -44,24 +47,31 @@
#define TRACE_AUDIO_CALLBACK_BUDGET(aFrames, aSampleRate) \
AutoTracer budget(gMSGTraceLogger, "Real-time budget", getpid(), 1, \
AutoTracer::EventType::BUDGET, aFrames, aSampleRate);
#define TRACE_AUDIO_CALLBACK_COMMENT(aFmt, ...) \
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), 0, \
AutoTracer::EventType::DURATION, \
aFmt, ##__VA_ARGS__);
#define TRACE() \
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), \
std::hash<std::thread::id>{}(std::this_thread::get_id()));
#define TRACE_COMMENT(aComment) \
#define TRACE_COMMENT(aFmt, ...) \
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), \
std::hash<std::thread::id>{}(std::this_thread::get_id()), \
AutoTracer::EventType::DURATION, \
aComment);
aFmt, ##__VA_ARGS__);
#else
#define TRACE_AUDIO_CALLBACK()
#define TRACE_AUDIO_CALLBACK_BUDGET(aFrames, aSampleRate)
#define TRACE_AUDIO_CALLBACK_COMMENT(aFmt, ...)
#define TRACE()
#define TRACE_COMMENT(aComment)
#define TRACE_COMMENT(aFmt, ...)
#endif
class MOZ_RAII AutoTracer
{
public:
static const int32_t BUFFER_SIZE = mozilla::AsyncLogger::MAX_MESSAGE_LENGTH / 2;
enum class EventType
{
DURATION,
@ -74,13 +84,39 @@ public:
uint64_t aTID,
EventType aEventType = EventType::DURATION,
const char* aComment = nullptr);
template<typename... Args>
AutoTracer(mozilla::AsyncLogger& aLogger,
const char* aLocation,
uint64_t aPID,
uint64_t aTID,
EventType aEventType,
uint64_t aSampleRate,
uint64_t aFrames);
const char* aFormat,
Args... aArgs)
: mLogger(aLogger)
, mLocation(aLocation)
, mComment(mBuffer)
, mEventType(aEventType)
, mPID(aPID)
, mTID(aTID)
{
MOZ_ASSERT(aEventType == EventType::DURATION);
if (aLogger.Enabled()) {
int32_t size = snprintf(mBuffer, BUFFER_SIZE, aFormat, aArgs...);
size = std::min(size, BUFFER_SIZE - 1);
mBuffer[size] = 0;
PrintEvent(aLocation, "perf", mComment, TracingPhase::BEGIN, NowInUs(), aPID, aTID);
}
}
AutoTracer(mozilla::AsyncLogger& aLogger,
const char* aLocation,
uint64_t aPID,
uint64_t aTID,
EventType aEventType,
uint64_t aFrames,
uint64_t aSampleRate);
~AutoTracer();
private:
uint64_t NowInUs();
@ -108,11 +144,11 @@ private:
void PrintBudget(const char* aName,
const char* aCategory,
const char* aComment,
uint64_t aDuration,
uint64_t aPID,
uint64_t aThread,
uint64_t aFrames);
uint64_t aFrames,
uint64_t aSampleRate);
// The logger to use. It musdt have a lifetime longer than the block an
// instance of this class traces.
@ -123,6 +159,8 @@ private:
// A comment for this trace point, abitrary string literal with a static
// lifetime.
const char* mComment;
// A buffer used to hold string-formatted traces.
char mBuffer[BUFFER_SIZE];
// The event type, for now either a budget or a duration.
const EventType mEventType;
// The process ID of the calling process. Traces are grouped by PID in the

View File

@ -68,7 +68,7 @@ TrackUnionStream::TrackUnionStream()
}
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
{
TRACE();
TRACE_AUDIO_CALLBACK_COMMENT("TrackUnionStream %p", this);
if (IsFinishedOnGraphThread()) {
return;
}
@ -290,6 +290,11 @@ TrackUnionStream::TrackUnionStream()
bool* aOutputTrackFinished)
{
TrackMapEntry* map = &mTrackMap[aMapIndex];
TRACE_AUDIO_CALLBACK_COMMENT("Input stream %p track %i -> TrackUnionStream %p track %i",
map->mInputPort->GetSource(),
map->mInputTrackID,
this,
map->mOutputTrackID);
StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track");

View File

@ -7,6 +7,7 @@
#include "VideoFrameContainer.h"
#include "mozilla/Telemetry.h"
#include "MediaDecoderOwner.h"
#include "Tracing.h"
using namespace mozilla::layers;
@ -118,6 +119,8 @@ private:
void VideoFrameContainer::SetCurrentFrames(const VideoSegment& aSegment)
{
TRACE();
if (aSegment.IsEmpty()) {
return;
}

View File

@ -27,6 +27,7 @@
#include "OggWriter.h"
#include "OpusTrackEncoder.h"
#include "TimeUnits.h"
#include "Tracing.h"
#ifdef MOZ_WEBM_ENCODER
#include "VP8TrackEncoder.h"
@ -89,6 +90,7 @@ public:
StreamTime aTrackOffset,
const MediaSegment& aQueuedMedia) override
{
TRACE_COMMENT("Encoder %p", mEncoder.get());
MOZ_ASSERT(mEncoder);
MOZ_ASSERT(mEncoderThread);
@ -137,6 +139,7 @@ public:
StreamTime aTrackOffset,
const MediaSegment& aMedia) override
{
TRACE_COMMENT("Encoder %p", mEncoder.get());
MOZ_ASSERT(mEncoder);
MOZ_ASSERT(mEncoderThread);
@ -249,6 +252,7 @@ public:
StreamTime aTrackOffset,
const MediaSegment& aQueuedMedia) override
{
TRACE_COMMENT("Encoder %p", mEncoder.get());
MOZ_ASSERT(mEncoder);
MOZ_ASSERT(mEncoderThread);
@ -291,6 +295,7 @@ public:
void SetCurrentFrames(const VideoSegment& aMedia) override
{
TRACE_COMMENT("Encoder %p", mEncoder.get());
MOZ_ASSERT(mEncoder);
MOZ_ASSERT(mEncoderThread);

View File

@ -29,6 +29,8 @@ if CONFIG['MOZ_WEBM_ENCODER']:
]
LOCAL_INCLUDES += ['/media/libyuv/libyuv/include']
DEFINES['TRACING'] = True
FINAL_LIBRARY = 'xul'
# These includes are from Android JB, for use of MediaCodec.

View File

@ -81,6 +81,7 @@ if CONFIG['MOZ_WEBRTC']:
XPIDL_SOURCES += [
'nsIAudioDeviceInfo.idl',
'nsIAutoplay.idl',
'nsIDOMNavigatorUserMedia.idl',
'nsIMediaManager.idl',
]

17
dom/media/nsIAutoplay.idl Normal file
View File

@ -0,0 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, uuid(048a24f6-c4d6-47bc-bea2-f6038d1db80a)]
interface nsIAutoplay : nsISupports
{
/*
* Possible values for the "media.autoplay.default" preference.
*/
const uint32_t ALLOWED = 0;
const uint32_t BLOCKED = 1;
const uint32_t PROMPT = 2;
};

View File

@ -14,7 +14,7 @@
let manager = new MediaTestManager;
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
window.info = function(msg, token) {
@ -71,7 +71,7 @@ function createTestArray()
/**
* Main test function for different autoplay cases without user interaction.
*
* When the pref "media.autoplay.enabled" is false and the pref
* When the pref "media.autoplay.default" is 1 and the pref
* "media.autoplay.enabled.user-gestures-needed" is true, we only allow
* audible media to autoplay after the website has been activated by specific
* user gestures. However, inaudible media won't be restricted.
@ -152,4 +152,4 @@ async function testAutoplayKeyword(test, token) {
removeNodeAndSource(element);
}
</script>
</script>

View File

@ -14,7 +14,7 @@
// Tests that videos can only play audibly in windows/frames
// which have been activated by same-origin user gesture.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
SpecialPowers.pushPrefEnv({'set': gTestPrefs}, () => {

View File

@ -15,7 +15,7 @@
// Tests that we gesture activate on mousedown and keydown.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => {
@ -52,4 +52,4 @@
</pre>
</body>
</html>
</html>

View File

@ -18,7 +18,7 @@
// don't gesture activate documents, and don't unblock
// audible autoplay.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => {
@ -44,4 +44,4 @@
</pre>
</body>
</html>
</html>

View File

@ -15,7 +15,7 @@
// Tests that origins with "autoplay-media" permission can autoplay.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true],
// Note: permission prompt disabled, as we want immediate
// notification in this test that an origin is blocked.

View File

@ -19,7 +19,7 @@
// Tests that videos which have no audio track will play if play()
// is called before the video has reached readyState >= HAVE_METADATA.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => {
@ -70,4 +70,4 @@
</pre>
</body>
</html>
</html>

View File

@ -19,7 +19,7 @@
// Tests that videos can only play audibly in windows/frames
// which have been activated by same-origin user gesture.
gTestPrefs.push(["media.autoplay.enabled", false],
gTestPrefs.push(["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]);
SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => {
@ -61,4 +61,4 @@
</pre>
</body>
</html>
</html>

View File

@ -439,7 +439,7 @@ function setupEnvironment() {
["media.navigator.video.default_width", 320],
["media.navigator.video.default_height", 240],
["media.navigator.video.max_fr", 10],
["media.autoplay.enabled", true]
["media.autoplay.default", Ci.nsIAutoplay.ALLOWED]
);
}

View File

@ -25,7 +25,7 @@ SimpleTest.registerCleanupFunction(function() {
SpecialPowers.removeAsyncObserver(observer, "webaudio-node-demise");
});
SpecialPowers.pushPrefEnv({"set": [["media.autoplay.enabled", false],
SpecialPowers.pushPrefEnv({"set": [["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]]},
startTest);

View File

@ -17,6 +17,7 @@
#include "nsIFilePicker.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "Tracing.h"
#ifdef MOZ_WIDGET_ANDROID
#include "nsISupportsUtils.h"
@ -330,6 +331,8 @@ MediaEngineDefaultVideoSource::Pull(const RefPtr<const AllocationHandle>& aHandl
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle)
{
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
aStream.get(), aTrackID);
// AppendFrame takes ownership of `segment`
VideoSegment segment;
@ -542,6 +545,8 @@ MediaEngineDefaultAudioSource::Pull(const RefPtr<const AllocationHandle>& aHandl
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle)
{
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
aStream.get(), aTrackID);
AudioSegment segment;
// avoid accumulating rounding errors
TrackTicks desired = aStream->TimeToTicksRoundUp(aStream->GraphRate(), aDesiredTime);

View File

@ -12,6 +12,7 @@
#include "mozilla/ErrorNames.h"
#include "mozilla/RefPtr.h"
#include "nsIPrefService.h"
#include "Tracing.h"
#include "VideoFrameUtils.h"
#include "VideoUtils.h"
#include "webrtc/common_video/include/video_frame_buffer.h"
@ -486,6 +487,8 @@ MediaEngineRemoteVideoSource::Pull(const RefPtr<const AllocationHandle>& aHandle
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle)
{
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
aStream.get(), aTrackID);
MutexAutoLock lock(mMutex);
if (mState == kReleased) {
// We end the track before deallocating, so this is safe.

View File

@ -25,6 +25,7 @@
#include "nsServiceManagerUtils.h"
#include "nsIPrefService.h"
#include "MediaTrackConstraints.h"
#include "Tracing.h"
namespace mozilla {
@ -257,6 +258,8 @@ MediaEngineTabVideoSource::Pull(const RefPtr<const AllocationHandle>& aHandle,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle)
{
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
aStream.get(), aTrackID);
VideoSegment segment;
RefPtr<layers::Image> image;
gfx::IntSize imageSize;

View File

@ -788,6 +788,8 @@ MediaEngineWebRTCMicrophoneSource::Pull(const RefPtr<const AllocationHandle>& aH
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle)
{
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p track %i",
aStream.get(), aTrackID);
StreamTime delta;
{

View File

@ -57,6 +57,7 @@
#endif
#ifdef XP_WIN
#include <windows.h>
#include "mozilla/WindowsVersion.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#endif
@ -2522,6 +2523,22 @@ gfxPlatform::WebRenderEnvvarEnabled()
return (env && *env == '1');
}
/* This is a pretty conservative check for having a battery.
* For now we'd rather err on the side of thinking we do. */
static bool HasBattery()
{
#ifdef XP_WIN
SYSTEM_POWER_STATUS status;
const BYTE NO_SYSTEM_BATTERY = 128;
if (GetSystemPowerStatus(&status)) {
if (status.BatteryFlag == NO_SYSTEM_BATTERY) {
return false;
}
}
#endif
return true;
}
void
gfxPlatform::InitWebRenderConfig()
{
@ -2572,7 +2589,7 @@ gfxPlatform::InitWebRenderConfig()
int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER,
discardFailureId, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK && !HasBattery()) {
featureWebRender.UserEnable("Qualified enabled by pref ");
} else {
featureWebRender.ForceDisable(FeatureStatus::Blocked,

View File

@ -345,8 +345,6 @@ __END
our $totalData = 0;
print HEADER "#pragma pack(1)\n\n";
sub sprintCharProps2_short
{
my $usv = shift;
@ -364,8 +362,6 @@ struct nsCharProps2 {
|;
&genTables("CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
print HEADER "#pragma pack()\n\n";
sub sprintHanVariants
{
my $baseUsv = shift;

View File

@ -47,9 +47,6 @@ for the Unicode Character Database, for Version 11.0.0 of the Unicode Standard.
#ifndef NS_UNICODE_SCRIPT_CODES
#define NS_UNICODE_SCRIPT_CODES
#pragma pack(1)
struct nsCharProps2 {
// Currently only 4 bits are defined here, so 4 more could be added without
// affecting the storage requirements for this struct. Or we could pack two
@ -58,8 +55,6 @@ struct nsCharProps2 {
unsigned char mIdType:2;
};
#pragma pack()
namespace mozilla {
namespace unicode {
enum class Script : int16_t {

View File

@ -162,7 +162,7 @@ uint8_t*
js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
{
VexOperandType type = VEX_PS;
uint32_t opcode = OP_HLT;
uint32_t opcode = OP_NOP_00;
uint8_t modrm = 0;
uint8_t sib = 0;
uint8_t rex = 0;

View File

@ -1730,6 +1730,8 @@ MediaPipelineTransmit::PipelineListener::NotifyQueuedChanges(
return;
}
TRACE_AUDIO_CALLBACK_COMMENT("Audio");
if (mDirectConnect) {
// ignore non-direct data if we're also getting direct data
return;
@ -2000,7 +2002,7 @@ private:
void NotifyPullImpl(StreamTime aDesiredTime)
{
TRACE();
TRACE_AUDIO_CALLBACK_COMMENT("Track %i", mTrackId);
uint32_t samplesPer10ms = mRate / 100;
// mSource's rate is not necessarily the same as the graph rate, since there
@ -2179,6 +2181,7 @@ public:
// Implement MediaStreamListener
void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
{
TRACE_AUDIO_CALLBACK_COMMENT("Track %i", mTrackId);
MutexAutoLock lock(mMutex);
RefPtr<Image> image = mImage;

View File

@ -26,4 +26,6 @@ UNIFIED_SOURCES += [
'TransportLayerPacketDumper.cpp',
]
DEFINES['TRACING'] = True
FINAL_LIBRARY = 'xul'

View File

@ -54,7 +54,7 @@
<PreferenceCategory android:title="@string/pref_category_media">
<SwitchPreference android:key="media.autoplay.enabled"
<SwitchPreference android:key="media.autoplay.default"
android:title="@string/pref_media_autoplay_enabled"
android:summary="@string/pref_media_autoplay_enabled_summary" />

View File

@ -14,6 +14,7 @@ import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.widget.AllCapsTextView;
import org.mozilla.gecko.widget.FocusableDatePicker;
import org.mozilla.gecko.widget.DateTimePicker;
import org.mozilla.gecko.widget.FocusableTimePicker;
import android.content.Context;
import android.content.res.Configuration;
@ -210,7 +211,8 @@ public abstract class PromptInput {
DateTimePicker.PickersState.WEEK, mMinValue, mMaxValue);
mView = (View)input;
} else if (mType.equals("time")) {
TimePicker input = new TimePicker(context);
// FocusableDatePicker allow us to have priority in responding to scroll events.
TimePicker input = new FocusableTimePicker(context);
input.setIs24HourView(DateFormat.is24HourFormat(context));
GregorianCalendar calendar = new GregorianCalendar();

View File

@ -0,0 +1,49 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewParent;
import android.widget.TimePicker;
/**
* This is based on the platform's {@link TimePicker}.<br>
* The only difference is that it will prevent it's parent from receiving touch events.
*/
public class FocusableTimePicker extends TimePicker {
public FocusableTimePicker(Context context) {
super(context);
}
public FocusableTimePicker(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FocusableTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@SuppressLint("NewApi")
public FocusableTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ViewParent parentView = getParent();
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (parentView != null) {
parentView.requestDisallowInterceptTouchEvent(true);
}
}
return false;
}
}

View File

@ -114,21 +114,42 @@ public class CrashReporterService extends JobIntentService {
Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
if (inFile.renameTo(outFile))
return true;
FileInputStream inStream = null;
FileOutputStream outStream = null;
try {
outFile.createNewFile();
Log.i(LOGTAG, "couldn't rename minidump file");
// so copy it instead
FileChannel inChannel = new FileInputStream(inFile).getChannel();
FileChannel outChannel = new FileOutputStream(outFile).getChannel();
inStream = new FileInputStream(inFile);
outStream = new FileOutputStream(outFile);
FileChannel inChannel = inStream.getChannel();
FileChannel outChannel = outStream.getChannel();
long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
if (transferred > 0)
inFile.delete();
} catch (Exception e) {
Log.e(LOGTAG, "exception while copying minidump file: ", e);
return false;
} finally {
// always try and close inStream and outStream while taking into
// consideration that `.close` throws as well.
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
Log.e(LOGTAG, "inStream could not be closed: ", e);
return false;
} finally {
try {
if (outStream != null) {
outStream.close();
}
} catch (IOException e) {
Log.e(LOGTAG, "outStream could not be closed: ", e);
return false;
}
}
}
return true;
}
@ -260,12 +281,23 @@ public class CrashReporterService extends JobIntentService {
}
private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
FileReader fileReader = null;
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
fileReader = new FileReader(filePath);
BufferedReader reader = new BufferedReader(fileReader);
return readStringsFromReader(reader, stringMap);
} catch (Exception e) {
Log.e(LOGTAG, "exception while reading strings: ", e);
return false;
} finally {
try {
if (fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
Log.e(LOGTAG, "exception while closing file: ", e);
return false;
}
}
}
@ -321,13 +353,13 @@ public class CrashReporterService extends JobIntentService {
if (spec == null) {
return;
}
HttpURLConnection conn = null;
try {
final URL url = new URL(URLDecoder.decode(spec, "UTF-8"));
final URI uri = new URI(url.getProtocol(), url.getUserInfo(),
url.getHost(), url.getPort(),
url.getPath(), url.getQuery(), url.getRef());
HttpURLConnection conn = (HttpURLConnection) ProxySelector.openConnectionWithProxy(uri);
conn = (HttpURLConnection) ProxySelector.openConnectionWithProxy(uri);
conn.setRequestMethod("POST");
String boundary = generateBoundary();
conn.setDoOutput(true);
@ -398,6 +430,10 @@ public class CrashReporterService extends JobIntentService {
Log.e(LOGTAG, "exception during send: ", e);
} catch (URISyntaxException e) {
Log.e(LOGTAG, "exception during new URI: ", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}

View File

@ -1711,7 +1711,7 @@ public class GeckoAppShell
final GeckoProfile profile = GeckoThread.getActiveProfile();
if (profile != null) {
File lock = profile.getFile(".parentlock");
return lock.exists() && lock.delete();
return lock != null && lock.exists() && lock.delete();
}
return false;
}

View File

@ -473,9 +473,11 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
@Override
protected Void doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader in = null;
try {
URI finalURI = new URI(mURL + "&signedRequest=" + URLEncoder.encode(new String(mDrmRequest), "UTF-8"));
HttpURLConnection urlConnection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(finalURI);
urlConnection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(finalURI);
urlConnection.setRequestMethod("POST");
if (DEBUG) Log.d(LOGTAG, "Provisioning, posting url =" + finalURI.toString());
@ -489,8 +491,7 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
int responseCode = urlConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in =
new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StringUtils.UTF_8));
in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StringUtils.UTF_8));
String inputLine;
StringBuffer response = new StringBuffer();
@ -508,6 +509,17 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
Log.e(LOGTAG, "Got exception during posting provisioning request ...", e);
} catch (URISyntaxException e) {
Log.e(LOGTAG, "Got exception during creating uri ...", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
Log.e(LOGTAG, "Exception during closing in ...", e);
}
}
return null;
}

View File

@ -563,12 +563,14 @@ pref("media.recorder.audio_node.enabled", false);
// to keep up under load. Useful for tests but beware of memory consumption!
pref("media.recorder.video.frame_drops", true);
// Whether to autostart a media element with an |autoplay| attribute
pref("media.autoplay.enabled", true);
// Whether to autostart a media element with an |autoplay| attribute.
// ALLOWED=0, BLOCKED=1, PROMPT=2, defined in dom/media/Autoplay.idl
pref("media.autoplay.default", 0);
// If "media.autoplay.enabled" is false, and this pref is true, then audible media
// would only be allowed to autoplay after website has been activated by specific
// user gestures, but the non-audible media won't be restricted.
// If "media.autoplay.default" is not ALLOWED, and this pref is true,
// then audible media would only be allowed to autoplay after website has
// been activated by specific user gestures, but non-audible
// media won't be restricted.
#ifdef NIGHTLY_BUILD
pref("media.autoplay.enabled.user-gestures-needed", false);
#endif

View File

@ -154,7 +154,7 @@ public:
// TODO (bug 1062823): from Sqlite 3.7.11 on, rollback won't ever return
// a busy error, so this handling can be removed.
nsresult rv = NS_OK;
nsresult rv;
do {
rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("ROLLBACK"));
if (rv == NS_ERROR_STORAGE_BUSY)

View File

@ -30,6 +30,7 @@ config = {
"clobber",
"download-and-extract",
"populate-webroot",
"install-chrome",
"create-virtualenv",
"install",
"run-tests",

View File

@ -29,6 +29,7 @@ config = {
"clobber",
"download-and-extract",
"populate-webroot",
"install-chrome",
"create-virtualenv",
"install",
"run-tests",

View File

@ -170,25 +170,42 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin):
# mozharness/base/script.py.self.platform_name will return one of:
# 'linux64', 'linux', 'macosx', 'win64', 'win32'
base_url = "http://commondatastorage.googleapis.com/chromium-browser-snapshots"
# note: temporarily use a specified chromium revision number to download; however
# in the future we will be using a fetch task to get a new chromium (Bug 1476372)
if 'mac' in self.platform_name():
chrome_archive_file = "googlechrome.dmg"
chrome_url = "https://dl.google.com/chrome/mac/stable/GGRO/%s" % chrome_archive_file
self.chrome_path = os.path.join(self.chrome_dest, 'Google Chrome.app',
'Contents', 'MacOS', 'Google Chrome')
# for now hardcoding a revision; but change this to update to newer version; from:
# http://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/LAST_CHANGE
chromium_rev = "575625"
chrome_archive_file = "chrome-mac.zip"
chrome_url = "%s/Mac/%s/%s" % (base_url, chromium_rev, chrome_archive_file)
self.chrome_path = os.path.join(self.chrome_dest, 'chrome-mac', 'Chromium.app',
'Contents', 'MacOS', 'Chromium')
elif 'linux' in self.platform_name():
chrome_archive_file = "google-chrome-stable_current_amd64.deb"
chrome_url = "https://dl.google.com/linux/direct/%s" % chrome_archive_file
self.chrome_path = os.path.join(self.chrome_dest, 'opt', 'google',
'chrome', 'google-chrome')
# for now hardcoding a revision; but change this to update to newer version; from:
# http://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/LAST_CHANGE
chromium_rev = "575640"
chrome_archive_file = "chrome-linux.zip"
chrome_url = "%s/Linux_x64/%s/%s" % (base_url, chromium_rev, chrome_archive_file)
self.chrome_path = os.path.join(self.chrome_dest, 'chrome-linux', 'chrome')
else:
# windows 7/10
# for now hardcoding a revision; but change this to update to newer version; from:
# http://commondatastorage.googleapis.com/chromium-browser-snapshots/Win_x64/LAST_CHANGE
chromium_rev = "575637"
chrome_archive_file = "chrome-win32.zip" # same zip name for win32/64
# url is different for win32/64
if '64' in self.platform_name():
chrome_archive_file = "standalonesetup64.exe"
chrome_url = "%s/Win_x64/%s/%s" % (base_url, chromium_rev, chrome_archive_file)
else:
chrome_archive_file = "standalonesetup.exe"
chrome_url = "https://dl.google.com/chrome/install/%s" % chrome_archive_file
chrome_url = "%s/Win_x32/%s/%s" % (base_url, chromium_rev, chrome_archive_file)
self.chrome_path = os.path.join(self.chrome_dest, 'chrome-win32', 'Chrome.exe')
chrome_archive = os.path.join(self.chrome_dest, chrome_archive_file)
@ -205,28 +222,7 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin):
self.download_file(chrome_url, parent_dir=self.chrome_dest)
commands = []
if 'mac' in self.platform_name():
# open the chrome dmg to have it mounted
commands.append(["open", chrome_archive_file])
# then extract/copy app from mnt to our folder
commands.append(["cp", "-r", "/Volumes/Google Chrome/Google Chrome.app", "."])
elif 'linux' in self.platform_name():
# on linux in order to avoid needing sudo, we unpack the google chrome deb
# manually using ar, and then unpack the contents of the ar after that
commands.append(["ar", "x", chrome_archive_file])
# now we have the google chrome .deb file unpacked using ar, we need to
# unpack the tar.xz file that was inside the .deb
commands.append(['tar', '-xJf',
os.path.join(self.chrome_dest, 'data.tar.xz'),
'-C', self.chrome_dest])
else:
# TODO: Bug 1473389 - finish this for windows 7 (x32) and winows 10 (x64)
pass
commands.append(['unzip', '-q', '-o', chrome_archive_file, '-d', self.chrome_dest])
# now run the commands to unpack / install google chrome
for next_command in commands:

View File

@ -87,7 +87,7 @@ Damp.prototype = {
// as it slow down next executions almost like a cold start.
// See minimizeMemoryUsage code to justify the 3 iterations and the setTimeout:
// https://searchfox.org/mozilla-central/source/xpcom/base/nsMemoryReporterManager.cpp#2574-2585
// https://searchfox.org/mozilla-central/rev/33c21c060b7f3a52477a73d06ebcb2bf313c4431/xpcom/base/nsMemoryReporterManager.cpp#2574-2585,2591-2594
for (let i = 0; i < 3; i++) {
// See minimizeMemoryUsage code here to justify the GC+CC+GC:
// https://searchfox.org/mozilla-central/rev/be78e6ea9b10b1f5b2b3b013f01d86e1062abb2b/dom/base/nsJSEnvironment.cpp#341-349

View File

@ -55,7 +55,6 @@ const {
LocaleData,
NoCloneSpreadArgs,
SchemaAPIInterface,
defineLazyGetter,
withHandlingUserInput,
} = ExtensionCommon;
@ -611,10 +610,6 @@ class BrowserExtensionContent extends EventEmitter {
this.MESSAGE_EMIT_EVENT = `Extension:EmitEvent:${this.instanceId}`;
Services.cpmm.addMessageListener(this.MESSAGE_EMIT_EVENT, this);
defineLazyGetter(this, "scripts", () => {
return data.contentScripts.map(scriptData => new ExtensionContent.Script(this, scriptData));
});
this.webAccessibleResources = data.webAccessibleResources.map(res => new MatchGlob(res));
this.permissions = data.permissions;
this.optionalPermissions = data.optionalPermissions;
@ -1034,6 +1029,9 @@ class ChildAPIManager {
close() {
this.messageManager.sendAsyncMessage("API:CloseProxyContext", {childId: this.id});
this.messageManager.removeMessageListener("API:CallResult", this);
MessageChannel.removeListener(this.messageManager, "API:RunListener", this);
if (this.updatePermissions) {
this.context.extension.off("add-permissions", this.updatePermissions);
this.context.extension.off("remove-permissions", this.updatePermissions);

View File

@ -274,6 +274,15 @@ defineLazyGetter(BrowserExtensionContent.prototype, "authorCSSCode", function()
// Represents a content script.
class Script {
/**
* @param {BrowserExtensionContent} extension
* @param {WebExtensionContentScript|object} matcher
* An object with a "matchesWindow" method and content script execution
* details. This is usually a plain WebExtensionContentScript object,
* except when the script is run via `tabs.executeScript`. In this
* case, the object may have some extra properties:
* wantReturnValue, removeCSS, cssOrigin, jsCode
*/
constructor(extension, matcher) {
this.extension = extension;
this.matcher = matcher;
@ -528,17 +537,6 @@ class ContentScriptContextChild extends BaseContext {
this.isExtensionPage = contentPrincipal.equals(extensionPrincipal);
let principal;
if (ssm.isSystemPrincipal(contentPrincipal)) {
// Make sure we don't hand out the system principal by accident.
// also make sure that the null principal has the right origin attributes
principal = ssm.createNullPrincipal(attrs);
} else if (this.isExtensionPage) {
principal = contentPrincipal;
} else {
principal = [contentPrincipal, extensionPrincipal];
}
if (this.isExtensionPage) {
// This is an iframe with content script API enabled and its principal
// should be the contentWindow itself. We create a sandbox with the
@ -553,6 +551,14 @@ class ContentScriptContextChild extends BaseContext {
isWebExtensionContentScript: true,
});
} else {
let principal;
if (ssm.isSystemPrincipal(contentPrincipal)) {
// Make sure we don't hand out the system principal by accident.
// Also make sure that the null principal has the right origin attributes.
principal = ssm.createNullPrincipal(attrs);
} else {
principal = [contentPrincipal, extensionPrincipal];
}
// This metadata is required by the Developer Tools, in order for
// the content script to be associated with both the extension and
// the tab holding the content page.

View File

@ -195,8 +195,8 @@ DocumentManager = {
});
},
initExtension(extension) {
this.injectExtensionScripts(extension);
initExtension(policy) {
this.injectExtensionScripts(policy);
},
// Listeners
@ -209,11 +209,11 @@ DocumentManager = {
// Script loading
injectExtensionScripts(extension) {
injectExtensionScripts(policy) {
for (let window of this.enumerateWindows()) {
let runAt = {document_start: [], document_end: [], document_idle: []};
for (let script of extension.contentScripts) {
for (let script of policy.contentScripts) {
if (script.matchesWindow(window)) {
runAt[script.runAt].push(script);
}
@ -296,7 +296,7 @@ DocumentManager = {
ExtensionManager = {
// WeakMap<WebExtensionPolicy, Map<string, WebExtensionContentScript>>
registeredContentScripts: new DefaultWeakMap((extension) => new Map()),
registeredContentScripts: new DefaultWeakMap((policy) => new Map()),
init() {
MessageChannel.setupMessageManagers([Services.cpmm]);

View File

@ -17,7 +17,7 @@ Cu.importGlobalProperties(["URL"]);
// Make sure media pre-loading is enabled on Android so that our <audio> and
// <video> elements trigger the expected requests.
Services.prefs.setBoolPref("media.autoplay.enabled", true);
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.ALLOWED);
Services.prefs.setIntPref("media.preload.default", 3);
// Increase the length of the code samples included in CSP reports so that we

View File

@ -0,0 +1,233 @@
"use strict";
const server = createHttpServer();
server.registerDirectory("/data/", do_get_file("data"));
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
// ExtensionContent.jsm needs to know when it's running from xpcshell,
// to use the right timeout for content scripts executed at document_idle.
ExtensionTestUtils.mockAppInfo();
// Each of these tests do the following:
// 1. Load document to create an extension context (instance of BaseContext).
// 2. Get weak reference to that context.
// 3. Unload the document.
// 4. Force GC and check that the weak reference has been invalidated.
async function reloadTopContext(contentPage) {
await contentPage.spawn(null, async () => {
let {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm", {});
let windowNukeObserved = TestUtils.topicObserved("inner-window-nuked");
info(`Reloading top-level document`);
this.content.location.reload();
await windowNukeObserved;
info(`Reloaded top-level document`);
});
}
async function assertContextReleased(contentPage, description) {
await contentPage.spawn(description, async assertionDescription => {
// Force GC, see https://searchfox.org/mozilla-central/rev/b0275bc977ad7fda615ef34b822bba938f2b16fd/testing/talos/talos/tests/devtools/addon/content/damp.js#84-98
// and https://searchfox.org/mozilla-central/rev/33c21c060b7f3a52477a73d06ebcb2bf313c4431/xpcom/base/nsMemoryReporterManager.cpp#2574-2585,2591-2594
let gcCount = 0;
while (gcCount < 30 && this.contextWeakRef.get() !== null) {
++gcCount;
Cu.forceGC();
Cu.forceCC();
Cu.forceGC();
await new Promise(resolve => this.content.setTimeout(resolve, 0));
}
// The above loop needs to be repeated at most 3 times according to MinimizeMemoryUsage:
// https://searchfox.org/mozilla-central/rev/6f86cc3479f80ace97f62634e2c82a483d1ede40/xpcom/base/nsMemoryReporterManager.cpp#2644-2647
Assert.lessOrEqual(gcCount, 3, `Context should have been GCd within a few GC attempts.`);
// Each test will set this.contextWeakRef before unloading the document.
Assert.ok(!this.contextWeakRef.get(), assertionDescription);
});
}
add_task(async function test_ContentScriptContextChild_in_child_frame() {
let extensionData = {
manifest: {
content_scripts: [
{
matches: ["http://*/*/file_iframe.html"],
js: ["content_script.js"],
all_frames: true,
},
],
},
files: {
"content_script.js": "browser.test.sendMessage('contentScriptLoaded');",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(`${BASE_URL}/file_toplevel.html`);
await extension.awaitMessage("contentScriptLoaded");
await contentPage.spawn(extension.id, async extensionId => {
let {DocumentManager} = ChromeUtils.import("resource://gre/modules/ExtensionContent.jsm", {});
let frame = this.content.document.querySelector("iframe[src*='file_iframe.html']");
let context = DocumentManager.getContext(extensionId, frame.contentWindow);
Assert.ok(context, "Got content script context");
this.contextWeakRef = Cu.getWeakReference(context);
frame.remove();
});
await assertContextReleased(contentPage, "ContentScriptContextChild should have been released");
await contentPage.close();
await extension.unload();
});
add_task(async function test_ContentScriptContextChild_in_toplevel() {
let extensionData = {
manifest: {
content_scripts: [
{
matches: ["http://*/*/file_sample.html"],
js: ["content_script.js"],
all_frames: true,
},
],
},
files: {
"content_script.js": "browser.test.sendMessage('contentScriptLoaded');",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(`${BASE_URL}/file_sample.html`);
await extension.awaitMessage("contentScriptLoaded");
await contentPage.spawn(extension.id, async extensionId => {
let {DocumentManager} = ChromeUtils.import("resource://gre/modules/ExtensionContent.jsm", {});
let context = DocumentManager.getContext(extensionId, this.content);
Assert.ok(context, "Got content script context");
this.contextWeakRef = Cu.getWeakReference(context);
});
await reloadTopContext(contentPage);
await extension.awaitMessage("contentScriptLoaded");
await assertContextReleased(contentPage, "ContentScriptContextChild should have been released");
await contentPage.close();
await extension.unload();
});
add_task(async function test_ExtensionPageContextChild_in_child_frame() {
let extensionData = {
files: {
"iframe.html": `
<!DOCTYPE html><meta charset="utf8">
<script src="script.js"></script>
`,
"toplevel.html": `
<!DOCTYPE html><meta charset="utf8">
<iframe src="iframe.html"></iframe>
`,
"script.js": "browser.test.sendMessage('extensionPageLoaded');",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(`moz-extension://${extension.uuid}/toplevel.html`, {
extension,
remote: extension.extension.remote,
});
await extension.awaitMessage("extensionPageLoaded");
await contentPage.spawn(extension.id, async extensionId => {
let {ExtensionPageChild} = ChromeUtils.import("resource://gre/modules/ExtensionPageChild.jsm", {});
let frame = this.content.document.querySelector("iframe[src*='iframe.html']");
let innerWindowID =
frame.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
let context = ExtensionPageChild.extensionContexts.get(innerWindowID);
Assert.ok(context, "Got extension page context for child frame");
this.contextWeakRef = Cu.getWeakReference(context);
frame.remove();
});
await assertContextReleased(contentPage, "ExtensionPageContextChild should have been released");
await contentPage.close();
await extension.unload();
});
add_task(async function test_ExtensionPageContextChild_in_toplevel() {
let extensionData = {
files: {
"toplevel.html": `
<!DOCTYPE html><meta charset="utf8">
<script src="script.js"></script>
`,
"script.js": "browser.test.sendMessage('extensionPageLoaded');",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(`moz-extension://${extension.uuid}/toplevel.html`, {
extension,
remote: extension.extension.remote,
});
await extension.awaitMessage("extensionPageLoaded");
await contentPage.spawn(extension.id, async extensionId => {
let {ExtensionPageChild} = ChromeUtils.import("resource://gre/modules/ExtensionPageChild.jsm", {});
let innerWindowID = this.content
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
let context = ExtensionPageChild.extensionContexts.get(innerWindowID);
Assert.ok(context, "Got extension page context for top-level document");
this.contextWeakRef = Cu.getWeakReference(context);
});
await reloadTopContext(contentPage);
await extension.awaitMessage("extensionPageLoaded");
// For some unknown reason, the context cannot forcidbly be released by the
// garbage collector unless we wait for a short while.
await contentPage.spawn(null, async () => {
let start = Date.now();
// The treshold was found after running this subtest only, 300 times
// in a release build (100 of xpcshell, xpcshell-e10s and xpcshell-remote).
// With treshold 8, almost half of the tests complete after a 17-18 ms delay.
// With treshold 7, over half of the tests complete after a 13-14 ms delay,
// with 12 failures in 300 tests runs.
// Let's double that number to have a safety margin.
for (let i = 0; i < 15; ++i) {
await new Promise(resolve => this.content.setTimeout(resolve, 0));
}
info(`Going to GC after waiting for ${Date.now() - start} ms.`);
});
await assertContextReleased(contentPage, "ExtensionPageContextChild should have been released");
await contentPage.close();
await extension.unload();
});

View File

@ -8,6 +8,7 @@ skip-if = debug # Bug 1407501
skip-if = (os == "android" && debug) || (os == "win" && debug) # Windows: Bug 1438796
[test_ext_contentscript_xrays.js]
[test_ext_contentScripts_register.js]
[test_ext_contexts_gc.js]
skip-if = os == "android"
[test_ext_adoption_with_xrays.js]
[test_ext_shadowdom.js]

View File

@ -47,6 +47,7 @@ add_task(async function test_urlbar_new_URL() {
add_task(async function test_urlbar_fragment_enter() {
await withTestPage(function(aBrowser) {
gURLBar.focus();
gURLBar.select();
EventUtils.synthesizeKey("KEY_ArrowRight");
EventUtils.sendString("#fragment");
EventUtils.synthesizeKey("KEY_Enter");

View File

@ -192,5 +192,5 @@ nsXRemoteService::EnsureAtoms(void)
sMozUserAtom = XAtoms[i++];
sMozProfileAtom = XAtoms[i++];
sMozProgramAtom = XAtoms[i++];
sMozCommandLineAtom = XAtoms[i++];
sMozCommandLineAtom = XAtoms[i];
}

View File

@ -159,5 +159,13 @@ KeyedStackCapturer::Clear()
mStacks.Clear();
}
size_t
KeyedStackCapturer::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
size_t n = 0;
n += mStackInfos.SizeOfExcludingThis(aMallocSizeOf);
n += mStacks.SizeOfExcludingThis();
return n;
}
} // namespace Telemetry
} // namespace mozilla

View File

@ -46,6 +46,8 @@ public:
*/
void Clear();
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
/**
* Describes how often a stack was captured.

View File

@ -363,24 +363,6 @@ browser.usage:
- 'main'
- 'content'
# The following section contains the session restore scalars.
browser.session.restore:
worker_restart_count:
bug_numbers:
- 1402267
description: >
A counter incremented every time the SessionFile worker is restarted due
to too many failures, as defined in the browser.sessionstore.max_write_failures
pref.
expires: "64"
kind: uint
notification_emails:
- mdeboer@mozilla.com
- session-restore-telemetry-alerts@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'main'
extensions.updates:
rdf:
bug_numbers:

View File

@ -148,7 +148,6 @@ public:
#if defined(MOZ_GECKO_PROFILER)
static void DoStackCapture(const nsACString& aKey);
#endif
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
struct Stat {
uint32_t hitCount;
uint32_t totalTime;
@ -220,10 +219,70 @@ NS_IMETHODIMP
TelemetryImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
MOZ_COLLECT_REPORT(
"explicit/telemetry", KIND_HEAP, UNITS_BYTES,
SizeOfIncludingThis(TelemetryMallocSizeOf),
"Memory used by the telemetry system.");
mozilla::MallocSizeOf aMallocSizeOf = TelemetryMallocSizeOf;
#define COLLECT_REPORT(name, size, desc) \
MOZ_COLLECT_REPORT(name, KIND_HEAP, UNITS_BYTES, size, desc)
COLLECT_REPORT("explicit/telemetry/impl", aMallocSizeOf(this),
"Memory used by the Telemetry core implemenation");
COLLECT_REPORT("explicit/telemetry/histogram/shallow",
TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf),
"Memory used by the Telemetry Histogram implementation");
COLLECT_REPORT("explicit/telemetry/scalar/shallow",
TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf),
"Memory used by the Telemetry Scalar implemenation");
COLLECT_REPORT("explicit/telemetry/WebRTC",
mWebrtcTelemetry.SizeOfExcludingThis(aMallocSizeOf),
"Memory used by WebRTC Telemetry");
{ // Scope for mHashMutex lock
MutexAutoLock lock(mHashMutex);
COLLECT_REPORT("explicit/telemetry/PrivateSQL",
mPrivateSQL.SizeOfExcludingThis(aMallocSizeOf),
"Memory used by the PrivateSQL Telemetry");
COLLECT_REPORT("explicit/telemetry/SanitizedSQL",
mSanitizedSQL.SizeOfExcludingThis(aMallocSizeOf),
"Memory used by the SanitizedSQL Telemetry");
}
if (sTelemetryIOObserver) {
COLLECT_REPORT("explicit/telemetry/IOObserver",
sTelemetryIOObserver->SizeOfIncludingThis(aMallocSizeOf),
"Memory used by the Telemetry IO Observer");
}
#if defined(MOZ_GECKO_PROFILER)
COLLECT_REPORT("explicit/telemetry/StackCapturer",
mStackCapturer.SizeOfExcludingThis(aMallocSizeOf),
"Memory used by the Telemetry Stack capturer");
#endif
COLLECT_REPORT("explicit/telemetry/LateWritesStacks",
mLateWritesStacks.SizeOfExcludingThis(),
"Memory used by the Telemetry LateWrites Stack capturer");
COLLECT_REPORT("explicit/telemetry/Callbacks",
mCallbacks.ShallowSizeOfExcludingThis(aMallocSizeOf),
"Memory used by the Telemetry Callbacks array (shallow)");
COLLECT_REPORT("explicit/telemetry/histogram/data",
TelemetryHistogram::GetHistogramSizesOfIncludingThis(aMallocSizeOf),
"Memory used by Telemetry Histogram data");
COLLECT_REPORT("explicit/telemetry/scalar/data",
TelemetryScalar::GetScalarSizesOfIncludingThis(aMallocSizeOf),
"Memory used by Telemetry Scalar data");
COLLECT_REPORT("explicit/telemetry/event/data",
TelemetryEvent::SizeOfIncludingThis(aMallocSizeOf),
"Memory used by Telemetry Event data");
#undef COLLECT_REPORT
return NS_OK;
}
@ -1741,33 +1800,6 @@ TelemetryImpl::FlushBatchedChildTelemetry()
return NS_OK;
}
size_t
TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
size_t n = aMallocSizeOf(this);
n += TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += mWebrtcTelemetry.SizeOfExcludingThis(aMallocSizeOf);
{ // Scope for mHashMutex lock
MutexAutoLock lock(mHashMutex);
n += mPrivateSQL.SizeOfExcludingThis(aMallocSizeOf);
n += mSanitizedSQL.SizeOfExcludingThis(aMallocSizeOf);
}
// It's a bit gross that we measure this other stuff that lives outside of
// TelemetryImpl... oh well.
if (sTelemetryIOObserver) {
n += sTelemetryIOObserver->SizeOfIncludingThis(aMallocSizeOf);
}
n += TelemetryHistogram::GetHistogramSizesofIncludingThis(aMallocSizeOf);
n += TelemetryScalar::GetScalarSizesOfIncludingThis(aMallocSizeOf);
n += TelemetryEvent::SizeOfIncludingThis(aMallocSizeOf);
return n;
}
} // namespace

View File

@ -200,6 +200,8 @@ public:
bool IsExpired() const { return mIsExpired; }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
private:
typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
@ -1038,6 +1040,15 @@ KeyedHistogram::Clear()
mHistogramMap.Clear();
}
size_t
KeyedHistogram::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
size_t n = 0;
n += aMallocSizeOf(this);
n += mHistogramMap.SizeOfIncludingThis(aMallocSizeOf);
return n;
}
nsresult
KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
{
@ -2560,12 +2571,44 @@ TelemetryHistogram::GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf
}
size_t
TelemetryHistogram::GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf
TelemetryHistogram::GetHistogramSizesOfIncludingThis(mozilla::MallocSizeOf
aMallocSizeOf)
{
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
// TODO
return 0;
size_t n = 0;
// If we allocated the array, let's count the number of pointers in there and
// each entry's size.
if (gKeyedHistogramStorage) {
n += HistogramCount * size_t(ProcessID::Count) * sizeof(KeyedHistogram*);
for (size_t i = 0; i < HistogramCount * size_t(ProcessID::Count); ++i) {
if (gKeyedHistogramStorage[i] && gKeyedHistogramStorage[i] != gExpiredKeyedHistogram) {
n += gKeyedHistogramStorage[i]->SizeOfIncludingThis(aMallocSizeOf);
}
}
}
// If we allocated the array, let's count the number of pointers in there.
if (gHistogramStorage) {
n += HistogramCount * size_t(ProcessID::Count) * sizeof(Histogram*);
for (size_t i = 0; i < HistogramCount * size_t(ProcessID::Count); ++i) {
if (gHistogramStorage[i] && gHistogramStorage[i] != gExpiredHistogram) {
n += gHistogramStorage[i]->SizeOfIncludingThis(aMallocSizeOf);
}
}
}
// We only allocate the expired (keyed) histogram once.
if (gExpiredKeyedHistogram) {
n += gExpiredKeyedHistogram->SizeOfIncludingThis(aMallocSizeOf);
}
if (gExpiredHistogram) {
n += gExpiredHistogram->SizeOfIncludingThis(aMallocSizeOf);
}
return n;
}
////////////////////////////////////////////////////////////////////////

View File

@ -80,7 +80,7 @@ size_t
GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
size_t
GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
GetHistogramSizesOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
// These functions are only meant to be used for GeckoView persistence.
// They are responsible for updating in-memory probes with the data persisted

View File

@ -316,3 +316,59 @@ TEST_F(TelemetryTestFixture, ScalarEventSummary_Dynamic) {
// which all end up in the same place.
CheckKeyedUintScalar(kScalarName, kLongestEvent, cx.GetJSContext(), scalarsSnapshot, 2);
}
TEST_F(TelemetryTestFixture, WrongScalarOperator) {
AutoJSContextWithGlobal cx(mCleanGlobal);
// Make sure we don't get scalars from other tests.
Unused << mTelemetry->ClearScalars();
const uint32_t expectedValue = 1172015;
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, expectedValue);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, NS_LITERAL_STRING(EXPECTED_STRING));
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, true);
TelemetryScalar::DeserializationStarted();
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, 1447);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, 1447);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, true);
TelemetryScalar::ApplyPendingOperations();
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(false, cx.GetJSContext(), &scalarsSnapshot);
CheckStringScalar("telemetry.test.string_kind", cx.GetJSContext(), scalarsSnapshot, EXPECTED_STRING);
CheckBoolScalar("telemetry.test.boolean_kind", cx.GetJSContext(), scalarsSnapshot, true);
CheckUintScalar("telemetry.test.unsigned_int_kind", cx.GetJSContext(), scalarsSnapshot, expectedValue);
}
TEST_F(TelemetryTestFixture, WrongKeyedScalarOperator) {
AutoJSContextWithGlobal cx(mCleanGlobal);
// Make sure we don't get scalars from other tests.
Unused << mTelemetry->ClearScalars();
const uint32_t kExpectedUint = 1172017;
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key1"), kExpectedUint);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key2"), true);
TelemetryScalar::DeserializationStarted();
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key1"), false);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key2"), static_cast<uint32_t>(13));
TelemetryScalar::ApplyPendingOperations();
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
CheckKeyedUintScalar("telemetry.test.keyed_unsigned_int", "key1",
cx.GetJSContext(), scalarsSnapshot, kExpectedUint);
CheckKeyedBoolScalar("telemetry.test.keyed_boolean_kind", "key2",
cx.GetJSContext(), scalarsSnapshot, true);
}

View File

@ -246,8 +246,10 @@ Classifier::Open(nsIFile& aCacheDirectory)
void
Classifier::Close()
{
// Close will be called by PreShutdown, so it is important to note that
// Close will be called by PreShutdown, set |mUpdateInterrupted| here
// to abort an ongoing update if possible. It is important to note that
// things put here should not affect an ongoing update thread.
mUpdateInterrupted = true;
mIsClosed = true;
DropStores();
}

View File

@ -24,7 +24,7 @@ const PAGE_A1_A2_B3 = "https://example.com/browser/toolkit/content/tests/browser
function setup_test_preference() {
return SpecialPowers.pushPrefEnv({"set": [
["media.autoplay.enabled", false],
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true]
]});
}

View File

@ -4,7 +4,7 @@ function setup_test_preference(enableUserGesture) {
let state = enableUserGesture ? "enable" : "disable";
info(`- set pref : ${state} user gesture -`);
return SpecialPowers.pushPrefEnv({"set": [
["media.autoplay.enabled", false],
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", enableUserGesture]
]});
}

View File

@ -10,7 +10,7 @@ const VIDEO_PAGE = "https://example.com/browser/toolkit/content/tests/browser/fi
add_task(() => {
return SpecialPowers.pushPrefEnv({"set": [
["media.autoplay.enabled", false],
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.PROMPT],
["media.autoplay.enabled.user-gestures-needed", true],
["media.autoplay.ask-permission", true],
["media.autoplay.block-event.enabled", true],

View File

@ -16,7 +16,7 @@ var UserGestureTests = [
function setup_test_preference() {
return SpecialPowers.pushPrefEnv({"set": [
["media.autoplay.enabled", false],
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.enabled.user-gestures-needed", true],
["media.navigator.permission.fake", true]
]});

View File

@ -84,7 +84,7 @@ add_task(async function block_autoplay_media() {
// a new document being loaded into the tab; the new document should have
// to satisfy the autoplay requirements on its own.
await SpecialPowers.pushPrefEnv({"set": [
["media.autoplay.enabled", false],
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.PROMPT],
["media.autoplay.enabled.user-gestures-needed", true],
["media.autoplay.ask-permission", true],
]});

View File

@ -21,6 +21,7 @@
#include "mozilla/XREAppData.h"
#include "mozilla/Services.h"
#include "mozilla/Unused.h"
#include "prtime.h"
using namespace mozilla;
@ -81,7 +82,7 @@ ProfileResetCleanup(nsIToolkitProfile* aOldProfile)
if (!sbs) return NS_ERROR_FAILURE;
nsCOMPtr<nsIStringBundle> sb;
rv = sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
Unused << sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
if (!sb) return NS_ERROR_FAILURE;
NS_ConvertUTF8toUTF16 appName(gAppData->name);
@ -92,6 +93,7 @@ ProfileResetCleanup(nsIToolkitProfile* aOldProfile)
static const char* kResetBackupDirectory = "resetBackupDirectory";
rv = sb->FormatStringFromName(kResetBackupDirectory, params, 2,
resetBackupDirectoryName);
if (NS_FAILED(rv)) return rv;
// Get info to copy the old root profile dir to the desktop as a backup.
nsCOMPtr<nsIFile> backupDest, containerDest, profileDest;

View File

@ -222,13 +222,12 @@ nsOSHelperAppService::LookUpTypeAndDescription(const nsAString& aFileExtension,
bool aUserData) {
LOG(("-- LookUpTypeAndDescription for extension '%s'\n",
NS_LossyConvertUTF16toASCII(aFileExtension).get()));
nsresult rv = NS_OK;
nsAutoString mimeFileName;
const char* filenamePref = aUserData ?
"helpers.private_mime_types_file" : "helpers.global_mime_types_file";
rv = GetFileLocation(filenamePref, nullptr, mimeFileName);
nsresult rv = GetFileLocation(filenamePref, nullptr, mimeFileName);
if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
rv = GetTypeAndDescriptionFromMimetypesFile(mimeFileName,
aFileExtension,
@ -315,15 +314,15 @@ nsOSHelperAppService::GetTypeAndDescriptionFromMimetypesFile(const nsAString& aF
NS_LossyConvertUTF16toASCII(aFilename).get()));
LOG(("Using extension '%s'\n",
NS_LossyConvertUTF16toASCII(aFileExtension).get()));
nsresult rv = NS_OK;
nsCOMPtr<nsIFileInputStream> mimeFile;
nsCOMPtr<nsILineInputStream> mimeTypes;
bool netscapeFormat;
nsAutoString buf;
nsAutoCString cBuf;
bool more = false;
rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
cBuf, &netscapeFormat, &more);
nsresult rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile),
getter_AddRefs(mimeTypes),
cBuf, &netscapeFormat, &more);
if (NS_FAILED(rv)) {
return rv;
@ -438,10 +437,10 @@ nsOSHelperAppService::LookUpExtensionsAndDescription(const nsAString& aMajorType
LOG(("-- LookUpExtensionsAndDescription for type '%s/%s'\n",
NS_LossyConvertUTF16toASCII(aMajorType).get(),
NS_LossyConvertUTF16toASCII(aMinorType).get()));
nsresult rv = NS_OK;
nsAutoString mimeFileName;
rv = GetFileLocation("helpers.private_mime_types_file", nullptr, mimeFileName);
nsresult rv = GetFileLocation("helpers.private_mime_types_file",
nullptr, mimeFileName);
if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
rv = GetExtensionsAndDescriptionFromMimetypesFile(mimeFileName,
aMajorType,
@ -482,17 +481,15 @@ nsOSHelperAppService::GetExtensionsAndDescriptionFromMimetypesFile(const nsAStri
LOG(("Using type '%s/%s'\n",
NS_LossyConvertUTF16toASCII(aMajorType).get(),
NS_LossyConvertUTF16toASCII(aMinorType).get()));
nsresult rv = NS_OK;
nsCOMPtr<nsIFileInputStream> mimeFile;
nsCOMPtr<nsILineInputStream> mimeTypes;
bool netscapeFormat;
nsAutoCString cBuf;
nsAutoString buf;
bool more = false;
rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
cBuf, &netscapeFormat, &more);
nsresult rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile),
getter_AddRefs(mimeTypes),
cBuf, &netscapeFormat, &more);
if (NS_FAILED(rv)) {
return rv;
}
@ -887,7 +884,6 @@ nsOSHelperAppService::DoLookUpHandlerAndDescription(const nsAString& aMajorType,
LOG(("-- LookUpHandlerAndDescription for type '%s/%s'\n",
NS_LossyConvertUTF16toASCII(aMajorType).get(),
NS_LossyConvertUTF16toASCII(aMinorType).get()));
nsresult rv = NS_OK;
nsAutoString mailcapFileName;
const char * filenamePref = aUserData ?
@ -895,7 +891,7 @@ nsOSHelperAppService::DoLookUpHandlerAndDescription(const nsAString& aMajorType,
const char * filenameEnvVar = aUserData ?
"PERSONAL_MAILCAP" : "MAILCAP";
rv = GetFileLocation(filenamePref, filenameEnvVar, mailcapFileName);
nsresult rv = GetFileLocation(filenamePref, filenameEnvVar, mailcapFileName);
if (NS_SUCCEEDED(rv) && !mailcapFileName.IsEmpty()) {
rv = GetHandlerAndDescriptionFromMailcapFile(mailcapFileName,
aMajorType,

View File

@ -22,6 +22,16 @@ NSArray *filteredProviderNames = @[
NSString* const remindersServiceName =
@"com.apple.reminders.RemindersShareExtension";
// These are some undocumented constants also used by Safari
// to let us open the preferences window
NSString* const extensionPrefPanePath =
@"/System/Library/PreferencePanes/Extensions.prefPane";
const UInt32 openSharingSubpaneDescriptorType = 'ptru';
NSString* const openSharingSubpaneActionKey = @"action";
NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
NSString* const openSharingSubpaneProtocolKey = @"protocol";
NSString* const openSharingSubpaneProtocolValue = @"com.apple.share-services";
// Expose the id so we can pass reference through to JS and back
@interface NSSharingService (ExposeName)
- (id)name;
@ -128,6 +138,40 @@ nsMacSharingService::GetSharingProviders(const nsAString& aPageUrl,
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsMacSharingService::OpenSharingPreferences()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSURL* prefPaneURL =
[NSURL fileURLWithPath:extensionPrefPanePath isDirectory:YES];
NSDictionary* args = @{
openSharingSubpaneActionKey: openSharingSubpaneActionValue,
openSharingSubpaneProtocolKey: openSharingSubpaneProtocolValue
};
NSData* data =
[NSPropertyListSerialization
dataWithPropertyList:args
format:NSPropertyListXMLFormat_v1_0
options:0
error:nil];
NSAppleEventDescriptor* descriptor =
[[NSAppleEventDescriptor alloc]
initWithDescriptorType:openSharingSubpaneDescriptorType
data:data];
[[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
withAppBundleIdentifier:nil
options:NSWorkspaceLaunchAsync
additionalEventParamDescriptor:descriptor
launchIdentifiers:NULL];
[descriptor release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsMacSharingService::ShareUrl(const nsAString& aServiceName,
const nsAString& aPageUrl,

View File

@ -22,4 +22,9 @@ interface nsIMacSharingService : nsISupports
void shareUrl(in AString serviceName,
in AString pageUrl,
in AString pageTitle);
/**
* Open the MacOS preferences window to the sharing panel
*/
void openSharingPreferences();
};