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

This commit is contained in:
Ciure Andrei 2019-07-25 19:24:23 +03:00
Родитель 86dcc39a2d 282afccb14
Коммит 3e816e5942
68 изменённых файлов: 1920 добавлений и 558 удалений

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

@ -1598,15 +1598,6 @@ pref("browser.contentblocking.fingerprinting.preferences.ui.enabled", true);
// One value from each section must be included in the browser.contentblocking.features.strict pref.
pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior4,cm,fp");
// Enable the Report Breakage UI on Nightly and Beta but not on Release yet.
#ifdef EARLY_BETA_OR_EARLIER
pref("browser.contentblocking.reportBreakage.enabled", true);
#else
pref("browser.contentblocking.reportBreakage.enabled", false);
#endif
// Show report breakage for tracking cookies in all channels.
pref("browser.contentblocking.rejecttrackers.reportBreakage.enabled", true);
pref("browser.contentblocking.reportBreakage.url", "https://tracking-protection-issues.herokuapp.com/new");
// Enable Protections report's Lockwise card by default.

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

@ -535,8 +535,6 @@ var TrackingProtection = {
var ThirdPartyCookies = {
PREF_ENABLED: "network.cookie.cookieBehavior",
PREF_REPORT_BREAKAGE_ENABLED:
"browser.contentblocking.rejecttrackers.reportBreakage.enabled",
PREF_ENABLED_VALUES: [
// These values match the ones exposed under the Content Blocking section
// of the Preferences UI.
@ -650,12 +648,6 @@ var ThirdPartyCookies = {
Ci.nsICookieService.BEHAVIOR_ACCEPT,
this.updateCategoryLabel.bind(this)
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"reportBreakageEnabled",
this.PREF_REPORT_BREAKAGE_ENABLED,
false
);
this.updateCategoryLabel();
},
@ -907,8 +899,6 @@ var ThirdPartyCookies = {
*/
var gProtectionsHandler = {
PREF_ANIMATIONS_ENABLED: "toolkit.cosmeticAnimations.enabled",
PREF_REPORT_BREAKAGE_ENABLED:
"browser.contentblocking.reportBreakage.enabled",
PREF_REPORT_BREAKAGE_URL: "browser.contentblocking.reportBreakage.url",
PREF_CB_CATEGORY: "browser.contentblocking.category",
PREF_SHOW_ALLOWED_LABELS:
@ -969,18 +959,18 @@ var gProtectionsHandler = {
"protections-popup-tp-switch-breakage-link"
));
},
get _protectionsPopupTPSwitchSection() {
delete this._protectionsPopupTPSwitchSection;
return (this._protectionsPopupTPSwitchSection = document.getElementById(
"protections-popup-tp-switch-section"
));
},
get _protectionsPopupTPSwitch() {
delete this._protectionsPopupTPSwitch;
return (this._protectionsPopupTPSwitch = document.getElementById(
"protections-popup-tp-switch"
));
},
get _breakageLink() {
delete this._breakageLink;
return (this._breakageLink = document.getElementById(
"protections-popup-tp-switch-breakage-link"
));
},
get _protectionPopupSettingsButton() {
delete this._protectionPopupSettingsButton;
return (this._protectionPopupSettingsButton = document.getElementById(
@ -1110,12 +1100,6 @@ var gProtectionsHandler = {
}
}
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"reportBreakageEnabled",
this.PREF_REPORT_BREAKAGE_ENABLED,
false
);
for (let blocker of this.blockers) {
if (blocker.init) {
@ -1453,10 +1437,19 @@ var gProtectionsHandler = {
tpSwitch.toggleAttribute("enabled", currentlyEnabled);
}
// Display the breakage link according to the current enable state.
// The display state of the breakage link will be fixed once the protections
// panel opened no matter how the TP switch state is.
this._protectionsPopupTPSwitchBreakageLink.hidden = !currentlyEnabled;
// Toggle the breakage link according to the current enable state.
this.toggleBreakageLink();
// Display a short TP switch section depending on the enable state. We need
// to use a separate attribute here since the 'hasException' attribute will
// be toggled as well as the TP switch, we cannot rely on that to decide the
// height of TP switch section, or it will change when toggling the switch,
// which is not desirable for us. So, we need to use a different attribute
// here.
this._protectionsPopupTPSwitchSection.toggleAttribute(
"short",
!currentlyEnabled
);
// Set the counter of the 'Trackers blocked This Week'.
// We need to get the statistics of trackers. So far, we haven't implemented
@ -1500,6 +1493,9 @@ var gProtectionsHandler = {
tpSwitch.toggleAttribute("enabled", !newExceptionState);
}
// Toggle the breakage link if needed.
this.toggleBreakageLink();
// Indicating that we need to show a toast after refreshing the page.
// And caching the current URI and window ID in order to only show the mini
// panel if it's still on the same page.
@ -1570,10 +1566,6 @@ var gProtectionsHandler = {
);
}
// Adjust "site not working?" visibility based on whether we're
// blocking something or not.
gProtectionsHandler.toggleBreakageLink();
// Check the panel state of the identity panel. Hide it if needed.
if (gIdentityHandler._identityPopup.state != "closed") {
PanelMultiView.hidePopup(gIdentityHandler._identityPopup);
@ -1611,18 +1603,18 @@ var gProtectionsHandler = {
},
toggleBreakageLink() {
// For release (due to the large volume) we only want to receive reports
// for breakage that is directly related to third party cookie blocking.
if (
this.reportBreakageEnabled ||
(ThirdPartyCookies.reportBreakageEnabled &&
ThirdPartyCookies.activated &&
!TrackingProtection.activated)
) {
this._breakageLink.removeAttribute("hidden");
} else {
this._breakageLink.setAttribute("hidden", "true");
}
// The breakage link will only be shown if tracking protection is enabled
// for the site and the TP toggle state is on. And we won't show the
// link as toggling TP switch to On from Off. In order to do so, we need to
// know the previous TP state. We check the ContentBlockingAllowList instead
// of 'hasException' attribute of the protection popup for the previous
// since the 'hasException' will also be toggled as well as toggling the TP
// switch. We won't be able to know the previous TP state through the
// 'hasException' attribute. So we fallback to check the
// ContentBlockingAllowList here.
this._protectionsPopupTPSwitchBreakageLink.hidden =
ContentBlockingAllowList.includes(gBrowser.selectedBrowser) ||
!this._protectionsPopupTPSwitch.hasAttribute("enabled");
},
submitBreakageReport(uri) {

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

@ -309,7 +309,10 @@ var gURLBarHandler = {
get urlbar() {
if (!this._urlbar) {
let textbox = document.getElementById("urlbar");
this._urlbar = new UrlbarInput({ textbox });
this._urlbar = new UrlbarInput({
textbox,
eventTelemetryCategory: "urlbar",
});
if (this._lastValue) {
this._urlbar.value = this._lastValue;
delete this._lastValue;

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

@ -204,7 +204,7 @@ var gSanitizePromptDialog = {
var prefs = this._getItemPrefs();
for (let i = 0; i < prefs.length; ++i) {
var p = prefs[i];
Services.prefs.setBoolPref(p.name, p.value);
Services.prefs.setBoolPref(p.id, p.value);
}
},

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

@ -332,16 +332,20 @@
gBrowser.selectedTab = lastSelectedTab;
// Make sure selection is cleared when tab-switch doesn't happen.
gBrowser.clearMultiSelectedTabs(false);
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
}
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
} else if (accelKey) {
// Ctrl (Cmd for mac) key is pressed
eventMaySelectTab = false;
if (this.multiselected) {
gBrowser.removeFromMultiSelectedTabs(this, true);
gBrowser.removeFromMultiSelectedTabs(this, {
isLastMultiSelectChange: true,
});
} else if (this != gBrowser.selectedTab) {
gBrowser.addToMultiSelectedTabs(this, false);
gBrowser.addToMultiSelectedTabs(this, {
isLastMultiSelectChange: true,
});
gBrowser.lastMultiSelectedTab = this;
}
} else if (!this.selected && this.multiselected) {
@ -382,9 +386,9 @@
// Force positional attributes to update when the
// target (of the click) is the "active" tab.
let updatePositionalAttr = gBrowser.selectedTab == this;
let isLastMultiSelectChange = gBrowser.selectedTab == this;
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange });
}
if (

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

@ -342,13 +342,13 @@
case KeyEvent.DOM_VK_SPACE:
if (visibleTabs[lastFocusedTabIndex].multiselected) {
gBrowser.removeFromMultiSelectedTabs(
visibleTabs[lastFocusedTabIndex]
visibleTabs[lastFocusedTabIndex],
{ isLastMultiSelectChange: false }
);
} else {
gBrowser.addToMultiSelectedTabs(
visibleTabs[lastFocusedTabIndex],
false
);
gBrowser.addToMultiSelectedTabs(visibleTabs[lastFocusedTabIndex], {
isLastMultiSelectChange: true,
});
}
break;
default:

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

@ -1201,7 +1201,7 @@
this._startMultiSelectChange();
this._multiSelectChangeSelected = true;
this.clearMultiSelectedTabs(true);
this.clearMultiSelectedTabs({ isLastMultiSelectChange: true });
if (oldBrowser != newBrowser && oldBrowser.getInPermitUnload) {
oldBrowser.getInPermitUnload(inPermitUnload => {
@ -4364,7 +4364,7 @@
return SessionStore.duplicateTab(window, aTab, 0, aRestoreTabImmediately);
},
addToMultiSelectedTabs(aTab, multiSelectMayChangeMore) {
addToMultiSelectedTabs(aTab, { isLastMultiSelectChange = false } = {}) {
if (aTab.multiselected) {
return;
}
@ -4379,10 +4379,12 @@
this._multiSelectChangeAdditions.add(aTab);
}
if (!multiSelectMayChangeMore) {
if (isLastMultiSelectChange) {
let { selectedTab } = this;
if (!selectedTab.multiselected) {
this.addToMultiSelectedTabs(selectedTab, true);
this.addToMultiSelectedTabs(selectedTab, {
isLastMultiSelectChange: false,
});
}
this.tabContainer._setPositionalAttributes();
}
@ -4406,12 +4408,17 @@
: [indexOfTab2, indexOfTab1];
for (let i = lowerIndex; i <= higherIndex; i++) {
this.addToMultiSelectedTabs(tabs[i], true);
this.addToMultiSelectedTabs(tabs[i], {
isLastMultiSelectChange: false,
});
}
this.tabContainer._setPositionalAttributes();
},
removeFromMultiSelectedTabs(aTab, isLastMultiSelectChange) {
removeFromMultiSelectedTabs(
aTab,
{ isLastMultiSelectChange = false } = {}
) {
if (!aTab.multiselected) {
return;
}
@ -4433,7 +4440,7 @@
}
},
clearMultiSelectedTabs(isLastMultiSelectChange) {
clearMultiSelectedTabs({ isLastMultiSelectChange = false } = {}) {
if (this._clearMultiSelectionLocked) {
if (this._clearMultiSelectionLockedOnce) {
this._clearMultiSelectionLockedOnce = false;
@ -4447,7 +4454,9 @@
}
for (let tab of this.selectedTabs) {
this.removeFromMultiSelectedTabs(tab, false);
this.removeFromMultiSelectedTabs(tab, {
isLastMultiSelectChange: false,
});
}
this._lastMultiSelectedTabRef = null;
if (isLastMultiSelectChange) {
@ -4508,7 +4517,7 @@
*/
avoidSingleSelectedTab() {
if (this.multiSelectedTabsCount == 1) {
this.clearMultiSelectedTabs();
this.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
}
},
@ -4535,11 +4544,13 @@
},
set selectedTabs(tabs) {
this.clearMultiSelectedTabs(false);
this.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
this.selectedTab = tabs[0];
if (tabs.length > 1) {
for (let tab of tabs) {
this.addToMultiSelectedTabs(tab, true);
this.addToMultiSelectedTabs(tab, {
isLastMultiSelectChange: false,
});
}
}
this.tabContainer._setPositionalAttributes();

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

@ -714,7 +714,7 @@ add_task(async function sendToDevice_title() {
// Add the other tab to the selection.
gBrowser.addToMultiSelectedTabs(
gBrowser.getTabForBrowser(otherBrowser),
false
{ isLastMultiSelectChange: true }
);
// Open the panel again. Now the action's title should be "Send 2 Tabs to

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

@ -25,6 +25,15 @@ add_task(async function testToggleSwitch() {
"https://example.com"
);
await openProtectionsPanel();
// Check the visibility of the "Site not working?" link.
ok(
BrowserTestUtils.is_visible(
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
),
"The 'Site not working?' link should be visible."
);
ok(
gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("enabled"),
"TP Switch should be enabled"
@ -35,6 +44,15 @@ add_task(async function testToggleSwitch() {
);
let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
gProtectionsHandler._protectionsPopupTPSwitch.click();
// The 'Site not working?' link should be hidden after clicking the TP switch.
ok(
BrowserTestUtils.is_hidden(
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
),
"The 'Site not working?' link should be hidden after TP switch turns to off."
);
await popuphiddenPromise;
// We need to wait toast's popup shown and popup hidden events. It won't fire
@ -60,6 +78,30 @@ add_task(async function testToggleSwitch() {
!gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("enabled"),
"TP Switch should be disabled"
);
// The 'Site not working?' link should be hidden if the TP is off.
ok(
BrowserTestUtils.is_hidden(
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
),
"The 'Site not working?' link should be hidden if TP is off."
);
// Click the TP switch again and check the visibility of the 'Site not
// Working?'. It should be hidden after toggling the TP switch.
browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
gProtectionsHandler._protectionsPopupTPSwitch.click();
ok(
BrowserTestUtils.is_hidden(
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
),
`The 'Site not working?' link should be still hidden after toggling TP
switch to on from off.`
);
await browserLoadedPromise;
ContentBlockingAllowList.remove(tab.linkedBrowser);
BrowserTestUtils.removeTab(tab);
});

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

@ -51,7 +51,7 @@ add_task(async function withAMultiSelectedTab() {
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
is(gBrowser.selectedTab, initialTab, "InitialTab is still the active tab");
gBrowser.clearMultiSelectedTabs(false);
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab4);
});

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

@ -142,63 +142,85 @@ add_task(async function clickWithPrefSet() {
"Unmultiselection tab with removeFromMultiSelectedTabs should trigger event"
);
await expectEvent(async () => {
gBrowser.removeFromMultiSelectedTabs(tab3, true);
gBrowser.removeFromMultiSelectedTabs(tab3, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info("Expect no event if the tab is not multiselected");
await expectNoEvent(async () => {
gBrowser.removeFromMultiSelectedTabs(tab3, true);
gBrowser.removeFromMultiSelectedTabs(tab3, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info(
"Clearing multiselection with clearMultiSelectedTabs should trigger event"
);
await expectEvent(async () => {
gBrowser.clearMultiSelectedTabs(tab3, true);
gBrowser.clearMultiSelectedTabs(tab3, {
isLastMultiSelectChange: true,
});
}, [tab1]);
info("Expect no event if there is no multiselection to clear");
await expectNoEvent(async () => {
gBrowser.clearMultiSelectedTabs(tab3, true);
gBrowser.clearMultiSelectedTabs(tab3, {
isLastMultiSelectChange: true,
});
}, [tab1]);
info(
"Expect no event if clearMultiSelectedTabs counteracts addToMultiSelectedTabs"
);
await expectNoEvent(async () => {
gBrowser.addToMultiSelectedTabs(tab3, true);
gBrowser.clearMultiSelectedTabs(true);
gBrowser.addToMultiSelectedTabs(tab3, {
isLastMultiSelectChange: false,
});
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: true });
}, [tab1]);
info(
"Multiselecting tab with gBrowser.addToMultiSelectedTabs should trigger event"
);
await expectEvent(async () => {
gBrowser.addToMultiSelectedTabs(tab2, false);
gBrowser.addToMultiSelectedTabs(tab2, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info(
"Expect no event if addToMultiSelectedTabs counteracts clearMultiSelectedTabs"
);
await expectNoEvent(async () => {
gBrowser.clearMultiSelectedTabs(false);
gBrowser.addToMultiSelectedTabs(tab2, false);
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
gBrowser.addToMultiSelectedTabs(tab2, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info(
"Expect no event if removeFromMultiSelectedTabs counteracts addToMultiSelectedTabs"
);
await expectNoEvent(async () => {
gBrowser.addToMultiSelectedTabs(tab3, true);
gBrowser.removeFromMultiSelectedTabs(tab3, true);
gBrowser.addToMultiSelectedTabs(tab3, {
isLastMultiSelectChange: false,
});
gBrowser.removeFromMultiSelectedTabs(tab3, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info(
"Expect no event if addToMultiSelectedTabs counteracts removeFromMultiSelectedTabs"
);
await expectNoEvent(async () => {
gBrowser.removeFromMultiSelectedTabs(tab2, false);
gBrowser.addToMultiSelectedTabs(tab2, false);
gBrowser.removeFromMultiSelectedTabs(tab2, {
isLastMultiSelectChange: false,
});
gBrowser.addToMultiSelectedTabs(tab2, {
isLastMultiSelectChange: true,
});
}, [tab1, tab2]);
info("Multiselection with addRangeToMultiSelectedTabs should trigger event");

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

@ -15,8 +15,6 @@ const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
const TP_PREF = "privacy.trackingprotection.enabled";
const CB_PREF = "network.cookie.cookieBehavior";
const PREF_REPORT_BREAKAGE_ENABLED =
"browser.contentblocking.reportBreakage.enabled";
const PREF_REPORT_BREAKAGE_URL = "browser.contentblocking.reportBreakage.url";
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
@ -34,7 +32,6 @@ add_task(async function setup() {
Services.prefs.clearUserPref(CB_PREF);
Services.prefs.clearUserPref(FP_PREF);
Services.prefs.clearUserPref(CM_PREF);
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL);
UrlClassifierTestUtils.cleanupTestTrackers();
@ -64,93 +61,8 @@ add_task(async function setup() {
});
});
add_task(async function testReportBreakageVisibility() {
let scenarios = [
{
url: TRACKING_PAGE,
prefs: {
"privacy.trackingprotection.enabled": true,
"browser.contentblocking.reportBreakage.enabled": true,
},
buttonVisible: true,
},
{
url: TRACKING_PAGE,
hasException: true,
prefs: {
"privacy.trackingprotection.enabled": true,
"browser.contentblocking.reportBreakage.enabled": true,
},
buttonVisible: true,
},
{
url: TRACKING_PAGE,
prefs: {
"privacy.trackingprotection.enabled": true,
"browser.contentblocking.reportBreakage.enabled": false,
},
buttonVisible: false,
},
{
url: BENIGN_PAGE,
prefs: {
"privacy.trackingprotection.enabled": true,
"browser.contentblocking.reportBreakage.enabled": true,
},
buttonVisible: false,
},
{
url: COOKIE_PAGE,
prefs: {
"privacy.trackingprotection.enabled": false,
"network.cookie.cookieBehavior":
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
"browser.contentblocking.reportBreakage.enabled": false,
"browser.contentblocking.rejecttrackers.reportBreakage.enabled": true,
},
buttonVisible: true,
},
];
for (let scenario of scenarios) {
for (let pref in scenario.prefs) {
Preferences.set(pref, scenario.prefs[pref]);
}
let uri = Services.io.newURI(scenario.url);
if (scenario.hasException) {
Services.perms.add(
uri,
"trackingprotection",
Services.perms.ALLOW_ACTION
);
}
await BrowserTestUtils.withNewTab(scenario.url, async function() {
await openProtectionsPopup();
let reportBreakageButton = document.getElementById(
"protections-popup-tp-switch-breakage-link"
);
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.is_visible(reportBreakageButton) ==
scenario.buttonVisible,
"waiting for correct visibility"
);
ok(true, "report breakage button has the correct visibility");
});
Services.perms.remove(uri, "trackingprotection");
for (let pref in scenario.prefs) {
Services.prefs.clearUserPref(pref);
}
}
});
add_task(async function testReportBreakageCancel() {
Services.prefs.setBoolPref(TP_PREF, true);
Services.prefs.setBoolPref(PREF_REPORT_BREAKAGE_ENABLED, true);
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
await openProtectionsPopup();
@ -195,7 +107,6 @@ add_task(async function testReportBreakageCancel() {
});
Services.prefs.clearUserPref(TP_PREF);
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
});
add_task(async function testTP() {
@ -265,7 +176,6 @@ async function testReportBreakage(url, tags) {
let path =
i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort + "/";
Services.prefs.setBoolPref(PREF_REPORT_BREAKAGE_ENABLED, true);
Services.prefs.setStringPref(PREF_REPORT_BREAKAGE_URL, path);
await openProtectionsPopup();
@ -384,6 +294,5 @@ async function testReportBreakage(url, tags) {
// Stop the server.
await new Promise(r => server.stop(r));
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL);
}

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

@ -53,7 +53,7 @@ function openProtectionsPopup() {
let mainView = document.getElementById("protections-popup-mainView");
let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
// TODO: This should click on the icon once we have it.
gProtectionsHandler.showProtectionsPopup();
gIdentityHandler._trackingProtectionIconContainer.click();
return viewShown;
}

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

@ -829,7 +829,9 @@ this.tabs = class extends ExtensionAPI {
}
if (updateProperties.highlighted) {
if (!nativeTab.selected && !nativeTab.multiselected) {
tabbrowser.addToMultiSelectedTabs(nativeTab, false);
tabbrowser.addToMultiSelectedTabs(nativeTab, {
isLastMultiSelectChange: true,
});
// Select the highlighted tab unless active:false is provided.
// Note that Chrome selects it even in that case.
if (updateProperties.active !== false) {
@ -838,7 +840,9 @@ this.tabs = class extends ExtensionAPI {
}
}
} else {
tabbrowser.removeFromMultiSelectedTabs(nativeTab, true);
tabbrowser.removeFromMultiSelectedTabs(nativeTab, {
isLastMultiSelectChange: true,
});
}
}
if (updateProperties.muted !== null) {

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

@ -156,23 +156,23 @@
<vbox flex="1">
<!-- by design, no tooltip for bookmarks or history -->
<checkbox data-l10n-id="sync-engine-bookmarks"
preference="engine.bookmarks"/>
preference="services.sync.engine.bookmarks"/>
<checkbox data-l10n-id="sync-engine-history"
preference="engine.history"/>
preference="services.sync.engine.history"/>
<checkbox data-l10n-id="sync-engine-tabs"
preference="engine.tabs"/>
preference="services.sync.engine.tabs"/>
<checkbox data-l10n-id="sync-engine-logins"
preference="engine.passwords"/>
preference="services.sync.engine.passwords"/>
</vbox>
<vbox flex="1">
<checkbox data-l10n-id="sync-engine-addresses"
preference="engine.addresses"/>
preference="services.sync.engine.addresses"/>
<checkbox data-l10n-id="sync-engine-creditcards"
preference="engine.creditcards"/>
preference="services.sync.engine.creditcards"/>
<checkbox data-l10n-id="sync-engine-addons"
preference="engine.addons"/>
preference="services.sync.engine.addons"/>
<checkbox data-l10n-id="sync-engine-prefs"
preference="engine.prefs"/>
preference="services.sync.engine.prefs"/>
</vbox>
<spacer/>
</hbox>

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

@ -31,30 +31,14 @@ const FXA_LOGIN_UNVERIFIED = 1;
const FXA_LOGIN_FAILED = 2;
Preferences.addAll([
{ id: "engine.addons", name: "services.sync.engine.addons", type: "bool" },
{
id: "engine.bookmarks",
name: "services.sync.engine.bookmarks",
type: "bool",
},
{ id: "engine.history", name: "services.sync.engine.history", type: "bool" },
{ id: "engine.tabs", name: "services.sync.engine.tabs", type: "bool" },
{ id: "engine.prefs", name: "services.sync.engine.prefs", type: "bool" },
{
id: "engine.passwords",
name: "services.sync.engine.passwords",
type: "bool",
},
{
id: "engine.addresses",
name: "services.sync.engine.addresses",
type: "bool",
},
{
id: "engine.creditcards",
name: "services.sync.engine.creditcards",
type: "bool",
},
{ id: "services.sync.engine.addons", type: "bool" },
{ id: "services.sync.engine.bookmarks", type: "bool" },
{ id: "services.sync.engine.history", type: "bool" },
{ id: "services.sync.engine.tabs", type: "bool" },
{ id: "services.sync.engine.prefs", type: "bool" },
{ id: "services.sync.engine.passwords", type: "bool" },
{ id: "services.sync.engine.addresses", type: "bool" },
{ id: "services.sync.engine.creditcards", type: "bool" },
]);
var gSyncPane = {
@ -111,8 +95,14 @@ var gSyncPane = {
// These 2 engines are unique in that there are prefs that make the
// entire engine unavailable (which is distinct from "disabled").
let enginePrefs = [
["services.sync.engine.addresses.available", "engine.addresses"],
["services.sync.engine.creditcards.available", "engine.creditcards"],
[
"services.sync.engine.addresses.available",
"services.sync.engine.addresses",
],
[
"services.sync.engine.creditcards.available",
"services.sync.engine.creditcards",
],
];
let numHidden = 0;
for (let [availablePref, prefName] of enginePrefs) {
@ -128,8 +118,12 @@ var gSyncPane = {
// the second column. (If we only moved one, it's still unbalanced, but
// there's an odd number of engines so that can't be avoided)
if (numHidden == 2) {
let history = document.querySelector('[preference="engine.history"]');
let addons = document.querySelector('[preference="engine.addons"]');
let history = document.querySelector(
'[preference="services.sync.engine.history"]'
);
let addons = document.querySelector(
'[preference="services.sync.engine.addons"]'
);
addons.parentNode.insertBefore(history, addons);
}
},

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

@ -369,7 +369,7 @@ const gPrefCache = new Map();
function cache_preferences(win) {
let prefs = win.Preferences.getAll();
for (let pref of prefs) {
gPrefCache.set(pref.name, pref.value);
gPrefCache.set(pref.id, pref.value);
}
}
@ -377,8 +377,8 @@ function reset_preferences(win) {
let prefs = win.Preferences.getAll();
// Avoid assigning undefined, which means clearing a "user"/test pref value
for (let pref of prefs) {
if (gPrefCache.has(pref.name)) {
pref.value = gPrefCache.get(pref.name);
if (gPrefCache.has(pref.id)) {
pref.value = gPrefCache.get(pref.id);
}
}
}

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

@ -95,7 +95,9 @@ add_task(async function test_movePendingTabToNewWindow() {
newWindowTabs[1].hasAttribute("pending"),
"Second tab in new window should still be pending"
);
newWindow.gBrowser.clearMultiSelectedTabs(true);
newWindow.gBrowser.clearMultiSelectedTabs({
isLastMultiSelectChange: true,
});
ok(
newWindowTabs.every(t => !t.multiselected),
"No multiselection should be present"

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

@ -65,6 +65,8 @@ class UrlbarController {
this._listeners = new Set();
this._userSelectionBehavior = "none";
this.engagementEvent = new TelemetryEvent(options.eventTelemetryCategory);
}
/**
@ -339,6 +341,7 @@ class UrlbarController {
}
if (executeAction) {
this.userSelectionBehavior = "arrow";
this.engagementEvent.start(event);
this.input.startQuery({ searchString: this.input.textValue });
}
}
@ -581,3 +584,196 @@ class UrlbarController {
}
}
}
/**
* Tracks and records telemetry events for the given category, if provided,
* otherwise it's a no-op.
* It is currently designed around the "urlbar" category, even if it can
* potentially be extended to other categories.
* To record an event, invoke start() with a starting event, then either
* invoke record() with a final event, or discard() to drop the recording.
* @see Events.yaml
*/
class TelemetryEvent {
constructor(category) {
this._category = category;
}
/**
* Start measuring the elapsed time from an input event.
* After this has been invoked, any subsequent calls to start() are ignored,
* until either record() or discard() are invoked. Thus, it is safe to keep
* invoking this on every input event.
* @param {event} event A DOM input event.
* @note This should never throw, or it may break the urlbar.
*/
start(event) {
// Start is invoked at any input, but we only count the first one.
// Once an engagement or abandoment happens, we clear the _startEventInfo.
if (!this._category || this._startEventInfo) {
return;
}
if (!event) {
Cu.reportError("Must always provide an event");
return;
}
if (!["input", "drop", "mousedown", "keydown"].includes(event.type)) {
Cu.reportError("Can't start recording from event type: " + event.type);
return;
}
// "typed" is used when the user types something, while "pasted" and
// "dropped" are used when the text is inserted at once, by a paste or drop
// operation. "topsites" is a bit special, it is used when the user opens
// the empty search dropdown, that is supposed to show top sites. That
// happens by clicking on the urlbar dropmarker, or pressing DOWN with an
// empty input field. Even if the user later types something, we still
// report "topsites", with a positive numChars.
let interactionType = "topsites";
if (event.type == "input") {
interactionType = UrlbarUtils.isPasteEvent(event) ? "pasted" : "typed";
} else if (event.type == "drop") {
interactionType = "dropped";
}
this._startEventInfo = {
timeStamp: event.timeStamp || Cu.now(),
interactionType,
};
}
/**
* Record an engagement telemetry event.
* When the user picks a result from a search through the mouse or keyboard,
* an engagement event is recorded. If instead the user abandons a search, by
* blurring the input field, an abandonment event is recorded.
* @param {event} [event] A DOM event.
* @param {object} details An object describing action details.
* @param {string} details.numChars Number of input characters.
* @param {string} details.selIndex Index of the selected result, undefined
* for "blur".
* @param {string} details.selType type of the selected element, undefined
* for "blur". One of "none", "autofill", "visit", "bookmark",
* "history", "keyword", "search", "searchsuggestion", "switchtab",
* "remotetab", "extension", "oneoff".
* @note event can be null, that usually happens for paste&go or drop&go.
* If there's no _startEventInfo this is a no-op.
*/
record(event, details) {
// This should never throw, or it may break the urlbar.
try {
this._internalRecord(event, details);
} catch (ex) {
Cu.reportError("Could not record event: " + ex);
} finally {
this._startEventInfo = null;
}
}
_internalRecord(event, details) {
if (!this._category || !this._startEventInfo) {
return;
}
if (
!event &&
this._startEventInfo.interactionType != "pasted" &&
this._startEventInfo.interactionType != "dropped"
) {
// If no event is passed, we must be executing either paste&go or drop&go.
throw new Error("Event must be defined, unless input was pasted/dropped");
}
if (!details) {
throw new Error("Invalid event details: " + details);
}
let endTime = (event && event.timeStamp) || Cu.now();
let startTime = this._startEventInfo.timeStamp || endTime;
// Synthesized events in tests may have a bogus timeStamp, causing a
// subtraction between monotonic and non-monotonic timestamps; that's why
// abs is necessary here. It should only happen in tests, anyway.
let elapsed = Math.abs(Math.round(endTime - startTime));
let action;
if (!event) {
action =
this._startEventInfo.interactionType == "dropped"
? "drop_go"
: "paste_go";
} else if (event.type == "blur") {
action = "blur";
} else {
action = event instanceof MouseEvent ? "click" : "enter";
}
let method = action == "blur" ? "abandonment" : "engagement";
let value = this._startEventInfo.interactionType;
// Rather than listening to the pref, just update status when we record an
// event, if the pref changed from the last time.
let recordingEnabled = UrlbarPrefs.get("eventTelemetry.enabled");
if (this._eventRecordingEnabled != recordingEnabled) {
this._eventRecordingEnabled = recordingEnabled;
Services.telemetry.setEventRecordingEnabled("urlbar", recordingEnabled);
}
let extra = {
elapsed: elapsed.toString(),
numChars: details.numChars.toString(),
};
if (method == "engagement") {
extra.selIndex = details.selIndex.toString();
extra.selType = details.selType;
}
// We invoke recordEvent regardless, if recording is disabled this won't
// report the events remotely, but will count it in the event_counts scalar.
Services.telemetry.recordEvent(
this._category,
method,
action,
value,
extra
);
}
/**
* Resets the currently tracked input event, that was registered via start(),
* so it won't be recorded.
* If there's no tracked input event, this is a no-op.
*/
discard() {
this._startEventInfo = null;
}
/**
* Extracts a type from a result, to be used in the telemetry event.
* @param {UrlbarResult} result The result to analyze.
* @returns {string} a string type for the telemetry event.
*/
typeFromResult(result) {
if (result) {
switch (result.type) {
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
return "switchtab";
case UrlbarUtils.RESULT_TYPE.SEARCH:
return result.payload.suggestion ? "searchsuggestion" : "search";
case UrlbarUtils.RESULT_TYPE.URL:
if (result.autofill) {
return "autofill";
}
if (result.heuristic) {
return "visit";
}
return result.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS
? "bookmark"
: "history";
case UrlbarUtils.RESULT_TYPE.KEYWORD:
return "keyword";
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
return "extension";
case UrlbarUtils.RESULT_TYPE.REMOTE_TAB:
return "remotetab";
}
}
return "none";
}
}

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

@ -93,6 +93,7 @@ class UrlbarInput {
options.controller ||
new UrlbarController({
browserWindow: this.window,
eventTelemetryCategory: options.eventTelemetryCategory,
});
this.controller.setInput(this);
this.view = new UrlbarView(this);
@ -207,6 +208,10 @@ class UrlbarInput {
this.view.panel.addEventListener("popupshowing", this);
this.view.panel.addEventListener("popuphidden", this);
// This is used to detect commands launched from the panel, to avoid
// recording abandonment events when the command causes a blur event.
this.view.panel.addEventListener("command", this, true);
this._copyCutController = new CopyCutController(this);
this.inputField.controllers.insertControllerAt(0, this._copyCutController);
@ -363,7 +368,7 @@ class UrlbarInput {
/**
* Handles an event which would cause a url or text to be opened.
*
* @param {Event} event The event triggering the open.
* @param {Event} [event] The event triggering the open.
* @param {string} [openWhere] Where we expect the result to be opened.
* @param {object} [openParams]
* The parameters related to where the result will be opened.
@ -390,6 +395,7 @@ class UrlbarInput {
}
// Do the command of the selected one-off if it's not an engine.
if (selectedOneOff && !selectedOneOff.engine) {
this.controller.engagementEvent.discard();
selectedOneOff.doCommand();
return;
}
@ -404,7 +410,11 @@ class UrlbarInput {
}
let url;
let selType = this.controller.engagementEvent.typeFromResult(result);
let numChars = this.textValue.length;
if (selectedOneOff) {
selType = "oneoff";
numChars = this._lastSearchString.length;
// If there's a selected one-off button then load a search using
// the button's engine.
result = this._resultForCurrentValue;
@ -436,6 +446,12 @@ class UrlbarInput {
openParams.allowInheritPrincipal = false;
url = this._maybeCanonizeURL(event, url) || url.trim();
this.controller.engagementEvent.record(event, {
numChars,
selIndex: this.view.selectedIndex,
selType,
});
try {
new URL(url);
} catch (ex) {
@ -479,6 +495,7 @@ class UrlbarInput {
allowInheritPrincipal: false,
};
let selIndex = this.view.selectedIndex;
if (!result.payload.isKeywordOffer) {
this.view.close();
}
@ -486,6 +503,11 @@ class UrlbarInput {
this.controller.recordSelectedResult(event, result);
if (isCanonized) {
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
selIndex,
selType: "canonized",
});
this._loadURL(this.value, where, openParams);
return;
}
@ -514,14 +536,18 @@ class UrlbarInput {
),
};
if (
this.window.switchToTabHavingURI(
Services.io.newURI(url),
false,
loadOpts
) &&
prevTab.isEmpty
) {
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
selIndex,
selType: "tabswitch",
});
let switched = this.window.switchToTabHavingURI(
Services.io.newURI(url),
false,
loadOpts
);
if (switched && prevTab.isEmpty) {
this.window.gBrowser.removeTab(prevTab);
}
return;
@ -533,6 +559,12 @@ class UrlbarInput {
// the user can directly start typing a query string at that point.
this.selectionStart = this.selectionEnd = this.value.length;
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
selIndex,
selType: "keywordoffer",
});
// Picking a keyword offer just fills it in the input and doesn't
// visit anything. The user can then type a search string. Also
// start a new search so that the offer appears in the view by itself
@ -549,6 +581,12 @@ class UrlbarInput {
break;
}
case UrlbarUtils.RESULT_TYPE.OMNIBOX: {
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
selIndex,
selType: "extension",
});
// The urlbar needs to revert to the loaded url when a command is
// handled by the extension.
this.handleRevert();
@ -578,6 +616,12 @@ class UrlbarInput {
);
}
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
selIndex,
selType: this.controller.engagementEvent.typeFromResult(result),
});
this._loadURL(url, where, openParams, {
source: result.source,
type: result.type,
@ -1393,7 +1437,23 @@ class UrlbarInput {
// Event handlers below.
_on_command(event) {
// Something is executing a command, likely causing a focus change. This
// should not be recorded as an abandonment.
this.controller.engagementEvent.discard();
}
_on_blur(event) {
// We cannot count every blur events after a missed engagement as abandoment
// because the user may have clicked on some view element that executes
// a command causing a focus change. For example opening preferences from
// the oneoff settings button, or from a contextual tip button.
// For now we detect that case by discarding the event on command, but we
// may want to figure out a more robust way to detect abandonment.
this.controller.engagementEvent.record(event, {
numChars: this._lastSearchString.length,
});
this.removeAttribute("focused");
this.formatValue();
this._resetSearchState();
@ -1469,6 +1529,7 @@ class UrlbarInput {
this.editor.selectAll();
event.preventDefault();
} else if (this.openViewOnFocus && !this.view.isOpen) {
this.controller.engagementEvent.start(event);
this.startQuery({
allowAutofill: false,
});
@ -1481,6 +1542,7 @@ class UrlbarInput {
this.view.close();
} else {
this.focus();
this.controller.engagementEvent.start(event);
this.startQuery({
allowAutofill: false,
});
@ -1534,12 +1596,13 @@ class UrlbarInput {
return;
}
this.controller.engagementEvent.start(event);
// Autofill only when text is inserted (i.e., event.data is not empty) and
// it's not due to pasting.
let allowAutofill =
!!event.data &&
!event.inputType.startsWith("insertFromPaste") &&
event.inputType != "insertFromYank" &&
!UrlbarUtils.isPasteEvent(event) &&
this._maybeAutofillOnInput(value);
this.startQuery({
@ -1754,6 +1817,9 @@ class UrlbarInput {
this.value = droppedURL;
this.window.SetPageProxyState("invalid");
this.focus();
// To simplify tracking of events, register an initial event for event
// telemetry, to replace the missing input event.
this.controller.engagementEvent.start(event);
this.handleCommand(null, undefined, undefined, principal);
// For safety reasons, in the drop case we don't want to immediately show
// the the dropped value, instead we want to keep showing the current page

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

@ -66,6 +66,9 @@ const PREF_URLBAR_DEFAULTS = new Map([
// clipboard on systems that support it.
["doubleClickSelectsAll", false],
// Whether telemetry events should be recorded.
["eventTelemetry.enabled", false],
// When true, `javascript:` URLs are not included in search results.
["filter.javascript", true],
@ -102,6 +105,7 @@ const PREF_URLBAR_DEFAULTS = new Map([
// should be opened in new tabs by default.
["openintab", false],
// Whether to open the urlbar view when the input field is focused by the user.
["openViewOnFocus", false],
// Whether the quantum bar is enabled.

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

@ -434,6 +434,19 @@ var UrlbarUtils = {
);
});
},
/**
* Whether the passed-in input event is paste event.
* @param {DOMEvent} event an input DOM event.
* @returns {boolean} Whether the event is a paste event.
*/
isPasteEvent(event) {
return (
event.inputType &&
(event.inputType.startsWith("insertFromPaste") ||
event.inputType == "insertFromYank")
);
},
};
XPCOMUtils.defineLazyGetter(UrlbarUtils.ICON, "DEFAULT", () => {

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

@ -3,8 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
prefs=browser.urlbar.quantumbar=true
tags=quantumbar
support-files =
dummy_page.html
head.js
@ -119,6 +117,10 @@ support-files =
[browser_urlbar_content_opener.js]
[browser_urlbar_display_selectedAction_Extensions.js]
[browser_urlbar_empty_search.js]
[browser_urlbar_event_telemetry.js]
support-files =
searchSuggestionEngine.xml
searchSuggestionEngine.sjs
[browser_urlbar_locationchange_urlbar_edit_dos.js]
support-files =
file_urlbar_edit_dos.html

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

@ -206,7 +206,7 @@ add_task(async function test_keyword_with_question_mark() {
UrlbarUtils.RESULT_TYPE.SEARCH,
"Result should be a search"
);
Assert.equal(result.searchParams.query, "question", "Check search query");
Assert.equal(result.searchParams.query, "question?", "Check search query");
result = await promise_first_result("question? something");
Assert.equal(

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

@ -0,0 +1,579 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function copyToClipboard(str) {
return new Promise((resolve, reject) => {
waitForClipboard(
str,
() => {
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyString(str);
},
resolve,
reject
);
});
}
// Each test is a function that executes an urlbar action and returns the
// expected event object, or null if no event is expected.
const tests = [
/*
* Engagement tests.
*/
async function() {
info("Type something, press Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("x", window, true);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
selIndex: "0",
selType: "search",
},
};
},
async function() {
info("Paste something, press Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await copyToClipboard("test");
document.commandDispatcher
.getControllerForCommand("cmd_paste")
.doCommand("cmd_paste");
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "pasted",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "4",
selIndex: "0",
selType: "search",
},
};
},
async function() {
info("Type something, click one-off.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("moz", window, true);
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true });
UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton.click();
await promise;
return {
category: "urlbar",
method: "engagement",
object: "click",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "3",
selIndex: "0",
selType: "oneoff",
},
};
},
async function() {
info("Type something, select one-off, Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("moz", window, true);
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true });
Assert.ok(UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "3",
selIndex: "0",
selType: "oneoff",
},
};
},
async function() {
info("Type something, ESC, type something else, press Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeKey("x");
EventUtils.synthesizeKey("VK_ESCAPE");
EventUtils.synthesizeKey("y");
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
selIndex: "0",
selType: "search",
},
};
},
async function() {
info("Type a keyword, Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("kw test", window, true);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "7",
selIndex: "0",
selType: "keyword",
},
};
},
async function() {
info("Type something and canonize");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("example", window, true);
EventUtils.synthesizeKey("VK_RETURN", { ctrlKey: true });
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "7",
selIndex: "0",
selType: "canonized",
},
};
},
async function() {
info("Type something, click on bookmark entry.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("exa", window, true);
while (gURLBar.value != "http://example.com/?q=%s") {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
let element = UrlbarTestUtils.getSelectedElement(window);
EventUtils.synthesizeMouseAtCenter(element, {});
await promise;
return {
category: "urlbar",
method: "engagement",
object: "click",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "3",
selIndex: val => parseInt(val) > 0,
selType: "bookmark",
},
};
},
async function() {
info("Type an autofilled string, Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("exa", window, true);
// Check it's autofilled.
Assert.equal(gURLBar.selectionStart, 3);
Assert.equal(gURLBar.selectionEnd, 12);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "3",
selIndex: "0",
selType: "autofill",
},
};
},
async function() {
info("Type something, select bookmark entry, Enter.");
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await promiseAutocompleteResultPopup("exa", window, true);
while (gURLBar.value != "http://example.com/?q=%s") {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "3",
selIndex: val => parseInt(val) > 0,
selType: "bookmark",
},
};
},
async function() {
info("Type @, Enter on a keywordoffer");
gURLBar.select();
await promiseAutocompleteResultPopup("@", window, true);
while (gURLBar.value != "@test ") {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
EventUtils.synthesizeKey("VK_RETURN");
await UrlbarTestUtils.promiseSearchComplete(window);
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
selIndex: val => parseInt(val) > 0,
selType: "keywordoffer",
},
};
},
async function() {
info("Drop something.");
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeDrop(
document.getElementById("home-button"),
gURLBar.inputField,
[[{ type: "text/plain", data: "www.example.com" }]],
"copy",
window
);
await promise;
return {
category: "urlbar",
method: "engagement",
object: "drop_go",
value: "dropped",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "15",
selIndex: "-1",
selType: "none",
},
};
},
async function() {
info("Paste & Go something.");
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await copyToClipboard("www.example.com");
let inputBox = gURLBar.querySelector("moz-input-box");
let cxmenu = inputBox.menupopup;
let cxmenuPromise = BrowserTestUtils.waitForEvent(cxmenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {
type: "contextmenu",
button: 2,
});
await cxmenuPromise;
let menuitem = inputBox.getMenuItem("paste-and-go");
EventUtils.synthesizeMouseAtCenter(menuitem, {});
await promise;
return {
category: "urlbar",
method: "engagement",
object: "paste_go",
value: "pasted",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "15",
selIndex: "-1",
selType: "none",
},
};
},
async function() {
info("Open the panel with DOWN, select with DOWN, Enter.");
gURLBar.value = "";
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeKey("KEY_ArrowDown", {});
});
await UrlbarTestUtils.promiseSearchComplete(window);
while (gURLBar.value != "http://mochi.test:8888/") {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
EventUtils.synthesizeKey("VK_RETURN");
await promise;
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "topsites",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "0",
selType: "history",
selIndex: val => parseInt(val) >= 0,
},
};
},
async function() {
info("Open the panel with DOWN, click on entry.");
gURLBar.value = "";
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeKey("KEY_ArrowDown", {});
});
while (gURLBar.value != "http://mochi.test:8888/") {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
let element = UrlbarTestUtils.getSelectedElement(window);
EventUtils.synthesizeMouseAtCenter(element, {});
await promise;
return {
category: "urlbar",
method: "engagement",
object: "click",
value: "topsites",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "0",
selType: "history",
selIndex: "0",
},
};
},
async function() {
info("Open the panel with dropmarker, type something, Enter.");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async browser => {
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeMouseAtCenter(gURLBar.dropmarker, {}, window);
});
await promiseAutocompleteResultPopup("x", window, true);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
}
);
return {
category: "urlbar",
method: "engagement",
object: "enter",
value: "topsites",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
selType: "search",
selIndex: "0",
},
};
},
/*
* Abandonment tests.
*/
async function() {
info("Type something, blur.");
gURLBar.select();
EventUtils.synthesizeKey("x");
gURLBar.blur();
return {
category: "urlbar",
method: "abandonment",
object: "blur",
value: "typed",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
},
};
},
async function() {
info("Open the panel with DOWN, don't type, blur it.");
gURLBar.value = "";
gURLBar.select();
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeKey("KEY_ArrowDown", {});
});
gURLBar.blur();
return {
category: "urlbar",
method: "abandonment",
object: "blur",
value: "topsites",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "0",
},
};
},
async function() {
info("Open the panel with dropmarker, type something, blur it.");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async browser => {
gURLBar.select();
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeMouseAtCenter(gURLBar.dropmarker, {}, window);
});
EventUtils.synthesizeKey("x");
gURLBar.blur();
}
);
return {
category: "urlbar",
method: "abandonment",
object: "blur",
value: "topsites",
extra: {
elapsed: val => parseInt(val) > 0,
numChars: "1",
},
};
},
/*
* No event tests.
*/
async function() {
info("Type something, click on search settings.");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async browser => {
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(browser);
await promiseAutocompleteResultPopup("x", window, true);
UrlbarTestUtils.getOneOffSearchButtons(window).settingsButton.click();
await promise;
}
);
return null;
},
async function() {
info("Type something, Up, Enter on search settings.");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async browser => {
gURLBar.select();
let promise = BrowserTestUtils.browserLoaded(browser);
await promiseAutocompleteResultPopup("x", window, true);
EventUtils.synthesizeKey("KEY_ArrowUp");
Assert.ok(
UrlbarTestUtils.getOneOffSearchButtons(
window
).selectedButton.classList.contains("search-setting-button-compact"),
"Should have selected the settings button"
);
EventUtils.synthesizeKey("VK_RETURN");
await promise;
}
);
return null;
},
];
add_task(async function test() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.eventTelemetry.enabled", true],
["browser.urlbar.suggest.searches", true],
],
});
// Create a new search engine and mark it as default
let engine = await SearchTestUtils.promiseNewSearchEngine(
getRootDirectory(gTestPath) + "searchSuggestionEngine.xml"
);
let oldDefaultEngine = await Services.search.getDefault();
await Services.search.setDefault(engine);
await Services.search.moveEngine(engine, 0);
let aliasEngine = await Services.search.addEngineWithDetails("Test", {
alias: "@test",
template: "http://example.com/?search={searchTerms}",
});
// Add a bookmark and a keyword.
let bm = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: "http://example.com/?q=%s",
title: "test",
});
await PlacesUtils.keywords.insert({
keyword: "kw",
url: "http://example.com/?q=%s",
});
await PlacesTestUtils.addVisits([
{
uri: "http://mochi.test:8888/",
transition: PlacesUtils.history.TRANSITIONS.TYPED,
},
]);
registerCleanupFunction(async function() {
await Services.search.setDefault(oldDefaultEngine);
await Services.search.removeEngine(aliasEngine);
await PlacesUtils.keywords.remove("kw");
await PlacesUtils.bookmarks.remove(bm);
await PlacesUtils.history.clear();
});
// This is not necessary after each loop, because assertEvents does it.
Services.telemetry.clearEvents();
for (let testFn of tests) {
let expectedEvents = [await testFn()].filter(e => !!e);
// Always blur to ensure it's not accounted as an additional abandonment.
gURLBar.blur();
TelemetryTestUtils.assertEvents(expectedEvents);
}
});

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

@ -620,13 +620,6 @@ description#identity-popup-content-verifier,
box-shadow: var(--focus-ring-box-shadow);
}
/* Hide the "report breakage" button if we have not detected any trackers
* (except if the user added an exception, in which case they might still
* (especially!) want to report the breakage). */
#protections-popup:not([blocking]):not([hasException]) #protections-popup-tp-switch-breakage-link {
display: none;
}
/* PERMISSIONS */
#identity-popup-permissions-content {
@ -803,6 +796,13 @@ description#identity-popup-content-verifier,
position: relative;
}
/* This is needed in order to show a correct height if the 'Site not working?'
link is not displaying. */
#protections-popup-tp-switch-section[short] > .protections-popup-tp-switch-label-box,
#protections-popup-tp-switch-section[short] > .protections-popup-tp-switch-box {
min-height: 30px;
}
.protections-popup-tp-switch-on-header,
.protections-popup-tp-switch-off-header {
font-weight: 600;

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

@ -49,6 +49,9 @@ async function testReloadAboutDevToolsToolbox(toolId) {
const toolbox = getToolbox(devtoolsWindow);
await toolbox.selectTool(toolId);
info("Wait for requests to settle before reloading");
await toolbox.target.client.waitForRequestsToSettle();
info("Reload about:devtools-toolbox page");
devtoolsBrowser.reload();
await gDevTools.once("toolbox-ready");

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

@ -24,6 +24,10 @@ Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
// Make sure the ADB addon is removed and ADB is stopped when the test ends.
registerCleanupFunction(async function() {
// Reset the selected tool in case we opened about:devtools-toolbox to
// avoid side effects between tests.
Services.prefs.clearUserPref("devtools.toolbox.selectedTool");
try {
const { adbAddon } = require("devtools/shared/adb/adb-addon");
await adbAddon.uninstall();
@ -118,6 +122,12 @@ async function closeAboutDevtoolsToolbox(
devtoolsTab,
win
) {
// Wait for all requests to settle on the opened about:devtools toolbox.
const devtoolsBrowser = devtoolsTab.linkedBrowser;
const devtoolsWindow = devtoolsBrowser.contentWindow;
const toolbox = getToolbox(devtoolsWindow);
await toolbox.target.client.waitForRequestsToSettle();
info("Close about:devtools-toolbox page");
const onToolboxDestroyed = gDevTools.once("toolbox-destroyed");

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

@ -1,13 +1,63 @@
.book .book-summary ul.summary li {
cursor: pointer;
cursor: pointer;
}
.book .book-body .page-wrapper .page-inner section.normal p,
.book .book-body .page-wrapper .page-inner section.normal pre {
margin: .85em 0;
margin: 0.85em 0;
}
.book .book-body .page-wrapper .page-inner section.normal pre {
line-height: 1.25em;
}
line-height: 1.25em;
}
/* Resets default style on the main page container */
.page-inner {
max-width: unset !important;
margin: 0 10px !important;
}
/*
* Sections are displayed on the grid. By default everything goes into the
* second column, and we use left and right columns to expand content when needed,
* for example for images, diagrams, code example,
*/
.normal.markdown-section {
display: grid;
grid-template-columns: 1fr minmax(min-content, 800px) 1fr;
margin: 0 50px;
}
.normal.markdown-section > * {
grid-column: 2 / 3;
}
/* Hero element take the whole row */
.normal.markdown-section > .hero {
grid-column: 1 / -1;
width: max-content;
max-width: 100%;
justify-self: center;
}
.diagram,
pre.diagram {
width: max-content;
max-width: 100%;
background-color: #f9f9fa;
border: 3px solid #d7d7db;
margin: 0 auto !important;
padding: 2em;
overflow-x: auto;
white-space: pre;
font-size: 11px;
}
figcaption {
max-width: 800px;
font-size: 0.85em !important;
text-align: center;
font-style: italic;
margin: 10px auto 0;
line-height: 1.25;
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 38 KiB

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

@ -7,28 +7,140 @@ The Console panel is responsible for rendering all logs coming from the current
Internal architecture of the Console panel (the client side) is described
on the following diagram.
![Console panel architecture](console-panel-architecture.png)
## Entry points
There are two ways to load the Console panel. It can either run on top
of the Launchpad (inside a browser tab) or within the DevTools Toolbox.
There are different entry points for these scenarios:
* Launchpad - uses `index.js` file as the entry point
* Toolbox - uses `panel.js` file as the entry point
<figure class="hero">
<pre class="diagram">
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
│ DevTools │ │ WebConsolePanel │
│ [client/framework/devtools.js] │ ┌ ─ ─ ─ ─ ─ ─│ [panel.js] │
└───────────────────────────────────┘ └───────────────────────────────────┘
│ │ │
openBrowserConsole() openWebConsole() │
│ │ │
▼ │
│ ┌───────────────────────────────────┐ │
│ HUDService │ │
└ ─ ─ ─ ─ ─ ▶│ [hudservice.js] │ {hud}
└───────────────────────────────────┘ │
│ │
│ │
│ │
│ │
┌─────────────{consoles}────────────┐ │
│ │ │
│ │ │
│ │ │
▼ n ▼ n ▼ 1
┌────────────────────────┐ ┌────────────────────────┐
│ BrowserConsole │ │ WebConsole │
│ [browser-console.js] │─ ─ ─ ─ ─extends─ ─ ─ ▶│ [webconsole.js] │
└────────────────────────┘ └────────────────────────┘
{ui}
▼ 1
┌────────────────────────┐ ┌─────────────────────────────────┐
│ WebConsoleUI │ 1│ WebConsoleConnectionProxy │
│ [webconsole-ui.js] │─────{proxy}────────▶│[webconsole-connection-proxy.js] │
└────────────────────────┘ └─────────────────────────────────┘
│ │
{wrapper} │
│ │
▼ 1
┌────────────────────────┐ │
│ WebConsoleWrapper │
│[webconsole-wrapper.js] │◀ ─ ─ ─ ─ ─ ─ calls methods from─ ─ ─ ┘
└────────────────────────┘
<renders>
┌────────────────────────┐
│ App │
└────────────────────────┘
</pre>
<figcaption>Elements between curly bracket on arrows represent the property name of the reference (for example, the WebConsolePanel as a `hud` property that is a reference to the WebConsole instance)</figcaption>
</figure>
## Components
The Console panel UI is built on top of [React](../frontend/react.md). It defines set of React components in `components` directory
The React architecture is described on the following diagram.
<figure class="hero">
<pre class="diagram">
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
WebConsole React components │
│ [/components] ┌────────────────────────┐
│ App │ │
│ └────────────────────────┘
│ │
│ │
┌───────────────────┬──────────────────────┬───────────────────┬───────────┴─────────┬───────────────────────┬────────────────────┬─────────────────┐ │
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │ ┌────────────────────────────────────────┐
│ ┌──────────┐ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ ┌────────────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐ │ Editor │
│ SideBar │ │NotificationBox │ │ ConfirmDialog │ │ FilterBar │ │ ReverseSearchInput │ │ConsoleOutput │ │EditorToolbar │ │ JSTerm │──{editor}──▶│ (CodeMirror) │
│ └──────────┘ └────────────────┘ │ (portal) │ └───────────┘ └────────────────────┘ └──────────────┘ └──────────────┘ └─────────┘ │ [client/shared/sourceeditor/editor.js] │
│ └────────────────┘ │ │ │ └────────────────────────────────────────┘
│ │ ┌─────────┴─────────────┐ │
│ │ │ │ │
│ │ ▼ ▼ ▼
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ │ FilterButton │ │ FilterCheckbox │ │ MessageContainer │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
│ │ │
│ │ │
│ │ │
│ ▼ │
│ │ ┌──────────────────┐
│ │ Message │ │
│ │ └──────────────────┘
│ │ │
│ │ │
│ ┌─────────────────────┬─────────────────────┬─────────────────────┬───────┴─────────────┬─────────────────────┬─────────────┼─────────────────────┬───────────────────────────────────────────┐
│ │ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │ ▼ ▼
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────────────────────────────┐ ┌────────────────────────────────────────┐
│ │ MessageIndent │ │ MessageIcon │ │ CollapseButton │ │ GripMessageBody │ │ ConsoleTable │ │ MessageRepeat │ │ │ Frame │ │ SmartTrace │
│ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ [client/shared/components/Frame.js] │ │[client/shared/components/SmartTrace.js]│
│ │ │ │ └─────────────────────────────────────┘ └────────────────────────────────────────┘
└ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ │ │
│ ├─────────────────────┘
│ │
│ ▼
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ Reps ┌──────────────────────┐ │
│ │ [client/shared/components/reps/reps.js] │ ObjectInspector │
│ └──────────────────────┘ │
│ │ │
│ ▼ │
│ │ ┌──────────────────────┐
│ │ ObjectInspectorItem │ │
│ │ └──────────────────────┘
└───────────────────────────────────────────────────────────────▶ │ │
│ ▼
┌──────────────────────┐ │
│ ┌─▶│ Rep │
│ └──────────────────────┘ │
│ │ │
│ │ │
│ └──────────────┘
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
</pre>
</figure>
## Actions
The Console panel implements a set of actions divided into several groups.
* **Filters** Actions related to content filtering.
* **Messages** Actions related to list of messages rendered in the panel.
* **UI** Actions related to the UI state.
- **Filters** Actions related to content filtering.
- **Messages** Actions related to list of messages rendered in the panel.
- **UI** Actions related to the UI state.
### State
@ -36,7 +148,7 @@ The Console panel manages the app state via [Redux](../frontend/redux.md).
There are following reducers defining the panel state:
* `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
* `reducers/messages.js` state of all messages rendered within the panel.
* `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
* `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.
- `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
- `reducers/messages.js` state of all messages rendered within the panel.
- `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
- `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.

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

@ -3366,13 +3366,9 @@ nsresult nsContentUtils::LoadImage(
// XXXbz using "documentURI" for the initialDocumentURI is not quite
// right, but the best we can do here...
nsCOMPtr<nsIURI> referrer = aReferrerInfo->GetOriginalReferrer();
auto referrerPolicy = static_cast<mozilla::net::ReferrerPolicy>(
aReferrerInfo->GetReferrerPolicy());
return imgLoader->LoadImage(aURI, /* uri to load */
documentURI, /* initialDocumentURI */
referrer, /* referrerInfo */
referrerPolicy, /* referrer policy */
aReferrerInfo, /* referrerInfo */
aLoadingPrincipal, /* loading principal */
aRequestContextID, /* request context ID */
loadGroup, /* loadgroup */

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

@ -40,6 +40,7 @@ skip-if = android_version == '18' # Android, bug 1147974
[test_input_datetime_focus_blur_events.html]
[test_input_datetime_focus_state.html]
[test_input_datetime_hidden.html]
[test_input_datetime_reset_button.html]
[test_input_datetime_reset_default_value_input_change_event.html]
[test_input_datetime_tabindex.html]
[test_input_defaultValue.html]

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

@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1479708
-->
<head>
<title>Test required date/time input can't be reset</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1479708">Mozilla Bug 1479708</a>
<p id="display"></p>
<div id="content">
<input type="date" id="id_date" value="2017-06-08">
<input type="time" id="id_time" value="10:30">
<input type="date" id="id_date_required" value="2017-06-08" required>
<input type="time" id="id_time_required" value="10:30" required>
</div>
<pre id="test">
<script class="testbody">
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
if (isDesktop) {
// Initial load.
assert_reset_visible("id_date");
assert_reset_visible("id_time");
assert_reset_hidden("id_date_required");
assert_reset_hidden("id_time_required");
// Dynamic toggling.
test_make_required("id_date");
test_make_required("id_time");
test_make_optional("id_date_required");
test_make_optional("id_time_required");
} else {
ok(true, "Mobile and tablet dont show reset button");
}
SimpleTest.finish();
});
function test_make_required(id) {
const input = document.getElementById(id);
is(input.required, false, `Precondition: input #${id} is optional`);
input.required = true;
assert_reset_hidden(id);
}
function test_make_optional(id) {
const input = document.getElementById(id);
is(input.required, true, `Precondition: input #${id} is required`);
input.required = false;
assert_reset_visible(id);
}
function assert_reset_visible(id) {
const resetButton = get_reset_button(id);
is(resetButton.style.visibility, "", `Reset button is visible on #${id}`);
}
function assert_reset_hidden(id) {
const resetButton = get_reset_button(id);
is(resetButton.style.visibility, "hidden", `Reset button is hidden on #${id}`);
}
function get_reset_button(id) {
const input = document.getElementById(id);
const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
return shadowRoot.getElementById("reset-button");
}
</script>
</pre>
</body>
</html>

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

@ -273,9 +273,7 @@ skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_callbacks.html]
skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_replaceTrack.html]
skip-if =
toolkit == 'android' || # Bug 1189784
(fission && debug) # Intermittently times out under Fission.
skip-if = toolkit == 'android' # Bug 1189784
[test_peerConnection_syncSetDescription.html]
skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]

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

@ -14,6 +14,7 @@ interface nsILoadGroup;
interface nsIPrincipal;
interface nsIStreamListener;
interface nsIURI;
interface nsIReferrerInfo;
interface nsISimpleEnumerator;
@ -40,10 +41,7 @@ interface imgILoader : nsISupports
* @param aURI the URI to load
* @param aInitialDocumentURI the URI that 'initiated' the load -- used for
* 3rd party cookie blocking
* @param aReferrerURI the 'referring' URI
* @param aReferrerPolicy the policy to apply to sending referrers.
* examples: "default", "never", "always", "origin"
* (see W3C referrer-policy spec for valid policy strings)
* @param aReferrerInfo the referrer info to compute sending referrer.
* @param aLoadingPrincipal the principal of the loading document
* @param aLoadGroup Loadgroup to put the image load into
* @param aObserver the observer (may be null)
@ -63,8 +61,7 @@ interface imgILoader : nsISupports
*/
imgIRequest loadImageXPCOM(in nsIURI aURI,
in nsIURI aInitialDocumentURL,
in nsIURI aReferrerURI,
in AString aReferrerPolicy,
in nsIReferrerInfo aReferrerInfo,
in nsIPrincipal aLoadingPrincipal,
in nsILoadGroup aLoadGroup,
in imgINotificationObserver aObserver,

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

@ -716,12 +716,26 @@ static bool ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
nsIPrincipal* triggeringPrincipal,
nsISupports* aCX,
nsContentPolicyType aPolicyType,
ReferrerPolicy referrerPolicy) {
// If the entry's Referrer Policy doesn't match, we can't use this request.
nsIReferrerInfo* aReferrerInfo) {
// If the referrer policy doesn't match, we can't use this request.
// XXX: Note that we only validate referrer policy, not referrerInfo object.
// We should do with referrerInfo object, but it will cause us to use more
// resources in the common case (the same policies but diferrent original
// referrers).
// XXX: this will return false if an image has different referrer attributes,
// i.e. we currently don't use the cached image but reload the image with
// the new referrer policy bug 1174921
if (referrerPolicy != request->GetReferrerPolicy()) {
uint32_t referrerPolicy = RP_Unset;
if (aReferrerInfo) {
referrerPolicy = aReferrerInfo->GetReferrerPolicy();
}
uint32_t requestReferrerPolicy = RP_Unset;
if (request->GetReferrerInfo()) {
requestReferrerPolicy = request->GetReferrerInfo()->GetReferrerPolicy();
}
if (referrerPolicy != requestReferrerPolicy) {
return false;
}
@ -762,8 +776,8 @@ static nsresult NewImageChannel(
// be set to true if this channel ends up depending on
// aTriggeringPrincipal and false otherwise.
bool* aForcePrincipalCheckForCacheEntry, nsIURI* aURI,
nsIURI* aInitialDocumentURI, int32_t aCORSMode, nsIURI* aReferringURI,
ReferrerPolicy aReferrerPolicy, nsILoadGroup* aLoadGroup,
nsIURI* aInitialDocumentURI, int32_t aCORSMode,
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
const nsCString& aAcceptHeader, nsLoadFlags aLoadFlags,
nsContentPolicyType aPolicyType, nsIPrincipal* aTriggeringPrincipal,
nsISupports* aRequestingContext, bool aRespectPrivacy) {
@ -885,10 +899,10 @@ static nsresult NewImageChannel(
NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
rv = httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsIReferrerInfo> referrerInfo =
new ReferrerInfo(aReferringURI, aReferrerPolicy);
rv = newHttpChannel->SetReferrerInfoWithoutClone(referrerInfo);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (aReferrerInfo) {
DebugOnly<nsresult> rv = newHttpChannel->SetReferrerInfo(aReferrerInfo);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
// Image channels are loaded by default with reduced priority.
@ -1649,9 +1663,9 @@ void imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue) {
bool imgLoader::ValidateRequestWithNewChannel(
imgRequest* request, nsIURI* aURI, nsIURI* aInitialDocumentURI,
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsISupports* aCX, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsISupports* aCX,
Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsContentPolicyType aLoadPolicyType, imgRequestProxy** aProxyRequest,
nsIPrincipal* aTriggeringPrincipal, int32_t aCORSMode,
bool* aNewChannelCreated) {
@ -1691,10 +1705,9 @@ bool imgLoader::ValidateRequestWithNewChannel(
nsCOMPtr<nsIChannel> newChannel;
bool forcePrincipalCheck;
rv = NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI,
aInitialDocumentURI, aCORSMode, aReferrerURI,
aReferrerPolicy, aLoadGroup, mAcceptHeader, aLoadFlags,
aLoadPolicyType, aTriggeringPrincipal, aCX,
mRespectPrivacy);
aInitialDocumentURI, aCORSMode, aReferrerInfo,
aLoadGroup, mAcceptHeader, aLoadFlags, aLoadPolicyType,
aTriggeringPrincipal, aCX, mRespectPrivacy);
if (NS_FAILED(rv)) {
return false;
}
@ -1756,9 +1769,9 @@ bool imgLoader::ValidateRequestWithNewChannel(
bool imgLoader::ValidateEntry(
imgCacheEntry* aEntry, nsIURI* aURI, nsIURI* aInitialDocumentURI,
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsISupports* aCX, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsISupports* aCX,
Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsContentPolicyType aLoadPolicyType, bool aCanMakeNewChannel,
bool* aNewChannelCreated, imgRequestProxy** aProxyRequest,
nsIPrincipal* aTriggeringPrincipal, int32_t aCORSMode) {
@ -1799,7 +1812,7 @@ bool imgLoader::ValidateEntry(
if (!ValidateSecurityInfo(request, aEntry->ForcePrincipalCheck(), aCORSMode,
aTriggeringPrincipal, aCX, aLoadPolicyType,
aReferrerPolicy))
aReferrerInfo))
return false;
// data URIs are immutable and by their nature can't leak data, so we can
@ -1877,10 +1890,9 @@ bool imgLoader::ValidateEntry(
LOG_SCOPE(gImgLog, "imgLoader::ValidateRequest |cache hit| must validate");
return ValidateRequestWithNewChannel(
request, aURI, aInitialDocumentURI, aReferrerURI, aReferrerPolicy,
aLoadGroup, aObserver, aCX, aLoadingDocument, aLoadFlags,
aLoadPolicyType, aProxyRequest, aTriggeringPrincipal, aCORSMode,
aNewChannelCreated);
request, aURI, aInitialDocumentURI, aReferrerInfo, aLoadGroup,
aObserver, aCX, aLoadingDocument, aLoadFlags, aLoadPolicyType,
aProxyRequest, aTriggeringPrincipal, aCORSMode, aNewChannelCreated);
}
return !validateRequest;
@ -2030,37 +2042,38 @@ bool imgLoader::PreferLoadFromCache(nsIURI* aURI) const {
nsIRequest::VALIDATE_ONCE_PER_SESSION)
NS_IMETHODIMP
imgLoader::LoadImageXPCOM(
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
const nsAString& aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsISupports* aCX, nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
nsContentPolicyType aContentPolicyType, imgIRequest** _retval) {
imgLoader::LoadImageXPCOM(nsIURI* aURI, nsIURI* aInitialDocumentURI,
nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aTriggeringPrincipal,
nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsISupports* aCX,
nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
nsContentPolicyType aContentPolicyType,
imgIRequest** _retval) {
// Optional parameter, so defaults to 0 (== TYPE_INVALID)
if (!aContentPolicyType) {
aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
}
imgRequestProxy* proxy;
ReferrerPolicy refpol = ReferrerPolicyFromString(aReferrerPolicy);
nsCOMPtr<nsINode> node = do_QueryInterface(aCX);
nsCOMPtr<Document> doc = do_QueryInterface(aCX);
nsresult rv =
LoadImage(aURI, aInitialDocumentURI, aReferrerURI, refpol,
aTriggeringPrincipal, 0, aLoadGroup, aObserver, node, doc,
aLoadFlags, aCacheKey, aContentPolicyType, EmptyString(),
LoadImage(aURI, aInitialDocumentURI, aReferrerInfo, aTriggeringPrincipal,
0, aLoadGroup, aObserver, node, doc, aLoadFlags, aCacheKey,
aContentPolicyType, EmptyString(),
/* aUseUrgentStartForChannel */ false, &proxy);
*_retval = proxy;
return rv;
}
nsresult imgLoader::LoadImage(
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
ReferrerPolicy aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
uint64_t aRequestContextID, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsINode* aContext,
Document* aLoadingDocument, nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
nsContentPolicyType aContentPolicyType, const nsAString& initiatorType,
bool aUseUrgentStartForChannel, imgRequestProxy** _retval) {
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aTriggeringPrincipal, uint64_t aRequestContextID,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsINode* aContext, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType,
const nsAString& initiatorType, bool aUseUrgentStartForChannel,
imgRequestProxy** _retval) {
VerifyCacheSizes();
NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
@ -2154,11 +2167,11 @@ nsresult imgLoader::LoadImage(
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
bool newChannelCreated = false;
if (ValidateEntry(
entry, aURI, aInitialDocumentURI, aReferrerURI, aReferrerPolicy,
aLoadGroup, aObserver, ToSupports(aLoadingDocument),
aLoadingDocument, requestFlags, aContentPolicyType, true,
&newChannelCreated, _retval, aTriggeringPrincipal, corsmode)) {
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerInfo,
aLoadGroup, aObserver, ToSupports(aLoadingDocument),
aLoadingDocument, requestFlags, aContentPolicyType, true,
&newChannelCreated, _retval, aTriggeringPrincipal,
corsmode)) {
request = entry->GetRequest();
// If this entry has no proxies, its request has no reference to the
@ -2206,10 +2219,10 @@ nsresult imgLoader::LoadImage(
bool forcePrincipalCheck;
rv = NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI,
aInitialDocumentURI, corsmode, aReferrerURI,
aReferrerPolicy, aLoadGroup, mAcceptHeader,
requestFlags, aContentPolicyType, aTriggeringPrincipal,
aContext, mRespectPrivacy);
aInitialDocumentURI, corsmode, aReferrerInfo,
aLoadGroup, mAcceptHeader, requestFlags,
aContentPolicyType, aTriggeringPrincipal, aContext,
mRespectPrivacy);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
@ -2246,7 +2259,7 @@ nsresult imgLoader::LoadImage(
rv = request->Init(aURI, aURI, /* aHadInsecureRedirect = */ false,
channelLoadGroup, newChannel, entry,
ToSupports(aLoadingDocument), aTriggeringPrincipal,
corsmode, aReferrerPolicy);
corsmode, aReferrerInfo);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
@ -2414,9 +2427,9 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
// default to the internal image type
nsContentPolicyType policyType = loadInfo->InternalContentPolicyType();
if (ValidateEntry(entry, uri, nullptr, nullptr, RP_Unset, nullptr,
aObserver, aCX, doc, requestFlags, policyType, false,
nullptr, nullptr, nullptr, imgIRequest::CORS_NONE)) {
if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver, aCX,
doc, requestFlags, policyType, false, nullptr, nullptr,
nullptr, imgIRequest::CORS_NONE)) {
request = entry->GetRequest();
} else {
nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));
@ -2511,7 +2524,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
// can set aHadInsecureRedirect to false here.
rv = request->Init(originalURI, uri, /* aHadInsecureRedirect = */ false,
channel, channel, entry, aCX, nullptr,
imgIRequest::CORS_NONE, RP_Unset);
imgIRequest::CORS_NONE, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<ProxyListener> pl =
@ -2886,7 +2899,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest) {
"uri", uri);
int32_t corsmode = mRequest->GetCORSMode();
ReferrerPolicy refpol = mRequest->GetReferrerPolicy();
nsCOMPtr<nsIReferrerInfo> referrerInfo = mRequest->GetReferrerInfo();
nsCOMPtr<nsIPrincipal> triggeringPrincipal =
mRequest->GetTriggeringPrincipal();
@ -2898,7 +2911,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest) {
channel->GetOriginalURI(getter_AddRefs(originalURI));
nsresult rv = mNewRequest->Init(originalURI, uri, mHadInsecureRedirect,
aRequest, channel, mNewEntry, context,
triggeringPrincipal, corsmode, refpol);
triggeringPrincipal, corsmode, referrerInfo);
if (NS_FAILED(rv)) {
UpdateProxies(/* aCancelRequest */ true, /* aSyncNotify */ true);
return rv;

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

@ -191,7 +191,6 @@ class imgLoader final : public imgILoader,
typedef nsRefPtrHashtable<nsGenericHashKey<ImageCacheKey>, imgCacheEntry>
imgCacheTable;
typedef nsTHashtable<nsPtrHashKey<imgRequest>> imgSet;
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
typedef mozilla::Mutex Mutex;
NS_DECL_ISUPPORTS
@ -241,15 +240,14 @@ class imgLoader final : public imgILoader,
imgLoader();
nsresult Init();
MOZ_MUST_USE nsresult
LoadImage(nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
ReferrerPolicy aReferrerPolicy, nsIPrincipal* aLoadingPrincipal,
uint64_t aRequestContextID, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsINode* aContext,
mozilla::dom::Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType,
const nsAString& initiatorType, bool aUseUrgentStartForChannel,
imgRequestProxy** _retval);
MOZ_MUST_USE nsresult LoadImage(
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aLoadingPrincipal, uint64_t aRequestContextID,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsINode* aContext, mozilla::dom::Document* aLoadingDocument,
nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
nsContentPolicyType aContentPolicyType, const nsAString& initiatorType,
bool aUseUrgentStartForChannel, imgRequestProxy** _retval);
MOZ_MUST_USE nsresult
LoadImageWithChannel(nsIChannel* channel, imgINotificationObserver* aObserver,
@ -347,8 +345,8 @@ class imgLoader final : public imgILoader,
bool PreferLoadFromCache(nsIURI* aURI) const;
bool ValidateEntry(imgCacheEntry* aEntry, nsIURI* aKey,
nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
ReferrerPolicy aReferrerPolicy, nsILoadGroup* aLoadGroup,
nsIURI* aInitialDocumentURI,
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsISupports* aCX,
mozilla::dom::Document* aLoadingDocument,
nsLoadFlags aLoadFlags,
@ -359,12 +357,12 @@ class imgLoader final : public imgILoader,
bool ValidateRequestWithNewChannel(
imgRequest* request, nsIURI* aURI, nsIURI* aInitialDocumentURI,
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
nsISupports* aCX, mozilla::dom::Document* aLoadingDocument,
nsLoadFlags aLoadFlags, nsContentPolicyType aContentPolicyType,
imgRequestProxy** aProxyRequest, nsIPrincipal* aLoadingPrincipal,
int32_t aCORSMode, bool* aNewChannelCreated);
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
imgINotificationObserver* aObserver, nsISupports* aCX,
mozilla::dom::Document* aLoadingDocument, nsLoadFlags aLoadFlags,
nsContentPolicyType aContentPolicyType, imgRequestProxy** aProxyRequest,
nsIPrincipal* aLoadingPrincipal, int32_t aCORSMode,
bool* aNewChannelCreated);
nsresult CreateNewProxyForRequest(imgRequest* aRequest,
nsILoadGroup* aLoadGroup,

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

@ -59,7 +59,6 @@ imgRequest::imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey)
mValidator(nullptr),
mInnerWindowId(0),
mCORSMode(imgIRequest::CORS_NONE),
mReferrerPolicy(mozilla::net::RP_Unset),
mImageErrorCode(NS_OK),
mImageAvailable(false),
mMutex("imgRequest"),
@ -86,7 +85,7 @@ nsresult imgRequest::Init(nsIURI* aURI, nsIURI* aFinalURI,
bool aHadInsecureRedirect, nsIRequest* aRequest,
nsIChannel* aChannel, imgCacheEntry* aCacheEntry,
nsISupports* aCX, nsIPrincipal* aTriggeringPrincipal,
int32_t aCORSMode, ReferrerPolicy aReferrerPolicy) {
int32_t aCORSMode, nsIReferrerInfo* aReferrerInfo) {
MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");
LOG_FUNC(gImgLog, "imgRequest::Init");
@ -105,7 +104,7 @@ nsresult imgRequest::Init(nsIURI* aURI, nsIURI* aFinalURI,
mTimedChannel = do_QueryInterface(mChannel);
mTriggeringPrincipal = aTriggeringPrincipal;
mCORSMode = aCORSMode;
mReferrerPolicy = aReferrerPolicy;
mReferrerInfo = aReferrerInfo;
// If the original URI and the final URI are different, check whether the
// original URI is secure. We deliberately don't take the final URI into

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

@ -19,7 +19,6 @@
#include "nsError.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "mozilla/Mutex.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "ImageCacheKey.h"
class imgCacheValidator;
@ -31,6 +30,7 @@ class nsIProperties;
class nsIRequest;
class nsITimedChannel;
class nsIURI;
class nsIReferrerInfo;
namespace mozilla {
namespace image {
@ -49,7 +49,6 @@ class imgRequest final : public nsIStreamListener,
typedef mozilla::image::Image Image;
typedef mozilla::image::ImageCacheKey ImageCacheKey;
typedef mozilla::image::ProgressTracker ProgressTracker;
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
public:
imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey);
@ -67,7 +66,7 @@ class imgRequest final : public nsIStreamListener,
nsIChannel* aChannel, imgCacheEntry* aCacheEntry,
nsISupports* aCX,
nsIPrincipal* aTriggeringPrincipal,
int32_t aCORSMode, ReferrerPolicy aReferrerPolicy);
int32_t aCORSMode, nsIReferrerInfo* aReferrerInfo);
void ClearLoader();
@ -113,8 +112,8 @@ class imgRequest final : public nsIStreamListener,
// The CORS mode for which we loaded this image.
int32_t GetCORSMode() const { return mCORSMode; }
// The Referrer Policy in effect when loading this image.
ReferrerPolicy GetReferrerPolicy() const { return mReferrerPolicy; }
// The ReferrerInfo in effect when loading this image.
nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
// The principal for the document that loaded this image. Used when trying to
// validate a CORS image load.
@ -264,8 +263,8 @@ class imgRequest final : public nsIStreamListener,
// default, imgIRequest::CORS_NONE.
int32_t mCORSMode;
// The Referrer Policy (defined in ReferrerPolicy.h) used for this image.
ReferrerPolicy mReferrerPolicy;
// The ReferrerInfo used for this image.
nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
nsresult mImageErrorCode;

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

@ -8,6 +8,11 @@
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const ReferrerInfo = Components.Constructor(
"@mozilla.org/referrer-info;1",
"nsIReferrerInfo",
"init"
);
var server = new HttpServer();
server.registerDirectory("/", do_get_file(""));
@ -94,12 +99,16 @@ function checkSecondLoad() {
var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener);
var referrerInfo = new ReferrerInfo(
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
true,
null
);
requests.push({
request: gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
referrerInfo,
null,
null,
outer,
@ -207,12 +216,16 @@ function startImageCallback(otherCb) {
var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener2);
var referrerInfo = new ReferrerInfo(
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
true,
null
);
requests.push({
request: gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
referrerInfo,
null,
null,
outer,
@ -257,11 +270,15 @@ function run_test() {
var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener);
var referrerInfo = new ReferrerInfo(
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
true,
null
);
var req = gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
referrerInfo,
null,
null,
outer,

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

@ -2,6 +2,12 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
const ReferrerInfo = Components.Constructor(
"@mozilla.org/referrer-info;1",
"nsIReferrerInfo",
"init"
);
var server = new HttpServer();
server.registerPathHandler("/image.png", imageHandler);
server.start(-1);
@ -84,12 +90,16 @@ function loadImage(isPrivate, callback) {
? privateLoadContext
: nonPrivateLoadContext;
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
var referrerInfo = new ReferrerInfo(
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
true,
null
);
requests.push(
loader.loadImageXPCOM(
uri,
null,
null,
"default",
referrerInfo,
null,
loadGroup,
outer,

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

@ -184,7 +184,11 @@ static_assert(
(JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == ValueObjectOrNullBit,
"ValueObjectOrNullBit must be consistent with object and null tags");
constexpr uint64_t ValuePrivateDoubleBit = 0x8000'0000'0000'0000;
constexpr uint64_t IsValidUserModePointer(uint64_t bits) {
// All 64-bit platforms that we support actually have a 48-bit address space
// for user-mode pointers, with the top 16 bits all set to zero.
return (bits & 0xFFFF'0000'0000'0000) == 0;
}
#endif /* JS_PUNBOX64 */
@ -837,7 +841,7 @@ union alignas(8) Value {
s_.tag_ = JSValueTag(0);
s_.payload_.ptr_ = ptr;
#elif defined(JS_PUNBOX64)
MOZ_ASSERT((uintptr_t(ptr) & detail::ValuePrivateDoubleBit) == 0);
MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr)));
asBits_ = uintptr_t(ptr);
#endif
MOZ_ASSERT(isDouble());
@ -848,7 +852,7 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return s_.payload_.ptr_;
#elif defined(JS_PUNBOX64)
MOZ_ASSERT((asBits_ & detail::ValuePrivateDoubleBit) == 0);
MOZ_ASSERT(detail::IsValidUserModePointer(asBits_));
return reinterpret_cast<void*>(asBits_);
#endif
}

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

@ -160,7 +160,7 @@ DefaultJitOptions::DefaultJitOptions() {
// How many invocations or loop iterations are needed before functions
// are compiled with the baseline compiler.
// Duplicated in all.js - ensure both match.
SET_DEFAULT(baselineJitWarmUpThreshold, 50);
SET_DEFAULT(baselineJitWarmUpThreshold, 100);
// How many invocations or loop iterations are needed before functions
// are compiled with the Ion compiler at OptimizationLevel::Normal.

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

@ -233,7 +233,8 @@ nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
// nsGkAtoms::disabled is handled by SyncDisabledState
if (aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::readonly ||
aAttribute == nsGkAtoms::tabindex) {
aAttribute == nsGkAtoms::tabindex ||
aAttribute == nsGkAtoms::required) {
MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
auto contentAsInputElem =
static_cast<dom::HTMLInputElement*>(GetContent());

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

@ -2397,7 +2397,7 @@ nsresult nsImageFrame::LoadIcon(const nsAString& aSpec,
relevant for cookies, so does not
apply to icons. */
nullptr, /* referrer (not relevant for icons) */
mozilla::net::RP_Unset, nullptr, /* principal (not relevant for icons) */
nullptr, /* principal (not relevant for icons) */
0, loadGroup, gIconLoad, nullptr, /* No context */
nullptr, /* Not associated with any particular document */
loadFlags, nullptr, contentPolicyType, EmptyString(),

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

@ -3453,6 +3453,11 @@ class nsDisplayList {
*/
template <typename Item, typename Comparator>
void Sort(const Comparator& aComparator) {
if (Count() < 2) {
// Only sort lists with more than one item.
return;
}
// Some casual local browsing testing suggests that a local preallocated
// array of 20 items should be able to avoid a lot of dynamic allocations
// here.

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

@ -477,13 +477,13 @@ DEFINE_GLOBAL(size_t) gPageSizeMask = gPageSize - 1;
// Number of pages in a chunk.
DEFINE_GLOBAL(size_t) gChunkNumPages = kChunkSize >> gPageSize2Pow;
// Number of pages necessary for a chunk header.
// Number of pages necessary for a chunk header plus a guard page.
DEFINE_GLOBAL(size_t)
gChunkHeaderNumPages =
((sizeof(arena_chunk_t) + sizeof(arena_chunk_map_t) * (gChunkNumPages - 1) +
gPageSizeMask) &
~gPageSizeMask) >>
gPageSize2Pow;
1 + (((sizeof(arena_chunk_t) +
sizeof(arena_chunk_map_t) * (gChunkNumPages - 1) + gPageSizeMask) &
~gPageSizeMask) >>
gPageSize2Pow);
// One chunk, minus the header, minus a guard page
DEFINE_GLOBAL(size_t)
@ -2300,31 +2300,40 @@ void arena_t::InitChunk(arena_chunk_t* aChunk, bool aZeroed) {
aChunk->ndirty = 0;
// Initialize the map to contain one maximal free untouched run.
#ifdef MALLOC_DECOMMIT
arena_run_t* run = (arena_run_t*)(uintptr_t(aChunk) +
(gChunkHeaderNumPages << gPageSize2Pow));
#endif
for (i = 0; i < gChunkHeaderNumPages; i++) {
// Clear the bits for the real header pages.
for (i = 0; i < gChunkHeaderNumPages - 1; i++) {
aChunk->map[i].bits = 0;
}
aChunk->map[i].bits = gMaxLargeClass | flags;
for (i++; i < gChunkNumPages - 2; i++) {
// Mark the leading guard page (last header page) as decommitted.
aChunk->map[i++].bits = CHUNK_MAP_DECOMMITTED;
// Mark the area usable for runs as available, note size at start and end
aChunk->map[i++].bits = gMaxLargeClass | flags;
for (; i < gChunkNumPages - 2; i++) {
aChunk->map[i].bits = flags;
}
aChunk->map[gChunkNumPages - 2].bits = gMaxLargeClass | flags;
// Mark the guard page as decommited.
// Mark the trailing guard page as decommitted.
aChunk->map[gChunkNumPages - 1].bits = CHUNK_MAP_DECOMMITTED;
#ifdef MALLOC_DECOMMIT
// Start out decommitted, in order to force a closer correspondence
// between dirty pages and committed untouched pages.
pages_decommit(run, gMaxLargeClass + gPageSize);
// between dirty pages and committed untouched pages. This includes
// leading and trailing guard pages.
pages_decommit((void*)(uintptr_t(run) - gPageSize),
gMaxLargeClass + 2 * gPageSize);
#else
// Only decommit the last page as a guard.
// Decommit the last header page (=leading page) as a guard.
pages_decommit((void*)(uintptr_t(run) - gPageSize), gPageSize);
// Decommit the last page as a guard.
pages_decommit((void*)(uintptr_t(aChunk) + kChunkSize - gPageSize),
gPageSize);
#endif
mStats.committed += gChunkHeaderNumPages;
// Insert the run into the tree of available runs.

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

@ -1215,7 +1215,7 @@ pref("javascript.options.blinterp", true);
pref("javascript.options.blinterp.threshold", 10);
pref("javascript.options.baselinejit", true);
// Duplicated in JitOptions - ensure both match.
pref("javascript.options.baselinejit.threshold", 50);
pref("javascript.options.baselinejit.threshold", 100);
pref("javascript.options.ion", true);
// Duplicated in JitOptions - ensure both match.
pref("javascript.options.ion.threshold", 1000);

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

@ -152,6 +152,12 @@ def get_paths(os_name):
return (mozbuild_path, sdk_path, ndk_path)
def sdkmanager_tool(sdk_path):
# sys.platform is win32 even if Python/Win64.
sdkmanager = 'sdkmanager.bat' if sys.platform.startswith('win') else 'sdkmanager'
return os.path.join(sdk_path, 'tools', 'bin', sdkmanager)
def ensure_dir(dir):
'''Ensures the given directory exists'''
if dir and not os.path.exists(dir):
@ -191,8 +197,8 @@ def ensure_android(os_name, artifact_mode=False, ndk_only=False, no_interactive=
# We expect the |sdkmanager| tool to be at
# ~/.mozbuild/android-sdk-$OS_NAME/tools/bin/sdkmanager.
sdkmanager_tool = os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')
ensure_android_packages(sdkmanager_tool=sdkmanager_tool, no_interactive=no_interactive)
ensure_android_packages(sdkmanager_tool=sdkmanager_tool(sdk_path),
no_interactive=no_interactive)
def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_path, ndk_url,
@ -221,7 +227,7 @@ def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_pa
# |sdkmanager| tool to install additional parts of the Android
# toolchain. If we overwrite, we lose whatever Android packages
# the user may have already installed.
if os.path.isfile(os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')):
if os.path.isfile(sdkmanager_tool(sdk_path)):
print(ANDROID_SDK_EXISTS % sdk_path)
elif os.path.isdir(sdk_path):
raise NotImplementedError(ANDROID_SDK_TOO_OLD % sdk_path)

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

@ -70,7 +70,30 @@ class MozillaBuildBootstrapper(BaseBootstrapper):
pass
def install_mobile_android_artifact_mode_packages(self):
pass
self.ensure_mobile_android_packages(artifact_mode=True)
def ensure_mobile_android_packages(self, artifact_mode=False):
# Get java path from registry key
import _winreg
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
r'SOFTWARE\JavaSoft\Java Development Kit\1.8')
java_path, regtype = _winreg.QueryValueEx(key, 'JavaHome')
_winreg.CloseKey(key)
os.environ['PATH'] = \
'{}{}{}'.format(os.path.join(java_path, 'bin'), os.pathsep, os.environ['PATH'])
self.ensure_java()
from mozboot import android
android.ensure_android('windows', artifact_mode=artifact_mode,
no_interactive=self.no_interactive)
def suggest_mobile_android_mozconfig(self, artifact_mode=False):
from mozboot import android
android.suggest_mozconfig('windows', artifact_mode=artifact_mode)
def suggest_mobile_android_artifact_mode_mozconfig(self):
self.suggest_mobile_android_mozconfig(artifact_mode=True)
def ensure_clang_static_analysis_package(self, state_dir, checkout_root):
from mozboot import static_analysis

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

@ -79,6 +79,10 @@ class StaticAnalysisMonitor(object):
self._warnings_database = WarningsDatabase()
def on_warning(warning):
# Output paths relative to repository root
warning['filename'] = os.path.relpath(warning['filename'], srcdir)
self._warnings_database.insert(warning)
self._warnings_collector = WarningsCollector(on_warning, objdir=objdir)
@ -1971,7 +1975,9 @@ class StaticAnalysis(MachCommandBase):
try:
output = check_output(args + l)
if output and output_format == 'json':
patches[original_path] = self._parse_xml_output(original_path, output)
# Output a relative path in json patch list
relative_path = os.path.relpath(original_path, self.topsrcdir)
patches[relative_path] = self._parse_xml_output(original_path, output)
except CalledProcessError as e:
# Something wrong happend
print("clang-format: An error occured while running clang-format.")

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

@ -111,7 +111,7 @@ def make_task_description(config, jobs):
'implementation': 'docker-worker',
'docker-image': {'in-tree': 'funsize-update-generator'},
'os': 'linux',
'max-run-time': 3600 if 'asan' in dep_job.label else 600,
'max-run-time': 3600 if 'asan' in dep_job.label else 900,
'chain-of-trust': True,
'taskcluster-proxy': True,
'env': {

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

@ -5,10 +5,13 @@
[iceConnectionState changes at the right time, with bundle policy max-bundle]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996
[iceConnectionState changes at the right time, with bundle policy max-compat]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996
[iceConnectionState changes at the right time, with bundle policy balanced]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996

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

@ -1,5 +1,3 @@
[RTCPeerConnection-onicecandidateerror.html]
expected: TIMEOUT
[Surfacing onicecandidateerror]
expected: TIMEOUT
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1561441

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

@ -1,13 +1,17 @@
[candidate-exchange.https.html]
[Adding only caller -> callee candidates gives a connection]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
[Adding only callee -> caller candidates gives a connection]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
[Explicit offer/answer exchange gives a connection]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
[Adding callee -> caller candidates from end-of-candidates gives a connection]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299

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

@ -291,10 +291,9 @@ nsresult AlertImageRequest::Start() {
int32_t loadFlags =
mInPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS : nsIRequest::LOAD_NORMAL;
rv = il->LoadImageXPCOM(mURI, nullptr, nullptr, NS_LITERAL_STRING("default"),
mPrincipal, nullptr, this, nullptr, loadFlags,
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
getter_AddRefs(mRequest));
rv = il->LoadImageXPCOM(
mURI, nullptr, nullptr, mPrincipal, nullptr, this, nullptr, loadFlags,
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, getter_AddRefs(mRequest));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyMissing();
}

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

@ -33,11 +33,204 @@ export const updateSelectedItem = (() => {
};
})();
const createEntryItem = (label, info) => {
return {
label,
info,
};
};
const adjustCertInformation = cert => {
let certItems = [];
// Subject Name section
certItems.push({
sectionTitle: "Subject Name",
sectionItems: cert.subject.entries.map(entry =>
createEntryItem(entry[0], entry[1])
),
Critical: false,
});
// Issuer Name section
certItems.push({
sectionTitle: "Issuer Name",
sectionItems: cert.issuer.entries.map(entry =>
createEntryItem(entry[0], entry[1])
),
Critical: false,
});
// Validity section
certItems.push({
sectionTitle: "Validity",
sectionItems: [
createEntryItem("Not Before", cert.notBefore),
createEntryItem("Not After", cert.notAfter),
],
Critical: false,
});
// Subject Alt Names section
certItems.push({
sectionTitle: "Subject Alt Names",
sectionItems: cert.ext.san.altNames.map(entry =>
createEntryItem(entry[0], entry[1])
),
Critical: cert.ext.san.critical || false,
});
// Public Key Info section
certItems.push({
sectionTitle: "Public Key Info",
sectionItems: [
createEntryItem("Algorithm", cert.subjectPublicKeyInfo.kty),
createEntryItem("Key size", cert.subjectPublicKeyInfo.keysize),
createEntryItem("Curve", cert.subjectPublicKeyInfo.crv),
createEntryItem("Public Value", cert.subjectPublicKeyInfo.xy),
createEntryItem("Exponent", cert.subjectPublicKeyInfo.e),
createEntryItem("Modulus", cert.subjectPublicKeyInfo.n),
],
Critical: false,
});
// Miscellaneous section
certItems.push({
sectionTitle: "Miscellaneous",
sectionItems: [
createEntryItem("Serial Number", cert.serialNumber),
createEntryItem("Signature Algorithm", cert.signature.name),
createEntryItem("Version", cert.version),
createEntryItem("Download", cert.files.pem),
],
Critical: false,
});
// Fingerprints section
certItems.push({
sectionTitle: "Fingerprints",
sectionItems: [
createEntryItem("SHA-256", cert.fingerprint.sha256),
createEntryItem("SHA-1", cert.fingerprint.sha1),
],
Critical: false,
});
// Basic Constraints section
certItems.push({
sectionTitle: "Basic Constraints",
sectionItems: [
createEntryItem("Certificate Authority", cert.ext.basicConstraintscA),
],
Critical: cert.ext.basicConstraints.critical || false,
});
// Key Usages section
certItems.push({
sectionTitle: "Key Usages",
sectionItems: [createEntryItem("Purposes", cert.ext.keyUsages.purposes)],
Critical: cert.ext.keyUsages.critical || false,
});
// Extended Key Usages section
certItems.push({
sectionTitle: "Extended Key Usages",
sectionItems: [createEntryItem("Purposes", cert.ext.eKeyUsages.purposes)],
Critical: cert.ext.eKeyUsages.critical || false,
});
// OCSP Stapling section
certItems.push({
sectionTitle: "OCSP Stapling",
sectionItems: [createEntryItem("Required", cert.ext.ocspStaple.critical)],
Critical: cert.ext.ocspStaple.critical || false,
});
// Subject Key ID section
certItems.push({
sectionTitle: "Subject Key ID",
sectionItems: [createEntryItem("Key ID", cert.ext.sKID.id)],
Critical: cert.ext.sKID.critical || false,
});
// Authority Key ID section
certItems.push({
sectionTitle: "Authority Key ID",
sectionItems: [createEntryItem("Key ID", cert.ext.aKID.id)],
Critical: cert.ext.aKID.critical || false,
});
// CRL Endpoints section
certItems.push({
sectionTitle: "CRL Endpoints",
sectionItems: cert.ext.crlPoints.points.map(entry => {
let label = "Distribution Point";
return createEntryItem(label, entry);
}),
Critical: cert.ext.crlPoints.critical || false,
});
// // Authority Info (AIA) section
let items = [];
cert.ext.aia.descriptions.forEach(entry => {
items.push(createEntryItem("Location", entry.location));
items.push(createEntryItem("Method", entry.method));
});
certItems.push({
sectionTitle: "Authority Info (AIA)",
sectionItems: items,
Critical: cert.ext.aia.critical || false,
});
// Certificate Policies section
items = [];
cert.ext.cp.policies.forEach(entry => {
items.push(createEntryItem("Policy", entry.name + " ( " + entry.id + " )"));
items.push(createEntryItem("Value", entry.value));
if (entry.qualifiers) {
entry.qualifiers.forEach(qualifier => {
items.push(
createEntryItem(
"Qualifier",
qualifier.name + " ( " + qualifier.id + " )"
)
);
items.push(createEntryItem("Value", qualifier.value));
});
}
});
certItems.push({
sectionTitle: "Certificate Policies",
sectionItems: items,
Critical: cert.ext.cp.critical || false,
});
// Embedded SCTs section
items = [];
cert.ext.scts.timestamps.forEach(entry => {
for (let key of Object.keys(entry)) {
items.push(createEntryItem(key, entry[key]));
}
});
certItems.push({
sectionTitle: "Embedded SCTs",
sectionItems: items,
Critical: cert.ext.scts.critical || false,
});
certItems.push({
tabName: cert.subject.cn,
});
return certItems;
};
const buildChain = async () => {
let chain = [derString];
let builtChain = chain.map(cert => {
return stringToArrayBuffer(cert);
});
let certs = await Promise.all(builtChain.map(cert => parse(cert)));
console.log("certs ", certs);
let adjustedCerts = certs.map(adjustCertInformation);
console.log("adjustedCerts ", adjustedCerts);
};

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

@ -647,7 +647,6 @@ function Search(
// This allows to handle leading or trailing restriction characters specially.
this._leadingRestrictionToken = null;
this._trailingRestrictionToken = null;
if (tokens.length > 0) {
if (
UrlbarTokenizer.isRestrictionToken(tokens[0]) &&
@ -656,13 +655,6 @@ function Search(
) {
this._leadingRestrictionToken = tokens[0].value;
}
if (
UrlbarTokenizer.isRestrictionToken(tokens[tokens.length - 1]) &&
(tokens.length > 1 ||
tokens[tokens.length - 1].type == UrlbarTokenizer.TYPE.RESTRICT_SEARCH)
) {
this._trailingRestrictionToken = tokens[tokens.length - 1].value;
}
// Check if the first token has a strippable prefix and remove it, but don't
// create an empty token.
@ -1739,17 +1731,14 @@ Search.prototype = {
if (!engine || !this.pending) {
return false;
}
// Strip a leading or trailing restriction char.
// Strip a leading search restriction char, because we prepend it to text
// when the search shortcut is used and it's not user typed. Don't strip
// other restriction chars, so that it's possible to search for things
// including one of those (e.g. "c#").
let query = this._trimmedOriginalSearchString;
if (this._leadingRestrictionToken) {
if (this._leadingRestrictionToken === UrlbarTokenizer.RESTRICT.SEARCH) {
query = substringAfter(query, this._leadingRestrictionToken).trim();
}
if (this._trailingRestrictionToken) {
query = query.substring(
0,
query.lastIndexOf(this._trailingRestrictionToken)
);
}
this._addSearchEngineMatch({ engine, query });
return true;
},

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

@ -0,0 +1,32 @@
/* 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/. */
/**
* Test that restriction tokens are not removed from the search string, apart
* from a leading search restriction token.
*/
add_task(async function test_searchstring() {
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
for (let search of [`${token} query`, `query ${token}`]) {
let searchQuery =
token == UrlbarTokenizer.RESTRICT.SEARCH &&
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
? search.substring(2)
: search;
info(`Searching for "${search}", expecting "${searchQuery}"`);
await check_autocomplete({
search,
searchParam: "enable-actions",
matches: [
makeSearchMatch(search, {
engineName: "MozSearch",
searchQuery,
heuristic: true,
}),
],
});
}
}
});

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

@ -111,15 +111,20 @@ add_task(async function basicGetAndPost() {
// be recognized. It should be treated as part of the search string. Try
// all the restriction tokens to test that. We should get a single "search
// with" heuristic result without an alias.
for (let restrictToken in UrlbarTokenizer.RESTRICT) {
let search = `${restrictToken} ${alias} query string`;
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
let search = `${token} ${alias} query string`;
let searchQuery =
token == UrlbarTokenizer.RESTRICT.SEARCH &&
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
? search.substring(2)
: search;
await check_autocomplete({
search,
searchParam: "enable-actions",
matches: [
makeSearchMatch(search, {
engineName: "MozSearch",
searchQuery: search,
searchQuery,
heuristic: true,
}),
],

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

@ -224,7 +224,7 @@ add_task(async function test_tab_matches() {
matches: [
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " abc", {
heuristic: true,
searchQuery: "abc",
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc",
}),
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
],
@ -247,7 +247,7 @@ add_task(async function test_tab_matches() {
matches: [
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla", {
heuristic: true,
searchQuery: "mozilla",
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla",
}),
makeSwitchToTabMatch("about:mozilla"),
],

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

@ -43,6 +43,7 @@ skip-if = appname == "thunderbird"
[test_query_url.js]
[test_remote_tab_matches.js]
skip-if = !sync
[test_restrict_searchstring.js]
[test_search_engine_alias.js]
[test_search_engine_default.js]
[test_search_engine_host.js]

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

@ -249,9 +249,9 @@ addonsManager:
An abuse report submitted by a user for a given extension. The object of the event
represent the report entry point, the value is the id of the addon being reported.
objects:
- menu
- toolbar_context_menu
- uninstall
- menu
- toolbar_context_menu
- uninstall
extra_keys:
addon_type: The type of the add-on being reported (missing on ERROR_ADDON_NOT_FOUND).
error_type: >
@ -317,6 +317,52 @@ navigation:
extra_keys:
engine: The id of the search engine used.
urlbar:
engagement:
objects: ["click", "enter", "paste_go", "drop_go"]
release_channel_collection: opt-out
products:
- "firefox"
record_in_processes: ["main"]
description: >
This is recorded on urlbar engagement, that is when the user picks a
search result.
The value field records the initial interaction type. One of:
"typed", "dropped", "pasted", "topsites"
bug_numbers: [1559136]
notification_emails:
- "rharter@mozilla.com"
- "fx-search@mozilla.com"
expiry_version: never
extra_keys:
elapsed: engagement time in milliseconds.
numChars: number of input characters.
selIndex: index of the selected result in the urlbar panel, or -1.
selType: >
type of the selected result in the urlbar panel. One of:
"autofill", "visit", "bookmark", "history", "keyword", "search",
"searchsuggestion", "switchtab", "remotetab", "extension", "oneoff",
"keywordoffer", "canonized", "none"
abandonment:
objects: ["blur"]
release_channel_collection: opt-out
products:
- "firefox"
record_in_processes: ["main"]
description: >
This is recorded on urlbar search abandon, that is when the user starts
an interaction but then blurs the urlbar.
The value field records the initial interaction type. One of:
"typed", "dropped", "pasted", "topsites"
bug_numbers: [1559136]
notification_emails:
- "rharter@mozilla.com"
- "fx-search@mozilla.com"
expiry_version: never
extra_keys:
elapsed: abandonement time in milliseconds.
numChars: number of input characters.
normandy:
enroll:
objects: ["preference_study", "addon_study", "preference_rollout"]
@ -505,7 +551,6 @@ pwmgr:
]
bug_numbers:
- 1548463
description: An action was taken on the about:logins page
expiry_version: "74"
notification_emails: ["loines@mozilla.com", "passwords-dev@mozilla.org", "jaws@mozilla.com"]
release_channel_collection: opt-out
@ -554,7 +599,7 @@ fxa_avatar_menu:
"sync_tabs_sidebar",
"toolbar_icon",
"unver_sync_settings"
]
]
methods: ["click"]
release_channel_collection: opt-out
products:
@ -583,7 +628,7 @@ fxa_app_menu:
"sync_tabs",
"sync_tabs_sidebar",
"toolbar_icon"
]
]
methods: ["click"]
release_channel_collection: opt-out
products:
@ -707,10 +752,6 @@ telemetry.test:
objects: ["object1"]
bug_numbers: [1452552]
notification_emails: ["telemetry-client-dev@mozilla.com"]
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["main"]
description: This event is used to test desktop-only main recording.
expiry_version: never
@ -719,10 +760,6 @@ telemetry.test:
objects: ["object1"]
bug_numbers: [1452552]
notification_emails: ["telemetry-client-dev@mozilla.com"]
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["main"]
description: This event is used to test multiproduct main recording.
expiry_version: never
@ -731,10 +768,6 @@ telemetry.test:
objects: ["object1"]
bug_numbers: [1452552]
notification_emails: ["telemetry-client-dev@mozilla.com"]
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["main"]
description: This event is used to test mobile-only main recording.
expiry_version: never
@ -1379,10 +1412,6 @@ security.ui.certerror:
- rtestard@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["main", "content"]
products:
- firefox
@ -1413,10 +1442,6 @@ security.ui.certerror:
- rtestard@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["content"]
products:
- firefox
@ -1442,10 +1467,6 @@ security.ui.identitypopup:
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-in
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes:
- main
products:
@ -1468,10 +1489,6 @@ security.ui.identitypopup:
- pdol@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-in
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes:
- main
products:
@ -1541,10 +1558,6 @@ intl.ui.browserLanguage:
- flod@mozilla.com
- mstriemer@mozilla.com
release_channel_collection: opt-out
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes: ["main"]
bug_numbers: [1486507, 1553311]
@ -1567,10 +1580,6 @@ security.ui.permissionprompt:
- ehsan@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes:
- main
extra_keys:
@ -1607,10 +1616,6 @@ security.ui.permissionprompt:
- ehsan@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
products:
- "firefox"
- "fennec"
- "geckoview"
record_in_processes:
- main
extra_keys:

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

@ -430,7 +430,7 @@ browser.usage:
- 1381591
description: >-
The number of plugin instances that were created.
expires: never # Jan-2021 but we don't have a version number for that
expires: never # Jan-2021 but we don't have a version number for that
kind: uint
notification_emails:
- bsmedberg@mozilla.com
@ -2225,83 +2225,83 @@ devtools.toolbox:
devtools.webreplay:
new_recording:
bug_numbers:
- 1495910
- 1495910
description: >
Number of times a blank recording tab was created.
expires: never
kind: uint
notification_emails:
- bhackett@mozilla.com
- bhackett@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'main'
- 'main'
reload_recording:
bug_numbers:
- 1495910
- 1495910
description: >
Number of times a non-recording tab was reloaded to create a recording tab.
expires: never
kind: uint
notification_emails:
- bhackett@mozilla.com
- bhackett@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'main'
- 'main'
stop_recording:
bug_numbers:
- 1495910
- 1495910
description: >
Number of times a recording tab was reloaded to create a non-recording tab.
expires: never
kind: uint
notification_emails:
- bhackett@mozilla.com
- bhackett@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'main'
- 'main'
save_recording:
bug_numbers:
- 1495910
- 1495910
description: >
Number of times a recording was saved.
expires: never
kind: uint
notification_emails:
- bhackett@mozilla.com
- bhackett@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'main'
- 'main'
load_recording:
bug_numbers:
- 1495910
- 1495910
description: >
Number of times a recording was loaded.
expires: never
kind: uint
notification_emails:
- bhackett@mozilla.com
- bhackett@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'main'
- 'main'
devtools.changesview:
opened_count:
@ -4853,10 +4853,6 @@ telemetry.test:
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:
@ -4871,10 +4867,6 @@ telemetry.test:
keyed: true
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:
@ -4888,10 +4880,6 @@ telemetry.test:
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:
@ -4907,10 +4895,6 @@ telemetry.test:
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:
@ -4925,10 +4909,6 @@ telemetry.test:
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:
@ -4943,10 +4923,6 @@ telemetry.test:
keyed: true
notification_emails:
- telemetry-client-dev@mozilla.com
products:
- 'firefox'
- 'fennec'
- 'geckoview'
record_in_processes:
- 'all'
products:

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

@ -344,7 +344,7 @@ const Preferences = (window.Preferences = (function() {
window.addEventListener("unload", Preferences, { once: true });
class Preference extends EventEmitter {
constructor({ id, name, type, inverted, disabled }) {
constructor({ id, type, inverted, disabled }) {
super();
this.on("change", this.onChange.bind(this));
@ -354,17 +354,10 @@ const Preferences = (window.Preferences = (function() {
this.batching = false;
this.id = id;
this._name = name || this.id;
this.type = type;
this.inverted = !!inverted;
this._disabled = !!disabled;
// if the element has been inserted without the name attribute set,
// we have nothing to do here
if (!this.name) {
throw new Error(`preference with id '${id}' doesn't have name`);
}
// In non-instant apply mode, we must try and use the last saved state
// from any previous opens of a child dialog instead of the value from
// preferences, to pick up any edits a user may have made.
@ -376,7 +369,7 @@ const Preferences = (window.Preferences = (function() {
window.opener.document.nodePrincipal.isSystemPrincipal
) {
// Try to find the preference in the parent window.
const preference = window.opener.Preferences.get(this.name);
const preference = window.opener.Preferences.get(this.id);
// Don't use the value setter here, we don't want updateElements to be
// prematurely fired.
@ -392,9 +385,9 @@ const Preferences = (window.Preferences = (function() {
}
_reportUnknownType() {
const msg = `Preference with id=${this.id} and name=${
this.name
} has unknown type ${this.type}.`;
const msg = `Preference with id=${this.id} has unknown type ${
this.type
}.`;
Services.console.logStringMessage(msg);
}
@ -530,20 +523,6 @@ const Preferences = (window.Preferences = (function() {
this.updateElements();
}
get name() {
return this._name;
}
set name(val) {
if (val == this.name) {
return val;
}
this._name = val;
return val;
}
get value() {
return this._value;
}
@ -560,7 +539,7 @@ const Preferences = (window.Preferences = (function() {
}
get locked() {
return Services.prefs.prefIsLocked(this.name);
return Services.prefs.prefIsLocked(this.id);
}
get disabled() {
@ -589,7 +568,7 @@ const Preferences = (window.Preferences = (function() {
get hasUserValue() {
return (
Services.prefs.prefHasUserValue(this.name) && this.value !== undefined
Services.prefs.prefHasUserValue(this.id) && this.value !== undefined
);
}
@ -609,28 +588,28 @@ const Preferences = (window.Preferences = (function() {
// Force a resync of value with preferences.
switch (this.type) {
case "int":
return this._branch.getIntPref(this.name);
return this._branch.getIntPref(this.id);
case "bool": {
const val = this._branch.getBoolPref(this.name);
const val = this._branch.getBoolPref(this.id);
return this.inverted ? !val : val;
}
case "wstring":
return this._branch.getComplexValue(
this.name,
this.id,
Ci.nsIPrefLocalizedString
).data;
case "string":
case "unichar":
return this._branch.getStringPref(this.name);
return this._branch.getStringPref(this.id);
case "fontname": {
const family = this._branch.getStringPref(this.name);
const family = this._branch.getStringPref(this.id);
const fontEnumerator = Cc[
"@mozilla.org/gfx/fontenumerator;1"
].createInstance(Ci.nsIFontEnumerator);
return fontEnumerator.getStandardFamilyName(family);
}
case "file": {
const f = this._branch.getComplexValue(this.name, Ci.nsIFile);
const f = this._branch.getComplexValue(this.id, Ci.nsIFile);
return f;
}
default:
@ -648,17 +627,17 @@ const Preferences = (window.Preferences = (function() {
// The special value undefined means 'reset preference to default'.
if (val === undefined) {
Services.prefs.clearUserPref(this.name);
Services.prefs.clearUserPref(this.id);
return val;
}
// Force a resync of preferences with value.
switch (this.type) {
case "int":
Services.prefs.setIntPref(this.name, val);
Services.prefs.setIntPref(this.id, val);
break;
case "bool":
Services.prefs.setBoolPref(this.name, this.inverted ? !val : val);
Services.prefs.setBoolPref(this.id, this.inverted ? !val : val);
break;
case "wstring": {
const pls = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(
@ -666,7 +645,7 @@ const Preferences = (window.Preferences = (function() {
);
pls.data = val;
Services.prefs.setComplexValue(
this.name,
this.id,
Ci.nsIPrefLocalizedString,
pls
);
@ -675,7 +654,7 @@ const Preferences = (window.Preferences = (function() {
case "string":
case "unichar":
case "fontname":
Services.prefs.setStringPref(this.name, val);
Services.prefs.setStringPref(this.id, val);
break;
case "file": {
let lf;
@ -688,7 +667,7 @@ const Preferences = (window.Preferences = (function() {
} else {
lf = val.QueryInterface(Ci.nsIFile);
}
Services.prefs.setComplexValue(this.name, Ci.nsIFile, lf);
Services.prefs.setComplexValue(this.id, Ci.nsIFile, lf);
break;
}
default:

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

@ -337,7 +337,7 @@ this.DateTimeInputBaseImplWidget = class {
}
updateResetButtonVisibility() {
if (this.isAnyFieldAvailable(false)) {
if (this.isAnyFieldAvailable(false) && !this.isRequired()) {
this.mResetButton.style.visibility = "";
} else {
this.mResetButton.style.visibility = "hidden";
@ -438,6 +438,7 @@ this.DateTimeInputBaseImplWidget = class {
}
this.mResetButton.disabled = this.mInputElement.disabled;
this.updateResetButtonVisibility();
}
isEmpty(aValue) {
@ -513,6 +514,10 @@ this.DateTimeInputBaseImplWidget = class {
return this.mInputElement.hasAttribute("readonly");
}
isRequired() {
return this.mInputElement.hasAttribute("required");
}
handleEvent(aEvent) {
this.log("handleEvent: " + aEvent.type);

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

@ -99,8 +99,8 @@ nsresult nsIconLoaderService::LoadIcon(nsIURI* aIconURI) {
}
nsresult rv = loader->LoadImage(
aIconURI, nullptr, nullptr, mozilla::net::RP_Unset, mContent->NodePrincipal(), 0, loadGroup,
this, mContent, document, nsIRequest::LOAD_NORMAL, nullptr, mContentType, EmptyString(),
aIconURI, nullptr, nullptr, mContent->NodePrincipal(), 0, loadGroup, this, mContent, document,
nsIRequest::LOAD_NORMAL, nullptr, mContentType, EmptyString(),
/* aUseUrgentStartForChannel */ false, getter_AddRefs(mIconRequest));
if (NS_FAILED(rv)) {
return rv;