Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Narcis Beleuzu 2018-10-12 00:59:25 +03:00
Родитель 2cfba34b8d d30168f45c
Коммит 3b0f157728
66 изменённых файлов: 1959 добавлений и 561 удалений

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

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<blocklist lastupdate="1537309752952" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<blocklist lastupdate="1538996335645" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
<prefs/>
@ -2396,6 +2396,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="dd5b0fa4-48fd-4bf6-943d-34de125bf502" id="{80869932-37ba-4dd4-8dfe-2ef30a2067cc}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
</emItems>
<pluginItems>
<pluginItem blockID="p332">

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

@ -1292,6 +1292,8 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// Is the sidebar positioned ahead of the content browser
pref("sidebar.position_start", true);
pref("security.identitypopup.recordEventElemetry", true);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);

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

@ -4,6 +4,7 @@
var FastBlock = {
reportBreakageLabel: "fastblock",
telemetryIdentifier: "fb",
PREF_ENABLED: "browser.fastblock.enabled",
PREF_UI_ENABLED: "browser.contentblocking.fastblock.control-center.ui.enabled",
@ -24,6 +25,7 @@ var FastBlock = {
var TrackingProtection = {
reportBreakageLabel: "trackingprotection",
telemetryIdentifier: "tp",
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
PREF_UI_ENABLED: "browser.contentblocking.trackingprotection.control-center.ui.enabled",
@ -65,9 +67,6 @@ var TrackingProtection = {
init() {
this.updateEnabled();
this.enabledHistogramAdd(this.enabledGlobally);
this.disabledPBMHistogramAdd(!this.enabledInPrivateWindows);
Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this);
Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
@ -89,20 +88,6 @@ var TrackingProtection = {
PrivateBrowsingUtils.isWindowPrivate(window));
},
enabledHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").add(value);
},
disabledPBMHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_PBM_DISABLED").add(value);
},
onGlobalToggleCommand() {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
Services.prefs.setBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, !this.enabledInPrivateWindows);
@ -142,6 +127,7 @@ var TrackingProtection = {
var ThirdPartyCookies = {
reportBreakageLabel: "cookierestrictions",
telemetryIdentifier: "cr",
PREF_ENABLED: "network.cookie.cookieBehavior",
PREF_REPORT_BREAKAGE_ENABLED: "browser.contentblocking.rejecttrackers.reportBreakage.enabled",
PREF_ENABLED_VALUES: [
@ -345,6 +331,11 @@ var ContentBlocking = {
this.appMenuButton.setAttribute("enabled", this.enabled);
this.appMenuButton.setAttribute("aria-pressed", this.enabled);
}
// The enabled state of blockers may also change since it depends on this.enabled.
for (let blocker of this.blockers) {
blocker.categoryItem.classList.toggle("blocked", this.enabled && blocker.enabled);
}
},
updateUIEnabled() {
@ -446,13 +437,6 @@ var ContentBlocking = {
this.identityPopupMultiView.showSubView("identity-popup-breakageReportView");
},
eventsHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS").add(value);
},
shieldHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
@ -551,9 +535,6 @@ var ContentBlocking = {
this.iconBox.removeAttribute("tooltiptext");
this.shieldHistogramAdd(0);
}
// Telemetry for state change.
this.eventsHistogramAdd(0);
},
disableForCurrentPage() {
@ -569,9 +550,6 @@ var ContentBlocking = {
"trackingprotection", Services.perms.ALLOW_ACTION);
}
// Telemetry for disable protection.
this.eventsHistogramAdd(1);
this.hideIdentityPopupAndReload();
},
@ -587,9 +565,6 @@ var ContentBlocking = {
Services.perms.remove(baseURI, "trackingprotection");
}
// Telemetry for enable protection.
this.eventsHistogramAdd(2);
this.hideIdentityPopupAndReload();
},

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

@ -244,6 +244,14 @@ var gIdentityHandler = {
openPreferences("privacy-permissions", { origin: "identityPopup-permissions-PreferencesButton" });
},
recordClick(object) {
let extra = {};
for (let blocker of ContentBlocking.blockers) {
extra[blocker.telemetryIdentifier] = blocker.activated ? "true" : "false";
}
Services.telemetry.recordEvent("security.ui.identitypopup", "click", object, null, extra);
},
/**
* Handler for mouseclicks on the "More Information" button in the
* "identity-popup" panel.
@ -841,6 +849,14 @@ var gIdentityHandler = {
if (event.target == this._identityPopup) {
window.addEventListener("focus", this, true);
}
let extra = {};
for (let blocker of ContentBlocking.blockers) {
extra[blocker.telemetryIdentifier] = blocker.activated ? "true" : "false";
}
let shieldStatus = ContentBlocking.iconBox.hasAttribute("active") ? "shield-showing" : "shield-hidden";
Services.telemetry.recordEvent("security.ui.identitypopup", "open", "identity_popup", shieldStatus, extra);
},
onPopupHidden(event) {

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

@ -63,6 +63,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
SiteDataManager: "resource:///modules/SiteDataManager.jsm",
SitePermissions: "resource:///modules/SitePermissions.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
Translation: "resource:///modules/translation/Translation.jsm",
UITour: "resource:///modules/UITour.jsm",
@ -1250,15 +1251,28 @@ var gBrowserInit = {
new LightweightThemeConsumer(document);
CompactTheme.init();
if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
window.matchMedia("(-moz-windows-default-theme)").matches) {
let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
.Windows8WindowFrameColor.get());
// Default to black for foreground text.
if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
document.documentElement.setAttribute("darkwindowframe", "true");
if (AppConstants.platform == "win") {
if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
window.matchMedia("(-moz-windows-default-theme)").matches) {
let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
.Windows8WindowFrameColor.get());
// Default to black for foreground text.
if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
document.documentElement.setAttribute("darkwindowframe", "true");
}
} else if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
TelemetryEnvironment.onInitialized().then(() => {
// 17763 is the build number of Windows 10 version 1809
if (TelemetryEnvironment.currentEnvironment.system.os.windowsBuildNumber < 17763) {
document.documentElement.setAttribute("always-use-accent-color-for-window-border", "");
}
});
}
}
// Call this after we set attributes that might change toolbars' computed
// text color.
ToolbarIconColor.init();
},

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

@ -8,6 +8,15 @@ const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSe
ChromeUtils.defineModuleGetter(this, "SiteDataTestUtils",
"resource://testing-common/SiteDataTestUtils.jsm");
add_task(async function setup() {
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
});
});
async function testClearing(testQuota, testCookies) {
// Add some test quota storage.
if (testQuota) {
@ -53,6 +62,8 @@ async function testClearing(testQuota, testCookies) {
]);
}
Services.telemetry.clearEvents();
// Click the "Clear data" button.
siteDataUpdated = TestUtils.topicObserved("sitedatamanager:sites-updated");
let hideEvent = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
@ -61,6 +72,11 @@ async function testClearing(testQuota, testCookies) {
await hideEvent;
await removeDialogPromise;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
let buttonEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "clear_sitedata");
is(buttonEvents.length, 1, "recorded telemetry for the button click");
await siteDataUpdated;
// Check that cookies were deleted.

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

@ -31,6 +31,14 @@ async function waitAndAssertPreferencesShown() {
add_task(async function setup() {
await UrlClassifierTestUtils.addTestTrackers();
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
});
Services.telemetry.clearEvents();
});
// Tests that pressing the preferences icon in the identity popup
@ -48,6 +56,11 @@ add_task(async function testOpenPreferencesFromPrefsButton() {
let shown = waitAndAssertPreferencesShown();
preferencesButton.click();
await shown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cb_prefs_button");
is(clickEvents.length, 1, "recorded telemetry for the click");
});
});
@ -76,6 +89,11 @@ add_task(async function testOpenPreferencesFromAddBlockingButtons() {
let shown = waitAndAssertPreferencesShown();
button.click();
await shown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3].endsWith("_add_blocking"));
is(clickEvents.length, 1, "recorded telemetry for the click");
}
});
});

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

@ -22,6 +22,13 @@ add_task(async function setup() {
[CB_UI_PREF, true],
]});
await UrlClassifierTestUtils.addTestTrackers();
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
});
});
function openIdentityPopup() {
@ -126,6 +133,8 @@ add_task(async function testReportBreakageCancel() {
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
await openIdentityPopup();
Services.telemetry.clearEvents();
let reportBreakageButton = document.getElementById("identity-popup-content-blocking-report-breakage");
ok(BrowserTestUtils.is_visible(reportBreakageButton), "report breakage button is visible");
let reportBreakageView = document.getElementById("identity-popup-breakageReportView");
@ -133,6 +142,11 @@ add_task(async function testReportBreakageCancel() {
reportBreakageButton.click();
await viewShown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "report_breakage");
is(clickEvents.length, 1, "recorded telemetry for the click");
ok(true, "Report breakage view was shown");
let mainView = document.getElementById("identity-popup-mainView");

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

@ -11,8 +11,6 @@ const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/
*/
var oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
Services.prefs.setBoolPref(PREF, false);
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").clear();
registerCleanupFunction(function() {
UrlClassifierTestUtils.cleanupTestTrackers();
Services.telemetry.canRecordExtended = oldCanRecord;
@ -23,26 +21,10 @@ function getShieldHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD");
}
function getEnabledHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED");
}
function getEventsHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
}
function getShieldCounts() {
return getShieldHistogram().snapshot().counts;
}
function getEnabledCounts() {
return getEnabledHistogram().snapshot().counts;
}
function getEventCounts() {
return getEventsHistogram().snapshot().counts;
}
add_task(async function setup() {
await UrlClassifierTestUtils.addTestTrackers();
@ -50,94 +32,105 @@ add_task(async function setup() {
ok(TrackingProtection, "TP is attached to the browser window");
ok(!TrackingProtection.enabled, "TP is not enabled");
// Open a window with TP disabled to make sure 'enabled' is logged correctly.
let newWin = await BrowserTestUtils.openNewBrowserWindow({});
newWin.close();
let enabledCounts =
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").snapshot().counts;
is(enabledCounts[0], 1, "TP was not enabled on start up");
is(getEnabledCounts()[0], 1, "TP was disabled once on start up");
is(getEnabledCounts()[1], 0, "TP was not enabled on start up");
let scalars = Services.telemetry.snapshotScalars(
Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT, false).parent;
// Enable TP so the next browser to open will log 'enabled'
Services.prefs.setBoolPref(PREF, true);
is(scalars["contentblocking.enabled"], true, "CB was enabled at startup");
is(scalars["contentblocking.fastblock_enabled"], true, "FB was enabled at startup");
is(scalars["contentblocking.exceptions"], 0, "no CB exceptions at startup");
});
add_task(async function testNewWindow() {
let newWin = await BrowserTestUtils.openNewBrowserWindow({});
let tab = await BrowserTestUtils.openNewForegroundTab(newWin.gBrowser);
let TrackingProtection = newWin.TrackingProtection;
ok(TrackingProtection, "TP is attached to the browser window");
is(getEnabledCounts()[0], 1, "TP was disabled once on start up");
is(getEnabledCounts()[1], 1, "TP was enabled once on start up");
add_task(async function testShieldHistogram() {
Services.prefs.setBoolPref(PREF, true);
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
// Reset these to make counting easier
getEventsHistogram().clear();
getShieldHistogram().clear();
await promiseTabLoadEvent(tab, BENIGN_PAGE);
is(getEventCounts()[0], 1, "Total page loads");
is(getEventCounts()[1], 0, "Disable actions");
is(getEventCounts()[2], 0, "Enable actions");
is(getShieldCounts()[0], 1, "Page loads without tracking");
await promiseTabLoadEvent(tab, TRACKING_PAGE);
// Note that right now the events and shield histogram is not measuring what
// Note that right now the shield histogram is not measuring what
// you might think. Since onSecurityChange fires twice for a tracking page,
// the total page loads count is double counting, and the shield count
// (which is meant to measure times when the shield wasn't shown) fires even
// when tracking elements exist on the page.
todo_is(getEventCounts()[0], 2, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
is(getEventCounts()[1], 0, "Disable actions");
is(getEventCounts()[2], 0, "Enable actions");
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
info("Disable TP for the page (which reloads the page)");
let tabReloadPromise = promiseTabLoadEvent(tab);
newWin.document.querySelector("#tracking-action-unblock").doCommand();
document.querySelector("#tracking-action-unblock").doCommand();
await tabReloadPromise;
todo_is(getEventCounts()[0], 3, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
is(getEventCounts()[1], 1, "Disable actions");
is(getEventCounts()[2], 0, "Enable actions");
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
info("Re-enable TP for the page (which reloads the page)");
tabReloadPromise = promiseTabLoadEvent(tab);
newWin.document.querySelector("#tracking-action-block").doCommand();
document.querySelector("#tracking-action-block").doCommand();
await tabReloadPromise;
todo_is(getEventCounts()[0], 4, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
is(getEventCounts()[1], 1, "Disable actions");
is(getEventCounts()[2], 1, "Enable actions");
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
newWin.close();
gBrowser.removeCurrentTab();
// Reset these to make counting easier for the next test
getEventsHistogram().clear();
getShieldHistogram().clear();
getEnabledHistogram().clear();
});
add_task(async function testPrivateBrowsing() {
let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
let tab = await BrowserTestUtils.openNewForegroundTab(privateWin.gBrowser);
let TrackingProtection = privateWin.TrackingProtection;
ok(TrackingProtection, "TP is attached to the browser window");
add_task(async function testIdentityPopupEvents() {
Services.prefs.setBoolPref(PREF, true);
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
// Do a bunch of actions and make sure that no telemetry data is gathered
await promiseTabLoadEvent(tab, BENIGN_PAGE);
Services.telemetry.clearEvents();
let { gIdentityHandler } = gBrowser.ownerGlobal;
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let openEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "open" && e[3] == "identity_popup");
is(openEvents.length, 1, "recorded telemetry for opening the identity popup");
is(openEvents[0][4], "shield-hidden", "recorded the shield as hidden");
await promiseTabLoadEvent(tab, TRACKING_PAGE);
promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
openEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "open" && e[3] == "identity_popup");
is(openEvents.length, 1, "recorded telemetry for opening the identity popup");
is(openEvents[0][4], "shield-showing", "recorded the shield as showing");
info("Disable TP for the page (which reloads the page)");
let tabReloadPromise = promiseTabLoadEvent(tab);
privateWin.document.querySelector("#tracking-action-unblock").doCommand();
document.querySelector("#tracking-action-unblock").doCommand();
await tabReloadPromise;
events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "unblock");
is(clickEvents.length, 1, "recorded telemetry for the click");
info("Re-enable TP for the page (which reloads the page)");
tabReloadPromise = promiseTabLoadEvent(tab);
privateWin.document.querySelector("#tracking-action-block").doCommand();
document.querySelector("#tracking-action-block").doCommand();
await tabReloadPromise;
// Sum up all the counts to make sure that nothing got logged
is(getEnabledCounts().reduce((p, c) => p + c), 0, "Telemetry logging off in PB mode");
is(getEventCounts().reduce((p, c) => p + c), 0, "Telemetry logging off in PB mode");
is(getShieldCounts().reduce((p, c) => p + c), 0, "Telemetry logging off in PB mode");
events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "block");
is(clickEvents.length, 1, "recorded telemetry for the click");
privateWin.close();
gBrowser.removeCurrentTab();
});

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

@ -10,6 +10,7 @@
// should use "expectUncaughtRejection" to flag individual failures.
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.whitelistRejectionsGlobally(/aborted by the user agent/);
ChromeUtils.import("resource:///modules/BrowserWindowTracker.jsm", this);
const permissionError = "error: NotAllowedError: The request is not allowed " +
"by the user agent or the platform in the current context.";
@ -584,6 +585,37 @@ var gTests = [
},
},
{
desc: "Switching between menu options maintains correct main action state while window sharing",
run: async function checkDoorhangerState() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:newtab");
BrowserWindowTracker.orderedWindows[1].focus();
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(false, true, null, "window");
await promise;
await expectObserverCalled("getUserMedia:request");
let menulist = document.getElementById("webRTC-selectWindow-menulist");
let notification = PopupNotifications.panel.firstElementChild;
let checkbox = notification.checkbox;
menulist.getItemAtIndex(2).doCommand();
checkbox.click();
ok(checkbox.checked, "checkbox now checked");
ok(notification.button.disabled, "Allow button is disabled");
ok(!notification.hasAttribute("warninghidden"), "warning message is shown");
menulist.getItemAtIndex(3).doCommand();
ok(checkbox.checked, "checkbox still checked");
ok(notification.button.disabled, "Allow button remains disabled");
ok(!notification.hasAttribute("warninghidden"), "warning message is still shown");
win.close();
},
},
];
add_task(async function test() {

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

@ -670,9 +670,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
return;
}
BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
event, this.userSelectionBehavior);
let where = openUILinkWhere || this._whereToOpen(event);
let url = this.value;
@ -680,6 +677,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
return;
}
BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
event, this.userSelectionBehavior);
let mayInheritPrincipal = false;
let postData = null;
let browser = gBrowser.selectedBrowser;

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

@ -76,7 +76,7 @@
<toolbarbutton id="tracking-protection-preferences-button"
class="identity-popup-preferences-button subviewbutton"
tooltiptext="&trackingProtection.tooltip;"
oncommand="ContentBlocking.openPreferences('identityPopup-TP-preferencesButton');" />
oncommand="ContentBlocking.openPreferences('identityPopup-TP-preferencesButton'); gIdentityHandler.recordClick('cb_prefs_button');" />
</hbox>
<description id="identity-popup-content-blocking-detected"
@ -91,7 +91,7 @@
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.fastBlock.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.fastBlock.blocked.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
onclick="ContentBlocking.openPreferences('identityPopup-CB-fastblock');">&contentBlocking.fastBlock.add.label;</label>
onclick="ContentBlocking.openPreferences('identityPopup-CB-fastblock'); gIdentityHandler.recordClick('fb_add_blocking');">&contentBlocking.fastBlock.add.label;</label>
</hbox>
<hbox id="identity-popup-content-blocking-category-tracking-protection"
class="identity-popup-content-blocking-category" align="center" role="group">
@ -99,7 +99,8 @@
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.trackingProtection3.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.trackingProtection.blocked.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
onclick="ContentBlocking.openPreferences('identityPopup-CB-tracking-protection');">&contentBlocking.trackingProtection.add.label;</label>
id="identity-popup-tracking-protection-add-blocking"
onclick="ContentBlocking.openPreferences('identityPopup-CB-tracking-protection'); gIdentityHandler.recordClick('tp_add_blocking');">&contentBlocking.trackingProtection.add.label;</label>
</hbox>
<hbox id="identity-popup-content-blocking-category-3rdpartycookies"
class="identity-popup-content-blocking-category" align="center" role="group">
@ -107,7 +108,8 @@
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.3rdPartyCookies.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.3rdPartyCookies.blocked.label;</label>
<label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
onclick="ContentBlocking.openPreferences('identityPopup-CB-3rdpartycookies');">&contentBlocking.3rdPartyCookies.add.label;</label>
id="identity-popup-3rdpartycookies-add-blocking"
onclick="ContentBlocking.openPreferences('identityPopup-CB-3rdpartycookies'); gIdentityHandler.recordClick('cookies_add_blocking');">&contentBlocking.3rdPartyCookies.add.label;</label>
</hbox>
</vbox>
@ -115,19 +117,19 @@
class="tracking-protection-button"
label="&trackingProtection.unblock4.label;"
accesskey="&trackingProtection.unblock4.accesskey;"
oncommand="ContentBlocking.disableForCurrentPage();" />
oncommand="ContentBlocking.disableForCurrentPage(); gIdentityHandler.recordClick('unblock');" />
<button id="tracking-action-unblock-private"
class="tracking-protection-button"
label="&trackingProtection.unblockPrivate4.label;"
accesskey="&trackingProtection.unblockPrivate4.accesskey;"
oncommand="ContentBlocking.disableForCurrentPage();" />
oncommand="ContentBlocking.disableForCurrentPage(); gIdentityHandler.recordClick('unblock_private');" />
<button id="tracking-action-block"
class="tracking-protection-button"
label="&trackingProtection.block5.label;"
accesskey="&trackingProtection.block5.accesskey;"
oncommand="ContentBlocking.enableForCurrentPage();" />
oncommand="ContentBlocking.enableForCurrentPage(); gIdentityHandler.recordClick('block');" />
<label id="identity-popup-content-blocking-report-breakage"
onclick="ContentBlocking.showReportBreakageSubview();"
onclick="ContentBlocking.showReportBreakageSubview(); gIdentityHandler.recordClick('report_breakage');"
class="text-link subviewkeynav"
flex="1">&contentBlocking.openBreakageReportView2.label;</label>
</vbox>
@ -160,7 +162,7 @@
class="identity-popup-footer">
<button id="identity-popup-clear-sitedata-button"
label="&identity.clearSiteData;"
oncommand="gIdentityHandler.clearSiteData(event);"/>
oncommand="gIdentityHandler.clearSiteData(event); gIdentityHandler.recordClick('clear_sitedata');"/>
</vbox>
</panelview>

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

@ -1350,6 +1350,34 @@ BrowserGlue.prototype = {
PlacesUtils.favicons.setDefaultIconURIPreferredSize(16 * aWindow.devicePixelRatio);
},
_recordContentBlockingTelemetry() {
let recordIdentityPopupEvents = Services.prefs.getBoolPref("security.identitypopup.recordEventElemetry");
Services.telemetry.setEventRecordingEnabled("security.ui.identitypopup", recordIdentityPopupEvents);
let tpEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled");
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").add(tpEnabled);
let tpPBDisabled = Services.prefs.getBoolPref("privacy.trackingprotection.pbmode.enabled");
Services.telemetry.getHistogramById("TRACKING_PROTECTION_PBM_DISABLED").add(!tpPBDisabled);
let cookieBehavior = Services.prefs.getIntPref("network.cookie.cookieBehavior");
Services.telemetry.getHistogramById("COOKIE_BEHAVIOR").add(cookieBehavior);
let fastBlockEnabled = Services.prefs.getBoolPref("browser.fastblock.enabled");
Services.telemetry.scalarSet("contentblocking.fastblock_enabled", fastBlockEnabled);
let contentBlockingEnabled = Services.prefs.getBoolPref("browser.contentblocking.enabled");
Services.telemetry.scalarSet("contentblocking.enabled", contentBlockingEnabled);
let exceptions = 0;
for (let permission of Services.perms.enumerator) {
if (permission.type == "trackingprotection") {
exceptions++;
}
}
Services.telemetry.scalarSet("contentblocking.exceptions", exceptions);
},
_sendMediaTelemetry() {
let win = Services.appShell.hiddenDOMWindow;
let v = win.document.createElementNS("http://www.w3.org/1999/xhtml", "video");
@ -2030,6 +2058,10 @@ BrowserGlue.prototype = {
this._placesBrowserInitComplete = true;
Services.obs.notifyObservers(null, "places-browser-init-complete");
});
Services.tm.idleDispatchToMainThread(() => {
this._recordContentBlockingTelemetry();
});
},
/**

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

@ -25,19 +25,17 @@
@media not all and (-moz-os-version: windows-win7) {
@media not all and (-moz-os-version: windows-win8) {
@media (-moz-windows-default-theme) {
:root[sizemode=normal][tabsintitlebar] {
border-top: 1px solid -moz-win-accentcolor;
}
:root[sizemode=normal][tabsintitlebar]:-moz-window-inactive {
border-top-color: rgba(0,0,0,.2);
}
:root:not(:-moz-lwtheme) {
background-color: hsl(0, 0%, 78%);
}
@media (-moz-windows-accent-color-in-titlebar: 0) {
:root[sizemode=normal][tabsintitlebar] {
border-top: 1px solid rgba(0,0,0,.7);
}
:root[sizemode=normal][tabsintitlebar][always-use-accent-color-for-window-border]:not(:-moz-window-inactive) {
border-top-color: -moz-win-accentcolor;
}
:root[tabsintitlebar]:not(:-moz-lwtheme) {
background-color: hsl(235,33%,19%);
}
@ -47,6 +45,9 @@
}
@media (-moz-windows-accent-color-in-titlebar) {
:root[sizemode=normal][tabsintitlebar] {
border-top: 1px solid -moz-win-accentcolor;
}
:root[tabsintitlebar]:not(:-moz-window-inactive):not(:-moz-lwtheme) {
background-color: -moz-win-accentcolor;
}
@ -55,6 +56,10 @@
}
}
:root[sizemode=normal][tabsintitlebar]:-moz-window-inactive {
border-top-color: rgba(0,0,0,.3);
}
:root[tabsintitlebar] .tab-label:-moz-window-inactive {
/* Calculated to match the opacity change of Windows Explorer
titlebar text change for inactive windows. */

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

@ -25,6 +25,8 @@ body {
width: calc(100% - 10px);
font-family: var(--monospace-font-family);
padding: 5px;
color: -moz-fieldtext;
background-color: -moz-field;
}
/**

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

@ -10,6 +10,7 @@
// tested with an xpcshell test as the output-parser requires the DOM to work.
const OutputParser = require("devtools/client/shared/output-parser");
const { CSS_PROPERTIES_DB} = require("devtools/shared/css/properties-db");
const {initCssProperties, getCssProperties} = require("devtools/shared/fronts/css-properties");
const COLOR_CLASS = "color-class";
@ -294,7 +295,13 @@ const TEST_DATA = [
add_task(async function() {
// Mock the toolbox that initCssProperties expect so we get the fallback css properties.
const toolbox = {target: {client: {}, hasActor: () => false}};
const toolbox = {
target: {
client: {},
hasActor: () => false,
getFront: typeName => ({getCSSDatabase: () => CSS_PROPERTIES_DB})
}
};
await initCssProperties(toolbox);
const cssProperties = getCssProperties(toolbox);

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

@ -5,6 +5,7 @@
const OutputParser = require("devtools/client/shared/output-parser");
const {initCssProperties, getCssProperties} = require("devtools/shared/fronts/css-properties");
const { CSS_PROPERTIES_DB} = require("devtools/shared/css/properties-db");
const CSS_SHAPES_ENABLED_PREF = "devtools.inspector.shapesHighlighter.enabled";
add_task(async function() {
@ -18,7 +19,13 @@ async function performTest() {
"<h1>browser_outputParser.js</h1><div></div>");
// Mock the toolbox that initCssProperties expect so we get the fallback css properties.
const toolbox = {target: {client: {}, hasActor: () => false}};
const toolbox = {
target: {
client: {},
hasActor: () => false,
getFront: typeName => ({getCSSDatabase: () => CSS_PROPERTIES_DB})
}
};
await initCssProperties(toolbox);
const cssProperties = getCssProperties(toolbox);

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

@ -233,17 +233,9 @@ const initCssProperties = async function(toolbox) {
return cachedCssProperties.get(client);
}
let db, front;
// Get the list dynamically if the cssProperties actor exists.
if (toolbox.target.hasActor("cssProperties")) {
front = toolbox.target.getFront("cssProperties");
db = await front.getCSSDatabase();
} else {
// The target does not support this actor, so require a static list of supported
// properties.
db = CSS_PROPERTIES_DB;
}
const front = toolbox.target.getFront("cssProperties");
const db = await front.getCSSDatabase();
const cssProperties = new CssProperties(normalizeCssData(db));
cachedCssProperties.set(client, {cssProperties, front});

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

@ -336,7 +336,8 @@ function lazyLoadFront(type) {
require(modulePath);
} catch (e) {
throw new Error(
`Unable to load lazy front module '${modulePath}' for type '${type}'`);
`Unable to load lazy front module '${modulePath}' for type '${type}'.
Error: ${e}`);
}
lazyFronts.delete(type);
return true;

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

@ -67,6 +67,8 @@
#include "mozilla/dom/FeaturePolicy.h"
#include "mozilla/dom/FramingChecker.h"
#include "mozilla/dom/HTMLSharedElement.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
#include "mozilla/dom/SVGUseElement.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/dom/CDATASection.h"
@ -5195,6 +5197,14 @@ nsIDocument::DispatchContentLoadedEvents()
NS_LITERAL_STRING("DOMContentLoaded"),
CanBubble::eYes, Cancelable::eNo);
if (auto* const window = GetInnerWindow()) {
const RefPtr<ServiceWorkerContainer> serviceWorker = window->Navigator()->ServiceWorker();
// This could cause queued messages from a service worker to get
// dispatched on serviceWorker.
serviceWorker->StartMessages();
}
if (MayStartLayout()) {
MaybeResolveReadyForIdle();
}

20
dom/cache/TypeUtils.cpp поставляемый
Просмотреть файл

@ -519,6 +519,26 @@ TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
autoStream->Serialize(aStream, GetIPCManager());
aStreamCleanupList.AppendElement(std::move(autoStream));
// This nested condition guards against silent failures in IPC code
// that would cause a crash when the message is sent. Specifically,
// if IPCStreamSource::Initialize fails to get a StrongWorkerRef
// (e.g. when the worker terminates), a nullptr is silently stored
// in IPCRemoteStreamType.
// This is a workaround, requested in bug 1484524, and a more
// reasonable solution should replace it.
if (cacheStream.stream().type() == OptionalIPCStream::TIPCStream) {
const auto& ipcStream = cacheStream.stream().get_IPCStream();
if (ipcStream.type() == IPCStream::TIPCRemoteStream) {
const auto& ipcRemoteStream = ipcStream.get_IPCRemoteStream();
using mozilla::ipc::IPCRemoteStreamType;
if (ipcRemoteStream.stream().type() == IPCRemoteStreamType::TPChildToParentStreamChild) {
if (!ipcRemoteStream.stream().get_PChildToParentStreamChild()) {
aRv.Throw(NS_ERROR_FAILURE);
}
}
}
}
}
} // namespace cache

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

@ -605,125 +605,17 @@ RefPtr<ClientOpPromise>
ClientSource::PostMessage(const ClientPostMessageArgs& aArgs)
{
NS_ASSERT_OWNINGTHREAD(ClientSource);
RefPtr<ClientOpPromise> ref;
ServiceWorkerDescriptor source(aArgs.serviceWorker());
const PrincipalInfo& principalInfo = source.PrincipalInfo();
StructuredCloneData clonedData;
clonedData.BorrowFromClonedMessageDataForBackgroundChild(aArgs.clonedData());
// Currently we only support firing these messages on window Clients.
// Once we expose ServiceWorkerContainer and the ServiceWorker on Worker
// threads then this will need to change. See bug 1113522.
if (mClientInfo.Type() != ClientType::Window) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
return ref.forget();
// TODO: Currently this function only supports clients whose global
// object is a Window; it should also support those whose global
// object is a WorkerGlobalScope.
if (nsPIDOMWindowInner* const window = GetInnerWindow()) {
const RefPtr<ServiceWorkerContainer> container = window->Navigator()->ServiceWorker();
container->ReceiveMessage(aArgs);
return ClientOpPromise::CreateAndResolve(NS_OK, __func__).forget();
}
MOZ_ASSERT(NS_IsMainThread());
RefPtr<ServiceWorkerContainer> target;
nsCOMPtr<nsIGlobalObject> globalObject;
// We don't need to force the creation of the about:blank document
// here because there is no postMessage listener. If a listener
// was registered then the document will already be created.
nsPIDOMWindowInner* window = GetInnerWindow();
if (window) {
globalObject = do_QueryInterface(window);
target = window->Navigator()->ServiceWorker();
}
if (NS_WARN_IF(!target)) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
// If AutoJSAPI::Init() fails then either global is nullptr or not
// in a usable state.
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
JSContext* cx = jsapi.cx();
ErrorResult result;
JS::Rooted<JS::Value> messageData(cx);
clonedData.Read(cx, &messageData, result);
if (result.MaybeSetPendingException(cx)) {
// We reported the error in the current window context. Resolve
// promise instead of rejecting.
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
RootedDictionary<MessageEventInit> init(cx);
init.mData = messageData;
if (!clonedData.TakeTransferredPortsAsSequence(init.mPorts)) {
// Report the error in the current window context and resolve the
// promise instead of rejecting.
xpc::Throw(cx, NS_ERROR_OUT_OF_MEMORY);
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(principalInfo, &rv);
if (NS_FAILED(rv) || !principal) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
nsAutoCString origin;
rv = principal->GetOriginNoSuffix(origin);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(origin, init.mOrigin);
}
RefPtr<ServiceWorker> instance;
if (ServiceWorkerParentInterceptEnabled()) {
instance = globalObject->GetOrCreateServiceWorker(source);
} else {
// If we are in legacy child-side intercept mode then we need to verify
// this registration exists in the current process.
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
// Shutting down. Just don't deliver this message.
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
RefPtr<ServiceWorkerRegistrationInfo> reg =
swm->GetRegistration(principal, source.Scope());
if (reg) {
instance = globalObject->GetOrCreateServiceWorker(source);
}
}
if (instance) {
init.mSource.SetValue().SetAsServiceWorker() = instance;
}
RefPtr<MessageEvent> event =
MessageEvent::Constructor(target, NS_LITERAL_STRING("message"), init);
event->SetTrusted(true);
target->DispatchEvent(*event, result);
if (result.Failed()) {
result.SuppressException();
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
return ClientOpPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__).forget();
}
RefPtr<ClientOpPromise>

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

@ -247,12 +247,14 @@ ContentEventHandler::ContentEventHandler(nsPresContext* aPresContext)
}
nsresult
ContentEventHandler::InitBasic()
ContentEventHandler::InitBasic(bool aRequireFlush)
{
NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
// If text frame which has overflowing selection underline is dirty,
// we need to flush the pending reflow here.
mDocument->FlushPendingNotifications(FlushType::Layout);
if (aRequireFlush) {
// If text frame which has overflowing selection underline is dirty,
// we need to flush the pending reflow here.
mDocument->FlushPendingNotifications(FlushType::Layout);
}
return NS_OK;
}
@ -314,7 +316,7 @@ ContentEventHandler::InitRootContent(Selection* aNormalSelection)
}
nsresult
ContentEventHandler::InitCommon(SelectionType aSelectionType)
ContentEventHandler::InitCommon(SelectionType aSelectionType, bool aRequireFlush)
{
if (mSelection && mSelection->Type() == aSelectionType) {
return NS_OK;
@ -324,7 +326,7 @@ ContentEventHandler::InitCommon(SelectionType aSelectionType)
mRootContent = nullptr;
mFirstSelectedRawRange.Clear();
nsresult rv = InitBasic();
nsresult rv = InitBasic(aRequireFlush);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelectionController> selectionController;
@ -399,7 +401,7 @@ ContentEventHandler::Init(WidgetQueryContentEvent* aEvent)
return NS_ERROR_FAILURE;
}
nsresult rv = InitCommon(selectionType);
nsresult rv = InitCommon(selectionType, aEvent->NeedsToFlushLayout());
NS_ENSURE_SUCCESS(rv, rv);
// Be aware, WidgetQueryContentEvent::mInput::mOffset should be made absolute

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

@ -153,8 +153,9 @@ protected:
nsresult Init(WidgetQueryContentEvent* aEvent);
nsresult Init(WidgetSelectionEvent* aEvent);
nsresult InitBasic();
nsresult InitCommon(SelectionType aSelectionType = SelectionType::eNormal);
nsresult InitBasic(bool aRequireFlush = true);
nsresult InitCommon(SelectionType aSelectionType = SelectionType::eNormal,
bool aRequireFlush = true);
/**
* InitRootContent() computes the root content of current focused editor.
*

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

@ -1547,7 +1547,7 @@ IMEContentObserver::MaybeNotifyCompositionEventHandled()
}
bool
IMEContentObserver::UpdateSelectionCache()
IMEContentObserver::UpdateSelectionCache(bool aRequireFlush /* = true */)
{
MOZ_ASSERT(IsSafeToNotifyIME());
@ -1560,6 +1560,7 @@ IMEContentObserver::UpdateSelectionCache()
// XXX Cannot we cache some information for reducing the cost to compute
// selection offset and writing mode?
WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget);
selection.mNeedsToFlushLayout = aRequireFlush;
ContentEventHandler handler(GetPresContext());
handler.OnQuerySelectedText(&selection);
if (NS_WARN_IF(!selection.mSucceeded) ||
@ -1966,7 +1967,8 @@ IMEContentObserver::IMENotificationSender::SendFocusSet()
observer->mIMEHasFocus = true;
// Initialize selection cache with the first selection data.
observer->UpdateSelectionCache();
// We avoid flushing for focus in the general case.
observer->UpdateSelectionCache(false);
MOZ_LOG(sIMECOLog, LogLevel::Info,
("0x%p IMEContentObserver::IMENotificationSender::"

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

@ -307,7 +307,7 @@ private:
*
* Note that this does nothing if WasInitializedWithPlugin() returns true.
*/
bool UpdateSelectionCache();
bool UpdateSelectionCache(bool aRequireFlush = true);
nsCOMPtr<nsIWidget> mWidget;
// mFocusedWidget has the editor observed by the instance. E.g., if the

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

@ -12,6 +12,7 @@
#include "nsIDocument.h"
#include "nsIServiceWorkerManager.h"
#include "nsIScriptError.h"
#include "nsThreadUtils.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
@ -22,11 +23,16 @@
#include "nsServiceManagerUtils.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorker.h"
#include "mozilla/dom/ServiceWorkerContainerBinding.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "RemoteServiceWorkerContainerImpl.h"
#include "ServiceWorker.h"
@ -34,6 +40,11 @@
#include "ServiceWorkerRegistration.h"
#include "ServiceWorkerUtils.h"
// This is defined to something else on Windows
#ifdef DispatchMessage
#undef DispatchMessage
#endif
namespace mozilla {
namespace dom {
@ -152,6 +163,39 @@ ServiceWorkerContainer::ControllerChanged(ErrorResult& aRv)
aRv = DispatchTrustedEvent(NS_LITERAL_STRING("controllerchange"));
}
using mozilla::dom::ipc::StructuredCloneData;
// A ReceivedMessage represents a message sent via
// Client.postMessage(). It is used as used both for queuing of
// incoming messages and as an interface to DispatchMessage().
struct MOZ_HEAP_CLASS ServiceWorkerContainer::ReceivedMessage
{
explicit ReceivedMessage(const ClientPostMessageArgs& aArgs)
: mServiceWorker(aArgs.serviceWorker())
{
mClonedData.CopyFromClonedMessageDataForBackgroundChild(aArgs.clonedData());
}
ServiceWorkerDescriptor mServiceWorker;
StructuredCloneData mClonedData;
NS_INLINE_DECL_REFCOUNTING(ReceivedMessage)
private:
~ReceivedMessage() = default;
};
void
ServiceWorkerContainer::ReceiveMessage(const ClientPostMessageArgs& aArgs)
{
RefPtr<ReceivedMessage> message = new ReceivedMessage(aArgs);
if (mMessagesStarted) {
EnqueueReceivedMessageDispatch(message.forget());
} else {
mPendingMessages.AppendElement(message.forget());
}
}
JSObject*
ServiceWorkerContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@ -426,6 +470,16 @@ ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
return outer.forget();
}
void
ServiceWorkerContainer::StartMessages()
{
while (!mPendingMessages.IsEmpty()) {
EnqueueReceivedMessageDispatch(mPendingMessages.ElementAt(0));
mPendingMessages.RemoveElementAt(0);
}
mMessagesStarted = true;
}
already_AddRefed<Promise>
ServiceWorkerContainer::GetRegistration(const nsAString& aURL,
ErrorResult& aRv)
@ -618,5 +672,153 @@ ServiceWorkerContainer::GetGlobalIfValid(ErrorResult& aRv,
return window->AsGlobal();
}
void
ServiceWorkerContainer::EnqueueReceivedMessageDispatch(RefPtr<ReceivedMessage> aMessage) {
if (nsPIDOMWindowInner* const window = GetOwner()) {
if (auto* const target = window->EventTargetFor(TaskCategory::Other)) {
target->Dispatch(
NewRunnableMethod<RefPtr<ReceivedMessage>>(
"ServiceWorkerContainer::DispatchMessage",
this,
&ServiceWorkerContainer::DispatchMessage,
std::move(aMessage)
)
);
}
}
}
template <typename F>
void
ServiceWorkerContainer::RunWithJSContext(F&& aCallable)
{
nsCOMPtr<nsIGlobalObject> globalObject;
if (nsPIDOMWindowInner* const window = GetOwner()) {
globalObject = do_QueryInterface(window);
}
// If AutoJSAPI::Init() fails then either global is nullptr or not
// in a usable state.
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return;
}
aCallable(jsapi.cx(), globalObject);
}
void
ServiceWorkerContainer::DispatchMessage(RefPtr<ReceivedMessage> aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
// When dispatching a message, either DOMContentLoaded has already
// been fired, or someone called startMessages() or set onmessage.
// Either way, a global object is supposed to be present. If it's
// not, we'd fail to initialize the JS API and exit.
RunWithJSContext([this, message = std::move(aMessage)](JSContext* const aCx,
nsIGlobalObject* const aGlobal) {
RootedDictionary<MessageEventInit> init(aCx);
if (!FillInMessageEventInit(aCx, aGlobal, *message, init)) {
// TODO: The spec requires us to fire a messageerror event here.
return;
}
RefPtr<MessageEvent> event =
MessageEvent::Constructor(this, NS_LITERAL_STRING("message"), init);
event->SetTrusted(true);
ErrorResult result;
DispatchEvent(*event, result);
if (result.Failed()) {
result.SuppressException();
}
});
}
namespace {
nsresult
FillInOriginNoSuffix(const ServiceWorkerDescriptor& aServiceWorker, nsString& aOrigin)
{
using mozilla::ipc::PrincipalInfoToPrincipal;
nsresult rv;
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(aServiceWorker.PrincipalInfo(), &rv);
if (NS_FAILED(rv) || !principal) {
return rv;
}
nsAutoCString originUTF8;
rv = principal->GetOriginNoSuffix(originUTF8);
if (NS_FAILED(rv)) {
return rv;
}
CopyUTF8toUTF16(originUTF8, aOrigin);
return NS_OK;
}
already_AddRefed<ServiceWorker>
GetOrCreateServiceWorkerWithoutWarnings(nsIGlobalObject* const aGlobal,
const ServiceWorkerDescriptor& aDescriptor)
{
// In child-intercept mode we have to verify that the registration
// exists in the current process. This exact check is also performed
// (indirectly) in nsIGlobalObject::GetOrCreateServiceWorker, but it
// also emits a warning when the registration is not present. To
// to avoid having too many warnings, we do a precheck here.
if (!ServiceWorkerParentInterceptEnabled()) {
const RefPtr<ServiceWorkerManager> serviceWorkerManager = ServiceWorkerManager::GetInstance();
if (!serviceWorkerManager) {
return nullptr;
}
const RefPtr<ServiceWorkerRegistrationInfo> registration =
serviceWorkerManager->GetRegistration(aDescriptor.PrincipalInfo(), aDescriptor.Scope());
if (!registration) {
return nullptr;
}
}
return aGlobal->GetOrCreateServiceWorker(aDescriptor).forget();
}
}
bool
ServiceWorkerContainer::FillInMessageEventInit(JSContext* const aCx,
nsIGlobalObject* const aGlobal,
ReceivedMessage& aMessage,
MessageEventInit& aInit)
{
ErrorResult result;
JS::Rooted<JS::Value> messageData(aCx);
aMessage.mClonedData.Read(aCx, &messageData, result);
if (result.Failed()) {
return false;
}
aInit.mData = messageData;
if (!aMessage.mClonedData.TakeTransferredPortsAsSequence(aInit.mPorts)) {
return false;
}
const nsresult rv = FillInOriginNoSuffix(aMessage.mServiceWorker, aInit.mOrigin);
if (NS_FAILED(rv)) {
return false;
}
const RefPtr<ServiceWorker> serviceWorkerInstance =
GetOrCreateServiceWorkerWithoutWarnings(aGlobal, aMessage.mServiceWorker);
if (serviceWorkerInstance) {
aInit.mSource.SetValue().SetAsServiceWorker() = serviceWorkerInstance;
}
return true;
}
} // namespace dom
} // namespace mozilla

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

@ -15,6 +15,8 @@ class nsIGlobalWindow;
namespace mozilla {
namespace dom {
class ClientPostMessageArgs;
struct MessageEventInit;
class Promise;
struct RegistrationOptions;
class ServiceWorker;
@ -64,7 +66,19 @@ public:
IMPL_EVENT_HANDLER(controllerchange)
IMPL_EVENT_HANDLER(error)
IMPL_EVENT_HANDLER(message)
// Almost a manual expansion of IMPL_EVENT_HANDLER(message), but
// with the additional StartMessages() when setting the handler, as
// required by the spec.
inline mozilla::dom::EventHandlerNonNull* GetOnmessage()
{
return GetEventHandler(nsGkAtoms::onmessage);
}
inline void SetOnmessage(mozilla::dom::EventHandlerNonNull* aCallback)
{
SetEventHandler(nsGkAtoms::onmessage, aCallback);
StartMessages();
}
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
@ -89,6 +103,9 @@ public:
already_AddRefed<Promise>
GetRegistrations(ErrorResult& aRv);
void
StartMessages();
Promise*
GetReady(ErrorResult& aRv);
@ -104,6 +121,9 @@ public:
void
ControllerChanged(ErrorResult& aRv);
void
ReceiveMessage(const ClientPostMessageArgs& aArgs);
private:
ServiceWorkerContainer(nsIGlobalObject* aGlobal,
already_AddRefed<ServiceWorkerContainer::Inner> aInner);
@ -121,6 +141,27 @@ private:
GetGlobalIfValid(ErrorResult& aRv,
const std::function<void(nsIDocument*)>&& aStorageFailureCB = nullptr) const;
struct ReceivedMessage;
// Dispatch a Runnable that dispatches the given message on this
// object. When the owner of this object is a Window, the Runnable
// is dispatched on the corresponding TabGroup.
void
EnqueueReceivedMessageDispatch(RefPtr<ReceivedMessage> aMessage);
template <typename F>
void
RunWithJSContext(F&& aCallable);
void
DispatchMessage(RefPtr<ReceivedMessage> aMessage);
static bool
FillInMessageEventInit(JSContext* aCx,
nsIGlobalObject* aGlobal,
ReceivedMessage& aMessage,
MessageEventInit& aInit);
RefPtr<Inner> mInner;
// This only changes when a worker hijacks everything in its scope by calling
@ -129,6 +170,13 @@ private:
RefPtr<Promise> mReadyPromise;
MozPromiseRequestHolder<ServiceWorkerRegistrationPromise> mReadyPromiseHolder;
// Set after StartMessages() has been called.
bool mMessagesStarted = false;
// Queue holding messages posted from service worker as long as
// StartMessages() hasn't been called.
nsTArray<RefPtr<ReceivedMessage>> mPendingMessages;
};
} // namespace dom

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

@ -1,5 +1,8 @@
[DEFAULT]
prefs = dom.performance.enable_scheduler_timing=true
prefs =
dom.performance.enable_scheduler_timing=true
dom.performance.children_results_ipc_timeout=500
support-files =
dummy.html
ping_worker.html
@ -7,6 +10,10 @@ support-files =
ping_worker.js
setinterval.html
settimeout.html
unresponsive.html
[browser_test_performance_metrics.js]
skip-if = verify
[browser_test_unresponsive.js]
skip-if = verify

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

@ -0,0 +1,31 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const ROOT_URL = "http://example.com/browser/dom/tests/browser/perfmetrics";
const PAGE_URL = ROOT_URL + "/unresponsive.html";
add_task(async function test() {
// dom.performance.enable_scheduler_timing is set to true in browser.ini
waitForExplicitFinish();
await BrowserTestUtils.withNewTab({ gBrowser, url: PAGE_URL },
async function(browser) {
let dataBack = 0;
let tabId = gBrowser.selectedBrowser.outerWindowID;
function exploreResults(data, filterByWindowId) {
for (let entry of data) {
if (entry.windowId == tabId && entry.host != "about:blank") {
dataBack += 1;
}
}
}
let results = await ChromeUtils.requestPerformanceMetrics();
exploreResults(results);
Assert.ok(dataBack == 0);
});
});

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

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<script type="text/javascript">
function fn() {
let start = Date.now();
while (Date.now() - start < 5000)
; // do nothing
setTimeout(fn, 0);
}
setTimeout(fn, 10);
</script>
</head>
<body>
<h1>An unresponsive page</h1>
</body>
</html>

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

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
* https://w3c.github.io/ServiceWorker/#serviceworkercontainer
*
*/
@ -29,6 +29,8 @@ interface ServiceWorkerContainer : EventTarget {
[NewObject]
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
void startMessages();
attribute EventHandler oncontrollerchange;
attribute EventHandler onerror;
attribute EventHandler onmessage;

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

@ -356,7 +356,7 @@ EditorEventListener::DetachedFromEditorOrDefaultPrevented(
}
bool
EditorEventListener::EnsureCommitCompoisition()
EditorEventListener::EnsureCommitComposition()
{
MOZ_ASSERT(!DetachedFromEditor());
RefPtr<EditorBase> editorBase(mEditorBase);
@ -674,7 +674,7 @@ EditorEventListener::MouseClick(WidgetMouseEvent* aMouseClickEvent)
// If we got a mouse down inside the editing area, we should force the
// IME to commit before we change the cursor position.
if (!EnsureCommitCompoisition()) {
if (!EnsureCommitComposition()) {
return NS_OK;
}
@ -745,7 +745,7 @@ EditorEventListener::MouseDown(MouseEvent* aMouseEvent)
if (DetachedFromEditor()) {
return NS_OK;
}
Unused << EnsureCommitCompoisition();
Unused << EnsureCommitComposition();
return NS_OK;
}

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

@ -110,7 +110,7 @@ protected:
* Returns false if the editor is detached from the listener, i.e.,
* impossible to continue to handle the event. Otherwise, true.
*/
MOZ_MUST_USE bool EnsureCommitCompoisition();
MOZ_MUST_USE bool EnsureCommitComposition();
EditorBase* mEditorBase; // weak
RefPtr<nsCaret> mCaret;

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

@ -72,7 +72,7 @@ HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent)
// event is fired outside of the active editing host), we need to commit
// composition because it will be change the selection to the clicked
// point. Then, we won't be able to commit the composition.
if (!EnsureCommitCompoisition()) {
if (!EnsureCommitComposition()) {
return NS_OK;
}

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

@ -8671,6 +8671,8 @@ FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
bool
nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
{
#define TRACE(reason) \
PROFILER_TRACING("Layout", "MaybeRecreateContainerForFrameRemoval: " reason, TRACING_EVENT)
MOZ_ASSERT(aFrame, "Must have a frame");
MOZ_ASSERT(aFrame->GetParent(), "Frame shouldn't be root");
MOZ_ASSERT(aFrame == aFrame->FirstContinuation(),
@ -8679,15 +8681,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
if (IsFramePartOfIBSplit(aFrame)) {
// The removal functions can't handle removal of an {ib} split directly; we
// need to rebuild the containing block.
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" is ib-split\n");
}
#endif
TRACE("IB split removal");
ReframeContainingBlock(aFrame);
return true;
}
@ -8695,6 +8689,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
if (insertionFrame && insertionFrame->IsLegendFrame() &&
aFrame->GetParent()->IsFieldSetFrame()) {
TRACE("Fieldset / Legend");
RecreateFramesForContent(aFrame->GetParent()->GetContent(),
InsertionKind::Async);
return true;
@ -8720,6 +8715,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
// When removing a summary, we should reframe the parent details frame to
// ensure that another summary is used or the default summary is
// generated.
TRACE("Details / Summary");
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -8743,6 +8739,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
// Similar if we're a table-caption.
(inFlowFrame->IsTableCaption() &&
parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
TRACE("Table or ruby pseudo parent");
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -8761,15 +8758,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
if (nextSibling && IsTableOrRubyPseudo(nextSibling)) {
nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
if (prevSibling && IsTableOrRubyPseudo(prevSibling)) {
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" has a table pseudo next sibling of different type and a "
"table pseudo prevsibling\n");
}
#endif
TRACE("Table or ruby pseudo sibling");
// Good enough to recreate frames for aFrame's parent's content; even if
// aFrame's parent is a pseudo, that'll be the right content node.
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
@ -8788,6 +8777,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
// frames may be constructed or destroyed accordingly.
// 2. The type of the first child of a ruby frame determines
// whether a pseudo ruby base container should exist.
TRACE("Ruby container");
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -8802,14 +8792,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
// non-replaced content (including whitespace).
if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" has an anonymous flex item as its next sibling\n");
}
#endif // DEBUG
TRACE("Anon flex or grid item next sibling");
// Recreate frames for the flex container (the removed frame's parent)
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
@ -8820,14 +8803,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
// remaining child of that anonymous flex item, which can then go away.)
if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" has an anonymous flex item as its parent\n");
}
#endif // DEBUG
TRACE("Anon flex or grid item parent");
// Recreate frames for the flex container (the removed frame's grandparent)
RecreateFramesForContent(parent->GetParent()->GetContent(),
InsertionKind::Async);
@ -8839,6 +8815,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
nsIPopupContainer* popupContainer =
nsIPopupContainer::GetPopupContainer(mPresShell);
if (popupContainer && popupContainer->GetPopupSetFrame() == aFrame) {
TRACE("PopupSet");
ReconstructDocElementHierarchy(InsertionKind::Async);
return true;
}
@ -8851,6 +8828,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
!inFlowFrame->GetNextSibling() &&
((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
(parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
TRACE("Removing last child of non-fluid split parent");
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -8878,17 +8856,10 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
return false;
}
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, parent);
printf(" is ib-split\n");
}
#endif
TRACE("IB split parent");
ReframeContainingBlock(parent);
return true;
#undef TRACE
}
void
@ -11343,6 +11314,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
bool aIsAppend,
nsIFrame* aPrevSibling)
{
#define TRACE(reason) \
PROFILER_TRACING("Layout", "WipeContainingBlock: " reason, TRACING_EVENT)
if (aItems.IsEmpty()) {
return false;
}
@ -11355,6 +11329,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (aFrame->IsXULBoxFrame() &&
!(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
aItems.AnyItemsNeedBlockParent()) {
TRACE("XUL with block-wrapped kids");
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11374,6 +11349,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
const bool isLegacyBox = IsFlexContainerForLegacyBox(aFrame);
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
TRACE("Inserting inline after anon flex or grid item");
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11385,6 +11361,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyBox)) {
TRACE("Inserting inline before anon flex or grid item");
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11413,6 +11390,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyBox)) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
TRACE("Inserting non-inlines inside anon flex or grid item");
RecreateFramesForContent(containerFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11423,7 +11401,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Situation #4 is a ruby-related frame that's getting new children.
// The situation for ruby is complex, especially when interacting with
// spaces. It containes these two special cases apart from tables:
// spaces. It contains these two special cases apart from tables:
// 1) There are effectively three types of white spaces in ruby frames
// we handle differently: leading/tailing/inter-level space,
// inter-base/inter-annotation space, and inter-segment space.
@ -11436,6 +11414,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// We want to optimize it better, and avoid reframing as much as
// possible. But given the cases above, and the fact that a ruby
// usually won't be very large, it should be fine to reframe it.
TRACE("Ruby");
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11602,6 +11581,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (!aItems.AllWantParentType(parentType)) {
// Reframing aFrame->GetContent() is good enough, since the content of
// table pseudo-frames is the ancestor content.
TRACE("Pseudo-frames going wrong");
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -11684,31 +11664,16 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// but it will *always* get the right answer.
nsIContent* blockContent = aContainingBlock->GetContent();
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
blockContent);
}
#endif
TRACE("IB splits");
RecreateFramesForContent(blockContent, InsertionKind::Async);
return true;
#undef TRACE
}
void
nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
{
#ifdef DEBUG
// ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
// so I want to see when it is happening! Unfortunately, it is happening way to often because
// so much content on the web causes block-in-inline frame situations and we handle them
// very poorly
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
aFrame);
}
#endif
// XXXbz how exactly would we get here while isReflowing anyway? Should this
// whole test be ifdef DEBUG?
if (mPresShell->IsReflowLocked()) {

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

@ -211,6 +211,12 @@ VARCACHE_PREF(
RelaxedAtomicBool, true
)
VARCACHE_PREF(
"dom.performance.children_results_ipc_timeout",
dom_performance_children_results_ipc_timeout,
uint32_t, 1000
)
// If true. then the service worker interception and the ServiceWorkerManager
// will live in the parent process. This only takes effect on browser start.
// Note, this is not currently safe to use for normal browsing yet.

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

@ -1420,7 +1420,7 @@ class PackageFrontend(MachCommandBase):
setup=record.setup)
if from_build:
if 'TASK_ID' in os.environ:
if 'MOZ_AUTOMATION' in os.environ:
self.log(logging.ERROR, 'artifact', {},
'Do not use --from-build in automation; all dependencies '
'should be determined in the decision task.')

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

@ -1171,4 +1171,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1547467493204000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1547726607892000);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -33,7 +33,7 @@ talos-bcv:
by-test-platform:
.*-qr/.*: [] # this test is not useful with webrender
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
tier:
by-test-platform:
.*-qr/.*: 3 # this should be disabled but might run via try syntax anyway, so explicitly downgrade to tier-3
@ -69,7 +69,7 @@ talos-chrome:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1200
mozharness:
extra-options:
@ -98,7 +98,7 @@ talos-damp:
by-test-platform:
linux64-ccov/.*: ['try'] # Bug 1407593
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=damp
@ -124,7 +124,7 @@ talos-dromaeojs:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 2100
mozharness:
extra-options:
@ -165,7 +165,7 @@ talos-g1:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time:
by-test-platform:
linux64.*: 3600
@ -198,7 +198,7 @@ talos-g3:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 900
mozharness:
extra-options:
@ -225,7 +225,7 @@ talos-g4:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time:
by-test-platform:
linux64.*: 1500
@ -258,7 +258,7 @@ talos-g5:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=g5
@ -291,7 +291,7 @@ talos-h1:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=h1
@ -311,7 +311,7 @@ talos-h2:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=h2
@ -360,7 +360,7 @@ talos-other:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1500
mozharness:
extra-options:
@ -400,7 +400,7 @@ talos-perf-reftest:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-central', 'try']
default: ['mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['trunk', 'try']
max-run-time: 1200
mozharness:
extra-options:
@ -427,7 +427,7 @@ talos-perf-reftest-singletons:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-central', 'try']
default: ['mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['trunk', 'try']
max-run-time: 1200
mozharness:
extra-options:
@ -454,7 +454,7 @@ talos-speedometer:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1500
mozharness:
extra-options:
@ -481,7 +481,7 @@ talos-svgr:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1800
mozharness:
extra-options:
@ -508,7 +508,7 @@ talos-tp5o:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1800
mozharness:
extra-options:
@ -535,7 +535,7 @@ talos-tp6:
run-on-projects:
by-test-platform:
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
max-run-time: 1200
mozharness:
extra-options:
@ -564,7 +564,7 @@ talos-tp6-stylo-threads:
by-test-platform:
macosx.*: ['mozilla-beta', 'autoland', 'try']
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=tp6-stylo-threads
@ -578,7 +578,7 @@ talos-tps:
by-test-platform:
linux64-ccov/.*: ['try'] # Bug 1407593
windows.*msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
default: ['mozilla-beta', 'trunk', 'try']
mozharness:
extra-options:
- --suite=tps
@ -610,8 +610,8 @@ talos-xperf:
run-on-projects:
by-test-platform:
windows7-32-msvc/.*: ['mozilla-beta', 'mozilla-central', 'try']
windows7-32(-pgo)?/.*: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
windows10-64.*/opt: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
windows7-32(-pgo)?/.*: ['mozilla-beta', 'trunk', 'try']
windows10-64.*/opt: ['mozilla-beta', 'trunk', 'try']
default: []
tier:
by-test-platform:

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

@ -21,7 +21,8 @@
}
promise_test(async t => {
const scope = SCOPE + "?q=aborted-not-intercepted";
const suffix = "?q=aborted-not-intercepted";
const scope = SCOPE + suffix;
await setupRegistration(t, scope);
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
@ -33,8 +34,13 @@
const nextData = new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', function once(event) {
w.navigator.serviceWorker.removeEventListener('message', once);
resolve(event.data);
// The message triggered by the iframe's document's fetch
// request cannot get dispatched by the time we add the event
// listener, so we have to guard against it.
if (!event.data.endsWith(suffix)) {
w.navigator.serviceWorker.removeEventListener('message', once);
resolve(event.data);
}
})
});

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

@ -1,7 +1,8 @@
self.addEventListener('fetch', function(event) {
if (event.request.url.includes('dummy')) {
const url = event.request.url;
if (url.includes('dummy') && url.includes('?')) {
event.waitUntil(async function() {
let destination = new URL(event.request.url).searchParams.get("dest");
let destination = new URL(url).searchParams.get("dest");
var result = "FAIL";
if (event.request.destination == destination) {
result = "PASS";

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

@ -51,4 +51,208 @@ promise_test(t => {
})
.then(e => { assert_equals(e.data, 'quit'); });
}, 'postMessage from ServiceWorker to Client.');
// This function creates a message listener that captures all messages
// sent to this window and matches them with corresponding requests.
// This frees test code from having to use clunky constructs just to
// avoid race conditions, since the relative order of message and
// request arrival doesn't matter.
function create_message_listener(t) {
const listener = {
messages: new Set(),
requests: new Set(),
waitFor: function(predicate) {
for (const event of this.messages) {
// If a message satisfying the predicate has already
// arrived, it gets matched to this request.
if (predicate(event)) {
this.messages.delete(event);
return Promise.resolve(event);
}
}
// If no match was found, the request is stored and a
// promise is returned.
const request = { predicate };
const promise = new Promise(resolve => request.resolve = resolve);
this.requests.add(request);
return promise;
}
};
window.onmessage = t.step_func(event => {
for (const request of listener.requests) {
// If the new message matches a stored request's
// predicate, the request's promise is resolved with this
// message.
if (request.predicate(event)) {
listener.requests.delete(request);
request.resolve(event);
return;
}
};
// No outstanding request for this message, store it in case
// it's requested later.
listener.messages.add(event);
});
return listener;
}
async function service_worker_register_and_activate(t, script, scope) {
const registration = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => registration.unregister());
const worker = registration.installing;
await wait_for_state(t, worker, 'activated');
return worker;
}
// Add an iframe (parent) whose document contains a nested iframe
// (child), then set the child's src attribute to child_url and return
// its Window (without waiting for it to finish loading).
async function with_nested_iframes(t, child_url) {
const parent = await with_iframe('resources/nested-iframe-parent.html?role=parent');
t.add_cleanup(() => parent.remove());
const child = parent.contentWindow.document.getElementById('child');
child.setAttribute('src', child_url);
return child.contentWindow;
}
// Returns a predicate matching a fetch message with the specified
// key.
function fetch_message(key) {
return event => event.data.type === 'fetch' && event.data.key === key;
}
// Returns a predicate matching a ping message with the specified
// payload.
function ping_message(data) {
return event => event.data.type === 'ping' && event.data.data === data;
}
// A client message queue test is a testharness.js test with some
// additional setup:
// 1. A listener (see create_message_listener)
// 2. An active service worker
// 3. Two nested iframes
// 4. A state transition function that controls the order of events
// during the test
function client_message_queue_test(url, test_function, description) {
promise_test(async t => {
t.listener = create_message_listener(t);
const script = 'resources/stalling-service-worker.js';
const scope = 'resources/';
t.service_worker = await service_worker_register_and_activate(t, script, scope);
// We create two nested iframes such that both are controlled by
// the newly installed service worker.
const child_url = url + '?role=child';
t.frame = await with_nested_iframes(t, child_url);
t.state_transition = async function(from, to, scripts) {
// A state transition begins with the child's parser
// fetching a script due to a <script> tag. The request
// arrives at the service worker, which notifies the
// parent, which in turn notifies the test. Note that the
// event loop keeps spinning while the parser is waiting.
const request = await this.listener.waitFor(fetch_message(to));
// The test instructs the service worker to send two ping
// messages through the Client interface: first to the
// child, then to the parent.
this.service_worker.postMessage(from);
// When the parent receives the ping message, it forwards
// it to the test. Assuming that messages to both child
// and parent are mapped to the same task queue (this is
// not [yet] required by the spec), receiving this message
// guarantees that the child has already dispatched its
// message if it was allowed to do so.
await this.listener.waitFor(ping_message(from));
// Finally, reply to the service worker's fetch
// notification with the script it should use as the fetch
// request's response. This is a defensive mechanism that
// ensures the child's parser really is blocked until the
// test is ready to continue.
request.ports[0].postMessage([`state = '${to}';`].concat(scripts));
};
await test_function(t);
}, description);
}
function client_message_queue_enable_test(
install_script,
start_script,
earliest_dispatch,
description)
{
function later_state(state1, state2) {
const states = ['init', 'install', 'start', 'finish', 'loaded'];
const index1 = states.indexOf(state1);
const index2 = states.indexOf(state2);
const max_index = Math.max(index1, index2);
return states[max_index];
}
client_message_queue_test('enable-client-message-queue.html', async t => {
// While parsing the child's document, the child transitions
// from the 'init' state all the way to the 'finish' state.
// Once parsing is finished it would enter the final 'loaded'
// state. All but the last transition require assitance from
// the test.
await t.state_transition('init', 'install', [install_script]);
await t.state_transition('install', 'start', [start_script]);
await t.state_transition('start', 'finish', []);
// Wait for all messages to get dispatched on the child's
// ServiceWorkerContainer and then verify that each message
// was dispatched while the child was in the correct state.
const report = await t.frame.report;
['init', 'install', 'start'].forEach(state => {
const dispatch = later_state(state, earliest_dispatch);
assert_equals(report[state], dispatch,
`Message sent in state '${state}' dispatched in state '${dispatch}'`);
});
}, description);
}
const empty_script = ``;
const add_event_listener =
`navigator.serviceWorker.addEventListener('message', handle_message);`;
const set_onmessage = `navigator.serviceWorker.onmessage = handle_message;`;
const start_messages = `navigator.serviceWorker.startMessages();`;
client_message_queue_enable_test(add_event_listener, empty_script, 'loaded',
'Messages from ServiceWorker to Client only received after DOMContentLoaded event.');
client_message_queue_enable_test(add_event_listener, start_messages, 'start',
'Messages from ServiceWorker to Client only received after calling startMessages().');
client_message_queue_enable_test(set_onmessage, empty_script, 'install',
'Messages from ServiceWorker to Client only received after setting onmessage.');
const resolve_manual_promise = `resolve_manual_promise();`
async function test_microtasks_when_client_message_queue_enabled(t, scripts) {
await t.state_transition('init', 'start', scripts.concat([resolve_manual_promise]));
let result = await t.frame.result;
assert_equals(result[0], 'microtask', 'The microtask was executed first.');
assert_equals(result[1], 'message', 'The message was dispatched.');
}
client_message_queue_test('message-vs-microtask.html', t => {
return test_microtasks_when_client_message_queue_enabled(t, [
add_event_listener,
start_messages,
]);
}, 'Microtasks run before dispatching messages after calling startMessages().');
client_message_queue_test('message-vs-microtask.html', t => {
return test_microtasks_when_client_message_queue_enabled(t, [set_onmessage]);
}, 'Microtasks run before dispatching messages after setting onmessage.');
</script>

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

@ -41,6 +41,7 @@ if (win.location.href !== 'about:blank') {
});
}
});
win.navigator.serviceWorker.startMessages();
}
</script>
</body>

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

@ -0,0 +1,39 @@
<!DOCTYPE html>
<script>
// The state variable is used by handle_message to record the time
// at which a message was handled. It's updated by the scripts
// loaded by the <script> tags at the bottom of the file as well as
// by the event listener added here.
var state = 'init';
addEventListener('DOMContentLoaded', () => state = 'loaded');
// We expect to get three ping messages from the service worker.
const expected = ['init', 'install', 'start'];
let promises = {};
let resolvers = {};
expected.forEach(name => {
promises[name] = new Promise(resolve => resolvers[name] = resolve);
});
// Once all messages have been dispatched, the state in which each
// of them was dispatched is recorded in the draft. At that point
// the draft becomes the final report.
var draft = {};
var report = Promise.all(Object.values(promises)).then(() => window.draft);
// This message handler is installed by the 'install' script.
function handle_message(event) {
const data = event.data.data;
draft[data] = state;
resolvers[data]();
}
</script>
<!--
The controlling service worker will delay the response to these
fetch requests until the test instructs it how to reply. Note that
the event loop keeps spinning while the parser is blocked.
-->
<script src="empty.js?key=install"></script>
<script src="empty.js?key=start"></script>
<script src="empty.js?key=finish"></script>

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<script>
let draft = [];
var resolve_manual_promise;
let manual_promise =
new Promise(resolve => resolve_manual_promise = resolve).then(() => draft.push('microtask'));
let resolve_message_promise;
let message_promise = new Promise(resolve => resolve_message_promise = resolve);
function handle_message(event) {
draft.push('message');
resolve_message_promise();
}
var result = Promise.all([manual_promise, message_promise]).then(() => draft);
</script>
<script src="empty.js?key=start"></script>

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

@ -0,0 +1,5 @@
<!DOCTYPE html>
<script>
navigator.serviceWorker.onmessage = event => parent.postMessage(event.data, '*', event.ports);
</script>
<iframe id='child'></iframe>

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

@ -0,0 +1,54 @@
async function post_message_to_client(role, message, ports) {
(await clients.matchAll()).forEach(client => {
if (new URL(client.url).searchParams.get('role') === role) {
client.postMessage(message, ports);
}
});
}
async function post_message_to_child(message, ports) {
await post_message_to_client('child', message, ports);
}
function ping_message(data) {
return { type: 'ping', data };
}
self.onmessage = event => {
const message = ping_message(event.data);
post_message_to_child(message);
post_message_to_parent(message);
}
async function post_message_to_parent(message, ports) {
await post_message_to_client('parent', message, ports);
}
function fetch_message(key) {
return { type: 'fetch', key };
}
// Send a message to the parent along with a MessagePort to respond
// with.
function report_fetch_request(key) {
const channel = new MessageChannel();
const reply = new Promise(resolve => {
channel.port1.onmessage = resolve;
}).then(event => event.data);
return post_message_to_parent(fetch_message(key), [channel.port2]).then(() => reply);
}
function respond_with_script(script) {
return new Response(new Blob(script, { type: 'text/javascript' }));
}
// Whenever a controlled document requests a URL with a 'key' search
// parameter we report the request to the parent frame and wait for
// a response. The content of the response is then used to respond to
// the fetch request.
addEventListener('fetch', event => {
let key = new URL(event.request.url).searchParams.get('key');
if (key) {
event.respondWith(report_fetch_request(key).then(respond_with_script));
}
});

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

@ -502,6 +502,9 @@ def check_args(kwargs):
kwargs["certutil_binary"] = path
if kwargs['extra_prefs']:
# If a single pref is passed in as a string, make it a list
if type(kwargs['extra_prefs']) in (str, unicode):
kwargs['extra_prefs'] = [kwargs['extra_prefs']]
missing = any('=' not in prefarg for prefarg in kwargs['extra_prefs'])
if missing:
print >> sys.stderr, "Preferences via --setpref must be in key=value format"

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

@ -8,6 +8,7 @@
#include "mozilla/Logging.h"
#include "mozilla/PerformanceUtils.h"
#include "mozilla/PerformanceMetricsCollector.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WorkerDebugger.h"
@ -24,6 +25,62 @@ static mozilla::LazyLogModule sPerfLog("PerformanceMetricsCollector");
namespace mozilla {
//
// class IPCTimeout
//
NS_IMPL_ISUPPORTS(IPCTimeout, nsIObserver)
// static
IPCTimeout*
IPCTimeout::CreateInstance(AggregatedResults* aResults)
{
MOZ_ASSERT(aResults);
uint32_t delay = StaticPrefs::dom_performance_children_results_ipc_timeout();
if (delay == 0) {
return nullptr;
}
return new IPCTimeout(aResults, delay);
}
IPCTimeout::IPCTimeout(AggregatedResults* aResults, uint32_t aDelay):
mResults(aResults)
{
MOZ_ASSERT(aResults);
MOZ_ASSERT(aDelay > 0);
mozilla::DebugOnly<nsresult> rv = NS_NewTimerWithObserver(getter_AddRefs(mTimer),
this,
aDelay,
nsITimer::TYPE_ONE_SHOT);
MOZ_ASSERT(NS_SUCCEEDED(rv));
LOG(("IPCTimeout timer created"));
}
IPCTimeout::~IPCTimeout()
{
Cancel();
}
void
IPCTimeout::Cancel()
{
if (mTimer) {
LOG(("IPCTimeout timer canceled"));
mTimer->Cancel();
mTimer = nullptr;
}
}
NS_IMETHODIMP
IPCTimeout::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0);
LOG(("IPCTimeout timer triggered"));
mResults->ResolveNow();
return NS_OK;
}
//
// class AggregatedResults
//
@ -37,6 +94,7 @@ AggregatedResults::AggregatedResults(nsID aUUID,
{
MOZ_ASSERT(aCollector);
MOZ_ASSERT(aPromise);
mIPCTimeout = IPCTimeout::CreateInstance(this);
}
void
@ -44,11 +102,25 @@ AggregatedResults::Abort(nsresult aReason)
{
MOZ_ASSERT(mPromise);
MOZ_ASSERT(NS_FAILED(aReason));
if (mIPCTimeout) {
mIPCTimeout->Cancel();
mIPCTimeout = nullptr;
}
mPromise->MaybeReject(aReason);
mPromise = nullptr;
mPendingResults = 0;
}
void
AggregatedResults::ResolveNow()
{
MOZ_ASSERT(mPromise);
LOG(("[%s] Early resolve", nsIDToCString(mUUID).get()));
mPromise->MaybeResolve(mData);
mIPCTimeout = nullptr;
mCollector->ForgetAggregatedResults(mUUID);
}
void
AggregatedResults::AppendResult(const nsTArray<dom::PerformanceInfo>& aMetrics)
{
@ -97,6 +169,10 @@ AggregatedResults::AppendResult(const nsTArray<dom::PerformanceInfo>& aMetrics)
}
LOG(("[%s] All data collected, resolving promise", nsIDToCString(mUUID).get()));
if (mIPCTimeout) {
mIPCTimeout->Cancel();
mIPCTimeout = nullptr;
}
mPromise->MaybeResolve(mData);
mCollector->ForgetAggregatedResults(mUUID);
}
@ -197,7 +273,13 @@ nsresult
PerformanceMetricsCollector::DataReceived(const nsID& aUUID,
const nsTArray<PerformanceInfo>& aMetrics)
{
MOZ_ASSERT(gInstance);
// If some content process were unresponsive on shutdown, we may get called
// here with late data received from children - so instead of asserting
// that gInstance is available, we just return.
if (!gInstance) {
LOG(("[%s] gInstance is gone", nsIDToCString(aUUID).get()));
return NS_OK;
}
MOZ_ASSERT(XRE_IsParentProcess());
return gInstance->DataReceivedInternal(aUUID, aMetrics);
}
@ -209,6 +291,7 @@ PerformanceMetricsCollector::DataReceivedInternal(const nsID& aUUID,
MOZ_ASSERT(gInstance == this);
UniquePtr<AggregatedResults>* results = mAggregatedResults.GetValue(aUUID);
if (!results) {
LOG(("[%s] UUID is gone from mAggregatedResults", nsIDToCString(aUUID).get()));
return NS_ERROR_FAILURE;
}

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

@ -6,6 +6,8 @@
#ifndef PerformanceMetricsCollector_h
#define PerformanceMetricsCollector_h
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsID.h"
#include "mozilla/dom/ChromeUtilsBinding.h" // defines PerformanceInfoDictionary
#include "mozilla/dom/DOMTypes.h" // defines PerformanceInfo
@ -17,6 +19,23 @@ namespace dom {
}
class PerformanceMetricsCollector;
class AggregatedResults;
class IPCTimeout final: public nsIObserver
{
public:
NS_DECL_NSIOBSERVER
NS_DECL_ISUPPORTS
static IPCTimeout* CreateInstance(AggregatedResults* aResults);
void Cancel();
private:
IPCTimeout(AggregatedResults* aResults, uint32_t aDelay);
~IPCTimeout();
nsCOMPtr<nsITimer> mTimer;
AggregatedResults* mResults;
};
// AggregatedResults receives PerformanceInfo results that are collected
// via IPDL from all content processes and the main process. They
@ -38,8 +57,10 @@ public:
void AppendResult(const nsTArray<dom::PerformanceInfo>& aMetrics);
void SetNumResultsRequired(uint32_t aNumResultsRequired);
void Abort(nsresult aReason);
void ResolveNow();
private:
RefPtr<IPCTimeout> mIPCTimeout;
RefPtr<dom::Promise> mPromise;
uint32_t mPendingResults;
FallibleTArray<dom::PerformanceInfoDictionary> mData;

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

@ -508,7 +508,9 @@ function looksLikeUrl(str, ignoreAlphanumericHosts = false) {
// Single word including special chars.
return !REGEXP_SPACES.test(str) &&
(["/", "@", ":", "["].some(c => str.includes(c)) ||
(ignoreAlphanumericHosts ? /(.*\..*){3,}/.test(str) : str.includes(".")));
(ignoreAlphanumericHosts ?
/^([\[\]A-Z0-9.:-]+[\.:]){3,}[\[\]A-Z0-9.:-]+$/i.test(str) :
str.includes(".")));
}
/**

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

@ -551,3 +551,58 @@ devtools.main:
time_open: Time open.
os: The OS name and version e.g. "Linux 4.4.0-1014-aws", "Darwin 14.5.0", "Windows_NT 6.1.7601" or "Windows_NT 10.0.15063." This can be used to make sense of data when a feature is only available from a particular operating system build number.
session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
security.ui.identitypopup:
open:
objects: ["identity_popup"]
bug_numbers:
- 1484251
description: >
How many times the control center was opened.
Keyed by the state of the content blocking shield, where the shield-showing key indicates
that the shield icon in the identity UI is visible to the user, and shield-hidden indicates
that it is not visible.
expiry_version: "70"
notification_emails:
- jhofmann@mozilla.com
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-in
record_in_processes:
- main
extra_keys:
fb: Whether FastBlock was active while the user opened the popup
tp: Whether Tracking Protection was active while the user opened the popup
cr: Whether Cookie Restrictions was active while the user opened the popup
products:
- firefox
click:
objects: [
"fb_add_blocking",
"tp_add_blocking",
"cookies_add_blocking",
"cb_prefs_button",
"clear_sitedata",
"unblock",
"unblock_private",
"block",
"report_breakage"
]
bug_numbers:
- 1484251
description: >
User interaction by click events in the identity popup.
expiry_version: "70"
notification_emails:
- jhofmann@mozilla.com
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-in
record_in_processes:
- main
extra_keys:
fb: Whether FastBlock was active while the user interacted with the UI
tp: Whether Tracking Protection was active while the user interacted with the UI
cr: Whether Cookie Restrictions was active while the user interacted with the UI
products:
- firefox

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

@ -11321,21 +11321,31 @@
"alert_emails": ["mobile-frontend@mozilla.com"],
"bug_numbers": [1235061]
},
"COOKIE_BEHAVIOR": {
"record_in_processes": ["main"],
"expires_in_version": "70",
"releaseChannelCollection": "opt-out",
"kind": "enumerated",
"n_values": 15,
"description": "Records the cookie behavior pref at startup.",
"alert_emails": ["jhofmann@mozilla.com", "pdol@mozilla.com", "seceng-telemetry@mozilla.com"],
"bug_numbers": [1484251]
},
"TRACKING_PROTECTION_ENABLED": {
"record_in_processes": ["main", "content"],
"record_in_processes": ["main"],
"expires_in_version": "never",
"releaseChannelCollection": "opt-out",
"kind": "boolean",
"description": "True if tracking protection is enabled globally at the time that a non-Private-Browsing session is initialized.",
"description": "True if tracking protection is enabled globally at startup.",
"alert_emails": ["pdol@mozilla.com", "safebrowsing-telemetry@mozilla.org"],
"bug_numbers": [1058133]
},
"TRACKING_PROTECTION_PBM_DISABLED": {
"record_in_processes": ["main", "content"],
"record_in_processes": ["main"],
"expires_in_version": "never",
"releaseChannelCollection": "opt-out",
"kind": "boolean",
"description": "True if tracking protection in Private Browsing mode is disabled at the time that a non-Private-Browsing session is initialized.",
"description": "True if tracking protection in Private Browsing mode is disabled at startup.",
"alert_emails": ["pdol@mozilla.com", "safebrowsing-telemetry@mozilla.org"],
"bug_numbers": [1200944]
},
@ -11363,9 +11373,10 @@
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 3,
"description": "A value of 0 is sent when the security UI changes on pages loaded outside of Private Browsing mode, a value of 1 is sent when users manually disable TP on that page, and 2 is sent when users manually re-enable TP on that page.",
"description": "(Fennec Only) A value of 0 is sent when the security UI changes on pages loaded outside of Private Browsing mode, a value of 1 is sent when users manually disable TP on that page, and 2 is sent when users manually re-enable TP on that page.",
"alert_emails": ["safebrowsing-telemetry@mozilla.org"],
"bug_numbers": [1058133]
"bug_numbers": [1058133],
"products": ["fennec"]
},
"SERVICE_WORKER_LAUNCH_TIME": {
"record_in_processes": ["main", "content"],

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

@ -494,6 +494,50 @@ security:
record_in_processes:
- main
contentblocking:
enabled:
bug_numbers:
- 1484251
description: >
Whether content blocking was enabled at startup.
expires: never
kind: boolean
notification_emails:
- jhofmann@mozilla.com
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
fastblock_enabled:
bug_numbers:
- 1484251
description: >
Whether FastBlock was enabled at startup.
expires: never
kind: boolean
notification_emails:
- jhofmann@mozilla.com
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
exceptions:
bug_numbers:
- 1484251
description: >
How many tracking protection/content blocking exceptions a user has at startup.
expires: "70"
kind: uint
notification_emails:
- jhofmann@mozilla.com
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
sandbox:
no_job:
bug_numbers:

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

@ -887,6 +887,42 @@ LaunchCrashHandlerService(XP_CHAR* aProgramPath, XP_CHAR* aMinidumpPath,
#endif
void
WriteEscapedMozCrashReason(PlatformWriter& aWriter)
{
const char *reason;
size_t len;
char *rust_panic_reason;
bool rust_panic = get_rust_panic_reason(&rust_panic_reason, &len);
if (rust_panic) {
reason = rust_panic_reason;
} else if (gMozCrashReason != nullptr) {
reason = gMozCrashReason;
len = strlen(reason);
} else {
return; // No crash reason, bail out
}
WriteString(aWriter, AnnotationToString(Annotation::MozCrashReason));
WriteLiteral(aWriter, "=");
// The crash reason might be non-null-terminated in the case of a rust panic,
// it has also not being escaped so escape it one character at a time and
// write out the resulting string.
for (size_t i = 0; i < len; i++) {
if (reason[i] == '\\') {
WriteLiteral(aWriter, "\\\\");
} else if (reason[i] == '\n') {
WriteLiteral(aWriter, "\\n");
} else {
aWriter.WriteBuffer(reason + i, 1);
}
}
WriteLiteral(aWriter, "\n");
}
// Callback invoked from breakpad's exception handler, this writes out the
// last annotations after a crash occurs and launches the crash reporter client.
//
@ -1088,18 +1124,8 @@ MinidumpCallback(
WriteGlobalMemoryStatus(&apiData, &eventFile);
#endif // XP_WIN
char* rust_panic_reason;
size_t rust_panic_len;
if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) {
// rust_panic_reason is not null-terminated.
WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason,
rust_panic_len);
WriteAnnotation(eventFile, Annotation::MozCrashReason, rust_panic_reason,
rust_panic_len);
} else if (gMozCrashReason) {
WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason);
WriteAnnotation(eventFile, Annotation::MozCrashReason, gMozCrashReason);
}
WriteEscapedMozCrashReason(apiData);
WriteEscapedMozCrashReason(eventFile);
if (oomAllocationSizeBuffer[0]) {
WriteAnnotation(apiData, Annotation::OOMAllocationSize,
@ -1293,15 +1319,7 @@ PrepareChildExceptionTimeAnnotations(void* context)
oomAllocationSizeBuffer);
}
char* rust_panic_reason;
size_t rust_panic_len;
if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) {
// rust_panic_reason is not null-terminated.
WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason,
rust_panic_len);
} else if (gMozCrashReason) {
WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason);
}
WriteEscapedMozCrashReason(apiData);
std::function<void(const char*)> getThreadAnnotationCB =
[&] (const char * aValue) -> void {
@ -3056,7 +3074,7 @@ IsDataEscaped(char* aData)
}
char* pos = aData;
while ((pos = strchr(pos, '\\'))) {
if (*(pos + 1) != '\\') {
if (*(pos + 1) != '\\' && *(pos + 1) != 'n') {
return false;
}
// Add 2 to account for the second pos

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

@ -0,0 +1,11 @@
function run_test() {
// Try crashing with a Rust panic
do_crash(function() {
Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).rustPanic("OH NO\nOH NOES!");
},
function(mdump, extra) {
Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!");
},
// process will exit with a zero exit status
true);
}

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

@ -8,6 +8,7 @@ support-files =
[test_crash_moz_crash.js]
[test_crash_purevirtual.js]
[test_crash_rust_panic.js]
[test_crash_rust_panic_multiline.js]
[test_crash_after_js_oom_reported.js]
[test_crash_after_js_oom_recovered.js]
[test_crash_after_js_oom_reported_2.js]

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

@ -0,0 +1,21 @@
/* import-globals-from ../unit/head_crashreporter.js */
load("../unit/head_crashreporter.js");
function run_test() {
if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) {
dump("INFO | test_content_rust_panic.js | Can't test crashreporter in a non-libxul build.\n");
return;
}
// Try crashing with a Rust panic
do_triggered_content_crash(
function() {
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.rustPanic("OH NO\nOH NOES!");
},
function(mdump, extra) {
Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!");
}
);
}

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

@ -12,4 +12,5 @@ support-files =
skip-if = os != 'win'
[test_content_memory_list.js]
skip-if = os != 'win'
[test_content_rust_panic.js]
[test_content_rust_panic.js]
[test_content_rust_panic_multiline.js]

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

@ -1477,7 +1477,15 @@ PopupNotifications.prototype = {
notificationEl =
notificationEl.ownerDocument.getBindingParent(notificationEl) || notificationEl.parentNode;
}
this._setNotificationUIState(notificationEl);
let notification = notificationEl.notification;
if (notification.options.checkbox) {
if (notificationEl.checkbox.checked) {
this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState);
} else {
this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState);
}
}
},
_onButtonEvent(event, type, source = "button", notificationEl = null) {

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

@ -914,6 +914,7 @@ private:
: mSucceeded(false)
, mUseNativeLineBreak(true)
, mWithFontRanges(false)
, mNeedsToFlushLayout(true)
{
MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
}
@ -930,6 +931,7 @@ public:
, mSucceeded(false)
, mUseNativeLineBreak(true)
, mWithFontRanges(false)
, mNeedsToFlushLayout(true)
{
}
@ -941,6 +943,7 @@ public:
, mSucceeded(false)
, mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak)
, mWithFontRanges(false)
, mNeedsToFlushLayout(aOtherEvent.mNeedsToFlushLayout)
{
}
@ -1035,6 +1038,15 @@ public:
Init(aOptions);
}
bool NeedsToFlushLayout() const
{
#ifdef XP_MACOSX
return true;
#else
return mNeedsToFlushLayout;
#endif
}
void RequestFontRanges()
{
NS_ASSERTION(mMessage == eQueryTextContent,
@ -1068,6 +1080,7 @@ public:
bool mSucceeded;
bool mUseNativeLineBreak;
bool mWithFontRanges;
bool mNeedsToFlushLayout;
struct Input final
{
uint32_t EndOffset() const

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

@ -415,6 +415,7 @@ STUB(gtk_table_get_type)
STUB(gtk_table_new)
STUB(gtk_target_list_add)
STUB(gtk_target_list_add_image_targets)
STUB(gtk_target_list_add_text_targets)
STUB(gtk_target_list_new)
STUB(gtk_target_list_unref)
STUB(gtk_targets_include_image)

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

@ -13,6 +13,7 @@
#if defined(MOZ_WAYLAND)
#include "nsClipboardWayland.h"
#endif
#include "nsContentUtils.h"
#include "HeadlessClipboard.h"
#include "nsSupportsPrimitives.h"
#include "nsString.h"
@ -163,22 +164,14 @@ nsClipboard::SetData(nsITransferable *aTransferable,
for (uint32_t i = 0; i < flavors.Length(); i++) {
nsCString& flavorStr = flavors[i];
// special case text/unicode since we can handle all of
// the string types
// Special case text/unicode since we can handle all of the string types.
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
gtk_target_list_add(list, gdk_atom_intern("UTF8_STRING", FALSE), 0, 0);
gtk_target_list_add(list, gdk_atom_intern("COMPOUND_TEXT", FALSE), 0, 0);
gtk_target_list_add(list, gdk_atom_intern("TEXT", FALSE), 0, 0);
gtk_target_list_add(list, GDK_SELECTION_TYPE_STRING, 0, 0);
gtk_target_list_add_text_targets(list, 0);
continue;
}
if (flavorStr.EqualsLiteral(kNativeImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) ||
flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime) ||
flavorStr.EqualsLiteral(kGIFImageMime)) {
// don't bother adding image targets twice
if (nsContentUtils::IsFlavorImage(flavorStr)) {
// Don't bother adding image targets twice
if (!imagesAdded) {
// accept any writable image type
gtk_target_list_add_image_targets(list, 0, TRUE);
@ -482,12 +475,8 @@ nsClipboard::SelectionGetEvent(GtkClipboard *aClipboard,
GdkAtom selectionTarget = gtk_selection_data_get_target(aSelectionData);
// Check to see if the selection data includes any of the string
// types that we support.
if (selectionTarget == gdk_atom_intern ("STRING", FALSE) ||
selectionTarget == gdk_atom_intern ("TEXT", FALSE) ||
selectionTarget == gdk_atom_intern ("COMPOUND_TEXT", FALSE) ||
selectionTarget == gdk_atom_intern ("UTF8_STRING", FALSE)) {
// Check to see if the selection data is some text type.
if (gtk_targets_include_text(&selectionTarget, 1)) {
// Try to convert our internal type into a text string. Get
// the transferable for this clipboard and try to get the
// text/unicode type for it.
@ -503,14 +492,10 @@ nsClipboard::SelectionGetEvent(GtkClipboard *aClipboard,
nsAutoString ucs2string;
wideString->GetData(ucs2string);
char *utf8string = ToNewUTF8String(ucs2string);
if (!utf8string)
return;
NS_ConvertUTF16toUTF8 utf8string(ucs2string);
gtk_selection_data_set_text (aSelectionData, utf8string,
strlen(utf8string));
free(utf8string);
gtk_selection_data_set_text(aSelectionData, utf8string.get(),
utf8string.Length());
return;
}