зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
3b0f157728
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче