Merge autoland to mozilla-central. a=merge

This commit is contained in:
shindli 2018-02-08 12:02:53 +02:00
Родитель e3330cdba4 40fbce0fbf
Коммит cc35095901
105 изменённых файлов: 1888 добавлений и 1296 удалений

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

@ -145,7 +145,6 @@ devtools/client/webaudioeditor/**
devtools/client/webconsole/net/**
devtools/client/webconsole/new-console-output/test/mochitest/**
devtools/client/webconsole/test/**
devtools/client/webconsole/hudservice.js
devtools/client/webconsole/webconsole-connection-proxy.js
devtools/client/webconsole/webconsole.js
devtools/client/webide/**

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

@ -25,6 +25,21 @@ module.exports = {
"eol-last": "off",
}
}, {
// These xbl bindings are assumed to be in the browser-window environment,
// we would mark it in the files, but ESLint made this more difficult with
// our xml processor, so we list them here. Bug 1397874 & co are working
// towards removing these files completely.
"files": [
"browser/base/content/tabbrowser.xml",
"browser/base/content/urlbarBindings.xml",
"browser/components/search/content/search.xml",
"browser/components/translation/translation-infobar.xml",
"toolkit/components/prompts/content/tabprompts.xml"
],
"env": {
"mozilla/browser-window": true
}
},{
// XXX Bug 1421969. These files/directories are still being fixed,
// so turn off mozilla/use-services for them for now.
"files": [

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

@ -3,7 +3,7 @@
module.exports = {
"rules": {
// Warn about cyclomatic complexity in functions.
"complexity": ["error", 42],
"complexity": ["error", 47],
// XXX These are rules that are enabled in the recommended configuration, but
// disabled here due to failures when initially implemented. They should be

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

@ -4,7 +4,7 @@ module.exports = {
"rules": {
// XXX Bug 1326071 - This should be reduced down - probably to 20 or to
// be removed & synced with the mozilla/recommended value.
"complexity": ["error", {"max": 40}],
"complexity": ["error", {"max": 44}],
// Disallow empty statements. This will report an error for:
// try { something(); } catch (e) {}

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

@ -390,9 +390,7 @@ pref("browser.search.order.2", "chrome://browser-region/locale/re
pref("browser.search.order.3", "chrome://browser-region/locale/region.properties");
// Market-specific search defaults
// This is disabled globally, and then enabled for individual locales
// in firefox-l10n.js (eg. it's enabled for en-US).
pref("browser.search.geoSpecificDefaults", false);
pref("browser.search.geoSpecificDefaults", true);
pref("browser.search.geoSpecificDefaults.url", "https://search.services.mozilla.com/1/%APP%/%VERSION%/%CHANNEL%/%LOCALE%/%REGION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%");
// US specific default (used as a fallback if the geoSpecificDefaults request fails).

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

@ -4,8 +4,6 @@
- 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/. -->
<!-- eslint-env mozilla/browser-window -->
<bindings id="tabBrowserBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
@ -644,6 +642,7 @@
aMaxTotalProgress);
},
/* eslint-disable complexity */
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (!aRequest)
return;
@ -845,6 +844,7 @@
this.mStateFlags = aStateFlags;
this.mStatus = aStatus;
},
/* eslint-enable complexity */
onLocationChange(aWebProgress, aRequest, aLocation,
aFlags) {

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

@ -7,8 +7,6 @@ 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/.
-->
<!-- eslint-env mozilla/browser-window -->
<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
%notificationDTD;

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

@ -4,7 +4,7 @@ module.exports = {
"rules": {
"block-scoped-var": "error",
"comma-dangle": ["error", "always-multiline"],
"complexity": ["error", {"max": 21}],
"complexity": ["error", {"max": 22}],
"indent-legacy": ["error", 2, {"SwitchCase": 1, "ArrayExpression": "first", "ObjectExpression": "first"}],
"max-nested-callbacks": ["error", 3],
"new-parens": "error",

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

@ -5,6 +5,7 @@
/* import-globals-from ../../base/content/utilityOverlay.js */
/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
/* import-globals-from in-content/extensionControlled.js */
Preferences.addAll([
{ id: "network.proxy.type", type: "int" },
@ -36,6 +37,14 @@ window.addEventListener("DOMContentLoaded", () => {
gConnectionsDialog.proxyTypeChanged.bind(gConnectionsDialog));
Preferences.get("network.proxy.socks_version").on("change",
gConnectionsDialog.updateDNSPref.bind(gConnectionsDialog));
document
.getElementById("disableProxyExtension")
.addEventListener(
"command", makeDisableControllingExtension(
PREF_SETTING_TYPE, PROXY_KEY).bind(gConnectionsDialog));
gConnectionsDialog.updateProxySettingsUI();
initializeProxyUI(gConnectionsDialog);
}, { once: true, capture: true });
var gConnectionsDialog = {
@ -227,5 +236,40 @@ var gConnectionsDialog = {
if (shareProxiesPref.value)
this.updateProtocolPrefs();
return undefined;
},
getProxyControls() {
let controlGroup = document.getElementById("networkProxyType");
return [
...controlGroup.querySelectorAll(":scope > radio"),
...controlGroup.querySelectorAll("label"),
...controlGroup.querySelectorAll("textbox"),
...controlGroup.querySelectorAll("checkbox"),
...document.querySelectorAll("#networkProxySOCKSVersion > radio"),
...document.querySelectorAll("#ConnectionsDialogPane > checkbox"),
];
},
// Update the UI to show/hide the extension controlled message for
// proxy settings.
async updateProxySettingsUI() {
let isLocked = API_PROXY_PREFS.some(
pref => Services.prefs.prefIsLocked(pref));
function setInputsDisabledState(isControlled) {
let disabled = isLocked || isControlled;
for (let element of gConnectionsDialog.getProxyControls()) {
element.disabled = disabled;
}
}
if (isLocked) {
// An extension can't control this setting if any pref is locked.
hideControllingExtension(PROXY_KEY);
setInputsDisabledState(false);
} else {
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY)
.then(setInputsDisabledState);
}
}
};

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

@ -9,6 +9,8 @@
%preferencesDTD;
<!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/preferences/connection.dtd">
%connectionDTD;
<!ENTITY % mainDTD SYSTEM "chrome://browser/locale/preferences/main.dtd">
%mainDTD;
]>
<?xml-stylesheet href="chrome://global/skin/"?>
@ -35,6 +37,7 @@
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
<script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
<script type="application/javascript" src="chrome://browser/content/preferences/in-content/extensionControlled.js"/>
<keyset>
<key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
@ -42,11 +45,19 @@
<vbox id="ConnectionsDialogPane" class="prefpane largeDialogContainer">
<stringbundle id="preferencesBundle" src="chrome://browser/locale/preferences/preferences.properties"/>
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
<stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
<script type="application/javascript" src="chrome://browser/content/preferences/connection.js"/>
<hbox id="proxyExtensionContent" align="top" hidden="true">
<description control="disableProxyExtension" flex="1" />
<button id="disableProxyExtension"
class="extension-controlled-button accessory-button"
label="&disableExtension.label;" />
</hbox>
<groupbox>
<caption><label>&proxyTitle.label;</label></caption>
<caption><label>&proxyTitle.label2;</label></caption>
<radiogroup id="networkProxyType" preference="network.proxy.type"
onsyncfrompreference="return gConnectionsDialog.readProxyType();">

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

@ -0,0 +1,221 @@
/* - 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/. */
/* import-globals-from preferences.js */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
ChromeUtils.defineModuleGetter(this, "DeferredTask",
"resource://gre/modules/DeferredTask.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
"privacy.trackingprotection.ui.enabled");
const PREF_SETTING_TYPE = "prefs";
const PROXY_KEY = "proxyConfig";
const API_PROXY_PREFS = [
"network.proxy.type",
"network.proxy.http",
"network.proxy.http_port",
"network.proxy.share_proxy_settings",
"network.proxy.ftp",
"network.proxy.ftp_port",
"network.proxy.ssl",
"network.proxy.ssl_port",
"network.proxy.socks",
"network.proxy.socks_port",
"network.proxy.socks_version",
"network.proxy.socks_remote_dns",
"network.proxy.no_proxies_on",
"network.proxy.autoconfig_url",
"signon.autologin.proxy",
];
let extensionControlledContentIds = {
"privacy.containers": "browserContainersExtensionContent",
"homepage_override": "browserHomePageExtensionContent",
"newTabURL": "browserNewTabExtensionContent",
"defaultSearch": "browserDefaultSearchExtensionContent",
"proxyConfig": "proxyExtensionContent",
get "websites.trackingProtectionMode"() {
return {
button: "trackingProtectionExtensionContentButton",
section:
trackingprotectionUiEnabled ?
"trackingProtectionExtensionContentLabel" :
"trackingProtectionPBMExtensionContentLabel",
};
}
};
function getExtensionControlledArgs(settingName) {
switch (settingName) {
case "proxyConfig":
return [document.getElementById("bundleBrand").getString("brandShortName")];
default:
return [];
}
}
let extensionControlledIds = {};
/**
* Check if a pref is being managed by an extension.
*/
async function getControllingExtensionInfo(type, settingName) {
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getSetting(type, settingName);
}
function getControllingExtensionEls(settingName) {
let idInfo = extensionControlledContentIds[settingName];
let section = document.getElementById(idInfo.section || idInfo);
let button = idInfo.button ?
document.getElementById(idInfo.button) :
section.querySelector("button");
return {
section,
button,
description: section.querySelector("description"),
};
}
async function getControllingExtension(type, settingName) {
let info = await getControllingExtensionInfo(type, settingName);
let addon = info && info.id
&& await AddonManager.getAddonByID(info.id);
return addon;
}
async function handleControllingExtension(type, settingName) {
let addon = await getControllingExtension(type, settingName);
// Sometimes the ExtensionSettingsStore gets in a bad state where it thinks
// an extension is controlling a setting but the extension has been uninstalled
// outside of the regular lifecycle. If the extension isn't currently installed
// then we should treat the setting as not being controlled.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example.
if (addon) {
extensionControlledIds[settingName] = addon.id;
showControllingExtension(settingName, addon);
} else {
let elements = getControllingExtensionEls(settingName);
if (extensionControlledIds[settingName]
&& !document.hidden
&& elements.button) {
showEnableExtensionMessage(settingName);
} else {
hideControllingExtension(settingName);
}
delete extensionControlledIds[settingName];
}
return !!addon;
}
function getControllingExtensionFragment(settingName, addon, ...extraArgs) {
let msg = document.getElementById("bundlePreferences")
.getString(`extensionControlled.${settingName}`);
let image = document.createElement("image");
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
image.setAttribute("src", addon.iconURL || defaultIcon);
image.classList.add("extension-controlled-icon");
let addonBit = document.createDocumentFragment();
addonBit.appendChild(image);
addonBit.appendChild(document.createTextNode(" " + addon.name));
return BrowserUtils.getLocalizedFragment(document, msg, addonBit, ...extraArgs);
}
async function showControllingExtension(settingName, addon) {
// Tell the user what extension is controlling the setting.
let elements = getControllingExtensionEls(settingName);
let extraArgs = getExtensionControlledArgs(settingName);
elements.section.classList.remove("extension-controlled-disabled");
let description = elements.description;
// Remove the old content from the description.
while (description.firstChild) {
description.firstChild.remove();
}
let fragment = getControllingExtensionFragment(
settingName, addon, ...extraArgs);
description.appendChild(fragment);
if (elements.button) {
elements.button.hidden = false;
}
// Show the controlling extension row and hide the old label.
elements.section.hidden = false;
}
function hideControllingExtension(settingName) {
let elements = getControllingExtensionEls(settingName);
elements.section.hidden = true;
if (elements.button) {
elements.button.hidden = true;
}
}
function showEnableExtensionMessage(settingName) {
let elements = getControllingExtensionEls(settingName);
elements.button.hidden = true;
elements.section.classList.add("extension-controlled-disabled");
let icon = url => {
let img = document.createElement("image");
img.src = url;
img.className = "extension-controlled-icon";
return img;
};
let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
let toolbarIcon = icon("chrome://browser/skin/menu.svg");
let message = document.getElementById("bundlePreferences")
.getString("extensionControlled.enable");
let frag = BrowserUtils.getLocalizedFragment(document, message, addonIcon, toolbarIcon);
elements.description.innerHTML = "";
elements.description.appendChild(frag);
let dismissButton = document.createElement("image");
dismissButton.setAttribute("class", "extension-controlled-icon close-icon");
dismissButton.addEventListener("click", function dismissHandler() {
hideControllingExtension(settingName);
dismissButton.removeEventListener("click", dismissHandler);
});
elements.description.appendChild(dismissButton);
}
function makeDisableControllingExtension(type, settingName) {
return async function disableExtension() {
let {id} = await getControllingExtensionInfo(type, settingName);
let addon = await AddonManager.getAddonByID(id);
addon.userDisabled = true;
};
}
function initializeProxyUI(container) {
let deferredUpdate = new DeferredTask(() => {
container.updateProxySettingsUI();
}, 10);
let proxyObserver = {
observe: (subject, topic, data) => {
if (API_PROXY_PREFS.includes(data)) {
deferredUpdate.arm();
}
},
};
Services.prefs.addObserver("", proxyObserver);
window.addEventListener("unload", () => {
Services.prefs.removeObserver("", proxyObserver);
});
}

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

@ -2,6 +2,7 @@
* 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/. */
/* import-globals-from extensionControlled.js */
/* import-globals-from preferences.js */
var gSearchResultsPane = {

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

@ -4,6 +4,7 @@
browser.jar:
content/browser/preferences/in-content/preferences.js
content/browser/preferences/in-content/extensionControlled.js
* content/browser/preferences/in-content/preferences.xul
content/browser/preferences/in-content/subdialogs.js

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

@ -2,6 +2,7 @@
* 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/. */
/* import-globals-from extensionControlled.js */
/* import-globals-from preferences.js */
/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
@ -367,6 +368,13 @@ var gMainPane = {
Services.obs.removeObserver(newTabObserver, "newtab-url-changed");
});
let connectionSettingsLink = document.getElementById("connectionSettingsLearnMore");
let connectionSettingsUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") +
"prefs-connection-settings";
connectionSettingsLink.setAttribute("href", connectionSettingsUrl);
this.updateProxySettingsUI();
initializeProxyUI(gMainPane);
if (AppConstants.platform == "win") {
// Functionality for "Show tabs in taskbar" on Windows 7 and up.
try {
@ -1086,7 +1094,28 @@ var gMainPane = {
* Displays a dialog in which proxy settings may be changed.
*/
showConnections() {
gSubDialog.open("chrome://browser/content/preferences/connection.xul");
gSubDialog.open("chrome://browser/content/preferences/connection.xul",
null, null, this.updateProxySettingsUI.bind(this));
},
// Update the UI to show the proper description depending on whether an
// extension is in control or not.
async updateProxySettingsUI() {
let controllingExtension = await getControllingExtension(PREF_SETTING_TYPE, PROXY_KEY);
let fragment = controllingExtension ?
getControllingExtensionFragment(PROXY_KEY, controllingExtension, this._brandShortName) :
BrowserUtils.getLocalizedFragment(
document,
this._prefsBundle.getString("connectionDesc.label"),
this._brandShortName);
let description = document.getElementById("connectionSettingsDescription");
// Remove the old content from the description.
while (description.firstChild) {
description.firstChild.remove();
}
description.appendChild(fragment);
},
checkBrowserContainers(event) {

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

@ -749,7 +749,15 @@
<caption class="search-header" hidden="true"><label>&networkProxy.label;</label></caption>
<hbox align="center">
<description flex="1" control="connectionSettings">&connectionDesc.label;</description>
<hbox align="center" flex="1">
<description id="connectionSettingsDescription" control="connectionSettings"></description>
<spacer width="5"/>
<label id="connectionSettingsLearnMore" class="learnMore text-link">
&connectionSettingsLearnMore.label;
</label>
<separator orient="vertical"/>
</hbox>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
<button id="connectionSettings"

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

@ -15,22 +15,12 @@
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.defineModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
ChromeUtils.defineModuleGetter(this, "formAutofillParent",
"resource://formautofill/FormAutofillParent.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
"privacy.trackingprotection.ui.enabled");
var gLastHash = "";
var gCategoryInits = new Map();
@ -417,148 +407,3 @@ function appendSearchKeywords(aId, keywords) {
}
element.setAttribute("searchkeywords", keywords.join(" "));
}
const PREF_SETTING_TYPE = "prefs";
let extensionControlledContentIds = {
"privacy.containers": "browserContainersExtensionContent",
"homepage_override": "browserHomePageExtensionContent",
"newTabURL": "browserNewTabExtensionContent",
"defaultSearch": "browserDefaultSearchExtensionContent",
get "websites.trackingProtectionMode"() {
return {
button: "trackingProtectionExtensionContentButton",
section:
trackingprotectionUiEnabled ?
"trackingProtectionExtensionContentLabel" :
"trackingProtectionPBMExtensionContentLabel",
};
}
};
let extensionControlledIds = {};
/**
* Check if a pref is being managed by an extension.
*/
async function getControllingExtensionInfo(type, settingName) {
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getSetting(type, settingName);
}
function getControllingExtensionEls(settingName) {
let idInfo = extensionControlledContentIds[settingName];
let section = document.getElementById(idInfo.section || idInfo);
let button = idInfo.button ?
document.getElementById(idInfo.button) :
section.querySelector("button");
return {
section,
button,
description: section.querySelector("description"),
};
}
async function handleControllingExtension(type, settingName) {
let info = await getControllingExtensionInfo(type, settingName);
let addon = info && info.id
&& await AddonManager.getAddonByID(info.id);
// Sometimes the ExtensionSettingsStore gets in a bad state where it thinks
// an extension is controlling a setting but the extension has been uninstalled
// outside of the regular lifecycle. If the extension isn't currently installed
// then we should treat the setting as not being controlled.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example.
if (addon) {
extensionControlledIds[settingName] = info.id;
showControllingExtension(settingName, addon);
} else {
let elements = getControllingExtensionEls(settingName);
if (extensionControlledIds[settingName]
&& !document.hidden
&& elements.button) {
showEnableExtensionMessage(settingName);
} else {
hideControllingExtension(settingName);
}
delete extensionControlledIds[settingName];
}
return !!addon;
}
async function showControllingExtension(settingName, addon) {
// Tell the user what extension is controlling the setting.
let elements = getControllingExtensionEls(settingName);
elements.section.classList.remove("extension-controlled-disabled");
let description = elements.description;
// Remove the old content from the description.
while (description.firstChild) {
description.firstChild.remove();
}
// Populate the description.
let msg = document.getElementById("bundlePreferences")
.getString(`extensionControlled.${settingName}`);
let image = document.createElement("image");
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
image.setAttribute("src", addon.iconURL || defaultIcon);
image.classList.add("extension-controlled-icon");
let addonBit = document.createDocumentFragment();
addonBit.appendChild(image);
addonBit.appendChild(document.createTextNode(" " + addon.name));
let fragment = BrowserUtils.getLocalizedFragment(document, msg, addonBit);
description.appendChild(fragment);
if (elements.button) {
elements.button.hidden = false;
}
// Show the controlling extension row and hide the old label.
elements.section.hidden = false;
}
function hideControllingExtension(settingName) {
let elements = getControllingExtensionEls(settingName);
elements.section.hidden = true;
if (elements.button) {
elements.button.hidden = true;
}
}
function showEnableExtensionMessage(settingName) {
let elements = getControllingExtensionEls(settingName);
elements.button.hidden = true;
elements.section.classList.add("extension-controlled-disabled");
let icon = url => {
let img = document.createElement("image");
img.src = url;
img.className = "extension-controlled-icon";
return img;
};
let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
let toolbarIcon = icon("chrome://browser/skin/menu.svg");
let message = document.getElementById("bundlePreferences")
.getString("extensionControlled.enable");
let frag = BrowserUtils.getLocalizedFragment(document, message, addonIcon, toolbarIcon);
elements.description.innerHTML = "";
elements.description.appendChild(frag);
let dismissButton = document.createElement("image");
dismissButton.setAttribute("class", "extension-controlled-icon close-icon");
dismissButton.addEventListener("click", function dismissHandler() {
hideControllingExtension(settingName);
dismissButton.removeEventListener("click", dismissHandler);
});
elements.description.appendChild(dismissButton);
}
function makeDisableControllingExtension(type, settingName) {
return async function disableExtension() {
let {id} = await getControllingExtensionInfo(type, settingName);
let addon = await AddonManager.getAddonByID(id);
addon.userDisabled = true;
};
}

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

@ -108,6 +108,8 @@
src="chrome://global/content/preferencesBindings.js"/>
<script type="application/javascript"
src="chrome://browser/content/preferences/in-content/preferences.js"/>
<script type="application/javascript"
src="chrome://browser/content/preferences/in-content/extensionControlled.js"/>
<script src="chrome://browser/content/preferences/in-content/findInPage.js"/>
<script src="chrome://browser/content/preferences/in-content/subdialogs.js"/>

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

@ -2,6 +2,7 @@
* 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/. */
/* import-globals-from extensionControlled.js */
/* import-globals-from preferences.js */
/* FIXME: ESlint globals workaround should be removed once bug 1395426 gets fixed */

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

@ -2,6 +2,7 @@
* 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/. */
/* import-globals-from extensionControlled.js */
/* import-globals-from preferences.js */
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");

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

@ -50,6 +50,7 @@ skip-if = os != "win" || (os == "win" && os_version == "6.1")
skip-if = true || !healthreport # Bug 1185403 for the "true"
[browser_homepages_filter_aboutpreferences.js]
[browser_extension_controlled.js]
[browser_languages_subdialog.js]
[browser_layersacceleration.js]
[browser_masterpassword.js]
[browser_notifications_do_not_disturb.js]

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

@ -1,10 +1,13 @@
/* eslint-env webextensions */
const PROXY_PREF = "network.proxy.type";
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF);
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
const CHROME_URL_ROOT = TEST_DIR + "/";
@ -48,26 +51,37 @@ function waitForMutation(target, opts, cb) {
});
}
function waitForMessageChange(id, cb, opts = { attributes: true, attributeFilter: ["hidden"] }) {
// eslint-disable-next-line mozilla/no-cpows-in-tests
return waitForMutation(gBrowser.contentDocument.getElementById(id), opts, cb);
function waitForMessageChange(element, cb, opts = { attributes: true, attributeFilter: ["hidden"] }) {
return waitForMutation(element, opts, cb);
}
function waitForMessageHidden(messageId) {
return waitForMessageChange(messageId, target => target.hidden);
// eslint-disable-next-line mozilla/no-cpows-in-tests
function getElement(id, doc = gBrowser.contentDocument) {
return doc.getElementById(id);
}
function waitForMessageShown(messageId) {
return waitForMessageChange(messageId, target => !target.hidden);
function waitForMessageHidden(messageId, doc) {
return waitForMessageChange(getElement(messageId, doc), target => target.hidden);
}
function waitForEnableMessage(messageId) {
function waitForMessageShown(messageId, doc) {
return waitForMessageChange(getElement(messageId, doc), target => !target.hidden);
}
function waitForEnableMessage(messageId, doc) {
return waitForMessageChange(
messageId,
getElement(messageId, doc),
target => target.classList.contains("extension-controlled-disabled"),
{ attributeFilter: ["class"], attributes: true });
}
function waitForMessageContent(messageId, content, doc) {
return waitForMessageChange(
getElement(messageId, doc),
target => target.textContent === content,
{ childList: true });
}
add_task(async function testExtensionControlledHomepage() {
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
@ -604,3 +618,193 @@ add_task(async function testExtensionControlledTrackingProtection() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
add_task(async function testExtensionControlledProxyConfig() {
const proxySvc = Ci.nsIProtocolProxyService;
const PROXY_DEFAULT = proxySvc.PROXYCONFIG_SYSTEM;
const EXTENSION_ID = "@set_proxy";
const CONTROLLED_SECTION_ID = "proxyExtensionContent";
const CONTROLLED_BUTTON_ID = "disableProxyExtension";
const CONNECTION_SETTINGS_DESC_ID = "connectionSettingsDescription";
const PANEL_URL = "chrome://browser/content/preferences/connection.xul";
await SpecialPowers.pushPrefEnv({"set": [[PROXY_PREF, PROXY_DEFAULT]]});
function background() {
browser.browserSettings.proxyConfig.set({value: {proxyType: "none"}});
}
function expectedConnectionSettingsMessage(doc, isControlled) {
let brandShortName = doc.getElementById("bundleBrand").getString("brandShortName");
return isControlled ?
`An extension, set_proxy, is controlling how ${brandShortName} connects to the internet.` :
`Configure how ${brandShortName} connects to the internet.`;
}
function connectionSettingsMessagePromise(doc, isControlled) {
return waitForMessageContent(
CONNECTION_SETTINGS_DESC_ID,
expectedConnectionSettingsMessage(doc, isControlled)
);
}
function verifyState(doc, isControlled) {
let isPanel = doc.getElementById(CONTROLLED_BUTTON_ID);
let brandShortName = doc.getElementById("bundleBrand").getString("brandShortName");
is(proxyType === proxySvc.PROXYCONFIG_DIRECT, isControlled,
"Proxy pref is set to the expected value.");
if (isPanel) {
let controlledSection = doc.getElementById(CONTROLLED_SECTION_ID);
is(controlledSection.hidden, !isControlled, "The extension controlled row's visibility is as expected.");
if (isPanel) {
is(doc.getElementById(CONTROLLED_BUTTON_ID).hidden, !isControlled,
"The disable extension button's visibility is as expected.");
}
if (isControlled) {
let controlledDesc = controlledSection.querySelector("description");
// There are two spaces before "set_proxy" because it's " <image /> set_proxy".
is(controlledDesc.textContent, `An extension, set_proxy, is controlling how ${brandShortName} connects to the internet.`,
"The user is notified that an extension is controlling proxy settings.");
}
function getProxyControls() {
let controlGroup = doc.getElementById("networkProxyType");
return [
...controlGroup.querySelectorAll(":scope > radio"),
...controlGroup.querySelectorAll("label"),
...controlGroup.querySelectorAll("textbox"),
...controlGroup.querySelectorAll("checkbox"),
...doc.querySelectorAll("#networkProxySOCKSVersion > radio"),
...doc.querySelectorAll("#ConnectionsDialogPane > checkbox"),
];
}
let controlState = isControlled ? "disabled" : "enabled";
for (let element of getProxyControls()) {
is(element.disabled, isControlled, `Proxy controls are ${controlState}.`);
}
} else {
is(doc.getElementById(CONNECTION_SETTINGS_DESC_ID).textContent,
expectedConnectionSettingsMessage(doc, isControlled),
"The connection settings description is as expected.");
}
}
async function disableViaClick() {
let sectionId = CONTROLLED_SECTION_ID;
let controlledSection = panelDoc.getElementById(sectionId);
let enableMessageShown = waitForEnableMessage(sectionId, panelDoc);
panelDoc.getElementById(CONTROLLED_BUTTON_ID).click();
await enableMessageShown;
// The user is notified how to enable the extension.
let controlledDesc = controlledSection.querySelector("description");
is(controlledDesc.textContent, "To enable the extension go to Add-ons in the menu.",
"The user is notified of how to enable the extension again");
// The user can dismiss the enable instructions.
let hidden = waitForMessageHidden(sectionId, panelDoc);
controlledSection.querySelector("image:last-of-type").click();
return hidden;
}
async function reEnableExtension(addon) {
let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
addon.userDisabled = false;
await messageChanged;
}
async function openProxyPanel() {
let panel = await openAndLoadSubDialog(PANEL_URL);
let closingPromise = waitForEvent(panel.document.documentElement, "dialogclosing");
ok(panel, "Proxy panel opened.");
return {panel, closingPromise};
}
async function closeProxyPanel(panelObj) {
panelObj.panel.document.documentElement.cancelDialog();
let panelClosingEvent = await panelObj.closingPromise;
ok(panelClosingEvent, "Proxy panel closed.");
}
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let mainDoc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#general",
"#general should be in the URI for about:preferences");
verifyState(mainDoc, false);
// Open the connections panel.
let panelObj = await openProxyPanel();
let panelDoc = panelObj.panel.document;
verifyState(panelDoc, false);
await closeProxyPanel(panelObj);
verifyState(mainDoc, false);
// Install an extension that sets Tracking Protection.
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
name: "set_proxy",
applications: {gecko: {id: EXTENSION_ID}},
permissions: ["browserSettings"],
},
background,
});
let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
await extension.startup();
await messageChanged;
let addon = await AddonManager.getAddonByID(EXTENSION_ID);
verifyState(mainDoc, true);
messageChanged = connectionSettingsMessagePromise(mainDoc, false);
panelObj = await openProxyPanel();
panelDoc = panelObj.panel.document;
verifyState(panelDoc, true);
await disableViaClick();
verifyState(panelDoc, false);
await closeProxyPanel(panelObj);
await messageChanged;
verifyState(mainDoc, false);
await reEnableExtension(addon);
verifyState(mainDoc, true);
messageChanged = connectionSettingsMessagePromise(mainDoc, false);
panelObj = await openProxyPanel();
panelDoc = panelObj.panel.document;
verifyState(panelDoc, true);
await disableViaClick();
verifyState(panelDoc, false);
await closeProxyPanel(panelObj);
await messageChanged;
verifyState(mainDoc, false);
// Enable the extension so we get the UNINSTALL event, which is needed by
// ExtensionPreferencesManager to clean up properly.
// TODO: BUG 1408226
await reEnableExtension(addon);
await extension.unload();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

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

@ -0,0 +1,62 @@
add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
// eslint-disable-next-line mozilla/no-cpows-in-tests
const contentDocument = gBrowser.contentDocument;
// eslint-disable-next-line mozilla/no-cpows-in-tests
const dialogOverlay = content.gSubDialog._preloadDialog._overlay;
async function languagesSubdialogOpened() {
const promiseSubDialogLoaded = promiseLoadSubDialog("chrome://browser/content/preferences/languages.xul");
contentDocument.getElementById("chooseLanguage").click();
const win = await promiseSubDialogLoaded;
win.Preferences.forceEnableInstantApply();
is(dialogOverlay.style.visibility, "visible", "The dialog is visible.");
return win;
}
function closeLanguagesSubdialog() {
const closeBtn = dialogOverlay.querySelector(".dialogClose");
closeBtn.doCommand();
}
is(dialogOverlay.style.visibility, "", "The dialog is invisible.");
let win = await languagesSubdialogOpened();
ok(win.document.getElementById("spoofEnglish").hidden, "The 'Request English' checkbox is hidden.");
closeLanguagesSubdialog();
is(dialogOverlay.style.visibility, "", "The dialog is invisible.");
await SpecialPowers.pushPrefEnv({set: [
["privacy.resistFingerprinting", true],
["privacy.spoof_english", 0],
]});
win = await languagesSubdialogOpened();
ok(!win.document.getElementById("spoofEnglish").hidden, "The 'Request English' checkbox isn't hidden.");
ok(!win.document.getElementById("spoofEnglish").checked, "The 'Request English' checkbox isn't checked.");
is(win.Preferences.get("privacy.spoof_english").value, 0, "The privacy.spoof_english pref is set to 0.");
win.document.getElementById("spoofEnglish").checked = true;
win.document.getElementById("spoofEnglish").doCommand();
ok(win.document.getElementById("spoofEnglish").checked, "The 'Request English' checkbox is checked.");
is(win.Preferences.get("privacy.spoof_english").value, 2, "The privacy.spoof_english pref is set to 2.");
closeLanguagesSubdialog();
win = await languagesSubdialogOpened();
ok(!win.document.getElementById("spoofEnglish").hidden, "The 'Request English' checkbox isn't hidden.");
ok(win.document.getElementById("spoofEnglish").checked, "The 'Request English' checkbox is checked.");
is(win.Preferences.get("privacy.spoof_english").value, 2, "The privacy.spoof_english pref is set to 2.");
win.document.getElementById("spoofEnglish").checked = false;
win.document.getElementById("spoofEnglish").doCommand();
ok(!win.document.getElementById("spoofEnglish").checked, "The 'Request English' checkbox isn't checked.");
is(win.Preferences.get("privacy.spoof_english").value, 1, "The privacy.spoof_english pref is set to 1.");
closeLanguagesSubdialog();
win = await languagesSubdialogOpened();
ok(!win.document.getElementById("spoofEnglish").hidden, "The 'Request English' checkbox isn't hidden.");
ok(!win.document.getElementById("spoofEnglish").checked, "The 'Request English' checkbox isn't checked.");
is(win.Preferences.get("privacy.spoof_english").value, 1, "The privacy.spoof_english pref is set to 1.");
closeLanguagesSubdialog();
gBrowser.removeCurrentTab();
});

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

@ -319,24 +319,24 @@ var gLanguagesDialog = {
return false;
}
var spoofEnglish = document.getElementById("privacy.spoof_english").value;
var spoofEnglish = Preferences.get("privacy.spoof_english").value;
var activeLanguages = this._activeLanguages;
var availableLanguages = this._availableLanguages;
checkbox.hidden = false;
switch (spoofEnglish) {
case 1: // don't spoof intl.accept_lanauges
case 1: // don't spoof intl.accept_languages
activeLanguages.disabled = false;
activeLanguages.selectItem(activeLanguages.firstChild);
availableLanguages.disabled = false;
this.onAvailableLanguageSelect();
return false;
case 2: // spoof intl.accept_lanauges
case 2: // spoof intl.accept_languages
activeLanguages.clearSelection();
activeLanguages.disabled = true;
availableLanguages.disabled = true;
this.onAvailableLanguageSelect();
return true;
default: // will prompt for spoofing intl.accept_lanauges if resisting fingerprinting
default: // will prompt for spoofing intl.accept_languages if resisting fingerprinting
return false;
}
},
@ -345,3 +345,8 @@ var gLanguagesDialog = {
return document.getElementById("spoofEnglish").checked ? 2 : 1;
}
};
// These focus and resize handlers hack around XUL bug 1194844
// by triggering extra reflow (see bug 1194346).
window.addEventListener("focus", () => gLanguagesDialog.forceReflow());
window.addEventListener("resize", () => gLanguagesDialog.forceReflow());

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

@ -26,12 +26,7 @@
onload="gLanguagesDialog.init();"
helpTopic="prefs-languages"
ondialoghelp="openPrefsHelp()"
style="width: &window.width;"
onfocus="gLanguagesDialog.forceReflow()"
onresize="gLanguagesDialog.forceReflow()">
<!-- The onfocus and onresize handlers above hack around XUL bug 1194844
- by triggering extra reflow (see bug 1194346). -->
style="width: &window.width;">
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
<script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>

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

@ -3,9 +3,6 @@
- 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/. -->
<!-- This file is imported into the browser window. -->
<!-- eslint-env mozilla/browser-window -->
<!-- XULCommandEvent is a specialised global. -->
<!-- global XULCommandEvent -->

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

@ -3,8 +3,6 @@
- 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/. -->
<!-- eslint-env mozilla/browser-window -->
<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
%notificationDTD;

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

@ -58,7 +58,7 @@ module.exports = {
"comma-dangle": ["error", "always-multiline"],
// Warn about cyclomatic complexity in functions.
"complexity": ["error", {"max": 20}],
"complexity": ["error", {"max": 26}],
// Enforce dots on the next line with property name.
"dot-location": ["error", "property"],

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

@ -123,6 +123,13 @@ class EditDialog {
this.handleChange(event);
break;
}
case "contextmenu": {
if (!(event.target instanceof HTMLInputElement) &&
!(event.target instanceof HTMLTextAreaElement)) {
event.preventDefault();
}
break;
}
}
}
@ -171,6 +178,7 @@ class EditDialog {
*/
attachEventListeners() {
window.addEventListener("keypress", this);
window.addEventListener("contextmenu", this);
this._elements.controlsContainer.addEventListener("click", this);
document.addEventListener("input", this);
}
@ -180,6 +188,7 @@ class EditDialog {
*/
detachEventListeners() {
window.removeEventListener("keypress", this);
window.removeEventListener("contextmenu", this);
this._elements.controlsContainer.removeEventListener("click", this);
document.removeEventListener("input", this);
}

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

@ -206,6 +206,10 @@ class ManageRecords {
this.handleKeyPress(event);
break;
}
case "contextmenu": {
event.preventDefault();
break;
}
}
}
@ -250,6 +254,7 @@ class ManageRecords {
attachEventListeners() {
window.addEventListener("unload", this, {once: true});
window.addEventListener("keypress", this);
window.addEventListener("contextmenu", this);
this._elements.records.addEventListener("change", this);
this._elements.records.addEventListener("click", this);
this._elements.controlsContainer.addEventListener("click", this);
@ -261,6 +266,7 @@ class ManageRecords {
*/
detachEventListeners() {
window.removeEventListener("keypress", this);
window.removeEventListener("contextmenu", this);
this._elements.records.removeEventListener("change", this);
this._elements.records.removeEventListener("click", this);
this._elements.controlsContainer.removeEventListener("click", this);

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

@ -14,10 +14,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
// Flag to control if we want to send new/old telemetry
// TODO: remove this flag and the legacy code in Bug 1419996
const NEW_TABLE = true;
// Validate the content has non-empty string
function hasString(str) {
return typeof str == "string" && str.length > 0;
@ -337,44 +333,6 @@ const EVENT_WHITELIST = {
},
};
/**
* We send 2 kinds (firefox-onboarding-event, firefox-onboarding-session) of pings to ping centre
* server (they call it `topic`). The `internal` state in `topic` field means this event is used internaly to
* track states and will not send out any message.
*
* To save server space and make query easier, we track session begin and end but only send pings
* when session end. Therefore the server will get single "onboarding/overlay/notification-session"
* event which includes both `session_begin` and `session_end` timestamp.
*
* We send `session_begin` and `session_end` timestamps instead of `session_duration` diff because
* of analytics engineer's request.
*/
const OLD_EVENT_WHITELIST = {
// track when click the notification close button
"notification-close-button-click": {topic: "firefox-onboarding-event", category: "notification-interactions"},
// track when click the notification Call-To-Action button
"notification-cta-click": {topic: "firefox-onboarding-event", category: "notification-interactions"},
// track when notification is shown
"notification-session-begin": {topic: "internal"},
// track when the notification closed
"notification-session-end": {topic: "firefox-onboarding-session", category: "notification-interactions"},
// init onboarding session with session_key and page url
"onboarding-register-session": {topic: "internal"},
// track when the onboarding script inited
"onboarding-session-begin": {topic: "internal"},
// track when the onboarding script destoryed
"onboarding-session-end": {topic: "firefox-onboarding-session", category: "overlay-interactions"},
// track when click the overlay Call-To-Action button
"overlay-cta-click": {topic: "firefox-onboarding-event", category: "overlay-interactions"},
// track when click or auto select the overlay navigate item
"overlay-nav-click": {topic: "firefox-onboarding-event", category: "overlay-interactions"},
// track when the overlay is shown
"overlay-session-begin": {topic: "internal"},
// track when the overlay is closed
"overlay-session-end": {topic: "firefox-onboarding-session", category: "overlay-interactions"},
// track when click the overlay "skip tour" button
"overlay-skip-tour": {topic: "firefox-onboarding-event", category: "overlay-interactions"},
};
const ONBOARDING_ID = "onboarding";
let OnboardingTelemetry = {
@ -385,34 +343,11 @@ let OnboardingTelemetry = {
},
init(startupData) {
if (NEW_TABLE) {
this.sessionProbe = new PingCentre({topic: "firefox-onboarding-session2"});
this.eventProbe = new PingCentre({topic: "firefox-onboarding-event2"});
} else {
this.sessionProbe = new PingCentre({topic: "firefox-onboarding-session"});
this.eventProbe = new PingCentre({topic: "firefox-onboarding-event"});
}
this.sessionProbe = new PingCentre({topic: "firefox-onboarding-session2"});
this.eventProbe = new PingCentre({topic: "firefox-onboarding-event2"});
this.state.addon_version = startupData.version;
},
// register per tab session data
registerNewTelemetrySession(data) {
let { page, session_key, tour_type } = data;
if (this.state.sessions[session_key]) {
return;
}
// session_key and page url are must have
if (!session_key || !page || !tour_type) {
throw new Error("session_key, page url, and tour_type are required for onboarding-register-session");
}
let session_id = gUUIDGenerator.generateUUID().toString();
this.state.sessions[session_key] = {
page,
session_id,
tour_type,
};
},
// register per tab session data
registerNewOnboardingSession(data) {
let { page, session_key, tour_type } = data;
@ -434,14 +369,6 @@ let OnboardingTelemetry = {
},
process(data) {
if (NEW_TABLE) {
this.processPings(data);
} else {
this.processOldPings(data);
}
},
processPings(data) {
let { type, session_key } = data;
if (type === "onboarding-register-session") {
this.registerNewOnboardingSession(data);
@ -619,123 +546,6 @@ let OnboardingTelemetry = {
}
},
processOldPings(data) {
let { event, session_key } = data;
let topic = OLD_EVENT_WHITELIST[event] && OLD_EVENT_WHITELIST[event].topic;
if (!topic) {
throw new Error(`ping-centre doesn't know ${event}, only knows ${Object.keys(OLD_EVENT_WHITELIST)}`);
}
if (event === "onboarding-register-session") {
this.registerNewTelemetrySession(data);
}
if (!this.state.sessions[session_key]) {
throw new Error(`should pass valid session_key`);
}
if (topic === "internal") {
switch (event) {
case "onboarding-session-begin":
this.state.sessions[session_key].onboarding_session_begin = Date.now();
break;
case "overlay-session-begin":
this.state.sessions[session_key].overlay_session_begin = Date.now();
break;
case "notification-session-begin":
this.state.sessions[session_key].notification_session_begin = Date.now();
break;
}
} else {
this._sendOldPings(topic, data);
}
},
// send out pings by topic
_sendOldPings(topic, data) {
let {
addon_version,
} = this.state;
let {
event,
tour_id = "",
session_key,
} = data;
let {
notification_session_begin,
onboarding_session_begin,
overlay_session_begin,
page,
session_id,
tour_type,
} = this.state.sessions[session_key];
let category = OLD_EVENT_WHITELIST[event].category;
// the field is used to identify how user open the overlay (through default logo or watermark),
// the number of open from notification can be retrieved via `notification-cta-click` event
let tour_source = Services.prefs.getStringPref("browser.onboarding.state", "default");
let session_begin;
switch (topic) {
case "firefox-onboarding-session":
switch (event) {
case "onboarding-session-end":
if (!onboarding_session_begin) {
throw new Error(`should fire onboarding-session-begin event before ${event}`);
}
event = "onboarding-session";
session_begin = onboarding_session_begin;
delete this.state.sessions[session_key];
break;
case "overlay-session-end":
if (!overlay_session_begin) {
throw new Error(`should fire overlay-session-begin event before ${event}`);
}
event = "overlay-session";
session_begin = overlay_session_begin;
break;
case "notification-session-end":
if (!notification_session_begin) {
throw new Error(`should fire notification-session-begin event before ${event}`);
}
event = "notification-session";
session_begin = notification_session_begin;
break;
}
let session_end = Date.now();
this.sessionProbe && this.sessionProbe.sendPing({
addon_version,
category,
event,
page,
session_begin,
session_end,
session_id,
tour_id,
tour_source,
tour_type,
}, {filter: ONBOARDING_ID});
break;
case "firefox-onboarding-event":
let impression = (event === "notification-close-button-click" ||
event === "notification-cta-click") ?
Services.prefs.getIntPref("browser.onboarding.notification.prompt-count", 0) : -1;
let timestamp = Date.now();
this.eventProbe && this.eventProbe.sendPing({
addon_version,
category,
event,
impression,
page,
session_id,
timestamp,
tour_id,
tour_source,
tour_type,
}, {filter: ONBOARDING_ID});
break;
}
},
// validate data sanitation and make sure correct ping params are sent
_validatePayload(payload) {
let type = payload.type;

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

@ -155,6 +155,19 @@ Enrollment
addonVersion
The add-on's version (example: ``"1.2.3"``).
Enroll Failure
method
The string ``"enrollFailed"``
object
The string ``"addon_study"``
value
The name of the study (``recipe.arguments.slug``).
reason
A string containing the filename and line number of the code
that failed, and the name of the error thrown. This information
is purposely limited to avoid leaking personally identifiable
information. This should be considered a bug.
Unenrollment
method
The string ``"unenroll"``.
@ -186,5 +199,5 @@ Unenrollment
uninstalled while Shield was inactive. This could be that
the add-on is no longer compatible, or was manually removed
from a profile.
* ``"unknown"``: A reason was not specificied. This should be
* ``"unknown"``: A reason was not specified. This should be
considered a bug.

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

@ -256,41 +256,48 @@ this.AddonStudies = {
throw new Error(`A study for recipe ${recipeId} already exists.`);
}
const addonFile = await this.downloadAddonToTemporaryFile(addonUrl);
const install = await AddonManager.getInstallForFile(addonFile);
const study = {
recipeId,
name,
description,
addonId: install.addon.id,
addonVersion: install.addon.version,
addonUrl,
active: true,
studyStartDate: new Date(),
};
TelemetryEvents.sendEvent("enroll", "addon_study", name, {
addonId: install.addon.id,
addonVersion: install.addon.version,
});
let addonFile;
try {
addonFile = await this.downloadAddonToTemporaryFile(addonUrl);
const install = await AddonManager.getInstallForFile(addonFile);
const study = {
recipeId,
name,
description,
addonId: install.addon.id,
addonVersion: install.addon.version,
addonUrl,
active: true,
studyStartDate: new Date(),
};
await getStore(db).add(study);
await Addons.applyInstall(install, false);
return study;
} catch (err) {
await getStore(db).delete(recipeId);
TelemetryEvents.sendEvent("unenroll", "addon_study", name, {
reason: "install-failure",
TelemetryEvents.sendEvent("enroll", "addon_study", name, {
addonId: install.addon.id,
addonVersion: install.addon.version,
});
return study;
} catch (err) {
await getStore(db).delete(recipeId);
// The actual stack trace and error message could possibly
// contain PII, so we don't include them here. Instead include
// some information that should still be helpful, and is less
// likely to be unsafe.
const safeErrorMessage = `${err.fileName}:${err.lineNumber}:${err.columnNumber} ${err.name}`;
TelemetryEvents.sendEvent("enrollFailed", "addon_study", name, {
reason: safeErrorMessage.slice(0, 80), // max length is 80 chars
});
throw err;
} finally {
Services.obs.notifyObservers(addonFile, "flush-cache-entry");
await OS.File.remove(addonFile.path);
if (addonFile) {
Services.obs.notifyObservers(addonFile, "flush-cache-entry");
await OS.File.remove(addonFile.path);
}
}
},

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

@ -20,6 +20,13 @@ const TelemetryEvents = {
record_on_release: true,
},
enroll_failure: {
methods: ["enrollFailed"],
objects: ["addon_study"],
extra_keys: ["reason"],
record_on_release: true,
},
unenroll: {
methods: ["unenroll"],
objects: ["preference_study", "addon_study"],

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

@ -142,19 +142,31 @@ decorate_task(
decorate_task(
withStub(Addons, "applyInstall"),
withStub(TelemetryEvents, "sendEvent"),
withWebExtension(),
async function testStartAddonCleanup(applyInstallStub, [addonId, addonFile]) {
applyInstallStub.rejects(new Error("Fake failure"));
async function testStartAddonCleanup(applyInstallStub, sendEventStub, [addonId, addonFile]) {
const fakeError = new Error("Fake failure");
fakeError.fileName = "fake/filename.js";
fakeError.lineNumber = 42;
fakeError.columnNumber = 54;
applyInstallStub.rejects(fakeError);
const addonUrl = Services.io.newFileURI(addonFile).spec;
const args = startArgsFactory({addonUrl});
await Assert.rejects(
AddonStudies.start(startArgsFactory({addonUrl})),
AddonStudies.start(args),
/Fake failure/,
"start rejects when the Addons.applyInstall function rejects"
);
const addon = await Addons.get(addonId);
ok(!addon, "If something fails during start after the add-on is installed, it is uninstalled.");
Assert.deepEqual(
sendEventStub.getCall(0).args,
["enrollFailed", "addon_study", args.name, {reason: "fake/filename.js:42:54 Error"}],
"AddonStudies.start() should send an enroll-failed event when applyInstall rejects",
);
}
);

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

@ -45,7 +45,7 @@ available. -->
<!ENTITY networkProxy.label "Network Proxy">
<!ENTITY connectionDesc.label "Configure how &brandShortName; connects to the Internet">
<!ENTITY connectionSettingsLearnMore.label "Learn more">
<!ENTITY connectionSettings.label "Settings…">
<!ENTITY connectionSettings.accesskey "e">

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

@ -7,7 +7,7 @@
<!ENTITY window.width2 "49em">
<!ENTITY window.macWidth2 "44em">
<!ENTITY proxyTitle.label "Configure Proxies to Access the Internet">
<!ENTITY proxyTitle.label2 "Configure Proxy Access to the Internet">
<!ENTITY noProxyTypeRadio.label "No proxy">
<!ENTITY noProxyTypeRadio.accesskey "y">
<!ENTITY systemTypeRadio.label "Use system proxy settings">

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

@ -295,8 +295,18 @@ extensionControlled.privacy.containers = An extension, %S, requires Container Ta
# This string is shown to notify the user that their tracking protection preferences are being controlled by an extension.
extensionControlled.websites.trackingProtectionMode = An extension, %S, is controlling tracking protection.
# LOCALIZATION NOTE (extensionControlled.proxyConfig):
# This string is shown to notify the user that their proxy configuration preferences are being controlled by an extension.
# %1$S is the icon and name of the extension.
# %2$S is the brandShortName from brand.properties (for example "Nightly")
extensionControlled.proxyConfig = An extension, %1$S, is controlling how %2$S connects to the internet.
# LOCALIZATION NOTE (extensionControlled.enable):
# %1$S is replaced with the icon for the add-ons menu.
# %2$S is replaced with the icon for the toolbar menu.
# This string is shown to notify the user how to enable an extension that they disabled.
extensionControlled.enable = To enable the extension go to %1$S Add-ons in the %2$S menu.
# LOCALIZATION NOTE (connectionDesc.label):
# %S is the brandShortName from brand.properties (for example "Nightly")
connectionDesc.label = Configure how %S connects to the internet.

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

@ -3,7 +3,3 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#filter substitution
# LOCALIZATION NOTE: this preference is set to true for en-US specifically,
# locales without this line have the setting set to false by default.
pref("browser.search.geoSpecificDefaults", true);

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

@ -0,0 +1,65 @@
diff -Nru gdb-7.12/debian/changelog gdb-7.12/debian/changelog
--- gdb-7.12/debian/changelog 2017-01-19 19:28:25.000000000 +0900
+++ gdb-7.12/debian/changelog 2018-02-07 15:36:15.000000000 +0900
@@ -1,3 +1,16 @@
+gdb (7.12-6.deb7moz1) wheezy; urgency=medium
+
+ * Mozilla backport for wheezy.
+ * debian/rules, debian/control: Don't use libbabeltrace, which is not
+ available on wheezy.
+ * debian/rules:
+ - Use DEB_HOST_{ARCH,GNU_TYPE} instead of DEB_TARGET_{ARCH,GNU_TYPE}
+ because the latter is not available on wheezy.
+ - Don't pass --dbgsym-migration to dh_strip, it's not supported on
+ wheezy's debhelper.
+
+ -- Mike Hommey <glandium@mozilla.com> Wed, 07 Feb 2018 15:36:15 +0900
+
gdb (7.12-6) unstable; urgency=medium
* debian/patches: import 7.12 branch fixes
diff -Nru gdb-7.12/debian/control gdb-7.12/debian/control
--- gdb-7.12/debian/control 2017-01-17 20:01:41.000000000 +0900
+++ gdb-7.12/debian/control 2018-02-07 15:36:06.000000000 +0900
@@ -33,8 +33,6 @@
libreadline-dev,
zlib1g-dev,
liblzma-dev,
- libbabeltrace-dev [amd64 armel armhf i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel mips64el powerpc s390x],
- libbabeltrace-ctf-dev [amd64 armel armhf i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel mips64el powerpc s390x],
python-dev,
# Python3 build
python3-dev,
diff -Nru gdb-7.12/debian/rules gdb-7.12/debian/rules
--- gdb-7.12/debian/rules 2016-12-15 09:31:54.000000000 +0900
+++ gdb-7.12/debian/rules 2018-02-07 15:36:15.000000000 +0900
@@ -4,7 +4,6 @@
DEB_BUILDDIR := $(ALL_BUILDDIR)/objdir
DEB_DH_INSTALL_SOURCEDIR := $(shell pwd)/debian/tmp
-DEB_DH_STRIP_ARGS_gdb = --dbgsym-migration='gdb-dbg (<< 7.12-1~)'
# Override CDBS's default CFLAGS, which also includes -Wall; gdb
# does not handle -Wunused well with -Werror, but defaults to
@@ -35,8 +34,8 @@
DEB_HOST_GNU_SYSTEM := $(shell dpkg-architecture -qDEB_HOST_GNU_SYSTEM)
DEB_HOST_GNU_CPU := $(shell dpkg-architecture -qDEB_HOST_GNU_CPU)
DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_TARGET_ARCH := $(shell dpkg-architecture -qDEB_TARGET_ARCH)
-DEB_TARGET_GNU_TYPE := $(shell dpkg-architecture -qDEB_TARGET_GNU_TYPE)
+DEB_TARGET_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_TARGET_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
# Cross configuration support. Check for an environment variable
# $GDB_TARGET, or a file debian/target.
@@ -89,10 +88,6 @@
arch_config_args := --with-libunwind-ia64
endif
-ifneq (,$(filter $(DEB_HOST_ARCH),amd64 armel armhf i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390x))
- arch_config_args += --with-babeltrace
-endif
-
ifdef GDB_TARGET
run_tests := no

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

@ -81,7 +81,7 @@ module.exports = {
// impair readability, but also not required either.
"comma-dangle": "off",
// Warn about cyclomatic complexity in functions.
"complexity": ["error", 35],
"complexity": ["error", 53],
// Don't warn for inconsistent naming when capturing this (not so important
// with auto-binding fat arrow functions).
"consistent-this": "off",

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

@ -18,7 +18,6 @@ class Font extends PureComponent {
constructor(props) {
super(props);
this.getSectionClasses = this.getSectionClasses.bind(this);
this.renderFontCSS = this.renderFontCSS.bind(this);
this.renderFontCSSCode = this.renderFontCSSCode.bind(this);
this.renderFontFormatURL = this.renderFontFormatURL.bind(this);
@ -26,19 +25,6 @@ class Font extends PureComponent {
this.renderFontPreview = this.renderFontPreview.bind(this);
}
getSectionClasses() {
let { font } = this.props;
let classes = ["font"];
classes.push((font.URI) ? "is-remote" : "is-local");
if (font.rule) {
classes.push("has-code");
}
return classes.join(" ");
}
renderFontCSS(cssFamilyName) {
return dom.p(
{
@ -59,12 +45,12 @@ class Font extends PureComponent {
);
}
renderFontCSSCode(rule, ruleText) {
renderFontCSSCode(ruleText) {
return dom.pre(
{
className: "font-css-code"
},
rule ? ruleText : null
ruleText
);
}
@ -134,32 +120,16 @@ class Font extends PureComponent {
URI,
} = font;
return dom.section(
return dom.li(
{
className: this.getSectionClasses(),
className: "font",
},
this.renderFontPreview(previewUrl),
dom.div(
{
className: "font-info",
},
this.renderFontName(name),
dom.span(
{
className: "font-is-local",
},
" " + getStr("fontinspector.system")
),
dom.span(
{
className: "font-is-remote",
},
" " + getStr("fontinspector.remote")
),
this.renderFontFormatURL(URI, format),
this.renderFontCSS(CSSFamilyName),
this.renderFontCSSCode(rule, ruleText)
)
this.renderFontName(name),
" " + (URI ? getStr("fontinspector.remote") : getStr("fontinspector.system")),
URI ? this.renderFontFormatURL(URI, format) : null,
this.renderFontCSS(CSSFamilyName),
rule ? this.renderFontCSSCode(ruleText) : null
);
}
}

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

@ -43,41 +43,46 @@ add_task(function* () {
yield testShowAllFonts(inspector, viewDoc);
});
function isRemote(fontLiEl) {
return fontLiEl.querySelectorAll(".font-format-url").length === 1;
}
function* testBodyFonts(inspector, viewDoc) {
let s = viewDoc.querySelectorAll("#all-fonts > section");
is(s.length, 5, "Found 5 fonts");
let lis = viewDoc.querySelectorAll("#all-fonts > li");
is(lis.length, 5, "Found 5 fonts");
for (let i = 0; i < FONTS.length; i++) {
let section = s[i];
let li = lis[i];
let font = FONTS[i];
is(section.querySelector(".font-name").textContent, font.name,
is(li.querySelector(".font-name").textContent, font.name,
"font " + i + " right font name");
is(section.classList.contains("is-remote"), font.remote,
is(isRemote(li), font.remote,
"font " + i + " remote value correct");
is(section.querySelector(".font-url").value, font.url,
is(li.querySelector(".font-url").value, font.url,
"font " + i + " url correct");
is(section.querySelector(".font-format").hidden, !font.format,
is(li.querySelector(".font-format").hidden, !font.format,
"font " + i + " format hidden value correct");
is(section.querySelector(".font-format").textContent,
is(li.querySelector(".font-format").textContent,
font.format, "font " + i + " format correct");
is(section.querySelector(".font-css-name").textContent,
is(li.querySelector(".font-css-name").textContent,
font.cssName, "font " + i + " css name correct");
}
// test that the bold and regular fonts have different previews
let regSrc = s[0].querySelector(".font-preview").src;
let boldSrc = s[1].querySelector(".font-preview").src;
let regSrc = lis[0].querySelector(".font-preview").src;
let boldSrc = lis[1].querySelector(".font-preview").src;
isnot(regSrc, boldSrc, "preview for bold font is different from regular");
// test system font
let localFontName = s[4].querySelector(".font-name").textContent;
let localFontCSSName = s[4].querySelector(".font-css-name").textContent;
let localFontName = lis[4].querySelector(".font-name").textContent;
let localFontCSSName = lis[4].querySelector(".font-css-name").textContent;
// On Linux test machines, the Arial font doesn't exist.
// The fallback is "Liberation Sans"
ok((localFontName == "Arial") || (localFontName == "Liberation Sans"),
"local font right font name");
ok(s[4].classList.contains("is-local"), "local font is local");
ok(!isRemote(lis[4]), "local font is local");
ok((localFontCSSName == "Arial") || (localFontCSSName == "Liberation Sans"),
"Arial", "local font has right css name");
}
@ -87,9 +92,9 @@ function* testDivFonts(inspector, viewDoc) {
yield selectNode("div", inspector);
yield updated;
let sections1 = viewDoc.querySelectorAll("#all-fonts > section");
is(sections1.length, 1, "Found 1 font on DIV");
is(sections1[0].querySelector(".font-name").textContent,
let lis = viewDoc.querySelectorAll("#all-fonts > li");
is(lis.length, 1, "Found 1 font on DIV");
is(lis[0].querySelector(".font-name").textContent,
"Ostrich Sans Medium",
"The DIV font has the right name");
}
@ -103,6 +108,6 @@ function* testShowAllFonts(inspector, viewDoc) {
// shouldn't change the node selection
is(inspector.selection.nodeFront.nodeName, "DIV", "Show all fonts selected");
let sections = viewDoc.querySelectorAll("#all-fonts > section");
is(sections.length, 6, "Font inspector shows 6 fonts (1 from iframe)");
let lis = viewDoc.querySelectorAll("#all-fonts > li");
is(lis.length, 6, "Font inspector shows 6 fonts (1 from iframe)");
}

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

@ -17,6 +17,6 @@ add_task(function* () {
let { nodes } = yield inspector.walker.children(bodyNode);
yield selectNode(nodes[0], inspector);
let sections = viewDoc.querySelectorAll("#all-fonts > section");
let sections = viewDoc.querySelectorAll("#all-fonts > li");
is(sections.length, 1, "Font inspector shows 1 font");
});

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

@ -21,11 +21,6 @@ NetworkPanel.durationMS=%Sms
ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
# LOCALIZATION NOTE (webConsoleWindowTitleAndURL): the Web Console floating
# panel title. For RTL languages you need to set the LRM in the string to give
# the URL the correct direction. Parameters: %S is the web page URL.
webConsoleWindowTitleAndURL=Web Console - %S
# LOCALIZATION NOTE (webConsoleXhrIndicator): the indicator displayed before
# a URL in the Web Console that was requested using an XMLHttpRequest.
# Should probably be the same as &btnConsoleXhr; in webConsole.dtd

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

@ -199,11 +199,11 @@ class Tabbar extends Component {
onTabChanged(index) {
this.setState({
activeTab: index
}, () => {
if (this.props.onSelect) {
this.props.onSelect(this.state.tabs[index].id);
}
});
if (this.props.onSelect) {
this.props.onSelect(this.state.tabs[index].id);
}
}
onAllTabsMenuClick(event) {

7
devtools/client/shared/widgets/Chart.js поставляемый
Просмотреть файл

@ -322,6 +322,12 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
* label1: total => l10n.getFormatStr("...", total), // 5
* label2: total => l10n.getFormatStr("...", total), // 9
* }
* - header: an object specifying strings to use for table column
* headers
* e.g. {
* label1: l10n.getStr(...),
* label2: l10n.getStr(...),
* }
* @return TableChart
* A table chart proxy instance, which emits the following events:
* - "mouseover", when the mouse enters a row
@ -331,6 +337,7 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
function createTableChart(document, { title, data, strings, totals, header }) {
strings = strings || {};
totals = totals || {};
header = header || {};
let isPlaceholder = false;
// If there's no data available, display an empty placeholder.

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

@ -33,20 +33,6 @@
text-decoration: underline;
}
.dim > #font-container,
.font:not(.has-code) .font-css-code,
.font-is-local,
.font-is-remote,
.font.is-local .font-format-url,
#font-template {
display: none;
}
.font.is-remote .font-is-remote,
.font.is-local .font-is-local {
display: inline;
}
.font-format::before {
content: "(";
}
@ -98,10 +84,6 @@
display: block;
}
.font-info {
display: block;
}
.font-name {
display: inline;
}

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

@ -4,15 +4,12 @@
"use strict";
var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
const {extend} = require("devtools/shared/extend");
var {TargetFactory} = require("devtools/client/framework/target");
var {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
var {Tools} = require("devtools/client/definitions");
const { Task } = require("devtools/shared/task");
var promise = require("promise");
const defer = require("devtools/shared/defer");
var Services = require("Services");
loader.lazyRequireGetter(this, "Utils", "devtools/client/webconsole/utils", true);
loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true);
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true);
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
loader.lazyRequireGetter(this, "NewWebConsoleFrame", "devtools/client/webconsole/new-webconsole", true);
@ -21,18 +18,15 @@ loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
loader.lazyRequireGetter(this, "showDoorhanger", "devtools/client/shared/doorhanger", true);
loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
const l10n = require("devtools/client/webconsole/webconsole-l10n");
const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/webconsole-l10n");
const BC_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
// The preference prefix for all of the Browser Console filters.
const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
const BC_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
var gHudId = 0;
// The HUD service
function HUD_SERVICE()
{
function HUD_SERVICE() {
this.consoles = new Map();
this.lastFinishedRequest = { callback: null };
}
@ -40,7 +34,7 @@ function HUD_SERVICE()
HUD_SERVICE.prototype =
{
_browserConsoleID: null,
_browserConsoleDefer: null,
_browserConsoleInitializing: null,
/**
* Keeps a reference for each Web Console / Browser Console that is created.
@ -72,7 +66,7 @@ HUD_SERVICE.prototype =
*
* @returns nsIDOMWindow
*/
currentContext: function HS_currentContext() {
currentContext() {
return Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
},
@ -81,19 +75,17 @@ HUD_SERVICE.prototype =
*
* @see devtools/framework/target.js for details about targets.
*
* @param object aTarget
* @param object target
* The target that the web console will connect to.
* @param nsIDOMWindow aIframeWindow
* @param nsIDOMWindow iframeWindow
* The window where the web console UI is already loaded.
* @param nsIDOMWindow aChromeWindow
* @param nsIDOMWindow chromeWindow
* The window of the web console owner.
* @return object
* A promise object for the opening of the new WebConsole instance.
*/
openWebConsole:
function HS_openWebConsole(aTarget, aIframeWindow, aChromeWindow)
{
let hud = new WebConsole(aTarget, aIframeWindow, aChromeWindow);
openWebConsole(target, iframeWindow, chromeWindow) {
let hud = new WebConsole(target, iframeWindow, chromeWindow);
this.consoles.set(hud.hudId, hud);
return hud.init();
},
@ -103,19 +95,17 @@ HUD_SERVICE.prototype =
*
* @see devtools/framework/target.js for details about targets.
*
* @param object aTarget
* @param object target
* The target that the browser console will connect to.
* @param nsIDOMWindow aIframeWindow
* @param nsIDOMWindow iframeWindow
* The window where the browser console UI is already loaded.
* @param nsIDOMWindow aChromeWindow
* @param nsIDOMWindow chromeWindow
* The window of the browser console owner.
* @return object
* A promise object for the opening of the new BrowserConsole instance.
*/
openBrowserConsole:
function HS_openBrowserConsole(aTarget, aIframeWindow, aChromeWindow)
{
let hud = new BrowserConsole(aTarget, aIframeWindow, aChromeWindow);
openBrowserConsole(target, iframeWindow, chromeWindow) {
let hud = new BrowserConsole(target, iframeWindow, chromeWindow);
this._browserConsoleID = hud.hudId;
this.consoles.set(hud.hudId, hud);
return hud.init();
@ -124,14 +114,13 @@ HUD_SERVICE.prototype =
/**
* Returns the Web Console object associated to a content window.
*
* @param nsIDOMWindow aContentWindow
* @param nsIDOMWindow contentWindow
* @returns object
*/
getHudByWindow: function HS_getHudByWindow(aContentWindow)
{
for (let [hudId, hud] of this.consoles) {
getHudByWindow(contentWindow) {
for (let [, hud] of this.consoles) {
let target = hud.target;
if (target && target.tab && target.window === aContentWindow) {
if (target && target.tab && target.window === contentWindow) {
return hud;
}
}
@ -141,12 +130,11 @@ HUD_SERVICE.prototype =
/**
* Returns the console instance for a given id.
*
* @param string aId
* @param string id
* @returns Object
*/
getHudReferenceById: function HS_getHudReferenceById(aId)
{
return this.consoles.get(aId);
getHudReferenceById(id) {
return this.consoles.get(id);
},
/**
@ -156,8 +144,7 @@ HUD_SERVICE.prototype =
* The WebConsole object or null if the active tab has no open Web
* Console.
*/
getOpenWebConsole: function HS_getOpenWebConsole()
{
getOpenWebConsole() {
let tab = this.currentContext().gBrowser.selectedTab;
if (!tab || !TargetFactory.isKnownTab(tab)) {
return null;
@ -171,25 +158,19 @@ HUD_SERVICE.prototype =
/**
* Toggle the Browser Console.
*/
toggleBrowserConsole: function HS_toggleBrowserConsole()
{
async toggleBrowserConsole() {
if (this._browserConsoleID) {
let hud = this.getHudReferenceById(this._browserConsoleID);
return hud.destroy();
}
if (this._browserConsoleDefer) {
return this._browserConsoleDefer.promise;
if (this._browserConsoleInitializing) {
return this._browserConsoleInitializing;
}
this._browserConsoleDefer = defer();
function connect()
{
let deferred = defer();
// Ensure that the root actor and the tab actors have been registered on the DebuggerServer,
// so that the Browser Console can retrieve the console actors.
async function connect() {
// Ensure that the root actor and the tab actors have been registered on the
// DebuggerServer, so that the Browser Console can retrieve the console actors.
// (See Bug 1416105 for rationale).
DebuggerServer.init();
DebuggerServer.registerActors({ root: true, tab: true });
@ -197,62 +178,60 @@ HUD_SERVICE.prototype =
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe());
return client.connect()
.then(() => client.getProcess())
.then(aResponse => {
// Use a TabActor in order to ensure calling `attach` to the ChromeActor
return { form: aResponse.form, client, chrome: true, isTabActor: true };
});
await client.connect();
let response = await client.getProcess();
return { form: response.form, client, chrome: true, isTabActor: true };
}
let target;
function getTarget(aConnection)
{
return TargetFactory.forRemoteTab(aConnection);
}
function openWindow(aTarget)
{
target = aTarget;
return new Promise(resolve => {
let browserConsoleURL = Tools.webConsole.browserConsoleURL;
let win = Services.ww.openWindow(null, browserConsoleURL, "_blank",
BROWSER_CONSOLE_WINDOW_FEATURES, null);
win.addEventListener("DOMContentLoaded", () => {
win.document.title = l10n.getStr("browserConsole.title");
if (browserConsoleURL === Tools.webConsole.oldWebConsoleURL) {
resolve({iframeWindow: win, chromeWindow: win});
} else {
win.document.querySelector("iframe").addEventListener("DOMContentLoaded", (e) => {
resolve({iframeWindow: e.target.defaultView, chromeWindow: win});
}, { once: true });
}
}, {once: true});
async function openWindow(t) {
let browserConsoleURL = Tools.webConsole.browserConsoleURL;
let win = Services.ww.openWindow(null, browserConsoleURL, "_blank",
BC_WINDOW_FEATURES, null);
await new Promise(resolve => {
win.addEventListener("DOMContentLoaded", resolve, {once: true});
});
}
connect().then(getTarget).then(openWindow).then(({iframeWindow, chromeWindow}) => {
return this.openBrowserConsole(target, iframeWindow, chromeWindow)
.then((aBrowserConsole) => {
this._browserConsoleDefer.resolve(aBrowserConsole);
this._browserConsoleDefer = null;
});
}, console.error.bind(console));
return this._browserConsoleDefer.promise;
win.document.title = l10n.getStr("browserConsole.title");
if (browserConsoleURL === Tools.webConsole.oldWebConsoleURL) {
return {iframeWindow: win, chromeWindow: win};
}
let iframe = win.document.querySelector("iframe");
await new Promise(resolve => {
iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
});
return {iframeWindow: iframe.contentWindow, chromeWindow: win};
}
// Temporarily cache the async startup sequence so that if toggleBrowserConsole
// gets called again we can return this console instead of opening another one.
this._browserConsoleInitializing = (async () => {
let connection = await connect();
let target = await TargetFactory.forRemoteTab(connection);
let {iframeWindow, chromeWindow} = await openWindow(target);
let browserConsole =
await this.openBrowserConsole(target, iframeWindow, chromeWindow);
return browserConsole;
})();
let browserConsole = await this._browserConsoleInitializing;
this._browserConsoleInitializing = null;
return browserConsole;
},
/**
* Opens or focuses the Browser Console.
*/
openBrowserConsoleOrFocus: function HS_openBrowserConsoleOrFocus()
{
openBrowserConsoleOrFocus() {
let hud = this.getBrowserConsole();
if (hud) {
hud.iframeWindow.focus();
return promise.resolve(hud);
}
else {
return this.toggleBrowserConsole();
return Promise.resolve(hud);
}
return this.toggleBrowserConsole();
},
/**
@ -262,13 +241,11 @@ HUD_SERVICE.prototype =
* A BrowserConsole instance or null if the Browser Console is not
* open.
*/
getBrowserConsole: function HS_getBrowserConsole()
{
getBrowserConsole() {
return this.getHudReferenceById(this._browserConsoleID);
},
};
/**
* A WebConsole instance is an interactive console initialized *per target*
* that displays console log data as well as provides an interactive terminal to
@ -279,25 +256,24 @@ HUD_SERVICE.prototype =
* UI and features.
*
* @constructor
* @param object aTarget
* @param object target
* The target that the web console will connect to.
* @param nsIDOMWindow aIframeWindow
* @param nsIDOMWindow iframeWindow
* The window where the web console UI is already loaded.
* @param nsIDOMWindow aChromeWindow
* @param nsIDOMWindow chromeWindow
* The window of the web console owner.
*/
function WebConsole(aTarget, aIframeWindow, aChromeWindow)
{
this.iframeWindow = aIframeWindow;
this.chromeWindow = aChromeWindow;
function WebConsole(target, iframeWindow, chromeWindow) {
this.iframeWindow = iframeWindow;
this.chromeWindow = chromeWindow;
this.hudId = "hud_" + ++gHudId;
this.target = aTarget;
this.target = target;
this.browserWindow = this.chromeWindow.top;
let element = this.browserWindow.document.documentElement;
if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
this.browserWindow = HUDService.currentContext();
}
if (aIframeWindow.location.href === Tools.webConsole.newWebConsoleURL) {
if (iframeWindow.location.href === Tools.webConsole.newWebConsoleURL) {
this.ui = new NewWebConsoleFrame(this);
} else {
this.ui = new WebConsoleFrame(this);
@ -320,8 +296,7 @@ WebConsole.prototype = {
*
* @type function
*/
get lastFinishedRequestCallback()
{
get lastFinishedRequestCallback() {
return HUDService.lastFinishedRequest.callback;
},
@ -333,8 +308,7 @@ WebConsole.prototype = {
* hosts the utilities there.
* @type nsIDOMWindow
*/
get chromeUtilsWindow()
{
get chromeUtilsWindow() {
if (this.browserWindow) {
return this.browserWindow;
}
@ -345,8 +319,7 @@ WebConsole.prototype = {
* Getter for the xul:popupset that holds any popups we open.
* @type nsIDOMElement
*/
get mainPopupSet()
{
get mainPopupSet() {
return this.chromeUtilsWindow.document.getElementById("mainPopupSet");
},
@ -354,13 +327,11 @@ WebConsole.prototype = {
* Getter for the output element that holds messages we display.
* @type nsIDOMElement
*/
get outputNode()
{
get outputNode() {
return this.ui ? this.ui.outputNode : null;
},
get gViewSourceUtils()
{
get gViewSourceUtils() {
return this.chromeUtilsWindow.gViewSourceUtils;
},
@ -370,30 +341,16 @@ WebConsole.prototype = {
* @return object
* A promise for the initialization.
*/
init: function WC_init()
{
init() {
return this.ui.init().then(() => this);
},
/**
* Retrieve the Web Console panel title.
*
* @return string
* The Web Console panel title.
*/
getPanelTitle: function WC_getPanelTitle()
{
let url = this.ui ? this.ui.contentLocation : "";
return l10n.getFormatStr("webConsoleWindowTitleAndURL", [url]);
},
/**
* The JSTerm object that manages the console's input.
* @see webconsole.js::JSTerm
* @type object
*/
get jsterm()
{
get jsterm() {
return this.ui ? this.ui.jsterm : null;
},
@ -401,8 +358,7 @@ WebConsole.prototype = {
* The clear output button handler.
* @private
*/
_onClearButton: function WC__onClearButton()
{
_onClearButton() {
if (this.target.isLocalTab) {
gDevToolsBrowser.getDeveloperToolbar(this.browserWindow)
.resetErrorsCount(this.target.tab);
@ -413,46 +369,45 @@ WebConsole.prototype = {
* Alias for the WebConsoleFrame.setFilterState() method.
* @see webconsole.js::WebConsoleFrame.setFilterState()
*/
setFilterState: function WC_setFilterState()
{
setFilterState() {
this.ui && this.ui.setFilterState.apply(this.ui, arguments);
},
/**
* Open a link in a new tab.
*
* @param string aLink
* @param string link
* The URL you want to open in a new tab.
*/
openLink: function WC_openLink(aLink, e)
{
openLink(link, e) {
let isOSX = Services.appinfo.OS == "Darwin";
if (e != null && (e.button === 1 || (e.button === 0 && (isOSX ? e.metaKey : e.ctrlKey)))) {
this.chromeUtilsWindow.openUILinkIn(aLink, "tabshifted");
if (e && (e.button === 1 || (e.button === 0 && (isOSX ? e.metaKey : e.ctrlKey)))) {
this.chromeUtilsWindow.openUILinkIn(link, "tabshifted");
} else {
this.chromeUtilsWindow.openUILinkIn(aLink, "tab");
this.chromeUtilsWindow.openUILinkIn(link, "tab");
}
},
/**
* Open a link in Firefox's view source.
*
* @param string aSourceURL
* @param string sourceURL
* The URL of the file.
* @param integer aSourceLine
* @param integer sourceLine
* The line number which should be highlighted.
*/
viewSource: function WC_viewSource(aSourceURL, aSourceLine) {
viewSource(sourceURL, sourceLine) {
// Attempt to access view source via a browser first, which may display it in
// a tab, if enabled.
let browserWin = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
if (browserWin && browserWin.BrowserViewSourceOfDocument) {
return browserWin.BrowserViewSourceOfDocument({
URL: aSourceURL,
lineNumber: aSourceLine
URL: sourceURL,
lineNumber: sourceLine
});
}
this.gViewSourceUtils.viewSource(aSourceURL, null, this.iframeWindow.document, aSourceLine || 0);
return this.gViewSourceUtils.viewSource(
sourceURL, null, this.iframeWindow.document, sourceLine || 0);
},
/**
@ -462,18 +417,18 @@ WebConsole.prototype = {
*
* Manually handle the case where toolbox does not exist (Browser Console).
*
* @param string aSourceURL
* @param string sourceURL
* The URL of the file.
* @param integer aSourceLine
* @param integer sourceLine
* The line number which you want to place the caret.
*/
viewSourceInStyleEditor: function WC_viewSourceInStyleEditor(aSourceURL, aSourceLine) {
viewSourceInStyleEditor(sourceURL, sourceLine) {
let toolbox = gDevTools.getToolbox(this.target);
if (!toolbox) {
this.viewSource(aSourceURL, aSourceLine);
this.viewSource(sourceURL, sourceLine);
return;
}
toolbox.viewSourceInStyleEditor(aSourceURL, aSourceLine);
toolbox.viewSourceInStyleEditor(sourceURL, sourceLine);
},
/**
@ -483,18 +438,18 @@ WebConsole.prototype = {
*
* Manually handle the case where toolbox does not exist (Browser Console).
*
* @param string aSourceURL
* @param string sourceURL
* The URL of the file.
* @param integer aSourceLine
* @param integer sourceLine
* The line number which you want to place the caret.
*/
viewSourceInDebugger: function WC_viewSourceInDebugger(aSourceURL, aSourceLine) {
viewSourceInDebugger(sourceURL, sourceLine) {
let toolbox = gDevTools.getToolbox(this.target);
if (!toolbox) {
this.viewSource(aSourceURL, aSourceLine);
this.viewSource(sourceURL, sourceLine);
return;
}
toolbox.viewSourceInDebugger(aSourceURL, aSourceLine).then(() => {
toolbox.viewSourceInDebugger(sourceURL, sourceLine).then(() => {
this.ui.emit("source-in-debugger-opened");
});
},
@ -503,11 +458,11 @@ WebConsole.prototype = {
* Tries to open a JavaScript file related to the web page for the web console
* instance in the corresponding Scratchpad.
*
* @param string aSourceURL
* @param string sourceURL
* The URL of the file which corresponds to a Scratchpad id.
*/
viewSourceInScratchpad: function WC_viewSourceInScratchpad(aSourceURL, aSourceLine) {
viewSource.viewSourceInScratchpad(aSourceURL, aSourceLine);
viewSourceInScratchpad(sourceURL, sourceLine) {
viewSource.viewSourceInScratchpad(sourceURL, sourceLine);
},
/**
@ -523,8 +478,7 @@ WebConsole.prototype = {
* If the debugger is not open or if it's not paused, then |null| is
* returned.
*/
getDebuggerFrames: function WC_getDebuggerFrames()
{
getDebuggerFrames() {
let toolbox = gDevTools.getToolbox(this.target);
if (!toolbox) {
return null;
@ -549,8 +503,7 @@ WebConsole.prototype = {
* If the inspector was never opened, or no node was ever selected,
* then |null| is returned.
*/
getInspectorSelection: function WC_getInspectorSelection()
{
getInspectorSelection() {
let toolbox = gDevTools.getToolbox(this.target);
if (!toolbox) {
return null;
@ -569,48 +522,40 @@ WebConsole.prototype = {
* @return object
* A promise object that is resolved once the Web Console is closed.
*/
destroy: function WC_destroy()
{
async destroy() {
if (this._destroyer) {
return this._destroyer.promise;
return this._destroyer;
}
HUDService.consoles.delete(this.hudId);
this._destroyer = (async () => {
HUDService.consoles.delete(this.hudId);
this._destroyer = defer();
// The document may already be removed
if (this.chromeUtilsWindow && this.mainPopupSet) {
let popupset = this.mainPopupSet;
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
for (let panel of panels) {
panel.hidePopup();
// The document may already be removed
if (this.chromeUtilsWindow && this.mainPopupSet) {
let popupset = this.mainPopupSet;
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
for (let panel of panels) {
panel.hidePopup();
}
}
if (this.ui) {
await this.ui.destroy();
}
}
let onDestroy = Task.async(function* () {
if (!this._browserConsole) {
try {
yield this.target.activeTab.focus();
}
catch (ex) {
await this.target.activeTab.focus();
} catch (ex) {
// Tab focus can fail if the tab or target is closed.
}
}
let id = WebConsoleUtils.supportsString(this.hudId);
let id = Utils.supportsString(this.hudId);
Services.obs.notifyObservers(id, "web-console-destroyed");
this._destroyer.resolve(null);
}.bind(this));
})();
if (this.ui) {
this.ui.destroy().then(onDestroy);
}
else {
onDestroy();
}
return this._destroyer.promise;
return this._destroyer;
},
};
@ -624,23 +569,22 @@ WebConsole.prototype = {
* UI and features.
*
* @constructor
* @param object aTarget
* @param object target
* The target that the browser console will connect to.
* @param nsIDOMWindow aIframeWindow
* @param nsIDOMWindow iframeWindow
* The window where the browser console UI is already loaded.
* @param nsIDOMWindow aChromeWindow
* @param nsIDOMWindow chromeWindow
* The window of the browser console owner.
*/
function BrowserConsole()
{
function BrowserConsole() {
WebConsole.apply(this, arguments);
this._telemetry = new Telemetry();
}
BrowserConsole.prototype = extend(WebConsole.prototype, {
_browserConsole: true,
_bc_init: null,
_bc_destroyer: null,
_bcInit: null,
_bcDestroyer: null,
$init: WebConsole.prototype.init,
@ -650,27 +594,24 @@ BrowserConsole.prototype = extend(WebConsole.prototype, {
* @return object
* A promise for the initialization.
*/
init: function BC_init()
{
if (this._bc_init) {
return this._bc_init;
init() {
if (this._bcInit) {
return this._bcInit;
}
// Only add the shutdown observer if we've opened a Browser Console window.
ShutdownObserver.init();
this.ui._filterPrefsPrefix = BROWSER_CONSOLE_FILTER_PREFS_PREFIX;
this.ui._filterPrefsPrefix = BC_FILTER_PREFS_PREFIX;
let window = this.iframeWindow;
// Make sure that the closing of the Browser Console window destroys this
// instance.
let onClose = () => {
window.removeEventListener("unload", onClose);
window.addEventListener("unload", () => {
window.removeEventListener("focus", onFocus);
this.destroy();
};
window.addEventListener("unload", onClose);
}, {once: true});
this._telemetry.toolOpened("browserconsole");
@ -680,8 +621,8 @@ BrowserConsole.prototype = extend(WebConsole.prototype, {
let onFocus = () => showDoorhanger({ window, type: "deveditionpromo" });
window.addEventListener("focus", onFocus);
this._bc_init = this.$init();
return this._bc_init;
this._bcInit = this.$init();
return this._bcInit;
},
$destroy: WebConsole.prototype.destroy,
@ -692,25 +633,20 @@ BrowserConsole.prototype = extend(WebConsole.prototype, {
* @return object
* A promise object that is resolved once the Browser Console is closed.
*/
destroy: function BC_destroy()
{
if (this._bc_destroyer) {
return this._bc_destroyer.promise;
destroy() {
if (this._bcDestroyer) {
return this._bcDestroyer;
}
this._telemetry.toolClosed("browserconsole");
this._bcDestroyer = (async () => {
this._telemetry.toolClosed("browserconsole");
await this.$destroy();
await this.target.client.close();
HUDService._browserConsoleID = null;
this.chromeWindow.close();
})();
this._bc_destroyer = defer();
let chromeWindow = this.chromeWindow;
this.$destroy().then(() =>
this.target.client.close().then(() => {
HUDService._browserConsoleID = null;
chromeWindow.close();
this._bc_destroyer.resolve(null);
}));
return this._bc_destroyer.promise;
return this._bcDestroyer;
},
});

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

@ -1040,6 +1040,7 @@ AudioCallbackDriver::StateCallback(cubeb_state aState)
LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) {
mShouldFallbackIfError = false;
MonitorAutoLock lock(GraphImpl()->GetMonitor());
RemoveCallback();
FallbackToSystemClockDriver();

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

@ -35,6 +35,12 @@ static mozilla::LazyLogModule gU2FLog("u2fmanager");
NS_NAMED_LITERAL_STRING(kFinishEnrollment, "navigator.id.finishEnrollment");
NS_NAMED_LITERAL_STRING(kGetAssertion, "navigator.id.getAssertion");
// Bug #1436078 - Permit Google Accounts. Remove in Bug #1436085 in Jan 2023.
NS_NAMED_LITERAL_STRING(kGoogleAccountsAppId1,
"https://www.gstatic.com/securitykey/origins.json");
NS_NAMED_LITERAL_STRING(kGoogleAccountsAppId2,
"https://www.gstatic.com/securitykey/a/google.com/origins.json");
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(U2F)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
@ -122,9 +128,15 @@ RegisteredKeysToScopedCredentialList(const nsAString& aAppId,
}
}
enum class U2FOperation
{
Register,
Sign
};
static ErrorCode
EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
/* in/out */ nsString& aAppId)
const U2FOperation& aOp, /* in/out */ nsString& aAppId)
{
// Facet is the specification's way of referring to the web origin.
nsAutoCString facetString = NS_ConvertUTF16toUTF8(aOrigin);
@ -208,6 +220,15 @@ EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
return ErrorCode::OK;
}
// Bug #1436078 - Permit Google Accounts. Remove in Bug #1436085 in Jan 2023.
if (aOp == U2FOperation::Sign && lowestFacetHost.EqualsLiteral("google.com") &&
(aAppId.Equals(kGoogleAccountsAppId1) ||
aAppId.Equals(kGoogleAccountsAppId2))) {
MOZ_LOG(gU2FLog, LogLevel::Debug,
("U2F permitted for Google Accounts via Bug #1436085"));
return ErrorCode::OK;
}
return ErrorCode::BAD_REQUEST;
}
@ -356,7 +377,8 @@ U2F::Register(const nsAString& aAppId,
// Evaluate the AppID
nsString adjustedAppId;
adjustedAppId.Assign(aAppId);
ErrorCode appIdResult = EvaluateAppID(mParent, mOrigin, adjustedAppId);
ErrorCode appIdResult = EvaluateAppID(mParent, mOrigin, U2FOperation::Register,
adjustedAppId);
if (appIdResult != ErrorCode::OK) {
RegisterResponse response;
response.mErrorCode.Construct(static_cast<uint32_t>(appIdResult));
@ -518,7 +540,8 @@ U2F::Sign(const nsAString& aAppId,
// Evaluate the AppID
nsString adjustedAppId;
adjustedAppId.Assign(aAppId);
ErrorCode appIdResult = EvaluateAppID(mParent, mOrigin, adjustedAppId);
ErrorCode appIdResult = EvaluateAppID(mParent, mOrigin, U2FOperation::Sign,
adjustedAppId);
if (appIdResult != ErrorCode::OK) {
SignResponse response;
response.mErrorCode.Construct(static_cast<uint32_t>(appIdResult));

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

@ -195,7 +195,7 @@ WebAuthnManager::~WebAuthnManager()
}
already_AddRefed<Promise>
WebAuthnManager::MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
WebAuthnManager::MakeCredential(const PublicKeyCredentialCreationOptions& aOptions,
const Optional<OwningNonNull<AbortSignal>>& aSignal)
{
MOZ_ASSERT(NS_IsMainThread());

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

@ -103,7 +103,7 @@ public:
{ }
already_AddRefed<Promise>
MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
MakeCredential(const PublicKeyCredentialCreationOptions& aOptions,
const Optional<OwningNonNull<AbortSignal>>& aSignal);
already_AddRefed<Promise>

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

@ -29,6 +29,6 @@ dictionary CredentialRequestOptions {
};
dictionary CredentialCreationOptions {
MakePublicKeyCredentialOptions publicKey;
PublicKeyCredentialCreationOptions publicKey;
AbortSignal signal;
};

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

@ -44,7 +44,7 @@ dictionary PublicKeyCredentialParameters {
required COSEAlgorithmIdentifier alg;
};
dictionary MakePublicKeyCredentialOptions {
dictionary PublicKeyCredentialCreationOptions {
required PublicKeyCredentialRpEntity rp;
required PublicKeyCredentialUserEntity user;

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

@ -20,6 +20,80 @@ class JSTracer;
class PseudoStack;
// This file defines the classes PseudoStack and ProfileEntry.
// The PseudoStack manages an array of ProfileEntries.
// Usage:
//
// PseudoStack* pseudoStack = ...;
//
// // For CPP stack frames:
// pseudoStack->pushCppFrame(...);
// // Execute some code. When finished, pop the entry:
// pseudoStack->pop();
//
// // For JS stack frames:
// pseudoStack->pushJSFrame(...);
// // Execute some code. When finished, pop the entry:
// pseudoStack->pop();
//
//
// Concurrency considerations
//
// A thread's pseudo stack (and the entries inside it) is only modified by
// that thread. However, the pseudo stack can be *read* by a different thread,
// the sampler thread: Whenever the profiler wants to sample a given thread A,
// the following happens:
// (1) Thread A is suspended.
// (2) The sampler thread (thread S) reads the PseudoStack of thread A,
// including all ProfileEntries that are currently in that stack
// (pseudoStack->entries[0..pseudoStack->stackSize()]).
// (3) Thread A is resumed.
//
// Thread suspension is achieved using platform-specific APIs; refer to each
// platform's Sampler::SuspendAndSampleAndResumeThread implementation in
// platform-*.cpp for details.
//
// When the thread is suspended, the values in pseudoStack->stackPointer and in
// the entry range pseudoStack->entries[0..pseudoStack->stackPointer] need to
// be in a consistent state, so that thread A does not read partially-
// constructed profile entries. More specifically, we have two requirements:
// (1) When adding a new entry at the top of the stack, its ProfileEntry data
// needs to be put in place *before* the stackPointer is incremented, and
// the compiler + CPU need to know that this order matters.
// (2) When popping an entry from the stack and then preparing the
// ProfileEntry data for the next frame that is about to be pushed, the
// decrement of the stackPointer in pop() needs to happen *before* the
// ProfileEntry for the new frame is being popuplated, and the compiler +
// CPU need to know that this order matters.
//
// We can express the relevance of these orderings in multiple ways.
// Option A is to make stackPointer an atomic with SequentiallyConsistent
// memory ordering. This would ensure that no writes in thread A would be
// reordered across any writes to stackPointer, which satisfies requirements
// (1) and (2) at the same time. Option A is the simplest.
// Option B is to use ReleaseAcquire memory ordering both for writes to
// stackPointer *and* for writes to ProfileEntry fields. Release-stores ensure
// that all writes that happened *before this write in program order* are not
// reordered to happen after this write. ReleaseAcquire ordering places no
// requirements on the ordering of writes that happen *after* this write in
// program order.
// Using release-stores for writes to stackPointer expresses requirement (1),
// and using release-stores for writes to the ProfileEntry fields expresses
// requirement (2).
//
// Option B is more complicated than option A, but has much better performance
// on x86/64: In a microbenchmark run on a Macbook Pro from 2017, switching
// from option A to option B reduced the overhead of pushing+popping a
// ProfileEntry by 10 nanoseconds.
// On x86/64, release-stores require no explicit hardware barriers or lock
// instructions.
// On ARM/64, option B may be slower than option A, because the compiler will
// generate hardware barriers for every single release-store instead of just
// for the writes to stackPointer. However, the actual performance impact of
// this has not yet been measured on ARM, so we're currently using option B
// everywhere. This is something that we may want to change in the future once
// we've done measurements.
namespace js {
// A call stack can be specified to the JS engine such that all JS entry/exits
@ -31,24 +105,38 @@ class ProfileEntry
{
// A ProfileEntry represents either a C++ profile entry or a JS one.
// WARNING WARNING WARNING
//
// All the fields below are Atomic<...,ReleaseAcquire>. This is needed so
// that writes to these fields are release-writes, which ensures that
// earlier writes in this thread don't get reordered after the writes to
// these fields. In particular, the decrement of the stack pointer in
// PseudoStack::pop() is a write that *must* happen before the values in
// this ProfileEntry are changed. Otherwise, the sampler thread might see
// an inconsistent state where the stack pointer still points to a
// ProfileEntry which has already been popped off the stack and whose
// fields have now been partially repopulated with new values.
// See the "Concurrency considerations" paragraph at the top of this file
// for more details.
// Descriptive label for this entry. Must be a static string! Can be an
// empty string, but not a null pointer.
const char* label_;
mozilla::Atomic<const char*, mozilla::ReleaseAcquire> label_;
// An additional descriptive string of this entry which is combined with
// |label_| in profiler output. Need not be (and usually isn't) static. Can
// be null.
const char* dynamicString_;
mozilla::Atomic<const char*, mozilla::ReleaseAcquire> dynamicString_;
// Stack pointer for non-JS entries, the script pointer otherwise.
void* spOrScript;
mozilla::Atomic<void*, mozilla::ReleaseAcquire> spOrScript;
// Line number for non-JS entries, the bytecode offset otherwise.
int32_t lineOrPcOffset;
mozilla::Atomic<int32_t, mozilla::ReleaseAcquire> lineOrPcOffset;
// Bits 0..1 hold the Kind. Bits 2..3 are unused. Bits 4..12 hold the
// Bits 0...1 hold the Kind. Bits 2...3 are unused. Bits 4...12 hold the
// Category.
uint32_t kindAndCategory_;
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> kindAndCategory_;
static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc);
@ -160,7 +248,8 @@ class ProfileEntry
// Note that the pointer returned might be invalid.
JSScript* rawScript() const {
MOZ_ASSERT(isJs());
return (JSScript*)spOrScript;
void* script = spOrScript;
return static_cast<JSScript*>(script);
}
// We can't know the layout of JSScript, so look in vm/GeckoProfiler.cpp.
@ -198,8 +287,9 @@ RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*));
//
// - When pushing a new entry, we increment the stack pointer -- making the new
// entry visible to the sampler thread -- only after the new entry has been
// fully written. The stack pointer is Atomic<> (with SequentiallyConsistent
// semantics) to ensure the incrementing is not reordered before the writes.
// fully written. The stack pointer is Atomic<uint32_t,ReleaseAcquire>, so
// the increment is a release-store, which ensures that this store is not
// reordered before the writes of the entry.
//
// - When popping an old entry, the only operation is the decrementing of the
// stack pointer, which is obviously atomic.
@ -225,8 +315,15 @@ class PseudoStack
}
// This must happen at the end! The compiler will not reorder this
// update because stackPointer is Atomic.
stackPointer++;
// update because stackPointer is Atomic<..., ReleaseAcquire>, so any
// the writes above will not be reordered below the stackPointer store.
// Do the read and the write as two separate statements, in order to
// make it clear that we don't need an atomic increment, which would be
// more expensive on x86 than the separate operations done here.
// This thread is the only one that ever changes the value of
// stackPointer.
uint32_t oldStackPointer = stackPointer;
stackPointer = oldStackPointer + 1;
}
void pushJsFrame(const char* label, const char* dynamicString, JSScript* script,
@ -236,13 +333,27 @@ class PseudoStack
}
// This must happen at the end! The compiler will not reorder this
// update because stackPointer is Atomic.
stackPointer++;
// update because stackPointer is Atomic<..., ReleaseAcquire>, which
// makes this assignment a release-store, so the writes above will not
// be reordered to occur after the stackPointer store.
// Do the read and the write as two separate statements, in order to
// make it clear that we don't need an atomic increment, which would be
// more expensive on x86 than the separate operations done here.
// This thread is the only one that ever changes the value of
// stackPointer.
uint32_t oldStackPointer = stackPointer;
stackPointer = oldStackPointer + 1;
}
void pop() {
MOZ_ASSERT(stackPointer > 0);
stackPointer--;
// Do the read and the write as two separate statements, in order to
// make it clear that we don't need an atomic decrement, which would be
// more expensive on x86 than the separate operations done here.
// This thread is the only one that ever changes the value of
// stackPointer.
uint32_t oldStackPointer = stackPointer;
stackPointer = oldStackPointer - 1;
}
uint32_t stackSize() const { return std::min(uint32_t(stackPointer), uint32_t(MaxEntries)); }
@ -262,7 +373,13 @@ class PseudoStack
// determine the number of valid samples in entries. When this is less
// than MaxEntries, it refers to the first free entry past the top of the
// in-use stack (i.e. entries[stackPointer - 1] is the top stack entry).
mozilla::Atomic<uint32_t, mozilla::SequentiallyConsistent> stackPointer;
//
// WARNING WARNING WARNING
//
// This is an atomic variable that uses ReleaseAcquire memory ordering.
// See the "Concurrency considerations" paragraph at the top of this file
// for more details.
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> stackPointer;
};
#endif /* js_ProfilingStack_h */

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

@ -427,7 +427,7 @@ JS_PUBLIC_API(JSScript*)
ProfileEntry::script() const
{
MOZ_ASSERT(isJs());
auto script = reinterpret_cast<JSScript*>(spOrScript);
auto script = reinterpret_cast<JSScript*>(spOrScript.operator void*());
if (!script)
return nullptr;

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

@ -80,7 +80,7 @@ struct DisplayItemClipChain {
DisplayItemClip mClip;
const ActiveScrolledRoot* mASR;
RefPtr<const DisplayItemClipChain> mParent;
mutable uint32_t mRefCount = 0;
uint32_t mRefCount = 0;
#ifdef DEBUG
bool mOnStack;
#endif

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

@ -52,13 +52,10 @@ public:
}
class AutoSaveRestore;
friend class AutoSaveRestore;
class AutoClipContainingBlockDescendantsToContentBox;
friend class AutoClipContainingBlockDescendantsToContentBox;
class AutoClipMultiple;
friend class AutoClipMultiple;
enum {
ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01

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

@ -1024,8 +1024,6 @@ public:
* set mCurrentFrame and related state. Also temporarily sets mDirtyRect.
* aDirtyRect is relative to aForChild.
*/
class AutoBuildingDisplayList;
friend class AutoBuildingDisplayList;
class AutoBuildingDisplayList {
public:
AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
@ -1117,8 +1115,6 @@ public:
/**
* A helper class to temporarily set the value of mInTransform.
*/
class AutoInTransformSetter;
friend class AutoInTransformSetter;
class AutoInTransformSetter {
public:
AutoInTransformSetter(nsDisplayListBuilder* aBuilder, bool aInTransform)
@ -1136,8 +1132,6 @@ public:
/**
* A helper class to temporarily set the value of mFilterASR.
*/
class AutoFilterASRSetter;
friend class AutoFilterASRSetter;
class AutoFilterASRSetter {
public:
AutoFilterASRSetter(nsDisplayListBuilder* aBuilder, bool aUsingFilter)
@ -1155,8 +1149,6 @@ public:
const ActiveScrolledRoot* mOldValue;
};
class AutoSaveRestorePerspectiveIndex;
friend class AutoSaveRestorePerspectiveIndex;
class AutoSaveRestorePerspectiveIndex {
public:
AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
@ -1184,8 +1176,6 @@ public:
/**
* A helper class to temporarily set the value of mCurrentScrollParentId.
*/
class AutoCurrentScrollParentIdSetter;
friend class AutoCurrentScrollParentIdSetter;
class AutoCurrentScrollParentIdSetter {
public:
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId)
@ -1230,8 +1220,6 @@ public:
* Used to update the current active scrolled root on the display list
* builder, and to create new active scrolled roots.
*/
class AutoCurrentActiveScrolledRootSetter;
friend class AutoCurrentActiveScrolledRootSetter;
class AutoCurrentActiveScrolledRootSetter {
public:
explicit AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder* aBuilder)
@ -1296,8 +1284,6 @@ public:
* The rule is: all child items of the container item need to have
* clipped bounds with respect to the container ASR.
*/
class AutoContainerASRTracker;
friend class AutoContainerASRTracker;
class AutoContainerASRTracker {
public:
explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder)
@ -1329,8 +1315,6 @@ public:
* A helper class to temporarily set the value of mCurrentScrollbarTarget
* and mCurrentScrollbarFlags.
*/
class AutoCurrentScrollbarInfoSetter;
friend class AutoCurrentScrollbarInfoSetter;
class AutoCurrentScrollbarInfoSetter {
public:
AutoCurrentScrollbarInfoSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
@ -1361,8 +1345,6 @@ public:
* context root. The 3D context root computes it's bounds from
* these transformed bounds.
*/
class AutoAccumulateTransform;
friend class AutoAccumulateTransform;
class AutoAccumulateTransform {
public:
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
@ -1402,8 +1384,6 @@ public:
* transform on the path, but it is not empty for the accumulated
* transform.
*/
class AutoAccumulateRect;
friend class AutoAccumulateRect;
class AutoAccumulateRect {
public:
explicit AutoAccumulateRect(nsDisplayListBuilder* aBuilder)
@ -1686,8 +1666,6 @@ public:
* the value of mPreserves3DCtx before returning back to the parent.
* This class do it for the users.
*/
class AutoPreserves3DContext;
friend class AutoPreserves3DContext;
class AutoPreserves3DContext {
public:
explicit AutoPreserves3DContext(nsDisplayListBuilder* aBuilder)

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

@ -142,6 +142,7 @@ for (let [key, val] of Object.entries({
startAfter: undefined,
suiteStarted: false,
manageSuite: false,
// The enabled-state of the test-plugins, stored so they can be reset later
testPluginEnabledStates: null,

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

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["ReadTopManifest"];
this.EXPORTED_SYMBOLS = ["ReadTopManifest", "CreateUrls"];
var CC = Components.classes;
const CI = Components.interfaces;
@ -296,25 +296,15 @@ function ReadManifest(aURL, aFilter)
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
ReadManifest(incURI, aFilter);
}
} else if (items[0] == TYPE_LOAD) {
} else if (items[0] == TYPE_LOAD || items[0] == TYPE_SCRIPT) {
if (items.length != 2)
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load";
if (expected_status != EXPECTED_PASS &&
expected_status != EXPECTED_DEATH)
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0];
if (items[0] == TYPE_LOAD && expected_status != EXPECTED_PASS && expected_status != EXPECTED_DEATH)
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect known failure type for load test";
var [testURI] = runHttp
? ServeFiles(principal, httpDepth,
listURL, [items[1]])
: [g.ioService.newURI(items[1], null, listURL)];
var prettyPath = runHttp
? g.ioService.newURI(items[1], null, listURL).spec
: testURI.spec;
secMan.checkLoadURIWithPrincipal(principal, testURI,
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
AddTestItem({ type: TYPE_LOAD,
expected: expected_status,
manifest: aURL.spec,
allowSilentFail: allow_silent_fail,
prettyPath: prettyPath,
minAsserts: minAsserts,
maxAsserts: maxAsserts,
needsFocus: needs_focus,
@ -325,36 +315,9 @@ function ReadManifest(aURL, aFilter)
fuzzyMaxDelta: fuzzy_delta.max,
fuzzyMinPixels: fuzzy_pixels.min,
fuzzyMaxPixels: fuzzy_pixels.max,
url1: testURI,
url2: null,
chaosMode: chaosMode }, aFilter);
} else if (items[0] == TYPE_SCRIPT) {
if (items.length != 2)
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script";
var [testURI] = runHttp
? ServeFiles(principal, httpDepth,
listURL, [items[1]])
: [g.ioService.newURI(items[1], null, listURL)];
var prettyPath = runHttp
? g.ioService.newURI(items[1], null, listURL).spec
: testURI.spec;
secMan.checkLoadURIWithPrincipal(principal, testURI,
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
AddTestItem({ type: TYPE_SCRIPT,
expected: expected_status,
allowSilentFail: allow_silent_fail,
prettyPath: prettyPath,
minAsserts: minAsserts,
maxAsserts: maxAsserts,
needsFocus: needs_focus,
slow: slow,
prefSettings1: testPrefSettings,
prefSettings2: refPrefSettings,
fuzzyMinDelta: fuzzy_delta.min,
fuzzyMaxDelta: fuzzy_delta.max,
fuzzyMinPixels: fuzzy_pixels.min,
fuzzyMaxPixels: fuzzy_pixels.max,
url1: testURI,
runHttp: runHttp,
httpDepth: httpDepth,
url1: items[1],
url2: null,
chaosMode: chaosMode }, aFilter);
} else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL || items[0] == TYPE_PRINT) {
@ -367,22 +330,9 @@ function ReadManifest(aURL, aFilter)
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": minimum fuzz must be zero for tests of type " + items[0];
}
var [testURI, refURI] = runHttp
? ServeFiles(principal, httpDepth,
listURL, [items[1], items[2]])
: [g.ioService.newURI(items[1], null, listURL),
g.ioService.newURI(items[2], null, listURL)];
var prettyPath = runHttp
? g.ioService.newURI(items[1], null, listURL).spec
: testURI.spec;
secMan.checkLoadURIWithPrincipal(principal, testURI,
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
secMan.checkLoadURIWithPrincipal(principal, refURI,
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var type = items[0];
if (g.compareStyloToGecko || g.compareRetainedDisplayLists) {
type = TYPE_REFTEST_EQUAL;
refURI = testURI;
// We expect twice as many assertion failures when running in
// styloVsGecko mode because we run each test twice: once in
@ -402,8 +352,8 @@ function ReadManifest(aURL, aFilter)
AddTestItem({ type: type,
expected: expected_status,
manifest: aURL.spec,
allowSilentFail: allow_silent_fail,
prettyPath: prettyPath,
minAsserts: minAsserts,
maxAsserts: maxAsserts,
needsFocus: needs_focus,
@ -414,8 +364,10 @@ function ReadManifest(aURL, aFilter)
fuzzyMaxDelta: fuzzy_delta.max,
fuzzyMinPixels: fuzzy_pixels.min,
fuzzyMaxPixels: fuzzy_pixels.max,
url1: testURI,
url2: refURI,
runHttp: runHttp,
httpDepth: httpDepth,
url1: items[1],
url2: items[2],
chaosMode: chaosMode }, aFilter);
} else {
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0];
@ -560,12 +512,7 @@ sandbox.compareRetainedDisplayLists = g.compareRetainedDisplayLists;
sandbox.styloVsGecko = false;
#endif
// Printing via Skia PDF is only supported on Mac for now.
#ifdef XP_MACOSX && MOZ_ENABLE_SKIA_PDF
sandbox.skiaPdf = true;
#else
sandbox.skiaPdf = false;
#endif
#ifdef RELEASE_OR_BETA
sandbox.release_or_beta = true;
@ -692,7 +639,7 @@ function ExtractRange(matches, startIndex, defaultMin = 0) {
};
}
function ServeFiles(manifestPrincipal, depth, aURL, files) {
function ServeTestBase(aURL, depth) {
var listURL = aURL.QueryInterface(CI.nsIFileURL);
var directory = listURL.file.parent;
@ -717,33 +664,51 @@ function ServeFiles(manifestPrincipal, depth, aURL, files) {
// Give the testbase URI access to XUL and XBL
Services.perms.add(testbase, "allowXULXBL", Services.perms.ALLOW_ACTION);
return testbase;
}
function CreateUrls(test) {
let secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
.getService(CI.nsIScriptSecurityManager);
let manifestURL = g.ioService.newURI(test.manifest);
let principal = secMan.createCodebasePrincipal(manifestURL, {});
let testbase = manifestURL;
if (test.runHttp)
testbase = ServeTestBase(manifestURL, test.httpDepth)
function FileToURI(file)
{
// Only serve relative URIs via the HTTP server, not absolute
// ones like about:blank.
if (file === null)
return file;
var testURI = g.ioService.newURI(file, null, testbase);
// XXX necessary? manifestURL guaranteed to be file, others always HTTP
secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI,
secMan.checkLoadURIWithPrincipal(principal, testURI,
CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
return testURI;
}
return files.map(FileToURI);
let files = [test.url1, test.url2];
[test.url1, test.url2] = files.map(FileToURI);
if (test.url2 && g.compareStyloToGecko)
test.url2 = test.url1;
return test;
}
function AddTestItem(aTest, aFilter) {
if (!aFilter)
aFilter = [null, [], false];
var {url1, url2} = CreateUrls(Object.assign({}, aTest));
var globalFilter = aFilter[0];
var manifestFilter = aFilter[1];
var invertManifest = aFilter[2];
if ((globalFilter && !globalFilter.test(aTest.url1.spec)) ||
if ((globalFilter && !globalFilter.test(url1.spec)) ||
(manifestFilter &&
!(invertManifest ^ manifestFilter.test(aTest.url1.spec))))
!(invertManifest ^ manifestFilter.test(url1.spec))))
return;
if (g.focusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
!aTest.needsFocus)
@ -752,10 +717,9 @@ function AddTestItem(aTest, aFilter) {
aTest.needsFocus)
return;
if (aTest.url2 !== null)
aTest.identifier = [aTest.prettyPath, aTest.type, aTest.url2.spec];
if (url2 !== null)
aTest.identifier = [url1.spec, aTest.type, url2.spec];
else
aTest.identifier = aTest.prettyPath;
aTest.identifier = url1.spec;
g.urls.push(aTest);
}

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

@ -4,6 +4,7 @@
import json
import threading
from collections import defaultdict
from mozlog.formatters import TbplFormatter
from mozrunner.utils import get_stack_fixer_function
@ -129,6 +130,7 @@ class OutputHandler(object):
self.stack_fixer_function = get_stack_fixer_function(utilityPath, symbolsPath)
self.log = log
self.proc_name = None
self.results = defaultdict(int)
def __call__(self, line):
# need to return processed messages to appease remoteautomation.py
@ -143,7 +145,11 @@ class OutputHandler(object):
return [line]
if isinstance(data, dict) and 'action' in data:
self.log.log_raw(data)
if data['action'] == 'results':
for k, v in data['results'].items():
self.results[k] += v
else:
self.log.log_raw(data)
else:
self.verbatim(json.dumps(data))

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

@ -321,10 +321,10 @@ function InitAndStartRefTests()
// Focus the content browser.
if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
g.browser.addEventListener("focus", StartTests, true);
g.browser.addEventListener("focus", ReadTests, true);
g.browser.focus();
} else {
StartTests();
ReadTests();
}
}
@ -346,13 +346,94 @@ function Shuffle(array)
}
}
function ReadTests() {
try {
if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
g.browser.removeEventListener("focus", ReadTests, true);
}
g.urls = [];
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
/* There are three modes implemented here:
* 1) reftest.manifests
* 2) reftest.manifests and reftest.manifests.dumpTests
* 3) reftest.tests
*
* The first will parse the specified manifests, then immediately
* run the tests. The second will parse the manifests, save the test
* objects to a file and exit. The third will load a file of test
* objects and run them.
*
* The latter two modes are used to pass test data back and forth
* with python harness.
*/
let manifests = prefs.getCharPref("reftest.manifests", null);
let dumpTests = prefs.getCharPref("reftest.manifests.dumpTests", null);
let testList = prefs.getCharPref("reftest.tests", null);
if ((testList && manifests) || !(testList || manifests)) {
logger.error("Exactly one of reftest.manifests or reftest.tests must be specified.");
DoneTests();
}
if (testList) {
logger.debug("Reading test objects from: " + testList);
let promise = OS.File.read(testList).then(function onSuccess(array) {
let decoder = new TextDecoder();
g.urls = JSON.parse(decoder.decode(array)).map(CreateUrls);
StartTests();
});
} else if (manifests) {
// Parse reftest manifests
// XXX There is a race condition in the manifest parsing code which
// sometimes shows up on Android jsreftests (bug 1416125). It seems
// adding/removing log statements can change its frequency.
logger.debug("Reading " + manifests.length + " manifests");
manifests = JSON.parse(manifests);
g.urlsFilterRegex = manifests[null];
var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null;
var manifestURLs = Object.keys(manifests);
// Ensure we read manifests from higher up the directory tree first so that we
// process includes before reading the included manifest again
manifestURLs.sort(function(a,b) {return a.length - b.length})
manifestURLs.forEach(function(manifestURL) {
logger.info("Reading manifest " + manifestURL);
var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null;
ReadTopManifest(manifestURL, [globalFilter, filter, false]);
});
if (dumpTests) {
logger.debug("Dumping test objects to file: " + dumpTests);
let encoder = new TextEncoder();
let tests = encoder.encode(JSON.stringify(g.urls));
OS.File.writeAtomic(dumpTests, tests, {flush: true}).then(
function onSuccess() {
DoneTests();
},
function onFailure(reason) {
logger.error("failed to write test data: " + reason);
DoneTests();
}
)
} else {
logger.debug("Running " + g.urls.length + " test objects");
g.manageSuite = true;
g.urls = g.urls.map(CreateUrls);
StartTests();
}
}
} catch(e) {
++g.testResults.Exception;
logger.error("EXCEPTION: " + e);
}
}
function StartTests()
{
if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
g.browser.removeEventListener("focus", StartTests, true);
}
var manifests;
/* These prefs are optional, so we don't need to spit an error to the log */
try {
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
@ -388,28 +469,7 @@ function StartTests()
g.noCanvasCache = true;
}
g.urls = [];
try {
var manifests = JSON.parse(prefs.getCharPref("reftest.manifests"));
g.urlsFilterRegex = manifests[null];
} catch(e) {
logger.error("Unable to find reftest.manifests pref. Please ensure your profile is setup properly");
DoneTests();
}
try {
var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null;
var manifestURLs = Object.keys(manifests);
// Ensure we read manifests from higher up the directory tree first so that we
// process includes before reading the included manifest again
manifestURLs.sort(function(a,b) {return a.length - b.length})
manifestURLs.forEach(function(manifestURL) {
logger.info("Reading manifest " + manifestURL);
var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null;
ReadTopManifest(manifestURL, [globalFilter, filter, false]);
});
BuildUseCounts();
// Filter tests which will be skipped to get a more even distribution when chunking
@ -449,7 +509,7 @@ function StartTests()
g.urls = g.urls.slice(start, end);
}
if (g.startAfter === undefined && !g.suiteStarted) {
if (g.manageSuite && g.startAfter === undefined && !g.suiteStarted) {
var ids = g.urls.map(function(obj) {
return obj.identifier;
});
@ -725,8 +785,12 @@ function StartCurrentURI(aURLTargetType)
function DoneTests()
{
logger.suiteEnd({'results': g.testResults});
g.suiteStarted = false
if (g.manageSuite) {
g.suiteStarted = false
logger.suiteEnd({'results': g.testResults});
} else {
logger._logData('results', {results: g.testResults});
}
logger.info("Slowest test took " + g.slowestTestTime + "ms (" + g.slowestTestURL + ")");
logger.info("Total canvas count = " + g.recycledCanvases.length);
if (g.failedUseWidgetLayers) {

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

@ -2,16 +2,16 @@
# 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/.
from contextlib import closing
import sys
import logging
import os
import psutil
import signal
import time
import sys
import tempfile
import time
import traceback
import urllib2
from contextlib import closing
import mozdevice
import mozinfo
@ -143,6 +143,7 @@ class ReftestServer:
class RemoteReftest(RefTest):
use_marionette = False
parse_manifest = False
remoteApp = ''
resolver_cls = RemoteReftestResolver
@ -167,11 +168,11 @@ class RemoteReftest(RefTest):
self._devicemanager.removeDir(self.remoteCache)
self._populate_logger(options)
outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath)
self.outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath)
# RemoteAutomation.py's 'messageLogger' is also used by mochitest. Mimic a mochitest
# MessageLogger object to re-use this code path.
outputHandler.write = outputHandler.__call__
self.automation._processArgs['messageLogger'] = outputHandler
self.outputHandler.write = self.outputHandler.__call__
self.automation._processArgs['messageLogger'] = self.outputHandler
def findPath(self, paths, filename=None):
for path in paths:
@ -259,12 +260,12 @@ class RemoteReftest(RefTest):
# may not be able to access process info for all processes
continue
def createReftestProfile(self, options, manifest, startAfter=None):
def createReftestProfile(self, options, startAfter=None, **kwargs):
profile = RefTest.createReftestProfile(self,
options,
manifest,
server=options.remoteWebServer,
port=options.httpPort)
port=options.httpPort,
**kwargs)
if startAfter is not None:
print ("WARNING: Continuing after a crash is not supported for remote "
"reftest yet.")
@ -283,6 +284,11 @@ class RemoteReftest(RefTest):
# reftest pages at 1.0 zoom, rather than zooming to fit the CSS viewport.
prefs["apz.allow_zooming"] = False
if options.totalChunks:
prefs['reftest.totalChunks'] = options.totalChunks
if options.thisChunk:
prefs['reftest.thisChunk'] = options.thisChunk
# Set the extra prefs.
profile.set_preferences(prefs)
@ -333,10 +339,21 @@ class RemoteReftest(RefTest):
del browserEnv["XPCOM_MEM_BLOAT_LOG"]
return browserEnv
def runApp(self, profile, binary, cmdargs, env,
timeout=None, debuggerInfo=None,
symbolsPath=None, options=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
def runApp(self, options, cmdargs=None, timeout=None, debuggerInfo=None, symbolsPath=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None, **profileArgs):
if cmdargs is None:
cmdargs = []
if self.use_marionette:
cmdargs.append('-marionette')
binary = options.app
profile = self.createReftestProfile(options, **profileArgs)
# browser environment
env = self.buildBrowserEnv(options, profile.profile)
self.log.info("Running with e10s: {}".format(options.e10s))
status, lastTestSeen = self.automation.runApp(None, env,
binary,
profile.profile,
@ -349,7 +366,9 @@ class RemoteReftest(RefTest):
if status == 1:
# when max run time exceeded, avoid restart
lastTestSeen = RefTest.TEST_SEEN_FINAL
return status, lastTestSeen
self.cleanup(profile.profile)
return status, lastTestSeen, self.outputHandler.results
def cleanup(self, profileDir):
# Pull results back from device

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

@ -18,6 +18,7 @@ import shutil
import signal
import subprocess
import sys
import tempfile
import threading
from datetime import datetime, timedelta
@ -28,12 +29,14 @@ if SCRIPT_DIRECTORY not in sys.path:
import mozcrash
import mozdebug
import mozfile
import mozinfo
import mozleak
import mozlog
import mozprocess
import mozprofile
import mozrunner
from manifestparser import TestManifest, filters as mpf
from mozrunner.utils import get_stack_fixer_function, test_environment
from mozscreenshot import printstatus, dump_screen
@ -226,9 +229,10 @@ class ReftestResolver(object):
class RefTest(object):
TEST_SEEN_INITIAL = 'reftest'
TEST_SEEN_FINAL = 'Main app process exited normally'
use_marionette = True
oldcwd = os.getcwd()
parse_manifest = True
resolver_cls = ReftestResolver
use_marionette = True
def __init__(self):
update_mozinfo()
@ -236,6 +240,7 @@ class RefTest(object):
self.haveDumpedScreen = False
self.resolver = self.resolver_cls()
self.log = None
self.testDumpFile = os.path.join(tempfile.gettempdir(), 'reftests.json')
def _populate_logger(self, options):
if self.log:
@ -259,17 +264,21 @@ class RefTest(object):
"Get an absolute path relative to self.oldcwd."
return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
def createReftestProfile(self, options, manifests, server='localhost', port=0,
profile_to_clone=None, startAfter=None):
def createReftestProfile(self, options, tests=None, manifests=None,
server='localhost', port=0, profile_to_clone=None,
startAfter=None, prefs=None):
"""Sets up a profile for reftest.
:param options: Object containing command line options
:param manifests: Dictionary of the form {manifest_path: [filters]}
:param tests: List of test objects to run
:param manifests: List of manifest files to parse (only takes effect
if tests were not passed in)
:param server: Server name to use for http tests
:param profile_to_clone: Path to a profile to use as the basis for the
test profile
:param startAfter: Start running tests after the specified test id
:param prefs: Extra preferences to set in the profile
"""
locations = mozprofile.permissions.ServerLocations()
locations.add_host(server, scheme='http', port=port)
locations.add_host(server, scheme='https', port=port)
@ -277,12 +286,8 @@ class RefTest(object):
# Set preferences for communication between our command line arguments
# and the reftest harness. Preferences that are required for reftest
# to work should instead be set in reftest-preferences.js .
prefs = {}
prefs = prefs or {}
prefs['reftest.timeout'] = options.timeout * 1000
if options.totalChunks:
prefs['reftest.totalChunks'] = options.totalChunks
if options.thisChunk:
prefs['reftest.thisChunk'] = options.thisChunk
if options.logFile:
prefs['reftest.logFile'] = options.logFile
if options.ignoreWindowSize:
@ -299,7 +304,6 @@ class RefTest(object):
prefs['reftest.cleanupPendingCrashes'] = True
prefs['reftest.focusFilterMode'] = options.focusFilterMode
prefs['reftest.logLevel'] = options.log_tbpl_level or 'info'
prefs['reftest.manifests'] = json.dumps(manifests)
prefs['reftest.suite'] = options.suite
if startAfter not in (None, self.TEST_SEEN_INITIAL, self.TEST_SEEN_FINAL):
@ -380,6 +384,14 @@ class RefTest(object):
else:
profile = mozprofile.Profile(**kwargs)
if tests:
testlist = os.path.join(profile.profile, 'reftests.json')
with open(testlist, 'w') as fh:
json.dump(tests, fh)
profile.set_preferences({'reftest.tests': testlist})
elif manifests:
profile.set_preferences({'reftest.manifests': json.dumps(manifests)})
if os.path.join(here, 'chrome') not in options.extraProfileFiles:
options.extraProfileFiles.append(os.path.join(here, 'chrome'))
@ -659,10 +671,23 @@ class RefTest(object):
self.log.info("Can't trigger Breakpad, just killing process")
process.kill()
def runApp(self, profile, binary, cmdargs, env,
timeout=None, debuggerInfo=None,
symbolsPath=None, options=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
def runApp(self, options, cmdargs=None, timeout=None, debuggerInfo=None,
symbolsPath=None, valgrindPath=None, valgrindArgs=None,
valgrindSuppFiles=None, **profileArgs):
if cmdargs is None:
cmdargs = []
if self.use_marionette:
cmdargs.append('-marionette')
binary = options.app
profile = self.createReftestProfile(options, **profileArgs)
# browser environment
env = self.buildBrowserEnv(options, profile.profile)
self.log.info("Running with e10s: {}".format(options.e10s))
def timeoutHandler():
self.handleTimeout(
@ -769,12 +794,44 @@ class RefTest(object):
status = 1
runner.cleanup()
self.cleanup(profile.profile)
if marionette_exception is not None:
exc, value, tb = marionette_exception
raise exc, value, tb
return status, self.lastTestSeen
self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
return status, self.lastTestSeen, outputHandler.results
def getActiveTests(self, manifests, options, testDumpFile=None):
# These prefs will cause reftest.jsm to parse the manifests,
# dump the resulting tests to a file, and exit.
prefs = {
'reftest.manifests': json.dumps(manifests),
'reftest.manifests.dumpTests': testDumpFile or self.testDumpFile,
}
cmdargs = [] # ['-headless']
status, _, _ = self.runApp(options, cmdargs=cmdargs, prefs=prefs)
with open(self.testDumpFile, 'r') as fh:
tests = json.load(fh)
if os.path.isfile(self.testDumpFile):
mozfile.remove(self.testDumpFile)
for test in tests:
# Name and path are expected by manifestparser, but not used in reftest.
test['name'] = test['path'] = test['url1']
mp = TestManifest(strict=False)
mp.tests = tests
filters = []
if options.totalChunks:
filters.append(mpf.chunk_by_slice(options.thisChunk, options.totalChunks))
tests = mp.active_tests(exists=False, filters=filters)
return tests
def runSerialTests(self, manifests, options, cmdargs=None):
debuggerInfo = None
@ -782,75 +839,67 @@ class RefTest(object):
debuggerInfo = mozdebug.get_debugger_info(options.debugger, options.debuggerArgs,
options.debuggerInteractive)
profileDir = None
tests = None
if self.parse_manifest:
tests = self.getActiveTests(manifests, options)
ids = [t['identifier'] for t in tests]
self.log.suite_start(ids, name=options.suite)
startAfter = None # When the previous run crashed, we skip the tests we ran before
prevStartAfter = None
for i in itertools.count():
try:
if cmdargs is None:
cmdargs = []
status, startAfter, results = self.runApp(
options,
tests=tests,
manifests=manifests,
cmdargs=cmdargs,
# We generally want the JS harness or marionette
# to handle timeouts if they can.
# The default JS harness timeout is currently
# 300 seconds (default options.timeout).
# The default Marionette socket timeout is
# currently 360 seconds.
# Give the JS harness extra time to deal with
# its own timeouts and try to usually exceed
# the 360 second marionette socket timeout.
# See bug 479518 and bug 1414063.
timeout=options.timeout + 70.0,
symbolsPath=options.symbolsPath,
debuggerInfo=debuggerInfo
)
mozleak.process_leak_log(self.leakLogFile,
leak_thresholds=options.leakThresholds,
stack_fixer=get_stack_fixer_function(options.utilityPath,
options.symbolsPath))
if self.use_marionette:
cmdargs.append('-marionette')
if status == 0:
break
profile = self.createReftestProfile(options,
manifests,
startAfter=startAfter)
profileDir = profile.profile # name makes more sense
if startAfter == self.TEST_SEEN_FINAL:
self.log.info("Finished running all tests, skipping resume "
"despite non-zero status code: %s" % status)
break
# browser environment
browserEnv = self.buildBrowserEnv(options, profileDir)
if startAfter is not None and options.shuffle:
self.log.error("Can not resume from a crash with --shuffle "
"enabled. Please consider disabling --shuffle")
break
if startAfter is not None and options.maxRetries <= i:
self.log.error("Hit maximum number of allowed retries ({}) "
"in the test run".format(options.maxRetries))
break
if startAfter == prevStartAfter:
# If the test stuck on the same test, or there the crashed
# test appeared more then once, stop
self.log.error("Force stop because we keep running into "
"test \"{}\"".format(startAfter))
break
prevStartAfter = startAfter
# TODO: we need to emit an SUITE-END log if it crashed
self.log.info("Running with e10s: {}".format(options.e10s))
status, startAfter = self.runApp(profile,
binary=options.app,
cmdargs=cmdargs,
env=browserEnv,
# We generally want the JS harness or marionette
# to handle timeouts if they can.
# The default JS harness timeout is currently
# 300 seconds (default options.timeout).
# The default Marionette socket timeout is
# currently 360 seconds.
# Give the JS harness extra time to deal with
# its own timeouts and try to usually exceed
# the 360 second marionette socket timeout.
# See bug 479518 and bug 1414063.
timeout=options.timeout + 70.0,
symbolsPath=options.symbolsPath,
options=options,
debuggerInfo=debuggerInfo)
self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
mozleak.process_leak_log(self.leakLogFile,
leak_thresholds=options.leakThresholds,
stack_fixer=get_stack_fixer_function(options.utilityPath,
options.symbolsPath))
if status == 0:
break
if startAfter == self.TEST_SEEN_FINAL:
self.log.info("Finished running all tests, skipping resume "
"despite non-zero status code: %s" % status)
break
if startAfter is not None and options.shuffle:
self.log.error("Can not resume from a crash with --shuffle "
"enabled. Please consider disabling --shuffle")
break
if startAfter is not None and options.maxRetries <= i:
self.log.error("Hit maximum number of allowed retries ({}) "
"in the test run".format(options.maxRetries))
break
if startAfter == prevStartAfter:
# If the test stuck on the same test, or there the crashed
# test appeared more then once, stop
self.log.error("Force stop because we keep running into "
"test \"{}\"".format(startAfter))
break
prevStartAfter = startAfter
# TODO: we need to emit an SUITE-END log if it crashed
finally:
self.cleanup(profileDir)
if self.parse_manifest:
self.log.suite_end(extra={'results': results})
return status
def copyExtraFilesToProfile(self, options, profile):

204
npm-shrinkwrap.json сгенерированный
Просмотреть файл

@ -4,9 +4,9 @@
"lockfileVersion": 1,
"dependencies": {
"acorn": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
"integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w=="
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",
"integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ=="
},
"acorn-jsx": {
"version": "3.0.1",
@ -24,9 +24,9 @@
}
},
"ajv": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz",
"integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=",
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
@ -167,6 +167,11 @@
}
}
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
},
"circular-json": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
@ -243,7 +248,7 @@
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"requires": {
"es5-ext": "0.10.35"
"es5-ext": "0.10.38"
}
},
"debug": {
@ -274,12 +279,11 @@
}
},
"doctrine": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz",
"integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"requires": {
"esutils": "2.0.2",
"isarray": "1.0.0"
"esutils": "2.0.2"
}
},
"dom-serializer": {
@ -326,9 +330,9 @@
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
},
"es5-ext": {
"version": "0.10.35",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz",
"integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=",
"version": "0.10.38",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.38.tgz",
"integrity": "sha512-jCMyePo7AXbUESwbl8Qi01VSH2piY9s/a3rSU/5w/MlTIx8HPL1xn2InGN8ejt/xulcJgnTO7vqNtOAxzYd2Kg==",
"requires": {
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1"
@ -340,7 +344,7 @@
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es5-ext": "0.10.38",
"es6-symbol": "3.1.1"
}
},
@ -350,7 +354,7 @@
"integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-set": "0.1.5",
"es6-symbol": "3.1.1",
@ -363,7 +367,7 @@
"integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1",
"event-emitter": "0.3.5"
@ -375,7 +379,7 @@
"integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35"
"es5-ext": "0.10.38"
}
},
"es6-weak-map": {
@ -384,7 +388,7 @@
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1"
}
@ -406,34 +410,34 @@
}
},
"eslint": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.8.0.tgz",
"integrity": "sha1-Ip7w41Tg5h2DfHqA/fuoJeGZgV4=",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.17.0.tgz",
"integrity": "sha512-AyxBUCANU/o/xC0ijGMKavo5Ls3oK6xykiOITlMdjFjrKOsqLrA7Nf5cnrDgcKrHzBirclAZt63XO7YZlVUPwA==",
"requires": {
"ajv": "5.3.0",
"ajv": "5.5.2",
"babel-code-frame": "6.26.0",
"chalk": "2.3.0",
"concat-stream": "1.6.0",
"cross-spawn": "5.1.0",
"debug": "3.1.0",
"doctrine": "2.0.0",
"doctrine": "2.1.0",
"eslint-scope": "3.7.1",
"espree": "3.5.2",
"eslint-visitor-keys": "1.0.0",
"espree": "3.5.3",
"esquery": "1.0.0",
"estraverse": "4.2.0",
"esutils": "2.0.2",
"file-entry-cache": "2.0.0",
"functional-red-black-tree": "1.0.1",
"glob": "7.1.2",
"globals": "9.18.0",
"globals": "11.3.0",
"ignore": "3.3.7",
"imurmurhash": "0.1.4",
"inquirer": "3.3.0",
"is-resolvable": "1.0.0",
"is-resolvable": "1.1.0",
"js-yaml": "3.10.0",
"json-stable-stringify": "1.0.1",
"json-stable-stringify-without-jsonify": "1.0.1",
"levn": "0.3.0",
"lodash": "4.17.4",
"lodash": "4.17.5",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"natural-compare": "1.4.0",
@ -442,7 +446,7 @@
"pluralize": "7.0.0",
"progress": "2.0.0",
"require-uncached": "1.0.3",
"semver": "5.4.1",
"semver": "5.5.0",
"strip-ansi": "4.0.0",
"strip-json-comments": "2.0.1",
"table": "4.0.2",
@ -450,9 +454,9 @@
}
},
"eslint-plugin-html": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-4.0.0.tgz",
"integrity": "sha512-xK/909qOTq5JVzuO2jo4a24nQcWhkOBz9dOIkORvB7RxC75a4b6B9wFpBXAl8WDhwJGFDj5gBDRN+/L3kK/ghw==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-4.0.2.tgz",
"integrity": "sha512-CrQd0F8GWdNWnu4PFrYZl+LjUCXNVy2h0uhDMtnf/7VKc9HRcnkXSrlg0BSGfptZPSzmwnnwCaREAa9+fnQhYw==",
"requires": {
"htmlparser2": "3.9.2"
}
@ -465,9 +469,9 @@
}
},
"eslint-plugin-no-unsanitized": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-2.0.1.tgz",
"integrity": "sha1-yt7dDQrRfI3FIm23/4hATlmo1n8=",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-2.0.2.tgz",
"integrity": "sha1-pCqDybPZOGEB1v1pFcQXWfp6N/c=",
"requires": {
"eslint": "3.19.0"
},
@ -528,9 +532,9 @@
"chalk": "1.1.3",
"concat-stream": "1.6.0",
"debug": "2.6.9",
"doctrine": "2.0.0",
"doctrine": "2.1.0",
"escope": "3.6.0",
"espree": "3.5.2",
"espree": "3.5.3",
"esquery": "1.0.0",
"estraverse": "4.2.0",
"esutils": "2.0.2",
@ -540,12 +544,12 @@
"ignore": "3.3.7",
"imurmurhash": "0.1.4",
"inquirer": "0.12.0",
"is-my-json-valid": "2.16.1",
"is-resolvable": "1.0.0",
"is-my-json-valid": "2.17.1",
"is-resolvable": "1.1.0",
"js-yaml": "3.10.0",
"json-stable-stringify": "1.0.1",
"levn": "0.3.0",
"lodash": "4.17.4",
"lodash": "4.17.5",
"mkdirp": "0.5.1",
"natural-compare": "1.4.0",
"optionator": "0.8.2",
@ -570,6 +574,11 @@
"object-assign": "4.1.1"
}
},
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
},
"inquirer": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
@ -581,7 +590,7 @@
"cli-cursor": "1.0.2",
"cli-width": "2.2.0",
"figures": "1.7.0",
"lodash": "4.17.4",
"lodash": "4.17.5",
"readline2": "1.0.1",
"run-async": "0.1.0",
"rx-lite": "3.1.2",
@ -666,7 +675,7 @@
"ajv": "4.11.8",
"ajv-keywords": "1.5.1",
"chalk": "1.1.3",
"lodash": "4.17.4",
"lodash": "4.17.5",
"slice-ansi": "0.0.4",
"string-width": "2.1.1"
},
@ -707,7 +716,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz",
"integrity": "sha1-J3cKzzn1/UnNCvQIPOWBBOs5DUw=",
"requires": {
"doctrine": "2.0.0",
"doctrine": "2.1.0",
"has": "1.0.1",
"jsx-ast-utils": "1.4.1"
}
@ -724,12 +733,17 @@
"estraverse": "4.2.0"
}
},
"eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
"integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
},
"espree": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.3.tgz",
"integrity": "sha512-Zy3tAJDORxQZLl2baguiRU1syPERAIg0L+JB2MWorORgTu/CplzvxS9WWA7Xh4+Q+eOQihNs/1o1Xep8cvCxWQ==",
"requires": {
"acorn": "5.2.1",
"acorn": "5.4.1",
"acorn-jsx": "3.0.1"
}
},
@ -771,7 +785,7 @@
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35"
"es5-ext": "0.10.38"
}
},
"exit-hook": {
@ -780,12 +794,12 @@
"integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g="
},
"external-editor": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz",
"integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz",
"integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==",
"requires": {
"chardet": "0.4.2",
"iconv-lite": "0.4.19",
"jschardet": "1.6.0",
"tmp": "0.0.33"
}
},
@ -874,9 +888,9 @@
}
},
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.3.0.tgz",
"integrity": "sha512-kkpcKNlmQan9Z5ZmgqKH/SMbSmjxQ7QjyNqfXVc8VJcoBV2UEg+sxQD15GQofGRh2hfpwUb70VC31DR7Rq5Hdw=="
},
"globby": {
"version": "5.0.0",
@ -973,9 +987,9 @@
"chalk": "2.3.0",
"cli-cursor": "2.1.0",
"cli-width": "2.2.0",
"external-editor": "2.0.5",
"external-editor": "2.1.0",
"figures": "2.0.0",
"lodash": "4.17.4",
"lodash": "4.17.5",
"mute-stream": "0.0.7",
"run-async": "2.3.0",
"rx-lite": "4.0.8",
@ -986,9 +1000,9 @@
}
},
"interpret": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz",
"integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
@ -996,9 +1010,9 @@
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-my-json-valid": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz",
"integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==",
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz",
"integrity": "sha512-Q2khNw+oBlWuaYvEEHtKSw/pCxD2L5Rc1C+UQme9X6JdRDh7m5D7HkozA0qa3DUkQ6VzCnEm8mVIQPyIRkI5sQ==",
"requires": {
"generate-function": "2.0.0",
"generate-object-property": "1.2.0",
@ -1016,13 +1030,13 @@
"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
"integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
"requires": {
"is-path-inside": "1.0.0"
"is-path-inside": "1.0.1"
}
},
"is-path-inside": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
"integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
"integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
"requires": {
"path-is-inside": "1.0.2"
}
@ -1038,12 +1052,9 @@
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
},
"is-resolvable": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
"integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=",
"requires": {
"tryit": "1.0.3"
}
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
},
"isarray": {
"version": "1.0.0",
@ -1069,11 +1080,6 @@
"esprima": "4.0.0"
}
},
"jschardet": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz",
"integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ=="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
@ -1087,6 +1093,11 @@
"jsonify": "0.0.0"
}
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
},
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
@ -1112,9 +1123,9 @@
}
},
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
"version": "4.17.5",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
},
"lru-cache": {
"version": "4.1.1",
@ -1126,9 +1137,9 @@
}
},
"mimic-fn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"minimatch": {
"version": "3.0.4",
@ -1189,7 +1200,7 @@
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"requires": {
"mimic-fn": "1.1.0"
"mimic-fn": "1.2.0"
}
},
"optionator": {
@ -1391,9 +1402,9 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
},
"shebang-command": {
"version": "1.2.0",
@ -1414,7 +1425,7 @@
"integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
"requires": {
"glob": "7.1.2",
"interpret": "1.0.4",
"interpret": "1.1.0",
"rechoir": "0.6.2"
}
},
@ -1488,10 +1499,10 @@
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
"integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
"requires": {
"ajv": "5.3.0",
"ajv": "5.5.2",
"ajv-keywords": "2.1.1",
"chalk": "2.3.0",
"lodash": "4.17.4",
"lodash": "4.17.5",
"slice-ansi": "1.0.0",
"string-width": "2.1.1"
}
@ -1514,11 +1525,6 @@
"os-tmpdir": "1.0.2"
}
},
"tryit": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz",
"integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics="
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",

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

@ -4,10 +4,10 @@
"repository": {},
"license": "MPL-2.0",
"dependencies": {
"eslint": "4.8.0",
"eslint-plugin-html": "4.0.0",
"eslint": "4.17.0",
"eslint-plugin-html": "4.0.2",
"eslint-plugin-mozilla": "file:tools/lint/eslint/eslint-plugin-mozilla",
"eslint-plugin-no-unsanitized": "2.0.1",
"eslint-plugin-no-unsanitized": "2.0.2",
"eslint-plugin-react": "7.1.0",
"eslint-plugin-spidermonkey-js": "file:tools/lint/eslint/eslint-plugin-spidermonkey-js"
},

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

@ -7,6 +7,7 @@ from __future__ import absolute_import
import errno
import random
import os
import shutil
import subprocess
import types
import xml.etree.ElementTree as ET
@ -171,6 +172,16 @@ class CppEclipseBackend(CommonBackend):
["eclipse", "-application", "-nosplash",
"org.eclipse.cdt.managedbuilder.core.headlessbuild",
"-data", self._workspace_dir, "-importAll", self._project_dir])
except OSError as e:
# Remove the workspace directory so we re-generate it and
# try to import again when the backend is invoked again.
shutil.rmtree(self._workspace_dir)
if e.errno == errno.ENOENT:
raise Exception("Failed to launch eclipse to import project. "
"Ensure 'eclipse' is in your PATH and try again")
else:
raise
finally:
self._remove_noindex()
@ -181,7 +192,12 @@ class CppEclipseBackend(CommonBackend):
def _remove_noindex(self):
noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
os.remove(noindex_path)
# This may fail if the entire tree has been removed; that's fine.
try:
os.remove(noindex_path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
def _define_entry(self, name, value):
define = ET.Element('entry')

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

@ -339,9 +339,8 @@ class Preprocessor:
"""
self.marker = aMarker
if aMarker:
self.instruction = re.compile('{0}(?P<cmd>[a-z]+)(?:\s(?P<args>.*))?$'
.format(aMarker),
re.U)
self.instruction = re.compile('{0}(?P<cmd>[a-z]+)(?:\s+(?P<args>.*?))?\s*$'
.format(aMarker))
self.comment = re.compile(aMarker, re.U)
else:
class NoMatch(object):
@ -606,7 +605,7 @@ class Preprocessor:
if self.disableLevel and not replace:
self.disableLevel += 1
return
if re.match('\W', args, re.U):
if re.search('\W', args, re.U):
raise Preprocessor.Error(self, 'INVALID_VAR', args)
if args not in self.context:
self.disableLevel = 1
@ -621,7 +620,7 @@ class Preprocessor:
if self.disableLevel and not replace:
self.disableLevel += 1
return
if re.match('\W', args, re.U):
if re.search('\W', args, re.U):
raise Preprocessor.Error(self, 'INVALID_VAR', args)
if args in self.context:
self.disableLevel = 1

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

@ -642,5 +642,24 @@ class TestPreprocessor(unittest.TestCase):
self.pp.handleCommandLine(['-Fsubstitution', '-Dfoo=foobarbaz', '@foo@.in'])
self.assertEqual(self.pp.out.getvalue(), 'foobarbaz\n')
def test_invalid_ifdef(self):
with MockedOpen({'dummy': '#ifdef FOO == BAR\nPASS\n#endif'}):
with self.assertRaises(Preprocessor.Error) as e:
self.pp.do_include('dummy')
self.assertEqual(e.exception.key, 'INVALID_VAR')
with MockedOpen({'dummy': '#ifndef FOO == BAR\nPASS\n#endif'}):
with self.assertRaises(Preprocessor.Error) as e:
self.pp.do_include('dummy')
self.assertEqual(e.exception.key, 'INVALID_VAR')
# Trailing whitespaces, while not nice, shouldn't be an error.
self.do_include_pass([
'#ifndef FOO ',
'PASS',
'#endif',
])
if __name__ == '__main__':
main()

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

@ -836,7 +836,7 @@ SyncEngine.prototype = {
if (Array.isArray(json)) {
// Pre-`JSONFile` storage stored an array, but `JSONFile` defaults to
// an object, so we wrap the array for consistency.
return { ids: json };
json = { ids: json };
}
if (!json.ids) {
json.ids = [];

1
servo/Cargo.lock сгенерированный
Просмотреть файл

@ -2918,6 +2918,7 @@ dependencies = [
"servo_url 0.0.1",
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style_derive 0.0.1",
"style_traits 0.0.1",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",

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

@ -21,7 +21,7 @@ gecko = ["nsstring", "num_cpus",
use_bindgen = ["bindgen", "regex", "toml"]
servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever",
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
"servo_url"]
"servo_url", "string_cache"]
gecko_debug = ["nsstring/gecko_debug"]
[dependencies]
@ -61,6 +61,7 @@ servo_atoms = {path = "../atoms", optional = true}
servo_config = {path = "../config", optional = true}
smallbitvec = "1.0.6"
smallvec = "0.6"
string_cache = { version = "0.7", optional = true }
style_derive = {path = "../style_derive"}
style_traits = {path = "../style_traits"}
servo_url = {path = "../url", optional = true}

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

@ -1728,10 +1728,10 @@ impl ToCss for PseudoElement {
dest.write_char('(')?;
let mut iter = args.iter();
if let Some(first) = iter.next() {
serialize_identifier(&first.to_string(), dest)?;
serialize_atom_identifier(first, dest)?;
for item in iter {
dest.write_str(", ")?;
serialize_identifier(&item.to_string(), dest)?;
serialize_atom_identifier(item, dest)?;
}
}
dest.write_char(')')?;

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

@ -8,13 +8,14 @@
//! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
//! need to update the checked-in files for Servo.
use cssparser::{ToCss, serialize_identifier};
use cssparser::ToCss;
use gecko_bindings::structs::{self, CSSPseudoElementType};
use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
use string_cache::Atom;
use values::serialize_atom_identifier;
include!(concat!(env!("OUT_DIR"), "/gecko/pseudo_element_definition.rs"));

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

@ -277,10 +277,10 @@ impl ToCss for PseudoElement {
dest.write_char('(')?;
let mut iter = args.iter();
if let Some(first) = iter.next() {
serialize_identifier(&first.to_string(), dest)?;
serialize_atom_identifier(&first, dest)?;
for item in iter {
dest.write_str(", ")?;
serialize_identifier(&item.to_string(), dest)?;
serialize_atom_identifier(item, dest)?;
}
}
dest.write_char(')')?;

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

@ -13,15 +13,14 @@ use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::{nsAtom, nsAtom_AtomKind, nsStaticAtom};
use nsstring::{nsAString, nsStr};
use precomputed_hash::PrecomputedHash;
use std::{mem, slice, str};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;
#[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)]
@ -128,21 +127,38 @@ impl WeakAtom {
/// Find alternatives to this function when possible, please, since it's
/// pretty slow.
pub fn with_str<F, Output>(&self, cb: F) -> Output
where F: FnOnce(&str) -> Output
where
F: FnOnce(&str) -> Output
{
// FIXME(bholley): We should measure whether it makes more sense to
// cache the UTF-8 version in the Gecko atom table somehow.
let owned = self.to_string();
cb(&owned)
}
let mut buffer: [u8; 64] = unsafe { mem::uninitialized() };
/// Convert this Atom into a string, decoding the UTF-16 bytes.
///
/// Find alternatives to this function when possible, please, since it's
/// pretty slow.
#[inline]
pub fn to_string(&self) -> String {
String::from_utf16(self.as_slice()).unwrap()
// The total string length in utf16 is going to be less than or equal
// the slice length (each utf16 character is going to take at least one
// and at most 2 items in the utf16 slice).
//
// Each of those characters will take at most four bytes in the utf8
// one. Thus if the slice is less than 64 / 4 (16) we can guarantee that
// we'll decode it in place.
let owned_string;
let len = self.len();
let utf8_slice = if len <= 16 {
let mut total_len = 0;
for c in self.chars() {
let c = c.unwrap_or(char::REPLACEMENT_CHARACTER);
let utf8_len = c.encode_utf8(&mut buffer[total_len..]).len();
total_len += utf8_len;
}
let slice = unsafe { str::from_utf8_unchecked(&buffer[..total_len]) };
debug_assert_eq!(slice, String::from_utf16_lossy(self.as_slice()));
slice
} else {
owned_string = String::from_utf16_lossy(self.as_slice());
&*owned_string
};
cb(utf8_slice)
}
/// Returns whether this atom is static.

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

@ -68,6 +68,7 @@ pub extern crate servo_arc;
#[cfg(feature = "servo")] extern crate servo_url;
extern crate smallbitvec;
extern crate smallvec;
#[cfg(feature = "servo")] extern crate string_cache;
#[macro_use]
extern crate style_derive;
extern crate style_traits;

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

@ -8,7 +8,7 @@
use Atom;
use cssparser::{AtRuleParser, AtRuleType, BasicParseErrorKind, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{CowRcStr, RuleListParser, SourceLocation, QualifiedRuleParser, Token, serialize_identifier};
use cssparser::{CowRcStr, RuleListParser, SourceLocation, QualifiedRuleParser, Token};
use error_reporting::{ContextualParseError, ParseErrorReporter};
#[cfg(feature = "gecko")]
use gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry;
@ -21,6 +21,7 @@ use str::CssStringWriter;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use stylesheets::CssRuleType;
use values::computed::font::FamilyName;
use values::serialize_atom_identifier;
/// A @font-feature-values block declaration.
/// It is `<ident>: <integer>+`.
@ -41,7 +42,7 @@ impl<T: ToCss> ToCss for FFVDeclaration<T> {
where
W: Write,
{
serialize_identifier(&self.name.to_string(), dest)?;
serialize_atom_identifier(&self.name, dest)?;
dest.write_str(": ")?;
self.value.to_css(dest)?;
dest.write_str(";")

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

@ -461,6 +461,7 @@ impl SingleFontFamily {
/// Get the corresponding font-family with family name
fn from_font_family_name(family: &structs::FontFamilyName) -> SingleFontFamily {
use gecko_bindings::structs::FontFamilyType;
use values::serialize_atom_identifier;
match family.mType {
FontFamilyType::eFamily_sans_serif => SingleFontFamily::Generic(atom!("sans-serif")),
@ -472,7 +473,7 @@ impl SingleFontFamily {
FontFamilyType::eFamily_named => {
let name = Atom::from(&*family.mName);
let mut serialization = String::new();
serialize_identifier(&name.to_string(), &mut serialization).unwrap();
serialize_atom_identifier(&name, &mut serialization).unwrap();
SingleFontFamily::FamilyName(FamilyName {
name: name.clone(),
syntax: FamilyNameSyntax::Identifiers(serialization),

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

@ -4,7 +4,9 @@
//! Computed values.
use {Atom, Namespace};
use Atom;
#[cfg(feature = "servo")]
use Prefix;
use context::QuirksMode;
use euclid::Size2D;
use font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
@ -414,7 +416,8 @@ trivial_to_computed_value!(u32);
trivial_to_computed_value!(Atom);
trivial_to_computed_value!(BorderStyle);
trivial_to_computed_value!(CursorKind);
trivial_to_computed_value!(Namespace);
#[cfg(feature = "servo")]
trivial_to_computed_value!(Prefix);
trivial_to_computed_value!(String);
trivial_to_computed_value!(Box<str>);

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

@ -7,11 +7,11 @@
//! [images]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::serialize_identifier;
use custom_properties;
use servo_arc::Arc;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
use values::serialize_atom_identifier;
/// An [image].
///
@ -151,7 +151,7 @@ impl ToCss for PaintWorklet {
W: Write,
{
dest.write_str("paint(")?;
serialize_identifier(&*self.name.to_string(), dest)?;
serialize_atom_identifier(&self.name, dest)?;
for argument in &self.arguments {
dest.write_str(", ")?;
argument.to_css(dest)?;
@ -200,7 +200,7 @@ impl<G, R, U> ToCss for Image<G, R, U>
Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest),
Image::Element(ref selector) => {
dest.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), dest)?;
serialize_atom_identifier(selector, dest)?;
dest.write_str(")")
},
}

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

@ -33,6 +33,25 @@ define_keyword_type!(None_, "none");
define_keyword_type!(Auto, "auto");
define_keyword_type!(Normal, "normal");
/// Serialize an identifier which is represented as an atom.
#[cfg(feature = "gecko")]
pub fn serialize_atom_identifier<W>(ident: &Atom, dest: &mut W) -> fmt::Result
where
W: Write,
{
ident.with_str(|s| serialize_identifier(s, dest))
}
/// Serialize an identifier which is represented as an atom.
#[cfg(feature = "servo")]
pub fn serialize_atom_identifier<Static, W>(ident: &::string_cache::Atom<Static>, dest: &mut W) -> fmt::Result
where
Static: ::string_cache::StaticAtomSet,
W: Write,
{
serialize_identifier(&ident, dest)
}
/// Serialize a normalized value into percentage.
pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
where
@ -114,7 +133,7 @@ impl ToCss for CustomIdent {
where
W: Write,
{
serialize_identifier(&self.0.to_string(), dest)
serialize_atom_identifier(&self.0, dest)
}
}

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

@ -165,9 +165,10 @@ impl From<LengthOrPercentage> for FontSize {
}
/// Specifies a prioritized list of font family names or generic family names.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, PartialEq, ToCss)]
pub enum FontFamily {
/// List of `font-family`
#[css(iterable, comma)]
Values(FontFamilyList),
/// System font
System(SystemFont),
@ -245,26 +246,6 @@ impl MallocSizeOf for FontFamily {
}
}
impl ToCss for FontFamily {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match *self {
FontFamily::Values(ref v) => {
let mut iter = v.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
FontFamily::System(sys) => sys.to_css(dest),
}
}
}
impl Parse for FontFamily {
/// <family-name>#
/// <family-name> = <string> | [ <ident>+ ]

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

@ -6,7 +6,7 @@
//!
//! TODO(emilio): Enhance docs.
use Namespace;
use Prefix;
use context::QuirksMode;
use cssparser::{Parser, Token, serialize_identifier};
use num_traits::One;
@ -22,6 +22,7 @@ use super::computed::{Context, ToComputedValue};
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
use super::generics::grid::{TrackSize as GenericTrackSize, TrackList as GenericTrackList};
use values::serialize_atom_identifier;
use values::specified::calc::CalcNode;
pub use properties::animated_properties::TransitionProperty;
@ -748,8 +749,8 @@ pub type NamespaceId = ();
/// `[namespace? `|`]? ident`
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct Attr {
/// Optional namespace
pub namespace: Option<(Namespace, NamespaceId)>,
/// Optional namespace prefix, with the actual namespace id.
pub namespace: Option<(Prefix, NamespaceId)>,
/// Attribute name
pub attribute: String,
}
@ -761,35 +762,18 @@ impl Parse for Attr {
}
}
#[cfg(feature = "gecko")]
/// Get the namespace id from the namespace map
fn get_id_for_namespace(namespace: &Namespace, context: &ParserContext) -> Result<NamespaceId, ()> {
let namespaces_map = match context.namespaces {
Some(map) => map,
None => {
// If we don't have a namespace map (e.g. in inline styles)
// we can't parse namespaces
return Err(());
}
};
match namespaces_map.prefixes.get(&namespace.0) {
Some(entry) => Ok(entry.1),
None => Err(()),
}
}
#[cfg(feature = "servo")]
/// Get the namespace id from the namespace map
fn get_id_for_namespace(_: &Namespace, _: &ParserContext) -> Result<NamespaceId, ()> {
Ok(())
/// Get the Namespace id from the namespace map.
fn get_id_for_namespace(prefix: &Prefix, context: &ParserContext) -> Option<NamespaceId> {
Some(context.namespaces.as_ref()?.prefixes.get(prefix)?.1)
}
impl Attr {
/// Parse contents of attr() assuming we have already parsed `attr` and are
/// within a parse_nested_block()
pub fn parse_function<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Attr, ParseError<'i>> {
pub fn parse_function<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Attr, ParseError<'i>> {
// Syntax is `[namespace? `|`]? ident`
// no spaces allowed
let first = input.try(|i| i.expect_ident_cloned()).ok();
@ -804,11 +788,14 @@ impl Attr {
};
let ns_with_id = if let Some(ns) = first {
let ns = Namespace::from(ns.as_ref());
let id: Result<_, ParseError> =
get_id_for_namespace(&ns, context)
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
Some((ns, id?))
let ns = Prefix::from(ns.as_ref());
let id = match get_id_for_namespace(&ns, context) {
Some(id) => id,
None => return Err(location.new_custom_error(
StyleParseErrorKind::UnspecifiedError
)),
};
Some((ns, id))
} else {
None
};
@ -819,7 +806,7 @@ impl Attr {
}
// In the case of attr(foobar ) we don't want to error out
// because of the trailing whitespace
Token::WhiteSpace(_) => (),
Token::WhiteSpace(..) => {},
ref t => return Err(input.new_unexpected_token_error(t.clone())),
}
}
@ -841,8 +828,8 @@ impl ToCss for Attr {
W: Write,
{
dest.write_str("attr(")?;
if let Some(ref ns) = self.namespace {
serialize_identifier(&ns.0.to_string(), dest)?;
if let Some((ref prefix, _id)) = self.namespace {
serialize_atom_identifier(prefix, dest)?;
dest.write_str("|")?;
}
serialize_identifier(&self.attribute, dest)?;

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

@ -44,7 +44,7 @@ pub fn derive(input: DeriveInput) -> Tokens {
#expr
for item in #binding.iter() {
writer.item(item)?;
writer.item(&item)?;
}
};
} else {

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

@ -29,6 +29,7 @@ jobs:
BASE_TAG: '20171210'
SNAPSHOT: '20171210T214726Z'
packages:
- deb7-gdb
- deb7-git
- deb7-make
- deb7-mercurial

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

@ -175,3 +175,14 @@ jobs:
# of devscripts.
- deb7-devscripts-2.14
- deb7-dpkg-1.17
deb7-gdb:
description: "gdb for Debian wheezy"
treeherder:
symbol: Deb7(gdb)
run:
using: debian-package
dsc:
url: http://snapshot.debian.org/archive/debian/20170119T152956Z/pool/main/g/gdb/gdb_7.12-6.dsc
sha256: 9727dcb3d6b655e4f2a92110f5db076a490aa50b739804be239905ecff3aacc8
patch: gdb-wheezy.diff

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

@ -1,5 +1,5 @@
#!/bin/sh
for task in "$@"; do
echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task/$task/runs/0/artifacts/public/build/ debian/"
done > /etc/apt/sources.list.d/99packages.list
echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task/$task/runs/0/artifacts/public/build/ debian/" > "/etc/apt/sources.list.d/99$task.list"
done

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

@ -16,6 +16,38 @@ git clone -n https://github.com/llvm-mirror/llvm
cd llvm
git checkout 4727bc748a48e46824eae55a81ae890cd25c3a34
patch -p1 <<'EOF'
diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp
index 17559d2..b08a8d9 100644
--- a/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -304,20 +304,24 @@ DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
Optional<DWARFFormValue>
DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
if (!isValid())
return None;
if (auto Value = find(Attrs))
return Value;
if (auto Die = getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) {
+ if (Die.getOffset() == getOffset())
+ return None;
if (auto Value = Die.findRecursively(Attrs))
return Value;
}
if (auto Die = getAttributeValueAsReferencedDie(DW_AT_specification)) {
+ if (Die.getOffset() == getOffset())
+ return None;
if (auto Value = Die.findRecursively(Attrs))
return Value;
}
return None;
}
DWARFDie
DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
EOF
mkdir build
cd build

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

@ -304,7 +304,7 @@ class StructuredLogger(object):
if not self._ensure_suite_state('suite_end', data):
return
self._log_data("suite_end")
self._log_data("suite_end", data)
@log_action(TestId("test"),
Unicode("path", default=None, optional=True))

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

@ -169,6 +169,6 @@ window.talosDebug = {
};
// Enable testing outside of talos by providing an alternative report function.
if (typeof (tpRecordTime) === "undefined") {
if (typeof(tpRecordTime) === "undefined") {
tpRecordTime = window.talosDebug.tpRecordTime;
}

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

@ -286,7 +286,7 @@ Damp.prototype = {
reloadPage(onReload) {
return new Promise(resolve => {
let browser = gBrowser.selectedBrowser;
if (typeof (onReload) == "function") {
if (typeof(onReload) == "function") {
onReload().then(resolve);
} else {
browser.addEventListener("load", resolve, {capture: true, once: true});

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

@ -4,7 +4,7 @@ module.exports = {
rules: {
// XXX Bug 1326071 - This should be reduced down - probably to 20 or to
// be removed & synced with the mozilla/recommended value.
"complexity": ["error", 41],
"complexity": ["error", 44],
"mozilla/no-task": "error",
}

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

@ -5,7 +5,7 @@ module.exports = {
"rules": {
// XXX Bug 1358949 - This should be reduced down - probably to 20 or to
// be removed & synced with the mozilla/recommended value.
"complexity": ["error", 43],
"complexity": ["error", 56],
"no-unused-vars": ["error", {"args": "none", "vars": "local", "varsIgnorePattern": "^(ids|ignored|unused)$"}],
}

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

@ -5,7 +5,6 @@
<!-- This file is imported into the browser window, and expects various variables,
e.g. Ci, Services, to be available. -->
<!-- eslint-env mozilla/browser-window -->
<!DOCTYPE bindings [
<!ENTITY % commonDialogDTD SYSTEM "chrome://global/locale/commonDialog.dtd">

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

@ -9,7 +9,7 @@ module.exports = {
"block-scoped-var": "error",
"comma-dangle": ["error", "always-multiline"],
complexity: ["error", {
max: 20,
max: 23,
}],
curly: ["error", "all"],
"dot-location": ["error", "property"],

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

@ -5,7 +5,7 @@ module.exports = {
// Warn about cyclomatic complexity in functions.
// XXX Bug 1326071 - This should be reduced down - probably to 20 or to
// be removed & synced with the mozilla/recommended value.
"complexity": ["error", {"max": 60}],
"complexity": ["error", {"max": 68}],
"no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}],
}

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

@ -119,7 +119,7 @@ module.exports = {
// Warn about cyclomatic complexity in functions.
// XXX Get this down to 20?
"complexity": ["error", 32],
"complexity": ["error", 34],
// Don't require spaces around computed properties
"computed-property-spacing": ["error", "never"],

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

@ -4,7 +4,7 @@
"visibility": "public",
"filename": "eslint-plugin-mozilla.tar.gz",
"unpack": true,
"digest": "eadcdb0395a62b361817c88889546f7e21dbcf8b34afed1abd9e24ea769e32e5a6b6b46330e5bb3151e9337e2b0193d63bae71b40d3eac21a5b2164af4a909aa",
"size": 3516485
"digest": "0de957b34d0d49cb0d682b39bc9e956f5a77d9836fc70ed6cca588b2acf83cdd9f2d3f17cb4187591bad30e01173c6e286fb6e28df4453d8611951769d2674ac",
"size": 3171850
}
]

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше