mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
127e89f5dd
@ -90,7 +90,7 @@
|
||||
<div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
|
||||
<div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
|
||||
<div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
|
||||
<div id="ed_nssBadCert">&certerror.introPara1;</div>
|
||||
<div id="ed_nssBadCert">&certerror.introPara2;</div>
|
||||
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
|
||||
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
|
||||
<div id="ed_corruptedContentErrorv2">&corruptedContentErrorv2.longDesc;</div>
|
||||
|
@ -477,6 +477,7 @@ support-files =
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_e10s_chrome_process.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
skip-if = (os == 'linux' && debug) || (os == 'osx' && debug) # Bug 1444565
|
||||
[browser_e10s_javascript.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_blockHPKP.js]
|
||||
|
@ -244,13 +244,23 @@ function getBaseUriForChromeUri(chromeUri) {
|
||||
return fileUri.resolve(".");
|
||||
}
|
||||
|
||||
function trackChromeUri(uri) {
|
||||
gChromeMap.set(getBaseUriForChromeUri(uri), uri);
|
||||
}
|
||||
|
||||
// formautofill registers resource://formautofill/ and
|
||||
// chrome://formautofill/content/ dynamically at runtime.
|
||||
// Bug 1480276 is about addressing this without this hard-coding.
|
||||
trackResourcePrefix("formautofill");
|
||||
trackChromeUri("chrome://formautofill/content/");
|
||||
|
||||
function parseManifest(manifestUri) {
|
||||
return fetchFile(manifestUri.spec).then(data => {
|
||||
for (let line of data.split("\n")) {
|
||||
let [type, ...argv] = line.split(/\s+/);
|
||||
if (type == "content" || type == "skin" || type == "locale") {
|
||||
let chromeUri = `chrome://${argv[0]}/${type}/`;
|
||||
gChromeMap.set(getBaseUriForChromeUri(chromeUri), chromeUri);
|
||||
trackChromeUri(chromeUri);
|
||||
} else if (type == "override" || type == "overlay") {
|
||||
// Overlays aren't really overrides, but behave the same in
|
||||
// that the overlay is only referenced if the original xul
|
||||
@ -271,6 +281,35 @@ function parseManifest(manifestUri) {
|
||||
});
|
||||
}
|
||||
|
||||
// If the given URI is a webextension manifest, extract the scripts
|
||||
// for any embedded APIs. Returns the passed in URI if the manifest
|
||||
// is not a webextension manifest, null otherwise.
|
||||
async function parseJsonManifest(uri) {
|
||||
let raw = await fetchFile(uri.spec);
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(raw);
|
||||
} catch (ex) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// Simplistic test for whether this is a webextension manifest:
|
||||
if (data.manifest_version !== 2) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
if (data.experiment_apis) {
|
||||
for (let api of Object.values(data.experiment_apis)) {
|
||||
if (api.parent && api.parent.script) {
|
||||
let script = uri.resolve(api.parent.script);
|
||||
gReferencesFromCode.set(script, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function addCodeReference(url, fromURI) {
|
||||
let from = convertToCodeURI(fromURI.spec);
|
||||
|
||||
@ -546,11 +585,15 @@ add_task(async function checkAllTheFiles() {
|
||||
// NOTE that this must be done before filtering out devtools paths
|
||||
// so that all chrome paths can be recorded.
|
||||
let manifestURIs = [];
|
||||
let jsonManifests = [];
|
||||
uris = uris.filter(uri => {
|
||||
let path = uri.pathQueryRef;
|
||||
if (path.endsWith(".manifest")) {
|
||||
manifestURIs.push(uri);
|
||||
return false;
|
||||
} else if (path.endsWith("/manifest.json")) {
|
||||
jsonManifests.push(uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -559,6 +602,15 @@ add_task(async function checkAllTheFiles() {
|
||||
// Wait for all manifest to be parsed
|
||||
await throttledMapPromises(manifestURIs, parseManifest);
|
||||
|
||||
// manifest.json is a common name, it is used for WebExtension manifests
|
||||
// but also for other things. To tell them apart, we have to actually
|
||||
// read the contents. This will populate gExtensionRoots with all
|
||||
// embedded extension APIs, and return any manifest.json files that aren't
|
||||
// webextensions.
|
||||
let nonWebextManifests = (await Promise.all(jsonManifests.map(parseJsonManifest)))
|
||||
.filter(uri => !!uri);
|
||||
uris.push(...nonWebextManifests);
|
||||
|
||||
addActorModules();
|
||||
|
||||
// We build a list of promises that get resolved when their respective
|
||||
|
@ -14,7 +14,7 @@ let gWhitelist = [{
|
||||
type: "single-quote"
|
||||
}, {
|
||||
file: "netError.dtd",
|
||||
key: "certerror.introPara1",
|
||||
key: "certerror.introPara2",
|
||||
type: "single-quote"
|
||||
}, {
|
||||
file: "netError.dtd",
|
||||
|
@ -218,6 +218,7 @@ skip-if = os == 'mac' # Save as PDF not supported on Mac OS X
|
||||
[browser_ext_themes_icons.js]
|
||||
[browser_ext_themes_validation.js]
|
||||
[browser_ext_url_overrides_newtab.js]
|
||||
skip-if = (os == 'linux' && debug) || (os == 'win' && debug) # Bug 1465508
|
||||
[browser_ext_user_events.js]
|
||||
[browser_ext_webRequest.js]
|
||||
[browser_ext_webNavigation_frameId0.js]
|
||||
|
@ -2,6 +2,10 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
// There are shutdown issues for which multiple rejections are left uncaught.
|
||||
// See bug 1018184 for resolving these issues.
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserToolboxProcess",
|
||||
"resource://devtools/client/framework/ToolboxProcess.jsm");
|
||||
|
||||
@ -111,6 +115,8 @@ add_task(async function test_addon_debugging_netmonitor_panel() {
|
||||
// Call a function defined in the target extension to make assertions
|
||||
// on the network requests collected by the netmonitor panel.
|
||||
await jsterm.execute(`testNetworkRequestReceived(${JSON.stringify(requests)});`);
|
||||
|
||||
await toolbox.destroy();
|
||||
/* eslint-enable no-undef */
|
||||
};
|
||||
|
||||
@ -119,11 +125,8 @@ add_task(async function test_addon_debugging_netmonitor_panel() {
|
||||
addonID: EXTENSION_ID,
|
||||
});
|
||||
|
||||
await extension.awaitFinish("netmonitor_request_logged");
|
||||
|
||||
let onToolboxClose = browserToolboxProcess.once("close");
|
||||
await browserToolboxProcess.close();
|
||||
|
||||
await extension.awaitFinish("netmonitor_request_logged");
|
||||
await onToolboxClose;
|
||||
|
||||
info("Addon Toolbox closed");
|
||||
|
@ -1790,6 +1790,10 @@ FormAutofillStorage.prototype = {
|
||||
_saveImmediately() {
|
||||
return this._store._save();
|
||||
},
|
||||
|
||||
_finalize() {
|
||||
return this._store.finalize();
|
||||
},
|
||||
};
|
||||
|
||||
// The singleton exposed by this module.
|
||||
|
145
browser/extensions/formautofill/api.js
Normal file
145
browser/extensions/formautofill/api.js
Normal file
@ -0,0 +1,145 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* globals ExtensionAPI */
|
||||
|
||||
const STYLESHEET_URI = "chrome://formautofill/content/formautofill.css";
|
||||
const CACHED_STYLESHEETS = new WeakMap();
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "FormAutofill",
|
||||
"resource://formautofill/FormAutofill.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "formAutofillParent",
|
||||
"resource://formautofill/FormAutofillParent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
"nsISubstitutingProtocolHandler");
|
||||
|
||||
const RESOURCE_HOST = "formautofill";
|
||||
|
||||
function insertStyleSheet(domWindow, url) {
|
||||
let doc = domWindow.document;
|
||||
let styleSheetAttr = `href="${url}" type="text/css"`;
|
||||
let styleSheet = doc.createProcessingInstruction("xml-stylesheet", styleSheetAttr);
|
||||
|
||||
doc.insertBefore(styleSheet, doc.documentElement);
|
||||
|
||||
if (CACHED_STYLESHEETS.has(domWindow)) {
|
||||
CACHED_STYLESHEETS.get(domWindow).push(styleSheet);
|
||||
} else {
|
||||
CACHED_STYLESHEETS.set(domWindow, [styleSheet]);
|
||||
}
|
||||
}
|
||||
|
||||
function onMaybeOpenPopup(evt) {
|
||||
let domWindow = evt.target.ownerGlobal;
|
||||
if (CACHED_STYLESHEETS.has(domWindow)) {
|
||||
// This window already has autofill stylesheets.
|
||||
return;
|
||||
}
|
||||
|
||||
insertStyleSheet(domWindow, STYLESHEET_URI);
|
||||
}
|
||||
|
||||
function isAvailable() {
|
||||
let availablePref = Services.prefs.getCharPref("extensions.formautofill.available");
|
||||
if (availablePref == "on") {
|
||||
return true;
|
||||
} else if (availablePref == "detect") {
|
||||
let locale = Services.locale.getRequestedLocale();
|
||||
let region = Services.prefs.getCharPref("browser.search.region", "");
|
||||
let supportedCountries = Services.prefs.getCharPref("extensions.formautofill.supportedCountries")
|
||||
.split(",");
|
||||
if (!Services.prefs.getBoolPref("extensions.formautofill.supportRTL") &&
|
||||
Services.locale.isAppLocaleRTL) {
|
||||
return false;
|
||||
}
|
||||
return locale == "en-US" && supportedCountries.includes(region);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.formautofill = class extends ExtensionAPI {
|
||||
onStartup() {
|
||||
// We have to do this before actually determining if we're enabled, since
|
||||
// there are scripts inside of the core browser code that depend on the
|
||||
// FormAutofill JSMs being registered.
|
||||
let uri = Services.io.newURI("chrome/res/", null, this.extension.rootURI);
|
||||
resProto.setSubstitution(RESOURCE_HOST, uri);
|
||||
|
||||
let aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"]
|
||||
.getService(Ci.amIAddonManagerStartup);
|
||||
const manifestURI = Services.io.newURI("manifest.json", null, this.extension.rootURI);
|
||||
this.chromeHandle = aomStartup.registerChrome(manifestURI, [
|
||||
["content", "formautofill", "chrome/content/"],
|
||||
["locale", "formautofill", "en-US", "en-US/locale/en-US/"],
|
||||
]);
|
||||
|
||||
if (!isAvailable()) {
|
||||
Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
|
||||
// reset the sync related prefs incase the feature was previously available
|
||||
// but isn't now.
|
||||
Services.prefs.clearUserPref("services.sync.engine.addresses.available");
|
||||
Services.prefs.clearUserPref("services.sync.engine.creditcards.available");
|
||||
Services.telemetry.scalarSet("formautofill.availability", false);
|
||||
return;
|
||||
}
|
||||
|
||||
// This pref is used for web contents to detect the autocomplete feature.
|
||||
// When it's true, "element.autocomplete" will return tokens we currently
|
||||
// support -- otherwise it'll return an empty string.
|
||||
Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
|
||||
Services.telemetry.scalarSet("formautofill.availability", true);
|
||||
|
||||
// This pref determines whether the "addresses"/"creditcards" sync engine is
|
||||
// available (ie, whether it is shown in any UI etc) - it *does not* determine
|
||||
// whether the engine is actually enabled or not.
|
||||
Services.prefs.setBoolPref("services.sync.engine.addresses.available", true);
|
||||
if (FormAutofill.isAutofillCreditCardsAvailable) {
|
||||
Services.prefs.setBoolPref("services.sync.engine.creditcards.available", true);
|
||||
} else {
|
||||
Services.prefs.clearUserPref("services.sync.engine.creditcards.available");
|
||||
}
|
||||
|
||||
// Listen for the autocomplete popup message to lazily append our stylesheet related to the popup.
|
||||
Services.mm.addMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
|
||||
|
||||
formAutofillParent.init().catch(Cu.reportError);
|
||||
/* eslint-disable no-unused-vars */
|
||||
Services.ppmm.loadProcessScript("data:,new " + function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
}, true);
|
||||
/* eslint-enable no-unused-vars */
|
||||
Services.mm.loadFrameScript("chrome://formautofill/content/FormAutofillFrameScript.js", true, true);
|
||||
}
|
||||
|
||||
onShutdown() {
|
||||
resProto.setSubstitution(RESOURCE_HOST, null);
|
||||
|
||||
this.chromeHandle.destruct();
|
||||
this.chromeHandle = null;
|
||||
|
||||
Services.mm.removeMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
|
||||
|
||||
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let win = enumerator.getNext();
|
||||
let domWindow = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
|
||||
let cachedStyleSheets = CACHED_STYLESHEETS.get(domWindow);
|
||||
|
||||
if (!cachedStyleSheets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (cachedStyleSheets.length !== 0) {
|
||||
cachedStyleSheets.pop().remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
8
browser/extensions/formautofill/background.js
Normal file
8
browser/extensions/formautofill/background.js
Normal file
@ -0,0 +1,8 @@
|
||||
/* eslint-env webextensions */
|
||||
|
||||
"use strict";
|
||||
|
||||
browser.runtime.onUpdateAvailable.addListener(details => {
|
||||
// By listening to but ignoring this event, any updates will
|
||||
// be delayed until the next browser restart.
|
||||
});
|
159
browser/extensions/formautofill/bootstrap.js
vendored
159
browser/extensions/formautofill/bootstrap.js
vendored
@ -1,159 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* exported startup, shutdown, install, uninstall */
|
||||
|
||||
const STYLESHEET_URI = "chrome://formautofill/content/formautofill.css";
|
||||
const CACHED_STYLESHEETS = new WeakMap();
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "AddonManagerPrivate",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "FormAutofill",
|
||||
"resource://formautofill/FormAutofill.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "formAutofillParent",
|
||||
"resource://formautofill/FormAutofillParent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
"nsISubstitutingProtocolHandler");
|
||||
|
||||
const RESOURCE_HOST = "formautofill";
|
||||
|
||||
function insertStyleSheet(domWindow, url) {
|
||||
let doc = domWindow.document;
|
||||
let styleSheetAttr = `href="${url}" type="text/css"`;
|
||||
let styleSheet = doc.createProcessingInstruction("xml-stylesheet", styleSheetAttr);
|
||||
|
||||
doc.insertBefore(styleSheet, doc.documentElement);
|
||||
|
||||
if (CACHED_STYLESHEETS.has(domWindow)) {
|
||||
CACHED_STYLESHEETS.get(domWindow).push(styleSheet);
|
||||
} else {
|
||||
CACHED_STYLESHEETS.set(domWindow, [styleSheet]);
|
||||
}
|
||||
}
|
||||
|
||||
function onMaybeOpenPopup(evt) {
|
||||
let domWindow = evt.target.ownerGlobal;
|
||||
if (CACHED_STYLESHEETS.has(domWindow)) {
|
||||
// This window already has autofill stylesheets.
|
||||
return;
|
||||
}
|
||||
|
||||
insertStyleSheet(domWindow, STYLESHEET_URI);
|
||||
}
|
||||
|
||||
function addUpgradeListener(instanceID) {
|
||||
AddonManager.addUpgradeListener(instanceID, upgrade => {
|
||||
// don't install the upgrade by doing nothing here.
|
||||
// The upgrade will be installed upon next restart.
|
||||
});
|
||||
}
|
||||
|
||||
function isAvailable() {
|
||||
let availablePref = Services.prefs.getCharPref("extensions.formautofill.available");
|
||||
if (availablePref == "on") {
|
||||
return true;
|
||||
} else if (availablePref == "detect") {
|
||||
let locale = Services.locale.getRequestedLocale();
|
||||
let region = Services.prefs.getCharPref("browser.search.region", "");
|
||||
let supportedCountries = Services.prefs.getCharPref("extensions.formautofill.supportedCountries")
|
||||
.split(",");
|
||||
if (!Services.prefs.getBoolPref("extensions.formautofill.supportRTL") &&
|
||||
Services.locale.isAppLocaleRTL) {
|
||||
return false;
|
||||
}
|
||||
return locale == "en-US" && supportedCountries.includes(region);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function startup(data) {
|
||||
// We have to do this before actually determining if we're enabled, since
|
||||
// there are scripts inside of the core browser code that depend on the
|
||||
// FormAutofill JSMs being registered.
|
||||
resProto.setSubstitution(RESOURCE_HOST,
|
||||
Services.io.newURI("chrome/res/", null, data.resourceURI));
|
||||
|
||||
if (!isAvailable()) {
|
||||
Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
|
||||
// reset the sync related prefs incase the feature was previously available
|
||||
// but isn't now.
|
||||
Services.prefs.clearUserPref("services.sync.engine.addresses.available");
|
||||
Services.prefs.clearUserPref("services.sync.engine.creditcards.available");
|
||||
Services.telemetry.scalarSet("formautofill.availability", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty("instanceID") && data.instanceID) {
|
||||
if (AddonManagerPrivate.isDBLoaded()) {
|
||||
addUpgradeListener(data.instanceID);
|
||||
} else {
|
||||
// Wait for the extension database to be loaded so we don't cause its init.
|
||||
Services.obs.addObserver(function xpiDatabaseLoaded() {
|
||||
Services.obs.removeObserver(xpiDatabaseLoaded, "xpi-database-loaded");
|
||||
addUpgradeListener(data.instanceID);
|
||||
}, "xpi-database-loaded");
|
||||
}
|
||||
} else {
|
||||
throw Error("no instanceID passed to bootstrap startup");
|
||||
}
|
||||
|
||||
// This pref is used for web contents to detect the autocomplete feature.
|
||||
// When it's true, "element.autocomplete" will return tokens we currently
|
||||
// support -- otherwise it'll return an empty string.
|
||||
Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
|
||||
Services.telemetry.scalarSet("formautofill.availability", true);
|
||||
|
||||
// This pref determines whether the "addresses"/"creditcards" sync engine is
|
||||
// available (ie, whether it is shown in any UI etc) - it *does not* determine
|
||||
// whether the engine is actually enabled or not.
|
||||
Services.prefs.setBoolPref("services.sync.engine.addresses.available", true);
|
||||
if (FormAutofill.isAutofillCreditCardsAvailable) {
|
||||
Services.prefs.setBoolPref("services.sync.engine.creditcards.available", true);
|
||||
} else {
|
||||
Services.prefs.clearUserPref("services.sync.engine.creditcards.available");
|
||||
}
|
||||
|
||||
// Listen for the autocomplete popup message to lazily append our stylesheet related to the popup.
|
||||
Services.mm.addMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
|
||||
|
||||
formAutofillParent.init().catch(Cu.reportError);
|
||||
/* eslint-disable no-unused-vars */
|
||||
Services.ppmm.loadProcessScript("data:,new " + function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
}, true);
|
||||
/* eslint-enable no-unused-vars */
|
||||
Services.mm.loadFrameScript("chrome://formautofill/content/FormAutofillFrameScript.js", true, true);
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
resProto.setSubstitution(RESOURCE_HOST, null);
|
||||
|
||||
Services.mm.removeMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
|
||||
|
||||
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let win = enumerator.getNext();
|
||||
let domWindow = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
|
||||
let cachedStyleSheets = CACHED_STYLESHEETS.get(domWindow);
|
||||
|
||||
if (!cachedStyleSheets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (cachedStyleSheets.length !== 0) {
|
||||
cachedStyleSheets.pop().remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function install() {}
|
||||
function uninstall() {}
|
@ -9,9 +9,9 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title data-localization="addNewAddressTitle"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill-shared/skin/editAddress.css"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editDialog-shared.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editAddress.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editDialog.css"/>
|
||||
<script src="chrome://formautofill/content/l10n.js"></script>
|
||||
<script src="chrome://formautofill/content/editDialog.js"></script>
|
||||
<script src="chrome://formautofill/content/autofillEditForms.js"></script>
|
||||
|
@ -9,9 +9,9 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title data-localization="addNewCreditCardTitle"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill-shared/skin/editCreditCard.css"/>
|
||||
<link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editDialog-shared.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editCreditCard.css"/>
|
||||
<link rel="stylesheet" href="resource://formautofill/editDialog.css"/>
|
||||
<script src="chrome://formautofill/content/l10n.js"></script>
|
||||
<script src="chrome://formautofill/content/editDialog.js"></script>
|
||||
<script src="chrome://formautofill/content/autofillEditForms.js"></script>
|
||||
|
@ -1,32 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
#filter substitution
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>formautofill@mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
||||
<!-- Target Application this extension can install into,
|
||||
with minimum and maximum supported versions. -->
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
|
||||
<em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Form Autofill</em:name>
|
||||
<em:description>Autofill forms with saved profiles</em:description>
|
||||
</Description>
|
||||
</RDF>
|
@ -3,16 +3,9 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[features/formautofill@mozilla.org] chrome.jar:
|
||||
% resource formautofill %res/
|
||||
res/ (*.jsm)
|
||||
res/phonenumberutils/ (phonenumberutils/*.jsm)
|
||||
res/addressmetadata/ (addressmetadata/*)
|
||||
res/ (skin/shared/*)
|
||||
|
||||
% content formautofill %content/
|
||||
content/ (content/*)
|
||||
|
||||
% skin formautofill classic/1.0 %skin/linux/ os=LikeUnix
|
||||
% skin formautofill classic/1.0 %skin/osx/ os=Darwin
|
||||
% skin formautofill classic/1.0 %skin/windows/ os=WINNT
|
||||
% skin formautofill-shared classic/1.0 %skin/shared/
|
||||
skin/ (skin/*)
|
||||
|
26
browser/extensions/formautofill/manifest.json
Normal file
26
browser/extensions/formautofill/manifest.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Form Autofill",
|
||||
"version": "1.0",
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "formautofill@mozilla.org"
|
||||
}
|
||||
},
|
||||
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
"experiment_apis": {
|
||||
"formautofill": {
|
||||
"schema": "schema.json",
|
||||
"parent": {
|
||||
"scopes": ["addon_parent"],
|
||||
"script": "api.js",
|
||||
"events": ["startup"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,12 +10,27 @@ DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
|
||||
DIRS += ['locales']
|
||||
|
||||
FINAL_TARGET_FILES.features['formautofill@mozilla.org'] += [
|
||||
'bootstrap.js'
|
||||
'api.js',
|
||||
'background.js',
|
||||
'manifest.json',
|
||||
'schema.json',
|
||||
]
|
||||
|
||||
FINAL_TARGET_PP_FILES.features['formautofill@mozilla.org'] += [
|
||||
'install.rdf.in'
|
||||
]
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
FINAL_TARGET_FILES.features['formautofill@mozilla.org'].chrome.res += [
|
||||
'skin/linux/autocomplete-item.css',
|
||||
'skin/linux/editDialog.css',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'Darwin':
|
||||
FINAL_TARGET_FILES.features['formautofill@mozilla.org'].chrome.res += [
|
||||
'skin/osx/autocomplete-item.css',
|
||||
'skin/osx/editDialog.css',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'WINNT':
|
||||
FINAL_TARGET_FILES.features['formautofill@mozilla.org'].chrome.res += [
|
||||
'skin/windows/autocomplete-item.css',
|
||||
'skin/windows/editDialog.css',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
|
||||
|
1
browser/extensions/formautofill/schema.json
Normal file
1
browser/extensions/formautofill/schema.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
@ -8,6 +8,9 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/ObjectUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/FormLikeFactory.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/FileTestUtils.jsm");
|
||||
ChromeUtils.import("resource://testing-common/MockDocument.jsm");
|
||||
ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
@ -17,9 +20,8 @@ ChromeUtils.defineModuleGetter(this, "DownloadPaths",
|
||||
ChromeUtils.defineModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
"nsISubstitutingProtocolHandler");
|
||||
ChromeUtils.defineModuleGetter(this, "ExtensionParent",
|
||||
"resource://gre/modules/ExtensionParent.jsm");
|
||||
|
||||
do_get_profile();
|
||||
|
||||
@ -31,26 +33,38 @@ Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js",
|
||||
/* globals sinon */
|
||||
// ================================================
|
||||
|
||||
// Load our bootstrap extension manifest so we can access our chrome/resource URIs.
|
||||
const EXTENSION_ID = "formautofill@mozilla.org";
|
||||
let extensionDir = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
extensionDir.append("browser");
|
||||
extensionDir.append("features");
|
||||
extensionDir.append(EXTENSION_ID);
|
||||
let bootstrapFile = extensionDir.clone();
|
||||
bootstrapFile.append("bootstrap.js");
|
||||
let bootstrapURI = Services.io.newFileURI(bootstrapFile).spec;
|
||||
// If the unpacked extension doesn't exist, use the packed version.
|
||||
if (!extensionDir.exists()) {
|
||||
extensionDir = extensionDir.parent;
|
||||
extensionDir.append(EXTENSION_ID + ".xpi");
|
||||
let jarURI = Services.io.newFileURI(extensionDir);
|
||||
bootstrapURI = "jar:" + jarURI.spec + "!/bootstrap.js";
|
||||
}
|
||||
Components.manager.addBootstrappedManifestLocation(extensionDir);
|
||||
|
||||
let resURI = Services.io.newURI("chrome/res/", null, Services.io.newURI(bootstrapURI));
|
||||
resProto.setSubstitution("formautofill", resURI);
|
||||
AddonTestUtils.init(this);
|
||||
|
||||
async function loadExtension() {
|
||||
AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
|
||||
let extensionPath = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
extensionPath.append("browser");
|
||||
extensionPath.append("features");
|
||||
extensionPath.append(EXTENSION_ID);
|
||||
|
||||
if (!extensionPath.exists()) {
|
||||
extensionPath.leafName = `${EXTENSION_ID}.xpi`;
|
||||
}
|
||||
|
||||
let startupPromise = new Promise(resolve => {
|
||||
const {apiManager} = ExtensionParent;
|
||||
function onReady(event, extension) {
|
||||
if (extension.id == EXTENSION_ID) {
|
||||
apiManager.off("ready", onReady);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
apiManager.on("ready", onReady);
|
||||
});
|
||||
|
||||
await AddonManager.installTemporaryAddon(extensionPath);
|
||||
await startupPromise;
|
||||
}
|
||||
|
||||
// Returns a reference to a temporary file that is guaranteed not to exist and
|
||||
// is cleaned up later. See FileTestUtils.getTempFile for details.
|
||||
@ -64,6 +78,15 @@ async function initProfileStorage(fileName, records, collectionName = "addresses
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
// AddonTestUtils inserts its own directory provider that manages TmpD.
|
||||
// It removes that directory at shutdown, which races with shutdown
|
||||
// handing in JSONFile/DeferredTask (which is used by FormAutofillStorage).
|
||||
// Avoid the race by explicitly finalizing any formautofill JSONFile
|
||||
// instances created manually by individual tests when the test finishes.
|
||||
registerCleanupFunction(function finalizeAutofillStorage() {
|
||||
return profileStorage._finalize();
|
||||
});
|
||||
|
||||
if (!records || !Array.isArray(records)) {
|
||||
return profileStorage;
|
||||
}
|
||||
@ -99,9 +122,11 @@ function verifySectionFieldDetails(sections, expectedResults) {
|
||||
});
|
||||
}
|
||||
|
||||
function runHeuristicsTest(patterns, fixturePathPrefix) {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
async function runHeuristicsTest(patterns, fixturePathPrefix) {
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
patterns.forEach(testPattern => {
|
||||
add_task(async function() {
|
||||
@ -194,4 +219,6 @@ add_task(async function head_initialize() {
|
||||
Services.prefs.clearUserPref("extensions.formautofill.section.enabled");
|
||||
Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
|
||||
});
|
||||
|
||||
await loadExtension();
|
||||
});
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let {FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {});
|
||||
let FormAutofillParent;
|
||||
|
||||
add_task(async function setup() {
|
||||
({FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {}));
|
||||
});
|
||||
|
||||
add_task(async function test_activeStatus_init() {
|
||||
let formAutofillParent = new FormAutofillParent();
|
||||
|
@ -1,7 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
const SUPPORT_COUNTRIES_TESTCASES = [
|
||||
{
|
||||
country: "US",
|
||||
@ -17,6 +15,10 @@ const SUPPORT_COUNTRIES_TESTCASES = [
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
add_task(async function test_initalState() {
|
||||
// addressData should not exist
|
||||
Assert.equal(AddressDataLoader._addressData, undefined);
|
||||
|
@ -5,8 +5,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
let {MasterPassword} = ChromeUtils.import("resource://formautofill/MasterPassword.jsm", {});
|
||||
let MasterPassword;
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
({MasterPassword} = ChromeUtils.import("resource://formautofill/MasterPassword.jsm", {}));
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
add_task(async function seutp() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -4,11 +4,15 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
|
||||
ChromeUtils.defineModuleGetter(this, "Preferences",
|
||||
"resource://gre/modules/Preferences.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/CreditCard.jsm");
|
||||
|
||||
let FormAutofillStorage;
|
||||
add_task(async function setup() {
|
||||
({FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {}));
|
||||
});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-credit-card.json";
|
||||
const COLLECTION_NAME = "creditCards";
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm");
|
||||
});
|
||||
|
||||
const DEFAULT_ADDRESS_RECORD = {
|
||||
"guid": "123",
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
add_task(async function test_isAddressField_isCreditCardField() {
|
||||
const TEST_CASES = {
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -4,10 +4,14 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let {FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {});
|
||||
ChromeUtils.import("resource://formautofill/MasterPassword.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/CreditCard.jsm");
|
||||
|
||||
let FormAutofillParent;
|
||||
add_task(async function setup() {
|
||||
({FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {}));
|
||||
ChromeUtils.import("resource://formautofill/MasterPassword.jsm");
|
||||
});
|
||||
|
||||
const TEST_ADDRESS_1 = {
|
||||
"given-name": "Timothy",
|
||||
"additional-name": "John",
|
||||
|
@ -4,13 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Load bootstrap.js into a sandbox to be able to test `isAvailable`
|
||||
let sandbox = {};
|
||||
Services.scriptloader.loadSubScript(bootstrapURI, sandbox, "utf-8");
|
||||
info("bootstrapURI: " + bootstrapURI);
|
||||
const DOM_ENABLED_PREF = "dom.forms.autocomplete.formautofill";
|
||||
|
||||
add_task(async function test_defaultTestEnvironment() {
|
||||
Assert.ok(sandbox.isAvailable());
|
||||
Assert.ok(Services.prefs.getBoolPref(DOM_ENABLED_PREF));
|
||||
});
|
||||
|
||||
add_task(async function test_unsupportedRegion() {
|
||||
@ -19,7 +16,11 @@ add_task(async function test_unsupportedRegion() {
|
||||
registerCleanupFunction(function cleanupRegion() {
|
||||
Services.prefs.clearUserPref("browser.search.region");
|
||||
});
|
||||
Assert.ok(!sandbox.isAvailable());
|
||||
|
||||
let addon = await AddonManager.getAddonByID(EXTENSION_ID);
|
||||
await addon.reload();
|
||||
|
||||
Assert.ok(!Services.prefs.getBoolPref(DOM_ENABLED_PREF));
|
||||
});
|
||||
|
||||
add_task(async function test_supportedRegion() {
|
||||
@ -28,5 +29,9 @@ add_task(async function test_supportedRegion() {
|
||||
registerCleanupFunction(function cleanupRegion() {
|
||||
Services.prefs.clearUserPref("browser.search.region");
|
||||
});
|
||||
Assert.ok(sandbox.isAvailable());
|
||||
|
||||
let addon = await AddonManager.getAddonByID(EXTENSION_ID);
|
||||
await addon.reload();
|
||||
|
||||
Assert.ok(Services.prefs.getBoolPref(DOM_ENABLED_PREF));
|
||||
});
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillNameUtils.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillNameUtils.jsm");
|
||||
});
|
||||
|
||||
// Test cases is initially copied from
|
||||
// https://cs.chromium.org/chromium/src/components/autofill/core/browser/autofill_data_util_unittest.cc
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
add_task(async function seutp() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
description: "Form containing 8 fields with autocomplete attribute.",
|
||||
@ -61,9 +59,14 @@ const TESTCASES = [
|
||||
];
|
||||
|
||||
let markedFieldId = [];
|
||||
FormAutofillContent._markAsAutofillField = function(field) {
|
||||
markedFieldId.push(field.id);
|
||||
};
|
||||
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
|
||||
FormAutofillContent._markAsAutofillField = function(field) {
|
||||
markedFieldId.push(field.id);
|
||||
};
|
||||
});
|
||||
|
||||
TESTCASES.forEach(testcase => {
|
||||
add_task(async function() {
|
||||
|
@ -5,7 +5,11 @@
|
||||
"use strict";
|
||||
const {MockRegistrar} =
|
||||
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm", {});
|
||||
let {MasterPassword} = ChromeUtils.import("resource://formautofill/MasterPassword.jsm", {});
|
||||
|
||||
let MasterPassword;
|
||||
add_task(async function setup() {
|
||||
({MasterPassword} = ChromeUtils.import("resource://formautofill/MasterPassword.jsm", {}));
|
||||
});
|
||||
|
||||
const TESTCASES = [{
|
||||
description: "With master password set",
|
||||
@ -67,10 +71,10 @@ registerCleanupFunction(() => {
|
||||
});
|
||||
|
||||
TESTCASES.forEach(testcase => {
|
||||
let token = MasterPassword._token;
|
||||
|
||||
add_task(async function test_encrypt_decrypt() {
|
||||
info("Starting testcase: " + testcase.description);
|
||||
|
||||
let token = MasterPassword._token;
|
||||
token.initPassword(testcase.masterPassword);
|
||||
|
||||
// Test only: Force the token login without asking for master password
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
|
||||
let FormAutofillStorage;
|
||||
|
||||
add_task(async function setup() {
|
||||
({FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {}));
|
||||
});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-profile.json";
|
||||
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillNameUtils.jsm");
|
||||
add_task(async function() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillNameUtils.jsm");
|
||||
});
|
||||
|
||||
// Test cases initially copied from
|
||||
// https://cs.chromium.org/chromium/src/components/autofill/core/browser/autofill_data_util_unittest.cc
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
});
|
||||
|
||||
const MOCK_DOC = MockDocument.createTestDocument("http://localhost:8080/test/",
|
||||
`<form id="form1">
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
add_task(async function test_parseAddressFormat() {
|
||||
const TEST_CASES = [
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/phonenumberutils/PhoneNumber.jsm");
|
||||
ChromeUtils.import("resource://formautofill/phonenumberutils/PhoneNumberNormalizer.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/phonenumberutils/PhoneNumber.jsm");
|
||||
ChromeUtils.import("resource://formautofill/phonenumberutils/PhoneNumberNormalizer.jsm");
|
||||
});
|
||||
|
||||
function IsPlain(dial, expected) {
|
||||
let result = PhoneNumber.IsPlain(dial);
|
||||
|
@ -1,8 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
/* global AddressResult, CreditCardResult */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
ChromeUtils.import("resource://formautofill/ProfileAutoCompleteResult.jsm");
|
||||
add_task(async function setup() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
ChromeUtils.import("resource://formautofill/ProfileAutoCompleteResult.jsm");
|
||||
});
|
||||
|
||||
let matchingProfiles = [{
|
||||
guid: "test-guid-1",
|
||||
@ -341,15 +343,15 @@ let creditCardTestCases = [{
|
||||
},
|
||||
}];
|
||||
|
||||
let testSets = [{
|
||||
collectionConstructor: AddressResult,
|
||||
testCases: addressTestCases,
|
||||
}, {
|
||||
collectionConstructor: CreditCardResult,
|
||||
testCases: creditCardTestCases,
|
||||
}];
|
||||
|
||||
add_task(async function test_all_patterns() {
|
||||
let testSets = [{
|
||||
collectionConstructor: AddressResult,
|
||||
testCases: addressTestCases,
|
||||
}, {
|
||||
collectionConstructor: CreditCardResult,
|
||||
testCases: creditCardTestCases,
|
||||
}];
|
||||
|
||||
testSets.forEach(({collectionConstructor, testCases}) => {
|
||||
testCases.forEach(testCase => {
|
||||
info("Starting testcase: " + testCase.description);
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let {FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {});
|
||||
let FormAutofillParent;
|
||||
|
||||
add_task(async function setup() {
|
||||
({FormAutofillParent} = ChromeUtils.import("resource://formautofill/FormAutofillParent.jsm", {}));
|
||||
});
|
||||
|
||||
add_task(async function test_profileSavedFieldNames_init() {
|
||||
let formAutofillParent = new FormAutofillParent();
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
|
||||
let FormAutofillStorage;
|
||||
add_task(async function setup() {
|
||||
({FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {}));
|
||||
});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-tombstones.json";
|
||||
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
|
||||
let FormAutofillStorage;
|
||||
add_task(async function setup() {
|
||||
({FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {}));
|
||||
});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-tombstones.json";
|
||||
|
||||
|
@ -13,8 +13,11 @@ ChromeUtils.import("resource://services-sync/service.js");
|
||||
ChromeUtils.import("resource://services-sync/constants.js");
|
||||
ChromeUtils.import("resource://testing-common/services/sync/utils.js");
|
||||
|
||||
let {sanitizeStorageObject, AutofillRecord, AddressesEngine} =
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillSync.jsm", {});
|
||||
let sanitizeStorageObject, AutofillRecord, AddressesEngine;
|
||||
add_task(async function() {
|
||||
({sanitizeStorageObject, AutofillRecord, AddressesEngine} =
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillSync.jsm", {}));
|
||||
});
|
||||
|
||||
|
||||
Services.prefs.setCharPref("extensions.formautofill.loglevel", "Trace");
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
add_task(async function setup() {
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
});
|
||||
|
||||
add_task(async function test_getCategoriesFromFieldNames() {
|
||||
const TEST_CASES = [
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
|
||||
let FormAutofillStorage;
|
||||
add_task(async function setup() {
|
||||
({FormAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {}));
|
||||
});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-profile.json";
|
||||
|
||||
@ -901,6 +904,8 @@ add_task(async function test_computeAddressFields() {
|
||||
|
||||
profileStorage.addresses.remove(guid);
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
|
||||
add_task(async function test_normalizeAddressFields() {
|
||||
@ -918,6 +923,8 @@ add_task(async function test_normalizeAddressFields() {
|
||||
|
||||
profileStorage.addresses.remove(guid);
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
|
||||
add_task(async function test_computeCreditCardFields() {
|
||||
@ -935,6 +942,8 @@ add_task(async function test_computeCreditCardFields() {
|
||||
|
||||
profileStorage.creditCards.remove(guid);
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
|
||||
add_task(async function test_normalizeCreditCardFields() {
|
||||
@ -952,4 +961,6 @@ add_task(async function test_normalizeCreditCardFields() {
|
||||
|
||||
profileStorage.creditCards.remove(guid);
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
|
@ -150,11 +150,11 @@
|
||||
|
||||
<!ENTITY certerror.longpagetitle1 "Your connection is not secure">
|
||||
<!ENTITY certerror.longpagetitle2 "Warning: Potential Security Risk Ahead">
|
||||
<!-- Localization note (certerror.introPara, certerror.introPara1) - The text content of the span tag
|
||||
<!-- Localization note (certerror.introPara, certerror.introPara2) - The text content of the span tag
|
||||
will be replaced at runtime with the name of the server to which the user
|
||||
was trying to connect. -->
|
||||
<!ENTITY certerror.introPara "The owner of <span class='hostname'/> has configured their website improperly. To protect your information from being stolen, &brandShortName; has not connected to this website.">
|
||||
<!ENTITY certerror.introPara1 "&brandShortName; detected a potential security threat and did not continue to <span class='hostname'/>. If you visit this site, attackers could try to steal information like your passwords, emails, or credit cards.">
|
||||
<!ENTITY certerror.introPara2 "&brandShortName; detected a potential security threat and did not continue to <span class='hostname'/>. If you visit this site, attackers could try to steal information like your passwords, emails, or credit card details.">
|
||||
|
||||
<!ENTITY certerror.expiredCert.secondPara "This issue is most likely because your computer clock is set to the wrong time, which would prevent &brandShortName; from connecting securely.">
|
||||
|
||||
|
@ -36,15 +36,6 @@ def GeckoBinary(linkage='dependent', mozglue=None):
|
||||
elif linkage != None:
|
||||
error('`linkage` must be "dependent", "standalone" or None')
|
||||
|
||||
if CONFIG['LIBFUZZER']:
|
||||
assert mozglue is not None, 'libfuzzer depends on "mozglue"'
|
||||
USE_LIBS += [
|
||||
'fuzzer'
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/tools/fuzzing/libfuzzer'
|
||||
]
|
||||
|
||||
if mozglue:
|
||||
LDFLAGS += CONFIG['MOZ_GLUE_WRAP_LDFLAGS']
|
||||
if mozglue == 'program':
|
||||
|
@ -4,7 +4,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/.
|
||||
|
||||
option('--enable-nodejs',
|
||||
option('--disable-nodejs',
|
||||
help='Require Node.js to build')
|
||||
|
||||
|
||||
@ -62,10 +62,19 @@ def nodejs_version(node):
|
||||
def nodejs_suitability(require, node, version):
|
||||
MIN_NODE_VERSION = Version('8.11')
|
||||
|
||||
MAYBE_FILE_A_BUG = '''
|
||||
|
||||
If you believe this is a bug, <https://mzl.la/2vLbXAv> is a good way
|
||||
to file. Executing `mach bootstrap --no-system changes` should
|
||||
install a compatible version in ~/.mozbuild on most platforms.
|
||||
More details: <https://bit.ly/2BbyD1E>
|
||||
'''
|
||||
|
||||
if not node:
|
||||
msg = ('could not find Node.js executable; ensure `node` or `nodejs` '
|
||||
'is in PATH or set NODEJS in environment to point to an '
|
||||
'executable')
|
||||
'executable.%s' % (MAYBE_FILE_A_BUG)
|
||||
)
|
||||
|
||||
if require:
|
||||
raise FatalCheckError(msg)
|
||||
@ -75,7 +84,7 @@ def nodejs_suitability(require, node, version):
|
||||
return
|
||||
|
||||
if not version:
|
||||
msg = 'could not resolve Node.js version'
|
||||
msg = 'could not resolve Node.js version.%s' % (MAYBE_FILE_A_BUG)
|
||||
if require:
|
||||
raise FatalCheckError(msg)
|
||||
else:
|
||||
@ -84,8 +93,8 @@ def nodejs_suitability(require, node, version):
|
||||
return
|
||||
|
||||
if version < MIN_NODE_VERSION:
|
||||
msg = 'NODEJS must point to node %s or newer; %s found' % (
|
||||
MIN_NODE_VERSION, version)
|
||||
msg = 'NODEJS must point to node %s or newer; %s found. %s' % (
|
||||
MIN_NODE_VERSION, version, MAYBE_FILE_A_BUG)
|
||||
|
||||
if require:
|
||||
raise FatalCheckError(msg)
|
||||
|
@ -28,43 +28,43 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
* To be removed, specify the ID of the Web console actor.
|
||||
* This is used to fake emitting an event from it to prevent changing RDP
|
||||
* behavior.
|
||||
* @param nsIMessageManager messageManager (optional)
|
||||
* Passed only when it is instanciated across processes. This is the manager to
|
||||
* use to communicate with the other process.
|
||||
* @param object stackTraceCollector (optional)
|
||||
* When the actor runs in the same process than the requests we are inspecting,
|
||||
* the web console actor hands over a shared instance to the stack trace
|
||||
* collector.
|
||||
* @param nsIMessageManager messageManager
|
||||
* This is the manager to use to communicate with the console actor. When both
|
||||
* netmonitor and console actor runs in the same process, this is an instance
|
||||
* of MockMessageManager instead of a real message manager.
|
||||
*/
|
||||
initialize(conn, filters, parentID, messageManager, stackTraceCollector) {
|
||||
initialize(conn, filters, parentID, messageManager) {
|
||||
Actor.prototype.initialize.call(this, conn);
|
||||
|
||||
this.parentID = parentID;
|
||||
this.messageManager = messageManager;
|
||||
this.stackTraceCollector = stackTraceCollector;
|
||||
|
||||
// Immediately start watching for new request according to `filters`.
|
||||
// NetworkMonitor will call `onNetworkEvent` method.
|
||||
this.netMonitor = new NetworkMonitor(filters, this);
|
||||
this.netMonitor.init();
|
||||
|
||||
if (this.messageManager) {
|
||||
this.stackTraces = new Set();
|
||||
this.onStackTraceAvailable = this.onStackTraceAvailable.bind(this);
|
||||
this.messageManager.addMessageListener("debug:request-stack-available",
|
||||
this.onStackTraceAvailable);
|
||||
this.onRequestContent = this.onRequestContent.bind(this);
|
||||
this.messageManager.addMessageListener("debug:request-content",
|
||||
this.onRequestContent);
|
||||
this.onSetPreference = this.onSetPreference.bind(this);
|
||||
this.messageManager.addMessageListener("debug:netmonitor-preference",
|
||||
this.onSetPreference);
|
||||
this.onGetNetworkEventActor = this.onGetNetworkEventActor.bind(this);
|
||||
this.messageManager.addMessageListener("debug:get-network-event-actor",
|
||||
this.onGetNetworkEventActor);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.messageManager.addMessageListener("debug:destroy-network-monitor",
|
||||
this.destroy);
|
||||
this.stackTraces = new Set();
|
||||
this.onStackTraceAvailable = this.onStackTraceAvailable.bind(this);
|
||||
this.messageManager.addMessageListener("debug:request-stack-available",
|
||||
this.onStackTraceAvailable);
|
||||
this.onRequestContent = this.onRequestContent.bind(this);
|
||||
this.messageManager.addMessageListener("debug:request-content",
|
||||
this.onRequestContent);
|
||||
this.onSetPreference = this.onSetPreference.bind(this);
|
||||
this.messageManager.addMessageListener("debug:netmonitor-preference",
|
||||
this.onSetPreference);
|
||||
this.onGetNetworkEventActor = this.onGetNetworkEventActor.bind(this);
|
||||
this.messageManager.addMessageListener("debug:get-network-event-actor",
|
||||
this.onGetNetworkEventActor);
|
||||
this.onDestroyMessage = this.onDestroyMessage.bind(this);
|
||||
this.messageManager.addMessageListener("debug:destroy-network-monitor",
|
||||
this.onDestroyMessage);
|
||||
},
|
||||
|
||||
onDestroyMessage({ data }) {
|
||||
if (data.actorID == this.parentID) {
|
||||
this.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
@ -76,8 +76,8 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
this.netMonitor = null;
|
||||
}
|
||||
|
||||
this.stackTraces.clear();
|
||||
if (this.messageManager) {
|
||||
this.stackTraces.clear();
|
||||
this.messageManager.removeMessageListener("debug:request-stack-available",
|
||||
this.onStackTraceAvailable);
|
||||
this.messageManager.removeMessageListener("debug:request-content",
|
||||
@ -87,7 +87,7 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
this.messageManager.removeMessageListener("debug:get-network-event-actor",
|
||||
this.onGetNetworkEventActor);
|
||||
this.messageManager.removeMessageListener("debug:destroy-network-monitor",
|
||||
this.destroy);
|
||||
this.onDestroyMessage);
|
||||
this.messageManager = null;
|
||||
}
|
||||
},
|
||||
@ -101,11 +101,7 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
}
|
||||
},
|
||||
|
||||
getRequestContentForURL(url) {
|
||||
const actor = this._networkEventActorsByURL.get(url);
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
getRequestContentForActor(actor) {
|
||||
const content = actor._response.content;
|
||||
if (actor._discardResponseBody || actor._truncated || !content || !content.size) {
|
||||
// Do not return the stylesheet text if there is no meaningful content or if it's
|
||||
@ -133,7 +129,10 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
|
||||
onRequestContent(msg) {
|
||||
const { url } = msg.data;
|
||||
const content = this.getRequestContentForURL(url);
|
||||
const actor = this._networkEventActorsByURL.get(url);
|
||||
// Always reply with a message, but with a null `content` if this instance
|
||||
// did not processed this request
|
||||
const content = actor ? this.getRequestContentForActor(actor) : null;
|
||||
this.messageManager.sendAsyncMessage("debug:request-content", {
|
||||
url,
|
||||
content,
|
||||
@ -151,7 +150,10 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
|
||||
onGetNetworkEventActor({ data }) {
|
||||
const actor = this.getNetworkEventActor(data.channelId);
|
||||
this.messageManager.sendAsyncMessage("debug:get-network-event-actor", actor.form());
|
||||
this.messageManager.sendAsyncMessage("debug:get-network-event-actor", {
|
||||
channelId: data.channelId,
|
||||
actor: actor.form()
|
||||
});
|
||||
},
|
||||
|
||||
getNetworkEventActor(channelId) {
|
||||
@ -175,13 +177,9 @@ const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, {
|
||||
const actor = this.getNetworkEventActor(channelId);
|
||||
this._netEvents.set(channelId, actor);
|
||||
|
||||
if (this.messageManager) {
|
||||
event.cause.stacktrace = this.stackTraces.has(channelId);
|
||||
if (event.cause.stacktrace) {
|
||||
this.stackTraces.delete(channelId);
|
||||
}
|
||||
} else {
|
||||
event.cause.stacktrace = this.stackTraceCollector.getStackTrace(channelId);
|
||||
event.cause.stacktrace = this.stackTraces.has(channelId);
|
||||
if (event.cause.stacktrace) {
|
||||
this.stackTraces.delete(channelId);
|
||||
}
|
||||
actor.init(event);
|
||||
|
||||
|
@ -30,6 +30,7 @@ loader.lazyRequireGetter(this, "addWebConsoleCommands", "devtools/server/actors/
|
||||
loader.lazyRequireGetter(this, "formatCommand", "devtools/server/actors/webconsole/commands", true);
|
||||
loader.lazyRequireGetter(this, "isCommand", "devtools/server/actors/webconsole/commands", true);
|
||||
loader.lazyRequireGetter(this, "validCommands", "devtools/server/actors/webconsole/commands", true);
|
||||
loader.lazyRequireGetter(this, "createMessageManagerMocks", "devtools/server/actors/webconsole/message-manager-mock", true);
|
||||
loader.lazyRequireGetter(this, "CONSOLE_WORKER_IDS", "devtools/server/actors/webconsole/utils", true);
|
||||
loader.lazyRequireGetter(this, "WebConsoleUtils", "devtools/server/actors/webconsole/utils", true);
|
||||
loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
|
||||
@ -325,22 +326,13 @@ WebConsoleActor.prototype =
|
||||
this.consoleServiceListener.destroy();
|
||||
this.consoleServiceListener = null;
|
||||
}
|
||||
if (this.networkMonitorActor) {
|
||||
this.networkMonitorActor.destroy();
|
||||
this.networkMonitorActor = null;
|
||||
}
|
||||
if (this.networkMonitorActorId) {
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
if (messageManager) {
|
||||
if (this.netmonitors) {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.sendAsyncMessage("debug:destroy-network-monitor", {
|
||||
actorId: this.networkMonitorActorId
|
||||
actorID: this.actorID
|
||||
});
|
||||
}
|
||||
this.networkMonitorActorId = null;
|
||||
}
|
||||
if (this.networkMonitorChildActor) {
|
||||
this.networkMonitorChildActor.destroy();
|
||||
this.networkMonitorChildActor = null;
|
||||
this.netmonitors = null;
|
||||
}
|
||||
if (this.consoleAPIListener) {
|
||||
this.consoleAPIListener.destroy();
|
||||
@ -589,20 +581,6 @@ WebConsoleActor.prototype =
|
||||
startListeners: async function(request) {
|
||||
const startedListeners = [];
|
||||
const window = !this.parentActor.isRootActor ? this.window : null;
|
||||
let messageManager = null;
|
||||
|
||||
// Check if the actor is running in a child process (but only if
|
||||
// Services.appinfo exists, to prevent startListeners to fail
|
||||
// when the target is a Worker).
|
||||
const processBoundary = Services.appinfo && (
|
||||
Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
|
||||
);
|
||||
|
||||
// Retrieve a message manager from the parent actor if this actor is
|
||||
// not currently running in the main process.
|
||||
if (processBoundary) {
|
||||
messageManager = this.parentActor.messageManager;
|
||||
}
|
||||
|
||||
while (request.listeners.length > 0) {
|
||||
const listener = request.listeners.shift();
|
||||
@ -634,19 +612,33 @@ WebConsoleActor.prototype =
|
||||
if (isWorker) {
|
||||
break;
|
||||
}
|
||||
if (!this.networkMonitorActorId && !this.networkMonitorActor) {
|
||||
// Create a StackTraceCollector that's going to be shared both by
|
||||
// the NetworkMonitorActor running in the same process for service worker
|
||||
// requests, as well with the NetworkMonitorActor running in the parent
|
||||
// process. It will communicate via message manager for this one.
|
||||
this.stackTraceCollector = new StackTraceCollector({ window },
|
||||
messageManager);
|
||||
this.stackTraceCollector.init();
|
||||
if (!this.netmonitors) {
|
||||
// Instanciate fake message managers used for service worker's netmonitor
|
||||
// when running in the content process, and for netmonitor running in the
|
||||
// same process when running in the parent process.
|
||||
// `createMessageManagerMocks` returns a couple of connected messages
|
||||
// managers that pass messages to each other to simulate the process
|
||||
// boundary. We will use the first one for the webconsole-actor and the
|
||||
// second one will be used by the netmonitor-actor.
|
||||
const [ mmMockParent, mmMockChild ] = createMessageManagerMocks();
|
||||
|
||||
if (messageManager && processBoundary) {
|
||||
// Maintain the list of message manager we should message to/listen from
|
||||
// to support the netmonitor instances, also records actorID of each
|
||||
// NetworkMonitorActor.
|
||||
// Array of `{ messageManager, parentProcess }`.
|
||||
// Where `parentProcess` is true for the netmonitor actor instanciated in the
|
||||
// parent process.
|
||||
this.netmonitors = [];
|
||||
|
||||
// Check if the actor is running in a content process
|
||||
const isInContentProcess =
|
||||
Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT &&
|
||||
this.parentActor.messageManager;
|
||||
if (isInContentProcess) {
|
||||
// Start a network monitor in the parent process to listen to
|
||||
// most requests than happen in parent
|
||||
this.networkMonitorActorId = await this.conn.spawnActorInParentProcess(
|
||||
// most requests that happen in parent. This one will communicate through
|
||||
// `messageManager`.
|
||||
await this.conn.spawnActorInParentProcess(
|
||||
this.actorID, {
|
||||
module: "devtools/server/actors/network-monitor",
|
||||
constructor: "NetworkMonitorActor",
|
||||
@ -655,17 +647,34 @@ WebConsoleActor.prototype =
|
||||
this.actorID
|
||||
],
|
||||
});
|
||||
|
||||
// Spawn also one in the child to listen to service workers
|
||||
this.networkMonitorChildActor = new NetworkMonitorActor(this.conn,
|
||||
{ window },
|
||||
this.actorID,
|
||||
null,
|
||||
this.stackTraceCollector);
|
||||
} else {
|
||||
this.networkMonitorActor = new NetworkMonitorActor(this.conn, { window },
|
||||
this.actorID, null, this.stackTraceCollector);
|
||||
this.netmonitors.push({
|
||||
messageManager: this.parentActor.messageManager,
|
||||
parentProcess: true
|
||||
});
|
||||
}
|
||||
|
||||
// When the console actor runs in the parent process, Netmonitor can be ran
|
||||
// in the process and communicate through `messageManagerMock`.
|
||||
// And while it runs in the content process, we also spawn one in the content
|
||||
// to listen to requests that happen in the content process (for instance
|
||||
// service workers requests)
|
||||
new NetworkMonitorActor(this.conn,
|
||||
{ window },
|
||||
this.actorID,
|
||||
mmMockParent);
|
||||
|
||||
this.netmonitors.push({
|
||||
messageManager: mmMockChild,
|
||||
parentProcess: !isInContentProcess
|
||||
});
|
||||
|
||||
// Create a StackTraceCollector that's going to be shared both by
|
||||
// the NetworkMonitorActor running in the same process for service worker
|
||||
// requests, as well with the NetworkMonitorActor running in the parent
|
||||
// process. It will communicate via message manager for this one.
|
||||
this.stackTraceCollector = new StackTraceCollector({ window },
|
||||
this.netmonitors);
|
||||
this.stackTraceCollector.init();
|
||||
}
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
@ -764,22 +773,13 @@ WebConsoleActor.prototype =
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
case "NetworkActivity":
|
||||
if (this.networkMonitorActor) {
|
||||
this.networkMonitorActor.destroy();
|
||||
this.networkMonitorActor = null;
|
||||
}
|
||||
if (this.networkMonitorActorId) {
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
if (messageManager) {
|
||||
if (this.netmonitors) {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.sendAsyncMessage("debug:destroy-network-monitor", {
|
||||
actorId: this.networkMonitorActorId
|
||||
actorID: this.actorID
|
||||
});
|
||||
}
|
||||
this.networkMonitorActorId = null;
|
||||
}
|
||||
if (this.networkMonitorChildActor) {
|
||||
this.networkMonitorChildActor.destroy();
|
||||
this.networkMonitorChildActor = null;
|
||||
this.netmonitors = null;
|
||||
}
|
||||
if (this.stackTraceCollector) {
|
||||
this.stackTraceCollector.destroy();
|
||||
@ -1252,31 +1252,19 @@ WebConsoleActor.prototype =
|
||||
for (const key in request.preferences) {
|
||||
this._prefs[key] = request.preferences[key];
|
||||
|
||||
if (key == "NetworkMonitor.saveRequestAndResponseBodies") {
|
||||
if (this.networkMonitorActor) {
|
||||
this.networkMonitorActor.netMonitor.saveRequestAndResponseBodies =
|
||||
this._prefs[key];
|
||||
}
|
||||
if (this.networkMonitorChildActor) {
|
||||
this.networkMonitorChildActor.netMonitor.saveRequestAndResponseBodies =
|
||||
this._prefs[key];
|
||||
}
|
||||
if (this.networkMonitorActorId) {
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
messageManager.sendAsyncMessage("debug:netmonitor-preference",
|
||||
{ saveRequestAndResponseBodies: this._prefs[key] });
|
||||
}
|
||||
} else if (key == "NetworkMonitor.throttleData") {
|
||||
if (this.networkMonitorActor) {
|
||||
this.networkMonitorActor.netMonitor.throttleData = this._prefs[key];
|
||||
}
|
||||
if (this.networkMonitorChildActor) {
|
||||
this.networkMonitorChildActor.netMonitor.throttleData = this._prefs[key];
|
||||
}
|
||||
if (this.networkMonitorActorId) {
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
messageManager.sendAsyncMessage("debug:netmonitor-preference",
|
||||
{ throttleData: this._prefs[key] });
|
||||
if (this.netmonitors) {
|
||||
if (key == "NetworkMonitor.saveRequestAndResponseBodies") {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.sendAsyncMessage("debug:netmonitor-preference", {
|
||||
saveRequestAndResponseBodies: this._prefs[key]
|
||||
});
|
||||
}
|
||||
} else if (key == "NetworkMonitor.throttleData") {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.sendAsyncMessage("debug:netmonitor-preference", {
|
||||
throttleData: this._prefs[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1818,26 +1806,30 @@ WebConsoleActor.prototype =
|
||||
* The URL of the request to search for.
|
||||
*/
|
||||
getRequestContentForURL(url) {
|
||||
// When running in Parent Process, call the NetworkMonitorActor directly.
|
||||
if (this.networkMonitorActor) {
|
||||
return this.networkMonitorActor.getRequestContentForURL(url);
|
||||
} else if (this.networkMonitorActorId) {
|
||||
// Otherwise, if the netmonitor is started, but on the parent process,
|
||||
// pipe the data through the message manager
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
return new Promise(resolve => {
|
||||
const onMessage = ({ data }) => {
|
||||
if (data.url == url) {
|
||||
if (!this.netmonitors) {
|
||||
return null;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
let messagesReceived = 0;
|
||||
const onMessage = ({ data }) => {
|
||||
if (data.url != url) {
|
||||
return;
|
||||
}
|
||||
messagesReceived++;
|
||||
// Either use the first response with a content, or return a null content
|
||||
// if we received the responses from all the message managers.
|
||||
if (data.content || messagesReceived == this.netmonitors.length) {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.removeMessageListener("debug:request-content", onMessage);
|
||||
resolve(data.content);
|
||||
}
|
||||
};
|
||||
resolve(data.content);
|
||||
}
|
||||
};
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.addMessageListener("debug:request-content", onMessage);
|
||||
messageManager.sendAsyncMessage("debug:request-content", { url });
|
||||
});
|
||||
}
|
||||
// Finally, if the netmonitor is not started at all, return null
|
||||
return null;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1883,30 +1875,28 @@ WebConsoleActor.prototype =
|
||||
|
||||
NetUtil.asyncFetch(channel, () => {});
|
||||
|
||||
// When running in Parent Process, call the NetworkMonitorActor directly.
|
||||
if (!this.netmonitors) {
|
||||
return null;
|
||||
}
|
||||
const { channelId } = channel;
|
||||
if (this.networkMonitorActor) {
|
||||
const actor = this.networkMonitorActor.getNetworkEventActor(channelId);
|
||||
return {
|
||||
eventActor: actor.form()
|
||||
};
|
||||
} else if (this.networkMonitorActorId) {
|
||||
// Otherwise, if the netmonitor is started, but on the parent process,
|
||||
// pipe the data through the message manager
|
||||
const messageManager = this.parentActor.messageManager;
|
||||
return new Promise(resolve => {
|
||||
const onMessage = ({ data }) => {
|
||||
// Only query the NetworkMonitorActor running in the parent process, where the
|
||||
// request will be done. There always is one listener running in the parent process,
|
||||
// see startListeners.
|
||||
const netmonitor = this.netmonitors.filter(({ parentProcess }) => parentProcess)[0];
|
||||
const { messageManager } = netmonitor;
|
||||
return new Promise(resolve => {
|
||||
const onMessage = ({ data }) => {
|
||||
if (data.channelId == channelId) {
|
||||
messageManager.removeMessageListener("debug:get-network-event-actor",
|
||||
onMessage);
|
||||
resolve({
|
||||
eventActor: data
|
||||
eventActor: data.actor
|
||||
});
|
||||
};
|
||||
messageManager.addMessageListener("debug:get-network-event-actor", onMessage);
|
||||
messageManager.sendAsyncMessage("debug:get-network-event-actor", { channelId });
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
messageManager.addMessageListener("debug:get-network-event-actor", onMessage);
|
||||
messageManager.sendAsyncMessage("debug:get-network-event-actor", { channelId });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
68
devtools/server/actors/webconsole/message-manager-mock.js
Normal file
68
devtools/server/actors/webconsole/message-manager-mock.js
Normal file
@ -0,0 +1,68 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Implements a fake MessageManager class that allows to use the message
|
||||
* manager API within the same process. This implementation will forward
|
||||
* messages within the same process.
|
||||
*
|
||||
* It helps having the same codepath for actors being evaluated in the same
|
||||
* process *and* in a remote one.
|
||||
*/
|
||||
function MessageManagerMock() {
|
||||
this._listeners = new Map();
|
||||
}
|
||||
MessageManagerMock.prototype = {
|
||||
addMessageListener(name, listener) {
|
||||
let listeners = this._listeners.get(name);
|
||||
if (!listeners) {
|
||||
listeners = [];
|
||||
this._listeners.set(name, listeners);
|
||||
}
|
||||
if (!listeners.includes(listener)) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
},
|
||||
removeMessageListener(name, listener) {
|
||||
const listeners = this._listeners.get(name);
|
||||
const idx = listeners.indexOf(listener);
|
||||
listeners.splice(idx, 1);
|
||||
},
|
||||
sendAsyncMessage(name, data) {
|
||||
this.other.internalSendAsyncMessage(name, data);
|
||||
},
|
||||
internalSendAsyncMessage(name, data) {
|
||||
const listeners = this._listeners.get(name);
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
const message = {
|
||||
target: this,
|
||||
data
|
||||
};
|
||||
for (const listener of listeners) {
|
||||
if (typeof listener === "object" &&
|
||||
typeof listener.receiveMessage === "function") {
|
||||
listener.receiveMessage(message);
|
||||
} else if (typeof listener === "function") {
|
||||
listener(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Create two MessageManager mocks, connected to each others.
|
||||
* Calling sendAsyncMessage on the first will dispatch messages on the second one,
|
||||
* and the other way around
|
||||
*/
|
||||
exports.createMessageManagerMocks = function() {
|
||||
const a = new MessageManagerMock();
|
||||
const b = new MessageManagerMock();
|
||||
a.other = b;
|
||||
b.other = a;
|
||||
return [a, b];
|
||||
};
|
@ -8,6 +8,7 @@ DevToolsModules(
|
||||
'commands.js',
|
||||
'content-process-forward.js',
|
||||
'listeners.js',
|
||||
'message-manager-mock.js',
|
||||
'screenshot.js',
|
||||
'utils.js',
|
||||
'worker-listeners.js',
|
||||
|
@ -198,22 +198,6 @@ var NetworkHelper = {
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the web appId that is associated with request.
|
||||
*
|
||||
* @param nsIHttpChannel request
|
||||
* @returns number|null
|
||||
* The appId for the given request, if available.
|
||||
*/
|
||||
getAppIdForRequest: function(request) {
|
||||
try {
|
||||
return this.getRequestLoadContext(request).appId;
|
||||
} catch (ex) {
|
||||
// request loadContent is not always available.
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the topFrameElement that is associated with request. This
|
||||
* works in single-process and multiprocess contexts. It may cross
|
||||
|
@ -17,12 +17,15 @@ loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||
"devtools/shared/DevToolsUtils");
|
||||
loader.lazyRequireGetter(this, "flags",
|
||||
"devtools/shared/flags");
|
||||
loader.lazyRequireGetter(this, "NetworkThrottleManager",
|
||||
"devtools/shared/webconsole/throttle", true);
|
||||
loader.lazyRequireGetter(this, "CacheEntry",
|
||||
"devtools/shared/platform/cache-entry", true);
|
||||
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
|
||||
loader.lazyServiceGetter(this, "gActivityDistributor",
|
||||
"@mozilla.org/network/http-activity-distributor;1",
|
||||
"nsIHttpActivityDistributor");
|
||||
const {NetworkThrottleManager} = require("devtools/shared/webconsole/throttle");
|
||||
const {CacheEntry} = require("devtools/shared/platform/cache-entry");
|
||||
|
||||
// Network logging
|
||||
|
||||
// The maximum uint32 value.
|
||||
@ -47,7 +50,7 @@ const HTTP_TEMPORARY_REDIRECT = 307;
|
||||
*/
|
||||
function matchRequest(channel, filters) {
|
||||
// Log everything if no filter is specified
|
||||
if (!filters.outerWindowID && !filters.window && !filters.appId) {
|
||||
if (!filters.outerWindowID && !filters.window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -93,13 +96,6 @@ function matchRequest(channel, filters) {
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.appId) {
|
||||
const appId = NetworkHelper.getAppIdForRequest(channel);
|
||||
if (appId && appId == filters.appId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -177,33 +173,33 @@ ChannelEventSinkFactory.getService = function() {
|
||||
return Cc[SINK_CONTRACT_ID].getService(Ci.nsIChannelEventSink).wrappedJSObject;
|
||||
};
|
||||
|
||||
function StackTraceCollector(filters, messageManager) {
|
||||
function StackTraceCollector(filters, netmonitors) {
|
||||
this.filters = filters;
|
||||
this.stacktracesById = new Map();
|
||||
this.messageManager = messageManager;
|
||||
this.netmonitors = netmonitors;
|
||||
}
|
||||
|
||||
StackTraceCollector.prototype = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, "http-on-opening-request");
|
||||
ChannelEventSinkFactory.getService().registerCollector(this);
|
||||
if (this.messageManager) {
|
||||
this.onGetStack = this.onGetStack.bind(this);
|
||||
this.messageManager.addMessageListener("debug:request-stack", this.onGetStack);
|
||||
this.onGetStack = this.onGetStack.bind(this);
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.addMessageListener("debug:request-stack", this.onGetStack);
|
||||
}
|
||||
},
|
||||
|
||||
destroy() {
|
||||
Services.obs.removeObserver(this, "http-on-opening-request");
|
||||
ChannelEventSinkFactory.getService().unregisterCollector(this);
|
||||
if (this.messageManager) {
|
||||
this.messageManager.removeMessageListener("debug:request-stack", this.onGetStack);
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.removeMessageListener("debug:request-stack", this.onGetStack);
|
||||
}
|
||||
},
|
||||
|
||||
_saveStackTrace(channel, stacktrace) {
|
||||
if (this.messageManager) {
|
||||
this.messageManager.sendAsyncMessage("debug:request-stack-available", {
|
||||
for (const { messageManager } of this.netmonitors) {
|
||||
messageManager.sendAsyncMessage("debug:request-stack-available", {
|
||||
channelId: channel.channelId,
|
||||
stacktrace: stacktrace && stacktrace.length > 0
|
||||
});
|
||||
@ -263,9 +259,10 @@ StackTraceCollector.prototype = {
|
||||
},
|
||||
|
||||
onGetStack(msg) {
|
||||
const messageManager = msg.target;
|
||||
const channelId = msg.data;
|
||||
const stack = this.getStackTrace(channelId);
|
||||
this.messageManager.sendAsyncMessage("debug:request-stack", {
|
||||
messageManager.sendAsyncMessage("debug:request-stack", {
|
||||
channelId,
|
||||
stack,
|
||||
});
|
||||
@ -769,7 +766,6 @@ NetworkResponseListener.prototype = {
|
||||
* Object with the filters to use for network requests:
|
||||
* - window (nsIDOMWindow): filter network requests by the associated
|
||||
* window object.
|
||||
* - appId (number): filter requests by the appId.
|
||||
* - outerWindowID (number): filter requests by their top frame's outerWindowID.
|
||||
* Filters are optional. If any of these filters match the request is
|
||||
* logged (OR is applied). If no filter is provided then all requests are
|
||||
|
@ -181,6 +181,11 @@ private:
|
||||
nsAttrValue mValue;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable MSVC warning 'nonstandard extension used: zero-sized array in struct/union'
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200)
|
||||
#endif
|
||||
class Impl
|
||||
{
|
||||
public:
|
||||
@ -213,6 +218,10 @@ private:
|
||||
// Allocated in the same buffer as `Impl`.
|
||||
InternalAttr mBuffer[0];
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
mozilla::Span<InternalAttr> NonMappedAttrs()
|
||||
{
|
||||
|
@ -22642,17 +22642,25 @@ DeleteDatabaseOp::LoadPreviousVersion(nsIFile* aDatabaseFile)
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
connection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT name "
|
||||
"FROM database"
|
||||
), getter_AddRefs(stmt)));
|
||||
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT name "
|
||||
"FROM database"
|
||||
), getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasResult;
|
||||
MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
|
||||
rv = stmt->ExecuteStep(&hasResult);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsString databaseName;
|
||||
MOZ_ALWAYS_SUCCEEDS(stmt->GetString(0, databaseName));
|
||||
rv = stmt->GetString(0, databaseName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCommonParams.metadata().name() == databaseName);
|
||||
}
|
||||
|
@ -221,6 +221,11 @@ skip-if = toolkit == 'android' # bug 1091965
|
||||
[test_periodicWave.html]
|
||||
[test_periodicWaveDisableNormalization.html]
|
||||
[test_periodicWaveBandLimiting.html]
|
||||
[test_retrospective-exponentialRampToValueAtTime.html]
|
||||
[test_retrospective-linearRampToValueAtTime.html]
|
||||
[test_retrospective-setTargetAtTime.html]
|
||||
[test_retrospective-setValueAtTime.html]
|
||||
[test_retrospective-setValueCurveAtTime.html]
|
||||
[test_ScriptProcessorCollected1.html]
|
||||
[test_scriptProcessorNode.html]
|
||||
[test_scriptProcessorNodeChannelCount.html]
|
||||
|
@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test exponentialRampToValue with end time in the past</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
function do_test(t, context) {
|
||||
var source = context.createConstantSource();
|
||||
source.start();
|
||||
|
||||
var test = context.createGain();
|
||||
test.gain.exponentialRampToValueAtTime(0.1, 0.5*context.currentTime);
|
||||
test.gain.exponentialRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
var reference = context.createGain();
|
||||
reference.gain.exponentialRampToValueAtTime(0.1, context.currentTime);
|
||||
reference.gain.exponentialRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
source.connect(test);
|
||||
source.connect(reference);
|
||||
|
||||
var merger = context.createChannelMerger();
|
||||
test.connect(merger, 0, 0);
|
||||
reference.connect(merger, 0, 1);
|
||||
|
||||
var processor = context.createScriptProcessor(0, 2, 0);
|
||||
merger.connect(processor);
|
||||
processor.onaudioprocess =
|
||||
t.step_func_done((e) => {
|
||||
source.stop();
|
||||
processor.onaudioprocess = null;
|
||||
|
||||
var testValue = e.inputBuffer.getChannelData(0)[0];
|
||||
var referenceValue = e.inputBuffer.getChannelData(1)[0];
|
||||
|
||||
assert_equals(testValue, referenceValue,
|
||||
"value matches expected");
|
||||
});
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
var context = new AudioContext;
|
||||
(function waitForTimeAdvance() {
|
||||
if (context.currentTime == 0) {
|
||||
t.step_timeout(waitForTimeAdvance, 0);
|
||||
} else {
|
||||
do_test(t, context);
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test linearRampToValue with end time in the past</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
function do_test(t, context) {
|
||||
var source = context.createConstantSource();
|
||||
source.start();
|
||||
|
||||
var test = context.createGain();
|
||||
test.gain.linearRampToValueAtTime(0.1, 0.5*context.currentTime);
|
||||
test.gain.linearRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
var reference = context.createGain();
|
||||
reference.gain.linearRampToValueAtTime(0.1, context.currentTime);
|
||||
reference.gain.linearRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
source.connect(test);
|
||||
source.connect(reference);
|
||||
|
||||
var merger = context.createChannelMerger();
|
||||
test.connect(merger, 0, 0);
|
||||
reference.connect(merger, 0, 1);
|
||||
|
||||
var processor = context.createScriptProcessor(0, 2, 0);
|
||||
merger.connect(processor);
|
||||
processor.onaudioprocess =
|
||||
t.step_func_done((e) => {
|
||||
source.stop();
|
||||
processor.onaudioprocess = null;
|
||||
|
||||
var testValue = e.inputBuffer.getChannelData(0)[0];
|
||||
var referenceValue = e.inputBuffer.getChannelData(1)[0];
|
||||
|
||||
assert_equals(testValue, referenceValue,
|
||||
"value matches expected");
|
||||
});
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
var context = new AudioContext;
|
||||
(function waitForTimeAdvance() {
|
||||
if (context.currentTime == 0) {
|
||||
t.step_timeout(waitForTimeAdvance, 0);
|
||||
} else {
|
||||
do_test(t, context);
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test setTargetAtTime with start time in the past</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
function do_test(t, context) {
|
||||
var source = context.createConstantSource();
|
||||
source.start();
|
||||
|
||||
var test = context.createGain();
|
||||
test.gain.setTargetAtTime(0.1, 0.5*context.currentTime, 0.1);
|
||||
test.gain.linearRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
var reference = context.createGain();
|
||||
reference.gain.setTargetAtTime(0.1, context.currentTime, 0.1);
|
||||
reference.gain.linearRampToValueAtTime(0.9, 2.0);
|
||||
|
||||
source.connect(test);
|
||||
source.connect(reference);
|
||||
|
||||
var merger = context.createChannelMerger();
|
||||
test.connect(merger, 0, 0);
|
||||
reference.connect(merger, 0, 1);
|
||||
|
||||
var processor = context.createScriptProcessor(0, 2, 0);
|
||||
merger.connect(processor);
|
||||
processor.onaudioprocess =
|
||||
t.step_func_done((e) => {
|
||||
source.stop();
|
||||
processor.onaudioprocess = null;
|
||||
|
||||
var testValue = e.inputBuffer.getChannelData(0)[0];
|
||||
var referenceValue = e.inputBuffer.getChannelData(1)[0];
|
||||
|
||||
assert_equals(testValue, referenceValue,
|
||||
"value matches expected");
|
||||
});
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
var context = new AudioContext;
|
||||
(function waitForTimeAdvance() {
|
||||
if (context.currentTime == 0) {
|
||||
t.step_timeout(waitForTimeAdvance, 0);
|
||||
} else {
|
||||
do_test(t, context);
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test setValueAtTime with startTime in the past</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
function do_test(t, context) {
|
||||
var source = context.createConstantSource();
|
||||
source.start();
|
||||
|
||||
// Use a ramp of slope 1/sample to measure time.
|
||||
// The end value is the extent of exact precision in single precision float.
|
||||
const rampEnd = Math.pow(2, 24);
|
||||
const rampEndSeconds = rampEnd / context.sampleRate;
|
||||
var test = context.createGain();
|
||||
test.gain.setValueAtTime(0.0, 0.5*context.currentTime);
|
||||
test.gain.linearRampToValueAtTime(rampEnd, rampEndSeconds);
|
||||
|
||||
var reference = context.createGain();
|
||||
reference.gain.setValueAtTime(0.0, context.currentTime);
|
||||
reference.gain.linearRampToValueAtTime(rampEnd, rampEndSeconds);
|
||||
|
||||
source.connect(test);
|
||||
source.connect(reference);
|
||||
|
||||
var merger = context.createChannelMerger();
|
||||
test.connect(merger, 0, 0);
|
||||
reference.connect(merger, 0, 1);
|
||||
|
||||
var processor = context.createScriptProcessor(0, 2, 0);
|
||||
merger.connect(processor);
|
||||
processor.onaudioprocess =
|
||||
t.step_func_done((e) => {
|
||||
source.stop();
|
||||
processor.onaudioprocess = null;
|
||||
|
||||
var testValue = e.inputBuffer.getChannelData(0)[0];
|
||||
var referenceValue = e.inputBuffer.getChannelData(1)[0];
|
||||
|
||||
assert_equals(testValue, referenceValue,
|
||||
"ramp value matches expected");
|
||||
});
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
var context = new AudioContext;
|
||||
(function waitForTimeAdvance() {
|
||||
if (context.currentTime == 0) {
|
||||
t.step_timeout(waitForTimeAdvance, 0);
|
||||
} else {
|
||||
do_test(t, context);
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test SetValueCurve with start time in the past</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
function do_test(t, context) {
|
||||
var source = context.createConstantSource();
|
||||
source.start();
|
||||
|
||||
var test = context.createGain();
|
||||
test.gain.setValueCurveAtTime(new Float32Array([1.0, 0.1]), 0.0, 1.0);
|
||||
|
||||
var reference = context.createGain();
|
||||
reference.gain.setValueCurveAtTime(new Float32Array([1.0, 0.1]), 0.5*context.currentTime, 1.0);
|
||||
|
||||
source.connect(test);
|
||||
source.connect(reference);
|
||||
|
||||
var merger = context.createChannelMerger();
|
||||
test.connect(merger, 0, 0);
|
||||
reference.connect(merger, 0, 1);
|
||||
|
||||
var processor = context.createScriptProcessor(0, 2, 0);
|
||||
merger.connect(processor);
|
||||
processor.onaudioprocess =
|
||||
t.step_func_done((e) => {
|
||||
source.stop();
|
||||
processor.onaudioprocess = null;
|
||||
|
||||
var testValue = e.inputBuffer.getChannelData(0)[0];
|
||||
var referenceValue = e.inputBuffer.getChannelData(1)[0];
|
||||
|
||||
assert_equals(testValue, referenceValue,
|
||||
"value matches expected");
|
||||
});
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
var context = new AudioContext;
|
||||
(function waitForTimeAdvance() {
|
||||
if (context.currentTime == 0) {
|
||||
t.step_timeout(waitForTimeAdvance, 0);
|
||||
} else {
|
||||
do_test(t, context);
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
@ -4537,7 +4537,7 @@ EditorBase::ClearSelection()
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
EditorBase::CreateHTMLContent(nsAtom* aTag)
|
||||
EditorBase::CreateHTMLContent(const nsAtom* aTag)
|
||||
{
|
||||
MOZ_ASSERT(aTag);
|
||||
|
||||
|
@ -1046,7 +1046,7 @@ protected: // May be called by friends.
|
||||
*
|
||||
* @param aTag Tag you want.
|
||||
*/
|
||||
already_AddRefed<Element> CreateHTMLContent(nsAtom* aTag);
|
||||
already_AddRefed<Element> CreateHTMLContent(const nsAtom* aTag);
|
||||
|
||||
/**
|
||||
* Creates text node which is marked as "maybe modified frequently".
|
||||
|
@ -1467,7 +1467,7 @@ HTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
|
||||
}
|
||||
|
||||
RefPtr<Element> divElement =
|
||||
CreateElementWithDefaults(NS_LITERAL_STRING("div"));
|
||||
CreateElementWithDefaults(*nsGkAtoms::div);
|
||||
if (NS_WARN_IF(!divElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2805,58 +2805,52 @@ HTMLEditor::GetSelectedElement(Selection& aSelection,
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
|
||||
HTMLEditor::CreateElementWithDefaults(const nsAtom& aTagName)
|
||||
{
|
||||
MOZ_ASSERT(!aTagName.IsEmpty());
|
||||
// NOTE: Despite of public method, this can be called for internal use.
|
||||
|
||||
nsAutoString tagName(aTagName);
|
||||
ToLowerCase(tagName);
|
||||
nsAutoString realTagName;
|
||||
const nsAtom* realTagName =
|
||||
IsLinkTag(aTagName) || IsNamedAnchorTag(aTagName) ? nsGkAtoms::a :
|
||||
&aTagName;
|
||||
|
||||
if (IsLinkTag(tagName) || IsNamedAnchorTag(tagName)) {
|
||||
realTagName.Assign('a');
|
||||
} else {
|
||||
realTagName = tagName;
|
||||
}
|
||||
// We don't use editor's CreateElement because we don't want to go through
|
||||
// the transaction system
|
||||
|
||||
// New call to use instead to get proper HTML element, bug 39919
|
||||
RefPtr<nsAtom> realTagAtom = NS_Atomize(realTagName);
|
||||
RefPtr<Element> newElement = CreateHTMLContent(realTagAtom);
|
||||
RefPtr<Element> newElement = CreateHTMLContent(realTagName);
|
||||
if (!newElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Mark the new element dirty, so it will be formatted
|
||||
ErrorResult rv;
|
||||
// XXX Don't we need to check the error result of setting _moz_dirty attr?
|
||||
IgnoredErrorResult rv;
|
||||
newElement->SetAttribute(NS_LITERAL_STRING("_moz_dirty"), EmptyString(), rv);
|
||||
|
||||
// Set default values for new elements
|
||||
if (tagName.EqualsLiteral("table")) {
|
||||
if (realTagName == nsGkAtoms::table) {
|
||||
newElement->SetAttribute(NS_LITERAL_STRING("cellpadding"),
|
||||
NS_LITERAL_STRING("2"), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
newElement->SetAttribute(NS_LITERAL_STRING("cellspacing"),
|
||||
NS_LITERAL_STRING("2"), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
newElement->SetAttribute(NS_LITERAL_STRING("border"),
|
||||
NS_LITERAL_STRING("1"), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
} else if (tagName.EqualsLiteral("td")) {
|
||||
} else if (realTagName == nsGkAtoms::td) {
|
||||
nsresult rv =
|
||||
SetAttributeOrEquivalent(
|
||||
newElement, nsGkAtoms::valign, NS_LITERAL_STRING("top"), true);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// ADD OTHER TAGS HERE
|
||||
|
||||
@ -2867,12 +2861,20 @@ NS_IMETHODIMP
|
||||
HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName,
|
||||
Element** aReturn)
|
||||
{
|
||||
NS_ENSURE_TRUE(!aTagName.IsEmpty() && aReturn, NS_ERROR_NULL_POINTER);
|
||||
if (NS_WARN_IF(aTagName.IsEmpty()) || NS_WARN_IF(!aReturn)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aReturn = nullptr;
|
||||
|
||||
nsCOMPtr<Element> newElement = CreateElementWithDefaults(aTagName);
|
||||
NS_ENSURE_TRUE(newElement, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
|
||||
if (NS_WARN_IF(!tagName)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
RefPtr<Element> newElement = CreateElementWithDefaults(*tagName);
|
||||
if (NS_WARN_IF(!newElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
newElement.forget(aReturn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -180,6 +180,22 @@ public:
|
||||
*/
|
||||
nsresult OnInputLineBreak();
|
||||
|
||||
/**
|
||||
* CreateElementWithDefaults() creates new element whose name is
|
||||
* aTagName with some default attributes are set. Note that this is a
|
||||
* public utility method. I.e., just creates element, not insert it
|
||||
* into the DOM tree.
|
||||
* NOTE: This is available for internal use too since this does not change
|
||||
* the DOM tree nor undo transactions, and does not refer Selection,
|
||||
* HTMLEditRules, etc.
|
||||
*
|
||||
* @param aTagName The new element's tag name. If the name is
|
||||
* one of "href", "anchor" or "namedanchor",
|
||||
* this creates an <a> element.
|
||||
* @return Newly created element.
|
||||
*/
|
||||
already_AddRefed<Element> CreateElementWithDefaults(const nsAtom& aTagName);
|
||||
|
||||
/**
|
||||
* Indent or outdent content around Selection.
|
||||
*/
|
||||
@ -1477,10 +1493,7 @@ protected: // Shouldn't be used by friend classes
|
||||
const nsAString& aValue);
|
||||
typedef enum { eInserted, eAppended } InsertedOrAppended;
|
||||
void DoContentInserted(nsIContent* aChild, InsertedOrAppended);
|
||||
// XXX Shouldn't this used by external classes instead of nsIHTMLEditor's
|
||||
// method?
|
||||
already_AddRefed<Element> CreateElementWithDefaults(
|
||||
const nsAString& aTagName);
|
||||
|
||||
/**
|
||||
* Returns an anonymous Element of type aTag,
|
||||
* child of aParentContent. If aIsCreatedHidden is true, the class
|
||||
|
@ -1536,12 +1536,16 @@ InsertTagCommand::DoCommand(const char* aCmdName, nsISupports* refCon)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<Element> newElement;
|
||||
nsresult rv = htmlEditor->CreateElementWithDefaults(
|
||||
nsDependentAtomString(mTagName), getter_AddRefs(newElement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return htmlEditor->InsertElementAtSelection(newElement, true);
|
||||
RefPtr<Element> newElement =
|
||||
htmlEditor->CreateElementWithDefaults(*mTagName);
|
||||
if (NS_WARN_IF(!newElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = htmlEditor->InsertElementAtSelection(newElement, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1591,22 +1595,32 @@ InsertTagCommand::DoCommandParams(const char *aCommandName,
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
RefPtr<Element> elem;
|
||||
rv = htmlEditor->CreateElementWithDefaults(nsDependentAtomString(mTagName),
|
||||
getter_AddRefs(elem));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> newElement =
|
||||
htmlEditor->CreateElementWithDefaults(*mTagName);
|
||||
if (NS_WARN_IF(!newElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult err;
|
||||
elem->SetAttribute(attributeType, attribute, err);
|
||||
newElement->SetAttribute(attributeType, attribute, err);
|
||||
if (NS_WARN_IF(err.Failed())) {
|
||||
return err.StealNSResult();
|
||||
}
|
||||
|
||||
// do actual insertion
|
||||
if (mTagName == nsGkAtoms::a) {
|
||||
return htmlEditor->InsertLinkAroundSelection(elem);
|
||||
rv = htmlEditor->InsertLinkAroundSelection(newElement);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return htmlEditor->InsertElementAtSelection(elem, true);
|
||||
|
||||
rv = htmlEditor->InsertElementAtSelection(newElement, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -109,8 +109,7 @@ HTMLEditor::InsertCell(Element* aCell,
|
||||
}
|
||||
|
||||
RefPtr<Element> newCell =
|
||||
CreateElementWithDefaults(aIsHeader ? NS_LITERAL_STRING("th") :
|
||||
NS_LITERAL_STRING("tb"));
|
||||
CreateElementWithDefaults(aIsHeader ? *nsGkAtoms::th : *nsGkAtoms::td);
|
||||
if (NS_WARN_IF(!newCell)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -202,10 +201,8 @@ HTMLEditor::InsertTableCell(int32_t aNumber,
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
|
||||
for (int32_t i = 0; i < aNumber; i++) {
|
||||
RefPtr<Element> newCell;
|
||||
rv = CreateElementWithDefaults(NS_LITERAL_STRING("td"),
|
||||
getter_AddRefs(newCell));
|
||||
if (NS_SUCCEEDED(rv) && newCell) {
|
||||
RefPtr<Element> newCell = CreateElementWithDefaults(*nsGkAtoms::td);
|
||||
if (newCell) {
|
||||
if (aAfter) {
|
||||
cellOffset++;
|
||||
}
|
||||
@ -214,6 +211,8 @@ HTMLEditor::InsertTableCell(int32_t aNumber,
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
// XXX This is perhaps the result of the last call of
|
||||
@ -625,13 +624,16 @@ HTMLEditor::InsertTableRow(int32_t aNumber,
|
||||
|
||||
for (int32_t row = 0; row < aNumber; row++) {
|
||||
// Create a new row
|
||||
nsCOMPtr<Element> newRow = CreateElementWithDefaults(trStr);
|
||||
NS_ENSURE_TRUE(newRow, NS_ERROR_FAILURE);
|
||||
RefPtr<Element> newRow = CreateElementWithDefaults(*nsGkAtoms::tr);
|
||||
if (NS_WARN_IF(!newRow)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < cellsInRow; i++) {
|
||||
nsCOMPtr<Element> newCell =
|
||||
CreateElementWithDefaults(NS_LITERAL_STRING("td"));
|
||||
NS_ENSURE_TRUE(newCell, NS_ERROR_FAILURE);
|
||||
RefPtr<Element> newCell = CreateElementWithDefaults(*nsGkAtoms::td);
|
||||
if (NS_WARN_IF(!newCell)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Don't use transaction system yet! (not until entire row is
|
||||
// inserted)
|
||||
|
@ -5,7 +5,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAutoConfig.idl',
|
||||
'nsIReadConfig.idl',
|
||||
]
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_AUTOCONFIG_CID\
|
||||
{ 0xe036c738,\
|
||||
0x1dd1,\
|
||||
0x11b2,\
|
||||
{ 0x93, 0x92, 0x9d, 0x94, 0xaa, 0x74, 0xb0, 0xc5 }\
|
||||
}
|
||||
|
||||
#define NS_AUTOCONFIG_CONTRACTID \
|
||||
"@mozilla.org/autoconfiguration;1"
|
||||
|
||||
%}
|
||||
|
||||
[uuid (80DB54AE-13F2-11d5-BE44-00108335A220)]
|
||||
interface nsIAutoConfig : nsISupports {
|
||||
attribute string configURL;
|
||||
};
|
@ -33,7 +33,7 @@ mozilla::LazyLogModule MCD("MCD");
|
||||
|
||||
// nsISupports Implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener,
|
||||
NS_IMPL_ISUPPORTS(nsAutoConfig, nsITimerCallback, nsIStreamListener,
|
||||
nsIObserver, nsIRequestObserver, nsISupportsWeakReference,
|
||||
nsINamed)
|
||||
|
||||
@ -63,28 +63,10 @@ nsAutoConfig::~nsAutoConfig()
|
||||
{
|
||||
}
|
||||
|
||||
// attribute string configURL
|
||||
NS_IMETHODIMP nsAutoConfig::GetConfigURL(char **aConfigURL)
|
||||
void
|
||||
nsAutoConfig::SetConfigURL(const char *aConfigURL)
|
||||
{
|
||||
if (!aConfigURL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (mConfigURL.IsEmpty()) {
|
||||
*aConfigURL = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aConfigURL = ToNewCString(mConfigURL);
|
||||
if (!*aConfigURL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP nsAutoConfig::SetConfigURL(const char *aConfigURL)
|
||||
{
|
||||
if (!aConfigURL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
mConfigURL.Assign(aConfigURL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6,7 +6,6 @@
|
||||
#ifndef nsAutoConfig_h
|
||||
#define nsAutoConfig_h
|
||||
|
||||
#include "nsIAutoConfig.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsINamed.h"
|
||||
@ -17,18 +16,16 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsAutoConfig : public nsIAutoConfig,
|
||||
public nsITimerCallback,
|
||||
public nsIStreamListener,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
public nsINamed
|
||||
class nsAutoConfig final : public nsITimerCallback,
|
||||
public nsIStreamListener,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
public nsINamed
|
||||
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIAUTOCONFIG
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIOBSERVER
|
||||
@ -38,6 +35,8 @@ class nsAutoConfig : public nsIAutoConfig,
|
||||
nsAutoConfig();
|
||||
nsresult Init();
|
||||
|
||||
void SetConfigURL(const char* aConfigURL);
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~nsAutoConfig();
|
||||
|
@ -4,24 +4,19 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsAutoConfig.h"
|
||||
#include "nsReadConfig.h"
|
||||
#include "nsIAppStartupNotifier.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAutoConfig, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsReadConfig, Init)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_AUTOCONFIG_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_READCONFIG_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kAutoConfigCIDs[] = {
|
||||
{ &kNS_AUTOCONFIG_CID, false, nullptr, nsAutoConfigConstructor },
|
||||
{ &kNS_READCONFIG_CID, false, nullptr, nsReadConfigConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kAutoConfigContracts[] = {
|
||||
{ NS_AUTOCONFIG_CONTRACTID, &kNS_AUTOCONFIG_CID },
|
||||
{ NS_READCONFIG_CONTRACTID, &kNS_READCONFIG_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "nsIAppStartup.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsIAutoConfig.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -233,14 +232,14 @@ nsresult nsReadConfig::readConfigFile()
|
||||
if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) {
|
||||
|
||||
// Instantiating nsAutoConfig object if the pref is present
|
||||
mAutoConfig = do_CreateInstance(NS_AUTOCONFIG_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mAutoConfig = new nsAutoConfig();
|
||||
|
||||
rv = mAutoConfig->SetConfigURL(urlName.get());
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = mAutoConfig->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mAutoConfig->SetConfigURL(urlName.get());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -6,14 +6,14 @@
|
||||
#ifndef nsReadConfig_h
|
||||
#define nsReadConfig_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIReadConfig.h"
|
||||
#include "nsIAutoConfig.h"
|
||||
#include "nsAutoConfig.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
|
||||
class nsReadConfig : public nsIReadConfig,
|
||||
public nsIObserver
|
||||
class nsReadConfig final : public nsIReadConfig,
|
||||
public nsIObserver
|
||||
{
|
||||
|
||||
public:
|
||||
@ -35,7 +35,7 @@ class nsReadConfig : public nsIReadConfig,
|
||||
bool isEncoded, bool isBinDir);
|
||||
bool mRead;
|
||||
private:
|
||||
nsCOMPtr<nsIAutoConfig> mAutoConfig;
|
||||
RefPtr<nsAutoConfig> mAutoConfig;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -23,15 +23,6 @@ LOCAL_INCLUDES += [
|
||||
'/xpcom/base',
|
||||
]
|
||||
|
||||
if CONFIG['LIBFUZZER']:
|
||||
USE_LIBS += [
|
||||
'fuzzer',
|
||||
'mozglue'
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/tools/fuzzing/libfuzzer',
|
||||
]
|
||||
|
||||
# DELAYLOAD_DLLS in this block ensures that the DLL blocklist is functional
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DELAYLOAD_DLLS += [
|
||||
|
@ -31,13 +31,12 @@ DoWhileEmitter::emitBody(const Maybe<uint32_t>& doPos, const Maybe<uint32_t>& bo
|
||||
return false;
|
||||
}
|
||||
|
||||
// Emit an annotated nop so IonBuilder can recognize the 'do' loop.
|
||||
if (!bce_->newSrcNote(SRC_WHILE, ¬eIndex_))
|
||||
return false;
|
||||
// We need a nop here to make it possible to set a breakpoint on `do`.
|
||||
if (!bce_->emit1(JSOP_NOP))
|
||||
return false;
|
||||
|
||||
if (!bce_->newSrcNote(SRC_WHILE, ¬eIndex2_))
|
||||
// Emit an annotated nop so IonBuilder can recognize the 'do' loop.
|
||||
if (!bce_->newSrcNote3(SRC_DO_WHILE, 0, 0, ¬eIndex_))
|
||||
return false;
|
||||
|
||||
loopInfo_.emplace(bce_, StatementKind::DoLoop);
|
||||
@ -84,18 +83,13 @@ DoWhileEmitter::emitEnd()
|
||||
|
||||
// Update the annotations with the update and back edge positions, for
|
||||
// IonBuilder.
|
||||
//
|
||||
// Be careful: We must set noteIndex2_ before_ noteIndex in case the
|
||||
// noteIndex_ note gets bigger. Otherwise noteIndex2_ can point wrong
|
||||
// position.
|
||||
if (!bce_->setSrcNoteOffset(noteIndex2_, SrcNote::DoWhile2::BackJumpOffset,
|
||||
loopInfo_->loopEndOffsetFromLoopHead()))
|
||||
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::CondOffset,
|
||||
loopInfo_->continueTargetOffsetFromLoopHead()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// +1 for NOP in emitBody.
|
||||
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile1::CondOffset,
|
||||
loopInfo_->continueTargetOffsetFromLoopHead() + 1))
|
||||
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::BackJumpOffset,
|
||||
loopInfo_->loopEndOffsetFromLoopHead()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -35,10 +35,8 @@ class MOZ_STACK_CLASS DoWhileEmitter
|
||||
{
|
||||
BytecodeEmitter* bce_;
|
||||
|
||||
// The source note indices for 2 SRC_WHILE's.
|
||||
// FIXME: Add SRC_DO_WHILE (bug 1477896).
|
||||
// The source note index for SRC_DO_WHILE.
|
||||
unsigned noteIndex_ = 0;
|
||||
unsigned noteIndex2_ = 0;
|
||||
|
||||
mozilla::Maybe<LoopControl> loopInfo_;
|
||||
|
||||
|
@ -64,23 +64,13 @@ class SrcNote {
|
||||
Count,
|
||||
};
|
||||
};
|
||||
// SRC_WHILE for do-while: Source note for JSOP_NOP at the top of do-while
|
||||
// loop
|
||||
// FIXME: Add SRC_DO_WHILE (bug 1477896).
|
||||
class DoWhile1 {
|
||||
// SRC_DO_WHILE: Source note for JSOP_LOOPHEAD at the top of do-while loop
|
||||
class DoWhile {
|
||||
public:
|
||||
enum Fields {
|
||||
// The offset of the condition ops from JSOP_NOP.
|
||||
// The offset of the condition ops from JSOP_LOOPHEAD.
|
||||
CondOffset,
|
||||
Count,
|
||||
};
|
||||
};
|
||||
// SRC_WHILE for do-while: Source note for JSOP_LOOPHEAD at the top of
|
||||
// do-while loop
|
||||
// FIXME: Add SRC_DO_WHILE (bug 1477896).
|
||||
class DoWhile2 {
|
||||
public:
|
||||
enum Fields {
|
||||
|
||||
// The offset of JSOP_IFNE at the end of the loop from
|
||||
// JSOP_LOOPHEAD.
|
||||
BackJumpOffset,
|
||||
@ -171,12 +161,6 @@ class SrcNote {
|
||||
};
|
||||
};
|
||||
|
||||
// FIXME: Add SRC_DO_WHILE (bug 1477896).
|
||||
static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile1::Count),
|
||||
"SRC_WHILE can be shared between while and do-while");
|
||||
static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile2::Count),
|
||||
"SRC_WHILE can be shared between while and do-while");
|
||||
|
||||
#define FOR_EACH_SRC_NOTE_TYPE(M) \
|
||||
M(SRC_NULL, "null", 0) /* Terminates a note vector. */ \
|
||||
M(SRC_IF, "if", 0) /* JSOP_IFEQ bytecode is from an if-then. */ \
|
||||
@ -184,6 +168,7 @@ static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile2::Cou
|
||||
M(SRC_COND, "cond", 0) /* JSOP_IFEQ is from conditional ?: operator. */ \
|
||||
M(SRC_FOR, "for", SrcNote::For::Count) \
|
||||
M(SRC_WHILE, "while", SrcNote::While::Count) \
|
||||
M(SRC_DO_WHILE, "do-while", SrcNote::DoWhile::Count) \
|
||||
M(SRC_FOR_IN, "for-in", SrcNote::ForIn::Count) \
|
||||
M(SRC_FOR_OF, "for-of", SrcNote::ForOf::Count) \
|
||||
M(SRC_CONTINUE, "continue", 0) /* JSOP_GOTO is a continue. */ \
|
||||
@ -201,7 +186,6 @@ static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile2::Cou
|
||||
M(SRC_COLSPAN, "colspan", SrcNote::ColSpan::Count) \
|
||||
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
|
||||
M(SRC_SETLINE, "setline", SrcNote::SetLine::Count) \
|
||||
M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \
|
||||
M(SRC_XDELTA, "xdelta", 0) /* 24-31 are for extended delta notes. */
|
||||
|
@ -264,17 +264,8 @@ ControlFlowGenerator::snoopControlFlow(JSOp op)
|
||||
switch (op) {
|
||||
case JSOP_NOP: {
|
||||
jssrcnote* sn = GetSrcNote(gsn, script, pc);
|
||||
if (sn) {
|
||||
// do { } while (cond)
|
||||
if (SN_TYPE(sn) == SRC_WHILE)
|
||||
return processDoWhileLoop(sn);
|
||||
// Build a mapping such that given a basic block, whose successor
|
||||
// has a phi
|
||||
|
||||
// for (; ; update?)
|
||||
if (SN_TYPE(sn) == SRC_FOR)
|
||||
return processForLoop(op, sn);
|
||||
}
|
||||
if (sn && SN_TYPE(sn) == SRC_FOR)
|
||||
return processForLoop(op, sn);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -312,6 +303,13 @@ ControlFlowGenerator::snoopControlFlow(JSOp op)
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_LOOPHEAD: {
|
||||
jssrcnote* sn = GetSrcNote(gsn, script, pc);
|
||||
if (sn && SN_TYPE(sn) == SRC_DO_WHILE)
|
||||
return processDoWhileLoop(sn);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_TABLESWITCH: {
|
||||
jssrcnote* sn = GetSrcNote(gsn, script, pc);
|
||||
return processTableSwitch(op, sn);
|
||||
@ -1505,24 +1503,22 @@ ControlFlowGenerator::ControlStatus
|
||||
ControlFlowGenerator::processDoWhileLoop(jssrcnote* sn)
|
||||
{
|
||||
// do { } while() loops have the following structure:
|
||||
// NOP ; SRC_WHILE (offset to COND)
|
||||
// LOOPHEAD ; SRC_WHILE (offset to IFNE)
|
||||
// NOP
|
||||
// LOOPHEAD ; SRC_DO_WHILE (offsets to COND and IFNE)
|
||||
// LOOPENTRY
|
||||
// ... ; body
|
||||
// ...
|
||||
// COND ; start of condition
|
||||
// ...
|
||||
// IFNE -> ; goes to LOOPHEAD
|
||||
int condition_offset = GetSrcNoteOffset(sn, SrcNote::DoWhile1::CondOffset);
|
||||
int condition_offset = GetSrcNoteOffset(sn, SrcNote::DoWhile::CondOffset);
|
||||
jsbytecode* conditionpc = pc + condition_offset;
|
||||
|
||||
jssrcnote* sn2 = GetSrcNote(gsn, script, pc + 1);
|
||||
int offset = GetSrcNoteOffset(sn2, SrcNote::DoWhile2::BackJumpOffset);
|
||||
jsbytecode* ifne = pc + offset + 1;
|
||||
int offset = GetSrcNoteOffset(sn, SrcNote::DoWhile::BackJumpOffset);
|
||||
jsbytecode* ifne = pc + offset;
|
||||
MOZ_ASSERT(ifne > pc);
|
||||
|
||||
// Verify that the IFNE goes back to a loophead op.
|
||||
jsbytecode* loopHead = GetNextPc(pc);
|
||||
jsbytecode* loopHead = pc;
|
||||
MOZ_ASSERT(JSOp(*loopHead) == JSOP_LOOPHEAD);
|
||||
MOZ_ASSERT(loopHead == ifne + GetJumpOffset(ifne));
|
||||
|
||||
|
@ -667,7 +667,6 @@ bool
|
||||
JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, const VMFunction& f)
|
||||
{
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
MOZ_ASSERT(functionWrappers_->initialized());
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
|
@ -646,7 +646,6 @@ bool
|
||||
JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, const VMFunction& f)
|
||||
{
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
MOZ_ASSERT(functionWrappers_->initialized());
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
|
@ -2752,20 +2752,24 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp)
|
||||
}
|
||||
break;
|
||||
|
||||
case SRC_WHILE:
|
||||
case SRC_FOR_IN:
|
||||
case SRC_FOR_OF:
|
||||
static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
|
||||
"SrcNote::{ForIn,ForOf}::BackJumpOffset should be same");
|
||||
static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForIn::BackJumpOffset),
|
||||
"SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
|
||||
static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
|
||||
"SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
|
||||
if (!sp->jsprintf(" backjump %u",
|
||||
unsigned(GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset))))
|
||||
unsigned(GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SRC_WHILE:
|
||||
if (!sp->jsprintf(" offset %u",
|
||||
unsigned(GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset))))
|
||||
case SRC_DO_WHILE:
|
||||
if (!sp->jsprintf(" cond %u backjump %u",
|
||||
unsigned(GetSrcNoteOffset(sn, SrcNote::DoWhile::CondOffset)),
|
||||
unsigned(GetSrcNoteOffset(sn, SrcNote::DoWhile::BackJumpOffset))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
|
||||
HandleFunction callee, HandleObject envChain)
|
||||
{
|
||||
MOZ_ASSERT(callee->isGenerator() || callee->isAsync());
|
||||
RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
|
||||
RootedScript script(cx, callee->nonLazyScript());
|
||||
InterpreterFrame* prev = regs.fp();
|
||||
jsbytecode* prevpc = regs.pc;
|
||||
Value* prevsp = regs.sp;
|
||||
|
112
mfbt/HashTable.h
112
mfbt/HashTable.h
@ -289,11 +289,11 @@ public:
|
||||
// Like putNew(), but should be only used when the table is known to be big
|
||||
// enough for the insertion, and hashing cannot fail. Typically this is used
|
||||
// to populate an empty map with known-unique keys after reserving space with
|
||||
// init(), e.g.
|
||||
// reserve(), e.g.
|
||||
//
|
||||
// using HM = HashMap<int,char>;
|
||||
// HM h;
|
||||
// if (!h.init(3)) {
|
||||
// if (!h.reserve(3)) {
|
||||
// MOZ_CRASH("OOM");
|
||||
// }
|
||||
// h.putNewInfallible(1, 'a'); // unique key
|
||||
@ -603,11 +603,11 @@ public:
|
||||
// Like putNew(), but should be only used when the table is known to be big
|
||||
// enough for the insertion, and hashing cannot fail. Typically this is used
|
||||
// to populate an empty set with known-unique elements after reserving space
|
||||
// with init(), e.g.
|
||||
// with reserve(), e.g.
|
||||
//
|
||||
// using HS = HashMap<int>;
|
||||
// HS h;
|
||||
// if (!h.init(3)) {
|
||||
// if (!h.reserve(3)) {
|
||||
// MOZ_CRASH("OOM");
|
||||
// }
|
||||
// h.putNewInfallible(1); // unique element
|
||||
@ -1444,7 +1444,7 @@ public:
|
||||
{
|
||||
if (mRekeyed) {
|
||||
mTable.mGen++;
|
||||
mTable.checkOverRemoved();
|
||||
mTable.infallibleRehashIfOverloaded();
|
||||
}
|
||||
|
||||
if (mRemoved) {
|
||||
@ -1636,17 +1636,6 @@ public:
|
||||
return table;
|
||||
}
|
||||
|
||||
static Entry* maybeCreateTable(AllocPolicy& aAllocPolicy, uint32_t aCapacity)
|
||||
{
|
||||
Entry* table = aAllocPolicy.template maybe_pod_malloc<Entry>(aCapacity);
|
||||
if (table) {
|
||||
for (uint32_t i = 0; i < aCapacity; i++) {
|
||||
new (&table[i]) Entry();
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static void destroyTable(AllocPolicy& aAllocPolicy,
|
||||
Entry* aOldTable,
|
||||
uint32_t aCapacity)
|
||||
@ -1708,29 +1697,6 @@ private:
|
||||
return (aHash1 - aDoubleHash.mHash2) & aDoubleHash.mSizeMask;
|
||||
}
|
||||
|
||||
// True if the current load is equal to or exceeds the maximum.
|
||||
bool overloaded()
|
||||
{
|
||||
static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator,
|
||||
"multiplication below could overflow");
|
||||
|
||||
// Note: if capacity() is zero, this will always succeed, which is
|
||||
// what we want.
|
||||
return mEntryCount + mRemovedCount >=
|
||||
capacity() * sMaxAlphaNumerator / sAlphaDenominator;
|
||||
}
|
||||
|
||||
// Would the table be underloaded if it had the given capacity and entryCount?
|
||||
static bool wouldBeUnderloaded(uint32_t aCapacity, uint32_t aEntryCount)
|
||||
{
|
||||
static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator,
|
||||
"multiplication below could overflow");
|
||||
return aCapacity > sMinCapacity &&
|
||||
aEntryCount <= aCapacity * sMinAlphaNumerator / sAlphaDenominator;
|
||||
}
|
||||
|
||||
bool underloaded() { return wouldBeUnderloaded(capacity(), mEntryCount); }
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool match(Entry& aEntry, const Lookup& aLookup)
|
||||
{
|
||||
return HashPolicy::match(HashPolicy::getKey(aEntry.get()), aLookup);
|
||||
@ -1796,8 +1762,8 @@ private:
|
||||
|
||||
// This is a copy of lookup() hardcoded to the assumptions:
|
||||
// 1. the lookup is for an add;
|
||||
// 2. the key, whose |keyHash| has been passed is not in the table.
|
||||
Entry& findFreeEntry(HashNumber aKeyHash)
|
||||
// 2. the key, whose |keyHash| has been passed, is not in the table.
|
||||
Entry& findNonLiveEntry(HashNumber aKeyHash)
|
||||
{
|
||||
MOZ_ASSERT(!(aKeyHash & sCollisionBit));
|
||||
MOZ_ASSERT(mTable);
|
||||
@ -1869,7 +1835,7 @@ private:
|
||||
for (Entry* src = oldTable; src < end; ++src) {
|
||||
if (src->isLive()) {
|
||||
HashNumber hn = src->getKeyHash();
|
||||
findFreeEntry(hn).setLive(
|
||||
findNonLiveEntry(hn).setLive(
|
||||
hn, std::move(const_cast<typename Entry::NonConstT&>(src->get())));
|
||||
}
|
||||
|
||||
@ -1881,34 +1847,34 @@ private:
|
||||
return Rehashed;
|
||||
}
|
||||
|
||||
bool shouldCompressTable()
|
||||
RebuildStatus rehashIfOverloaded(
|
||||
FailureBehavior aReportFailure = ReportFailure)
|
||||
{
|
||||
static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator,
|
||||
"multiplication below could overflow");
|
||||
|
||||
// Note: if capacity() is zero, this will always succeed, which is
|
||||
// what we want.
|
||||
bool overloaded = mEntryCount + mRemovedCount >=
|
||||
capacity() * sMaxAlphaNumerator / sAlphaDenominator;
|
||||
|
||||
if (!overloaded) {
|
||||
return NotOverloaded;
|
||||
}
|
||||
|
||||
// Succeed if a quarter or more of all entries are removed. Note that this
|
||||
// always succeeds if capacity() == 0 (i.e. entry storage has not been
|
||||
// allocated), which is what we want, because it means changeTableSize()
|
||||
// will allocate the requested capacity rather than doubling it.
|
||||
return mRemovedCount >= (capacity() >> 2);
|
||||
}
|
||||
|
||||
RebuildStatus checkOverloaded(FailureBehavior aReportFailure = ReportFailure)
|
||||
{
|
||||
if (!overloaded()) {
|
||||
return NotOverloaded;
|
||||
}
|
||||
|
||||
uint32_t newCapacity = shouldCompressTable()
|
||||
? rawCapacity()
|
||||
: rawCapacity() * 2;
|
||||
bool manyRemoved = mRemovedCount >= (capacity() >> 2);
|
||||
uint32_t newCapacity = manyRemoved ? rawCapacity() : rawCapacity() * 2;
|
||||
return changeTableSize(newCapacity, aReportFailure);
|
||||
}
|
||||
|
||||
// Infallibly rehash the table if we are overloaded with removals.
|
||||
void checkOverRemoved()
|
||||
void infallibleRehashIfOverloaded()
|
||||
{
|
||||
if (overloaded()) {
|
||||
if (checkOverloaded(DontReportFailure) == RehashFailed) {
|
||||
rehashTableInPlace();
|
||||
}
|
||||
if (rehashIfOverloaded(DontReportFailure) == RehashFailed) {
|
||||
rehashTableInPlace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1928,9 +1894,15 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
void checkUnderloaded()
|
||||
void shrinkIfUnderloaded()
|
||||
{
|
||||
if (underloaded()) {
|
||||
static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator,
|
||||
"multiplication below could overflow");
|
||||
bool underloaded =
|
||||
capacity() > sMinCapacity &&
|
||||
mEntryCount <= capacity() * sMinAlphaNumerator / sAlphaDenominator;
|
||||
|
||||
if (underloaded) {
|
||||
(void)changeTableSize(capacity() / 2, DontReportFailure);
|
||||
}
|
||||
}
|
||||
@ -1989,7 +1961,7 @@ private:
|
||||
MOZ_ASSERT(mTable);
|
||||
|
||||
HashNumber keyHash = prepareHash(aLookup);
|
||||
Entry* entry = &findFreeEntry(keyHash);
|
||||
Entry* entry = &findNonLiveEntry(keyHash);
|
||||
MOZ_ASSERT(entry);
|
||||
|
||||
if (entry->isRemoved()) {
|
||||
@ -2019,7 +1991,7 @@ public:
|
||||
}
|
||||
|
||||
// Resize the table down to the smallest capacity that doesn't overload the
|
||||
// table. Since we call checkUnderloaded() on every remove, you only need
|
||||
// table. Since we call shrinkIfUnderloaded() on every remove, you only need
|
||||
// to call this after a bulk removal of items done without calling remove().
|
||||
void compact()
|
||||
{
|
||||
@ -2180,7 +2152,7 @@ public:
|
||||
aPtr.mKeyHash |= sCollisionBit;
|
||||
} else {
|
||||
// Preserve the validity of |aPtr.mEntry|.
|
||||
RebuildStatus status = checkOverloaded();
|
||||
RebuildStatus status = rehashIfOverloaded();
|
||||
if (status == RehashFailed) {
|
||||
return false;
|
||||
}
|
||||
@ -2188,7 +2160,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
if (status == Rehashed) {
|
||||
aPtr.mEntry = &findFreeEntry(aPtr.mKeyHash);
|
||||
aPtr.mEntry = &findNonLiveEntry(aPtr.mKeyHash);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2223,7 +2195,7 @@ public:
|
||||
if (!EnsureHash<HashPolicy>(aLookup)) {
|
||||
return false;
|
||||
}
|
||||
if (checkOverloaded() == RehashFailed) {
|
||||
if (rehashIfOverloaded() == RehashFailed) {
|
||||
return false;
|
||||
}
|
||||
putNewInfallible(aLookup, std::forward<Args>(aArgs)...);
|
||||
@ -2261,7 +2233,7 @@ public:
|
||||
MOZ_ASSERT(aPtr.found());
|
||||
MOZ_ASSERT(aPtr.mGeneration == generation());
|
||||
remove(*aPtr.mEntry);
|
||||
checkUnderloaded();
|
||||
shrinkIfUnderloaded();
|
||||
}
|
||||
|
||||
void rekeyWithoutRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey)
|
||||
@ -2279,7 +2251,7 @@ public:
|
||||
void rekeyAndMaybeRehash(Ptr aPtr, const Lookup& aLookup, const Key& aKey)
|
||||
{
|
||||
rekeyWithoutRehash(aPtr, aLookup, aKey);
|
||||
checkOverRemoved();
|
||||
infallibleRehashIfOverloaded();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -46,12 +46,6 @@
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
/* workaround for bug 1306642 */
|
||||
#if defined(_MSC_VER) && defined(__clang__)
|
||||
#pragma clang diagnostic warning "-Wdll-attribute-on-redeclaration"
|
||||
#pragma clang diagnostic warning "-Winconsistent-dllimport"
|
||||
#endif
|
||||
|
||||
/* These definitions are usually provided through the
|
||||
* sanitizer/asan_interface.h header installed by ASan.
|
||||
*/
|
||||
|
@ -247,6 +247,37 @@ public final class GeckoRuntimeSettings implements Parcelable {
|
||||
mSettings.mDisplayDensityOverride = density;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Set whether or not known malware sites should be blocked.
|
||||
*
|
||||
* Note: For each blocked site, {@link NavigationDelegate#onLoadError}
|
||||
* with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING}
|
||||
* is called.
|
||||
*
|
||||
* @param enabled A flag determining whether or not to block malware
|
||||
* sites.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public @NonNull Builder blockMalware(boolean enabled) {
|
||||
mSettings.mSafebrowsingMalware.set(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not known phishing sites should be blocked.
|
||||
*
|
||||
* Note: For each blocked site, {@link NavigationDelegate#onLoadError}
|
||||
* with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING}
|
||||
* is called.
|
||||
*
|
||||
* @param enabled A flag determining whether or not to block phishing
|
||||
* sites.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public @NonNull Builder blockPhishing(boolean enabled) {
|
||||
mSettings.mSafebrowsingPhishing.set(enabled);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ GeckoRuntime runtime;
|
||||
@ -305,6 +336,10 @@ public final class GeckoRuntimeSettings implements Parcelable {
|
||||
TrackingProtectionDelegate.CATEGORY_AD));
|
||||
/* package */ Pref<Boolean> mConsoleOutput = new Pref<Boolean>(
|
||||
"geckoview.console.enabled", false);
|
||||
/* package */ Pref<Boolean> mSafebrowsingMalware = new Pref<Boolean>(
|
||||
"browser.safebrowsing.malware.enabled", true);
|
||||
/* package */ Pref<Boolean> mSafebrowsingPhishing = new Pref<Boolean>(
|
||||
"browser.safebrowsing.phishing.enabled", true);
|
||||
|
||||
/* package */ boolean mNativeCrashReporting;
|
||||
/* package */ boolean mJavaCrashReporting;
|
||||
@ -314,7 +349,8 @@ public final class GeckoRuntimeSettings implements Parcelable {
|
||||
|
||||
private final Pref<?>[] mPrefs = new Pref<?>[] {
|
||||
mCookieBehavior, mCookieLifetime, mConsoleOutput,
|
||||
mJavaScript, mRemoteDebugging, mTrackingProtection, mWebFonts
|
||||
mJavaScript, mRemoteDebugging, mSafebrowsingMalware,
|
||||
mSafebrowsingPhishing, mTrackingProtection, mWebFonts,
|
||||
};
|
||||
|
||||
/* package */ GeckoRuntimeSettings() {
|
||||
@ -623,12 +659,60 @@ public final class GeckoRuntimeSettings implements Parcelable {
|
||||
/**
|
||||
* Get whether or not web console messages are sent to logcat.
|
||||
*
|
||||
* @return This GeckoRuntimeSettings instance.
|
||||
* @return True if console output is enabled.
|
||||
*/
|
||||
public boolean getConsoleOutputEnabled() {
|
||||
return mConsoleOutput.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not known malware sites should be blocked.
|
||||
*
|
||||
* Note: For each blocked site, {@link NavigationDelegate#onLoadError}
|
||||
* with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING}
|
||||
* is called.
|
||||
*
|
||||
* @param enabled A flag determining whether or not to block malware sites.
|
||||
* @return The GeckoRuntimeSettings instance.
|
||||
*/
|
||||
public @NonNull GeckoRuntimeSettings setBlockMalware(boolean enabled) {
|
||||
mSafebrowsingMalware.set(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not known malware sites are blocked.
|
||||
*
|
||||
* @return True if malware site blocking is enabled.
|
||||
*/
|
||||
public boolean getBlockMalware() {
|
||||
return mSafebrowsingMalware.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not known phishing sites should be blocked.
|
||||
*
|
||||
* Note: For each blocked site, {@link NavigationDelegate#onLoadError}
|
||||
* with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING}
|
||||
* is called.
|
||||
*
|
||||
* @param enabled A flag determining whether or not to block phishing sites.
|
||||
* @return The GeckoRuntimeSettings instance.
|
||||
*/
|
||||
public @NonNull GeckoRuntimeSettings setBlockPhishing(boolean enabled) {
|
||||
mSafebrowsingPhishing.set(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not known phishing sites are blocked.
|
||||
*
|
||||
* @return True if phishing site blocking is enabled.
|
||||
*/
|
||||
public boolean getBlockPhishing() {
|
||||
return mSafebrowsingPhishing.get();
|
||||
}
|
||||
|
||||
@Override // Parcelable
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
@ -7,19 +7,13 @@
|
||||
var EXPORTED_SYMBOLS = ["GeckoViewSettings"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/GeckoViewModule.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
/* global SafeBrowsing:false */
|
||||
GeckoViewUtils.addLazyGetter(this, "SafeBrowsing", {
|
||||
module: "resource://gre/modules/SafeBrowsing.jsm",
|
||||
init: sb => sb.init(),
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "DESKTOP_USER_AGENT",
|
||||
function() {
|
||||
@ -42,6 +36,8 @@ class GeckoViewSettings extends GeckoViewModule {
|
||||
onInit() {
|
||||
this._useTrackingProtection = false;
|
||||
this._useDesktopMode = false;
|
||||
// Required for safe browsing and tracking protection.
|
||||
SafeBrowsing.init();
|
||||
}
|
||||
|
||||
onSettingsUpdate() {
|
||||
@ -49,7 +45,6 @@ class GeckoViewSettings extends GeckoViewModule {
|
||||
debug `onSettingsUpdate: ${settings}`;
|
||||
|
||||
this.displayMode = settings.displayMode;
|
||||
this.useTrackingProtection = !!settings.useTrackingProtection;
|
||||
this.useDesktopMode = !!settings.useDesktopMode;
|
||||
}
|
||||
|
||||
@ -57,15 +52,6 @@ class GeckoViewSettings extends GeckoViewModule {
|
||||
return this.browser.isRemoteBrowser;
|
||||
}
|
||||
|
||||
get useTrackingProtection() {
|
||||
return this._useTrackingProtection;
|
||||
}
|
||||
|
||||
set useTrackingProtection(aUse) {
|
||||
aUse && SafeBrowsing;
|
||||
this._useTrackingProtection = aUse;
|
||||
}
|
||||
|
||||
onUserAgentRequest(aSubject, aTopic, aData) {
|
||||
debug `onUserAgentRequest`;
|
||||
|
||||
|
@ -1374,7 +1374,7 @@ pref("dom.event.highrestimestamp.enabled", true);
|
||||
pref("dom.event.coalesce_mouse_move", true);
|
||||
|
||||
#if defined(NIGHTLY_BUILD) && !defined(ANDROID)
|
||||
pref("dom.ua_widget.enabled", true);
|
||||
pref("dom.ua_widget.enabled", false);
|
||||
#else
|
||||
pref("dom.ua_widget.enabled", false);
|
||||
#endif
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/Move.h"
|
||||
#include "SandboxLogging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -170,57 +170,6 @@ android-x86/opt:
|
||||
- linux64-sccache
|
||||
- linux64-node
|
||||
|
||||
android-x86-fuzzing/debug:
|
||||
description: "Android x86 Fuzzing Debug"
|
||||
index:
|
||||
product: mobile
|
||||
job-name: android-x86-fuzzing-debug
|
||||
treeherder:
|
||||
platform: android-4-2-x86/debug
|
||||
symbol: Bf
|
||||
worker-type: aws-provisioner-v1/gecko-{level}-b-android
|
||||
worker:
|
||||
docker-image: {in-tree: android-build}
|
||||
max-run-time: 7200
|
||||
env:
|
||||
GRADLE_USER_HOME: "/builds/worker/workspace/build/src/mobile/android/gradle/dotgradle-offline"
|
||||
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android-x86/releng.manifest"
|
||||
artifacts:
|
||||
- name: public/android/R
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
|
||||
type: directory
|
||||
- name: public/android/maven
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
|
||||
type: directory
|
||||
- name: public/build/geckoview-androidTest.apk
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/outputs/apk/androidTest/officialWithGeckoBinariesNoMinApi/debug/geckoview-official-withGeckoBinaries-noMinApi-debug-androidTest.apk
|
||||
type: file
|
||||
- name: public/build/geckoview_example.apk
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
|
||||
type: file
|
||||
- name: public/build
|
||||
path: /builds/worker/artifacts/
|
||||
type: directory
|
||||
run:
|
||||
using: mozharness
|
||||
actions: [get-secrets build multi-l10n update]
|
||||
config:
|
||||
- builds/releng_base_android_64_builds.py
|
||||
script: "mozharness/scripts/fx_desktop_build.py"
|
||||
secrets: true
|
||||
custom-build-variant-cfg: x86-fuzzing-debug
|
||||
tooltool-downloads: internal
|
||||
toolchains:
|
||||
- android-gradle-dependencies
|
||||
- android-ndk-linux
|
||||
- android-sdk-linux
|
||||
- linux64-clang
|
||||
- linux64-rust-android
|
||||
- linux64-rust-size
|
||||
- linux64-cbindgen
|
||||
- linux64-sccache
|
||||
- linux64-node
|
||||
|
||||
android-x86-nightly/opt:
|
||||
description: "Android 4.2 x86 Nightly"
|
||||
attributes:
|
||||
|
@ -225,4 +225,4 @@ channel on irc.mozilla.org. Don’t ask if you can ask a question, just
|
||||
ask, and please wait for an answer as we might not be in your timezone.
|
||||
|
||||
[subscribe]: https://lists.mozilla.org/listinfo/tools-marionette
|
||||
[archive]: https://groups.google.com/group/mozilla.tools.marionette
|
||||
[archive]: https://lists.mozilla.org/pipermail/tools-marionette/
|
||||
|
@ -649,4 +649,4 @@ There is also an IRC channel to talk about using and developing
|
||||
geckodriver in #ateam on irc.mozilla.org.
|
||||
|
||||
[subscribe]: https://lists.mozilla.org/listinfo/tools-marionette
|
||||
[archive]: https://groups.google.com/group/mozilla.tools.marionette
|
||||
[archive]: https://lists.mozilla.org/pipermail/tools-marionette/
|
||||
|
@ -67,4 +67,4 @@ channel on irc.mozilla.org. Don’t ask if you may ask a question; just go ahea
|
||||
and ask, and please wait for an answer as we might not be in your timezone.
|
||||
|
||||
.. _subscribe: https://lists.mozilla.org/listinfo/tools-marionette
|
||||
.. _archive: https://groups.google.com/group/mozilla.tools.marionette
|
||||
.. _archive: https://lists.mozilla.org/pipermail/tools-marionette/
|
||||
|
@ -118,6 +118,11 @@ XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory",
|
||||
for (let path of gPathsToRemove) {
|
||||
await this.tolerantRemove(path);
|
||||
}
|
||||
|
||||
if (!(await OS.File.exists(dir.path))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect any extra files, like the ".part" files of downloads.
|
||||
let iterator = new OS.File.DirectoryIterator(dir.path);
|
||||
try {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user