Merge autoland to mozilla-central. a=merge

This commit is contained in:
shindli 2019-03-21 06:33:42 +02:00
commit 987aa4b78c
295 changed files with 5043 additions and 4156 deletions

23
Cargo.lock generated
View File

@ -376,6 +376,20 @@ name = "cc"
version = "1.0.23"
source = "git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64#2aa71628b1261b5515bd8668afca591669ba195d"
[[package]]
name = "cert_storage"
version = "0.0.1"
dependencies = [
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0",
"rkv 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"xpcom 0.1.0",
]
[[package]]
name = "cexpr"
version = "0.3.3"
@ -1127,6 +1141,7 @@ dependencies = [
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc-client 0.4.0",
"audioipc-server 0.2.3",
"cert_storage 0.0.1",
"cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-pulse 0.2.0",
"cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1172,7 +1187,7 @@ dependencies = [
[[package]]
name = "gleam"
version = "0.6.12"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3133,7 +3148,7 @@ dependencies = [
"dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3184,7 +3199,7 @@ dependencies = [
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nsstring 0.1.0",
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3439,7 +3454,7 @@ dependencies = [
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604"
"checksum gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f1519ca611d230e1deadbedfb79044b921ac4a961ab8823fef10e37271e2c38e"
"checksum gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "17bca843dd3cf25db1bf415d55de9c0f0ae09dd7fa952ec3cef9930f90de1339"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum goblin 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5911d7df7b8f65ab676c5327b50acea29d3c6a1a4ad05e444cf5dce321b26db2"
"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"

View File

@ -10,12 +10,8 @@ ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Logger",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Roles",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Events",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States",
"resource://gre/modules/accessibility/Constants.jsm");
var EXPORTED_SYMBOLS = ["EventManager"];
@ -85,27 +81,6 @@ this.EventManager.prototype = {
}
switch (aEvent.eventType) {
case Events.VIRTUALCURSOR_CHANGED:
{
if (!aEvent.isFromUserInput) {
break;
}
const event = aEvent.
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
const position = event.newAccessible;
// We pass control to the vc in the embedded frame.
if (position && position.role == Roles.INTERNAL_FRAME) {
break;
}
// Blur to document if new position is not explicitly focused.
if (!position || !Utils.getState(position).contains(States.FOCUSED)) {
aEvent.accessibleDocument.takeFocus();
}
break;
}
case Events.NAME_CHANGE:
{
// XXX: Port to Android

View File

@ -23,6 +23,12 @@ function isEventForAutocompleteItem(event) {
* search isn't finished yet.
*/
function waitForSearchFinish() {
if (UrlbarPrefs.get("quantumbar")) {
return Promise.all([
gURLBar.lastQueryContextPromise,
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen)
]);
}
return BrowserTestUtils.waitForCondition(() =>
(gURLBar.popupOpen && gURLBar.controller.searchStatus >=
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH),

View File

@ -3318,7 +3318,7 @@ window._gBrowser = {
this._isBusy = true;
}
this._swapBrowserDocShells(aOurTab, otherBrowser, Ci.nsIBrowser.SWAP_DEFAULT, stateFlags);
this._swapBrowserDocShells(aOurTab, otherBrowser, stateFlags);
}
// Unregister the previously opened URI
@ -3367,7 +3367,7 @@ window._gBrowser = {
return true;
},
swapBrowsers(aOurTab, aOtherTab, aFlags) {
swapBrowsers(aOurTab, aOtherTab) {
let otherBrowser = aOtherTab.linkedBrowser;
let otherTabBrowser = otherBrowser.getTabBrowser();
@ -3378,7 +3378,7 @@ window._gBrowser = {
filter.removeProgressListener(tabListener);
// Perform the docshell swap through the common mechanism.
this._swapBrowserDocShells(aOurTab, otherBrowser, aFlags);
this._swapBrowserDocShells(aOurTab, otherBrowser);
// Restore the listeners for the swapped in tab.
tabListener = new otherTabBrowser.ownerGlobal.TabProgressListener(aOtherTab, otherBrowser, false, false);
@ -3389,7 +3389,7 @@ window._gBrowser = {
otherBrowser.webProgress.addProgressListener(filter, notifyAll);
},
_swapBrowserDocShells(aOurTab, aOtherBrowser, aFlags, aStateFlags) {
_swapBrowserDocShells(aOurTab, aOtherBrowser, aStateFlags) {
// aOurTab's browser needs to be inserted now if it hasn't already.
this._insertBrowser(aOurTab);
@ -3432,17 +3432,15 @@ window._gBrowser = {
remoteBrowser._outerWindowIDBrowserMap.set(aOtherBrowser.outerWindowID, aOtherBrowser);
}
if (!(aFlags & Ci.nsIBrowser.SWAP_KEEP_PERMANENT_KEY)) {
// Swap permanentKey properties.
let ourPermanentKey = ourBrowser.permanentKey;
ourBrowser.permanentKey = aOtherBrowser.permanentKey;
aOtherBrowser.permanentKey = ourPermanentKey;
aOurTab.permanentKey = ourBrowser.permanentKey;
if (remoteBrowser) {
let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
if (otherTab) {
otherTab.permanentKey = aOtherBrowser.permanentKey;
}
// Swap permanentKey properties.
let ourPermanentKey = ourBrowser.permanentKey;
ourBrowser.permanentKey = aOtherBrowser.permanentKey;
aOtherBrowser.permanentKey = ourPermanentKey;
aOurTab.permanentKey = ourBrowser.permanentKey;
if (remoteBrowser) {
let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
if (otherTab) {
otherTab.permanentKey = aOtherBrowser.permanentKey;
}
}

View File

@ -14,20 +14,6 @@
/* These reflows happen only the first time the panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
// 1359989, which was filed against the legacy awesomebar but applies here too
// because it seems to be caused by platform code.
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
{
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
@ -46,6 +32,15 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
*/
],
},
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
// 1359989, which was filed against the legacy awesomebar but applies here too
// because it seems to be caused by platform code.
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
],
},
];
add_task(async function quantumbar() {

View File

@ -14,17 +14,6 @@
/* These reflows happen only the first time the panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
{
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
@ -43,6 +32,15 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
*/
],
},
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
// 1359989, which was filed against the legacy awesomebar but applies here too
// because it seems to be caused by platform code.
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
],
},
];
/* These reflows happen every time the panel opens. */
@ -54,11 +52,6 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
];

View File

@ -693,6 +693,24 @@ async function runUrlbarTest(useAwesomebar,
fn();
}, ms);
};
} else {
let popup = URLBar.view;
let oldOnQueryResults = popup.onQueryResults.bind(popup);
let oldOnQueryFinished = popup.onQueryFinished.bind(popup);
// We need to invalidate the frame tree outside of the normal
// mechanism since invalidations and result additions to the
// URL bar occur without firing JS events (which is how we
// normally know to dirty the frame tree).
popup.onQueryResults = (context) => {
dirtyFrame(win);
oldOnQueryResults(context);
};
popup.onQueryFinished = (context) => {
dirtyFrame(win);
oldOnQueryFinished(context);
};
}
let waitExtra = async () => {

View File

@ -172,8 +172,6 @@ var whitelist = [
// kvstore.jsm wraps the API in nsIKeyValue.idl in a more ergonomic API
// It landed in bug 1490496, and we expect to start using it shortly.
{file: "resource://gre/modules/kvstore.jsm"},
{file: "chrome://devtools/content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl",
isFromDevTools: true},
// Bug 1526672
{file: "resource://app/localization/en-US/browser/touchbar/touchbar.ftl",
platforms: ["linux", "win"]},

View File

@ -2272,7 +2272,7 @@ BrowserGlue.prototype = {
_migrateUI: function BG__migrateUI() {
// Use an increasing number to keep track of the current migration state.
// Completely unrelated to the current Firefox release number.
const UI_VERSION = 80;
const UI_VERSION = 81;
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
let currentUIVersion;
@ -2585,6 +2585,26 @@ BrowserGlue.prototype = {
Services.prefs.setCharPref("network.proxy.no_proxies_on", hosts);
}
if (currentUIVersion < 81) {
// Reset homepage pref for users who have it set to a default from before Firefox 4:
// <locale>.(start|start2|start3).mozilla.(com|org)
const HOMEPAGE_PREF = "browser.startup.homepage";
if (Services.prefs.prefHasUserValue(HOMEPAGE_PREF)) {
const DEFAULT = Services.prefs.getDefaultBranch(HOMEPAGE_PREF).getCharPref("");
let value = Services.prefs.getCharPref(HOMEPAGE_PREF);
let updated = value.replace(
/https?:\/\/([\w\-]+[.])?start[\d]*\.mozilla\.(org|com)[^|]*/ig, DEFAULT);
if (updated != value) {
if (updated == DEFAULT) {
Services.prefs.clearUserPref(HOMEPAGE_PREF);
} else {
value = updated;
Services.prefs.setCharPref(HOMEPAGE_PREF, value);
}
}
}
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

View File

@ -17,7 +17,6 @@ add_task(async function testAutoconfigReloadButton() {
await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
const connectionURL = "chrome://browser/content/preferences/connection.xul";
const promiseDialogLoaded = promiseLoadSubDialog(connectionURL);
// eslint-disable-next-line mozilla/no-cpows-in-tests
gBrowser.contentDocument.getElementById("connectionSettings").click();
const dialog = await promiseDialogLoaded;

View File

@ -88,7 +88,6 @@ async function openNotificationsPermissionDialog() {
add_task(async function testExtensionControlledHomepage() {
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#home",
"#home should be in the URI for about:preferences");
@ -158,7 +157,6 @@ add_task(async function testExtensionControlledHomepage() {
add_task(async function testPrefLockedHomepage() {
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#home",
"#home should be in the URI for about:preferences");
@ -305,7 +303,6 @@ add_task(async function testPrefLockedHomepage() {
add_task(async function testExtensionControlledNewTab() {
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#home",
"#home should be in the URI for about:preferences");
@ -533,7 +530,6 @@ add_task(async function testExtensionControlledDefaultSearch() {
add_task(async function testExtensionControlledHomepageUninstalledAddon() {
async function checkHomepageEnabled() {
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#home",
"#home should be in the URI for about:preferences");

View File

@ -4,7 +4,6 @@ add_task(async function testSetHomepageUseCurrent() {
is(gBrowser.currentURI.spec, "about:blank", "Test starts with about:blank open");
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
// eslint-disable-next-line mozilla/no-cpows-in-tests
let doc = gBrowser.contentDocument;
is(gBrowser.currentURI.spec, "about:preferences#home",
"#home should be in the URI for about:preferences");

View File

@ -91,6 +91,8 @@ class UrlbarInput {
this.isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.window);
this.lastQueryContextPromise = Promise.resolve();
this._actionOverrideKeyCount = 0;
this._autofillPlaceholder = "";
this._lastSearchString = "";
this._resultForCurrentValue = null;
this._suppressStartQuery = false;
this._untrimmedValue = "";
@ -468,12 +470,10 @@ class UrlbarInput {
this._lastSearchString : this.textValue);
if (canonizedUrl) {
this.value = canonizedUrl;
} else if (result.autofill) {
this._autofillValue(result.autofill);
} else {
this.value = this._getValueFromResult(result);
if (result.autofill) {
this.selectionStart = result.autofill.selectionStart;
this.selectionEnd = result.autofill.selectionEnd;
}
}
}
this._resultForCurrentValue = result;
@ -497,37 +497,53 @@ class UrlbarInput {
}
/**
* Starts a query based on the user input.
* Starts a query based on the current input value.
*
* @param {boolean} [options.allowAutofill]
* Whether or not to allow providers to include autofill results.
* @param {number} [options.lastKey]
* The last key the user entered (as a key code).
* @param {string} [options.searchString]
* The search string. If not given, the current input value is used.
* Otherwise, the current input value must start with this value. The
* intended use for this parameter is related to the autofill placeholder.
* When the placeholder is autofilled before the new search starts, the
* current input value will be the entire autofilled placeholder, not the
* value the user typed, which is the value we should search with.
* @param {boolean} [resetSearchState]
* If this is the first search of a user interaction with the input, set
* this to true (the default) so that search-related state from the previous
* interaction doesn't interfere with the new interaction. Otherwise set it
* to false so that state is maintained during a single interaction. The
* intended use for this parameter is that it should be set to false when
* this method is called due to input events.
*/
startQuery({
allowAutofill = true,
lastKey = null,
searchString = null,
resetSearchState = true,
} = {}) {
if (this._suppressStartQuery) {
return;
}
let searchString = this.textValue;
if (resetSearchState) {
this._resetSearchState();
}
// We should autofill only when all of the following are true:
// * The pref is enabled.
// * The end of the selection is at the end of the input.
// * The user hasn't deleted text at the end of the input since the last
// query. Do a simple prefix comparison to guess whether that happened.
let enableAutofill =
UrlbarPrefs.get("autoFill") &&
this.selectionEnd == searchString.length &&
(!this._lastSearchString ||
!this._lastSearchString.startsWith(searchString));
if (!searchString) {
searchString = this.textValue;
} else if (!this.textValue.startsWith(searchString)) {
throw new Error("The current value doesn't start with the search string");
}
this._lastSearchString = searchString;
// TODO (Bug 1522902): This promise is necessary for tests, because some
// tests are not listening for completion when starting a query through
// other methods than startQuery (input events for example).
this.lastQueryContextPromise = this.controller.startQuery(new UrlbarQueryContext({
enableAutofill,
allowAutofill,
isPrivate: this.isPrivate,
lastKey,
maxResults: UrlbarPrefs.get("maxRichResults"),
@ -560,9 +576,10 @@ class UrlbarInput {
// Note: proper IME Composition handling depends on the fact this generates
// an input event, rather than directly invoking the controller; everything
// goes through _on_input, that will properly skip the search until the
// composition is committed.
// If this assumption changes, we'll have to first check we are not
// composing, before starting a search.
// composition is committed. _on_input also skips the search when it's the
// same as the previous search, but we want to allow consecutive searches
// with the same string. So clear _lastSearchString first.
this._lastSearchString = "";
let event = this.document.createEvent("UIEvents");
event.initUIEvent("input", true, false, this.window, 0);
this.inputField.dispatchEvent(event);
@ -605,6 +622,12 @@ class UrlbarInput {
}
set value(val) {
return this._setValue(val, true);
}
// Private methods below.
_setValue(val, allowTrim) {
this._untrimmedValue = val;
let originalUrl = ReaderMode.getOriginalUrlObjectForDisplay(val);
@ -612,7 +635,7 @@ class UrlbarInput {
val = originalUrl.displaySpec;
}
val = this.trimValue(val);
val = allowTrim ? this.trimValue(val) : val;
this.valueIsTyped = false;
this._resultForCurrentValue = null;
@ -628,13 +651,7 @@ class UrlbarInput {
return val;
}
// Private methods below.
_getValueFromResult(result) {
if (result.autofill) {
return result.autofill.value;
}
switch (result.type) {
case UrlbarUtils.RESULT_TYPE.KEYWORD:
return result.payload.input;
@ -655,6 +672,56 @@ class UrlbarInput {
return "";
}
/**
* Resets some state so that searches from the user's previous interaction
* with the input don't interfere with searches from a new interaction.
*/
_resetSearchState() {
this._lastSearchString = this.textValue;
this._autofillPlaceholder = "";
}
/**
* Autofills the autofill placeholder string if appropriate, and determines
* whether autofill should be allowed for the new search started by an input
* event.
*
* @param {string} value
* The new search string.
* @param {boolean} deletedAutofilledSubstring
* Whether the user deleted the previously autofilled substring.
* @returns {boolean}
* Whether autofill should be allowed in the new search.
*/
_maybeAutofillOnInput(value, deletedAutofilledSubstring) {
// Determine whether autofill should be allowed for the new search triggered
// by the input event.
let lastSearchStartsWithNewSearch =
value.length < this._lastSearchString.length &&
this._lastSearchString.startsWith(value);
let allowAutofill =
!lastSearchStartsWithNewSearch &&
!deletedAutofilledSubstring &&
this.selectionEnd == value.length;
// The autofill placeholder is a string that we autofill now, before we
// start waiting on the new search's first result, in order to prevent a
// flicker in the input caused by the previous autofilled substring
// disappearing and reappearing when the new first result arrives. Of
// course we can only autofill the placeholder if it starts with the new
// search string.
if (!allowAutofill ||
this._autofillPlaceholder.length <= value.length ||
!this._autofillPlaceholder.startsWith(value)) {
this._autofillPlaceholder = "";
}
if (this._autofillPlaceholder) {
this._autofillValueOnInput(this._autofillPlaceholder);
}
return allowAutofill;
}
_updateTextOverflow() {
if (!this._overflowing) {
this.removeAttribute("textoverflow");
@ -860,6 +927,49 @@ class UrlbarInput {
return value;
}
/**
* Autofills a value into the input in response to the user's typing. The
* autofill value must start with the value that's already in the input. If
* it doesn't, this method doesn't do anything. If it does, this method will
* autofill and set the selection automatically.
*
* @param {string} value
* The value to autofill.
*/
_autofillValueOnInput(value) {
// Don't ever autofill on input if the caret/selection isn't at the end, or
// if the value doesn't start with what the user typed.
if (this.selectionEnd != this.value.length ||
!value.startsWith(this._lastSearchString)) {
return;
}
this._autofillValue({
value,
selectionStart: this._lastSearchString.length,
selectionEnd: value.length,
});
}
/**
* Autofills a value into the input. The value will be autofilled regardless
* of the input's current value.
*
* @param {string} options.value
* The value to autofill.
* @param {integer} options.selectionStart
* The new selectionStart.
* @param {integer} options.selectionEnd
* The new selectionEnd.
*/
_autofillValue({ value, selectionStart, selectionEnd } = {}) {
// The autofilled value may be a URL that includes a scheme at the
// beginning. Do not allow it to be trimmed.
this._setValue(value, false);
this.selectionStart = selectionStart;
this.selectionEnd = selectionEnd;
this._autofillPlaceholder = value;
}
/**
* Loads the url in the appropriate place.
*
@ -1034,6 +1144,7 @@ class UrlbarInput {
if (this.getAttribute("pageproxystate") != "valid") {
this.window.UpdatePopupNotificationsVisibility();
}
this._resetSearchState();
}
_on_focus(event) {
@ -1099,18 +1210,40 @@ class UrlbarInput {
return;
}
if (this._compositionState == UrlbarUtils.COMPOSITION.COMMIT) {
let handlingCompositionCommit =
this._compositionState == UrlbarUtils.COMPOSITION.COMMIT;
if (handlingCompositionCommit) {
this._compositionState = UrlbarUtils.COMPOSITION.NONE;
}
// Note: if in the future we should re-implement the legacy optimization
// where we didn't search again when the string is the same, skip it if we
// are committing a composition; since the search was canceled on
// composition start, we should restart it.
let sameSearchStrings = value == this._lastSearchString;
// TODO (bug 1524550): Properly detect autofill removal, rather than
// guessing based on string prefixes.
let deletedAutofilledSubstring =
sameSearchStrings &&
value.length < this._autofillPlaceholder.length &&
this._autofillPlaceholder.startsWith(value);
// Don't search again when the new search would produce the same results.
// If we're handling a composition commit, we must continue the search
// because we canceled the previous search on composition start.
if (sameSearchStrings &&
!deletedAutofilledSubstring &&
!handlingCompositionCommit &&
value.length > 0) {
return;
}
let allowAutofill =
this._maybeAutofillOnInput(value, deletedAutofilledSubstring);
// XXX Fill in lastKey, and add anything else we need.
this.startQuery({
searchString: value,
allowAutofill,
lastKey: null,
resetSearchState: false,
});
}
@ -1194,6 +1327,7 @@ class UrlbarInput {
}
_on_TabSelect(event) {
this._resetSearchState();
this.controller.viewContextChanged();
}

View File

@ -114,7 +114,7 @@ class ProviderUnifiedComplete extends UrlbarProvider {
if (queryContext.userContextId) {
params.push(`user-context-id:${queryContext.userContextId}}`);
}
if (!queryContext.enableAutofill) {
if (!queryContext.allowAutofill) {
params.push("prohibit-autofill");
}

View File

@ -389,12 +389,12 @@ class UrlbarQueryContext {
* Set to true if this query was started from a private browsing window.
* @param {number} options.maxResults
* The maximum number of results that will be displayed for this query.
* @param {boolean} options.enableAutofill
* Whether or not to include autofill results.
* @param {boolean} options.allowAutofill
* Whether or not to allow providers to include autofill results.
*/
constructor(options = {}) {
this._checkRequiredOptions(options, [
"enableAutofill",
"allowAutofill",
"isPrivate",
"lastKey",
"maxResults",

View File

@ -46,15 +46,24 @@ var UrlbarTestUtils = {
let urlbar = getUrlbarAbstraction(win);
let restoreAnimationsFn = urlbar.disableAnimations();
await new Promise(resolve => waitForFocus(resolve, win));
let lastSearchString = urlbar.lastSearchString;
urlbar.focus();
urlbar.value = inputText;
if (fireInputEvent) {
// This is necessary to get the urlbar to set gBrowser.userTypedValue.
urlbar.fireInputEvent();
}
// In the quantum bar it's enough to fire the input event to start a query,
// invoking startSearch would do it twice.
if (!urlbar.quantumbar || !fireInputEvent) {
// With awesomebar, we must call startSearch to start the search. With
// quantumbar, we can either fire an input event or call start search, so be
// careful not to do both since that would start two searches. However,
// there's one wrinkle with quantumbar: If the new search and old search are
// the same, the input event will *not* start a new search, by design. Many
// existing tests do consecutive searches with the same string and expect
// new searches to start. To keep those tests running, call startSearch
// directly in those cases.
if (!urlbar.quantumbar ||
!fireInputEvent ||
inputText == lastSearchString) {
urlbar.startSearch(inputText);
}
return this.promiseSearchComplete(win, restoreAnimationsFn);
@ -288,6 +297,11 @@ class UrlbarAbstraction {
return this.urlbar.value;
}
get lastSearchString() {
return this.quantumbar ? this.urlbar._lastSearchString :
this.urlbar.controller.searchString;
}
get panel() {
return this.quantumbar ? this.urlbar.panel : this.urlbar.popup;
}

View File

@ -24,13 +24,10 @@ skip-if = true # Bug 1524539 - need to fix a11y. When removing this line, uncomm
skip-if = os != "mac" # Mac only feature
[browser_autocomplete_tag_star_visibility.js]
[browser_autoFill_backspaced.js]
skip-if = true # Bug 1531348 - Failing with QuantumBar.
[browser_autoFill_canonize.js]
skip-if = true # Bug 1531348 - Failing with QuantumBar.
[browser_autoFill_caretNotAtEnd.js]
[browser_autoFill_preserveCase.js]
skip-if = true # Bug 1531348 - Failing with QuantumBar.
[browser_autoFill_trimURLs.js]
skip-if = true # Bug 1531348 - Failing with QuantumBar.
[browser_canonizeURL.js]
[browser_caret_navigation.js]
[browser_dragdropURL.js]
@ -108,7 +105,6 @@ support-files =
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_urlbarFocusedCmdK.js]
[browser_urlbarHashChangeProxyState.js]
[browser_UrlbarInput_autofill.js]
[browser_UrlbarInput_formatValue.js]
[browser_UrlbarInput_hiddenFocus.js]
[browser_UrlbarInput_overflow.js]

View File

@ -1,54 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the autofill functionality of UrlbarInput.
*/
"use strict";
add_task(async function setValueFromResult() {
gURLBar.setValueFromResult({
autofill: {
value: "foobar",
selectionStart: "foo".length,
selectionEnd: "foobar".length,
},
type: UrlbarUtils.RESULT_TYPE.URL,
});
Assert.equal(gURLBar.value, "foobar",
"The input value should be correct");
Assert.equal(gURLBar.selectionStart, "foo".length,
"The start of the selection should be correct");
Assert.equal(gURLBar.selectionEnd, "foobar".length,
"The end of the selection should be correct");
});
add_task(async function noAutofillWhenCaretNotAtEnd() {
gURLBar.focus();
// Autofill is disabled when the new search starts with the previous search,
// so to make sure that doesn't mess up this test, trigger a search now.
EventUtils.sendString("blah");
// Add a visit that can be autofilled.
await PlacesUtils.history.clear();
await PlacesTestUtils.addVisits([{
uri: "http://example.com/",
}]);
// Fill the input with xample.com.
gURLBar.inputField.value = "xample.com";
// Move the caret to the beginning and type e.
gURLBar.selectionStart = 0;
gURLBar.selectionEnd = 0;
EventUtils.sendString("e");
// Get the first result.
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.ok(!result.autofill, "The first result should not be autofill");
await UrlbarTestUtils.promisePopupClose(window);
await PlacesUtils.history.clear();
});

View File

@ -165,7 +165,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
});
checkStartQueryCall(fakeController.startQuery, {
searchString: "autofill",
enableAutofill: true,
allowAutofill: true,
});
// search for "auto" -- autofill should be disabled since the previous
@ -177,7 +177,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
});
checkStartQueryCall(fakeController.startQuery, {
searchString: "auto",
enableAutofill: false,
allowAutofill: false,
}, 1);
// search for "autofill" again -- autofill should be enabled
@ -188,7 +188,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
});
checkStartQueryCall(fakeController.startQuery, {
searchString: "autofill",
enableAutofill: true,
allowAutofill: true,
}, 2);
sandbox.resetHistory();

View File

@ -16,6 +16,7 @@ async function test_autocomplete(data) {
if (onAutoFill)
onAutoFill();
info("Synthesizing keys");
keys.forEach(key => EventUtils.synthesizeKey(key));
Assert.equal(gURLBar.textValue, modified, "backspaced value is as expected");

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_task(async function noAutofillWhenCaretNotAtEnd() {
gURLBar.focus();
// Add a visit that can be autofilled.
await PlacesUtils.history.clear();
await PlacesTestUtils.addVisits([{
uri: "http://example.com/",
}]);
// Fill the input with xample.
gURLBar.inputField.value = "xample";
// Move the caret to the beginning and type e.
gURLBar.selectionStart = 0;
gURLBar.selectionEnd = 0;
EventUtils.sendString("e");
// Check the first result and input.
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.ok(!result.autofill, "The first result should not be autofill");
Assert.equal(gURLBar.value, "example");
Assert.equal(gURLBar.selectionStart, 1);
Assert.equal(gURLBar.selectionEnd, 1);
await UrlbarTestUtils.promisePopupClose(window);
await PlacesUtils.history.clear();
});

View File

@ -38,7 +38,7 @@ async function promiseSearch(searchtext) {
}
async function promiseTestResult(test) {
info("Searching for '${test.search}'");
info(`Searching for '${test.search}'`);
await promiseSearch(test.search);
@ -61,31 +61,34 @@ async function promiseTestResult(test) {
Assert.equal(result.type, test.resultListType,
`Autocomplete result should have searchengine for the type for search '${test.search}'`);
if (UrlbarPrefs.get("quantumbar")) {
Assert.equal(result.url, test.expectedUrl, "Should have the correct URL");
} else {
let actualValue = gURLBar.mController.getFinalCompleteValueAt(0);
let actualAction = PlacesUtils.parseActionUrl(actualValue);
let expectedAction = PlacesUtils.parseActionUrl(test.finalCompleteValue);
Assert.equal(!!actualAction, !!expectedAction,
"Should have an action if expected");
if (actualAction) {
Assert.deepEqual(actualAction, expectedAction,
"Should have the correct action details");
} else {
Assert.equal(actualValue, test.finalCompleteValue,
"Should have the correct action details");
Assert.equal(!!result.searchParams, !!test.searchParams,
"Should have search params if expected");
if (test.searchParams) {
let definedParams = {};
for (let [k, v] of Object.entries(result.searchParams)) {
if (v !== undefined) {
definedParams[k] = v;
}
}
Assert.deepEqual(definedParams, test.searchParams,
"Shoud have the correct search params");
} else {
Assert.equal(result.url, test.finalCompleteValue,
"Should have the correct URL/finalCompleteValue");
}
}
const tests = [{
const tests = [
{
search: "http://",
autofilledValue: "http://",
resultListDisplayTitle: "http://",
resultListActionText: "Search with Google",
resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"http%3A%2F%2F","searchQuery":"http%3A%2F%2F"}',
searchParams: {
engine: "Google",
query: "http://",
},
},
{
search: "https://",
@ -93,7 +96,10 @@ const tests = [{
resultListDisplayTitle: "https://",
resultListActionText: "Search with Google",
resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"https%3A%2F%2F","searchQuery":"https%3A%2F%2F"}',
searchParams: {
engine: "Google",
query: "https://",
},
},
{
search: "au",

View File

@ -320,8 +320,8 @@ async function doSimpleTest(revertBetweenSteps) {
});
// "@tes" -- not an alias, no highlight
gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
await promiseSearchComplete();
await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
window, true);
await waitForAutocompleteResultAt(0);
await assertAlias(false);
@ -331,8 +331,7 @@ async function doSimpleTest(revertBetweenSteps) {
}
// "@test" -- alias, highlight
gURLBar.search(ALIAS);
await promiseSearchComplete();
await promiseAutocompleteResultPopup(ALIAS, window, true);
await waitForAutocompleteResultAt(0);
await assertAlias(true);
@ -342,8 +341,7 @@ async function doSimpleTest(revertBetweenSteps) {
}
// "@test foo" -- alias, highlight
gURLBar.search(ALIAS + " foo");
await promiseSearchComplete();
await promiseAutocompleteResultPopup(ALIAS + " foo", window, true);
await waitForAutocompleteResultAt(0);
await assertAlias(true);
@ -353,8 +351,7 @@ async function doSimpleTest(revertBetweenSteps) {
}
// "@test" -- alias, highlight
gURLBar.search(ALIAS);
await promiseSearchComplete();
await promiseAutocompleteResultPopup(ALIAS, window, true);
await waitForAutocompleteResultAt(0);
await assertAlias(true);
@ -364,8 +361,8 @@ async function doSimpleTest(revertBetweenSteps) {
}
// "@tes" -- not an alias, no highlight
gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
await promiseSearchComplete();
await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
window, true);
await waitForAutocompleteResultAt(0);
await assertAlias(false);

View File

@ -35,7 +35,7 @@ const {sinon} = ChromeUtils.import("resource://testing-common/Sinon.jsm");
*/
function createContext(searchString = "foo", properties = {}) {
let context = new UrlbarQueryContext({
enableAutofill: UrlbarPrefs.get("autoFill"),
allowAutofill: UrlbarPrefs.get("autoFill"),
isPrivate: true,
lastKey: searchString ? searchString[searchString.length - 1] : "",
maxResults: UrlbarPrefs.get("maxRichResults"),

View File

@ -149,7 +149,7 @@ add_task(function test_handle_query_starts_search() {
sandbox.resetHistory();
});
add_task(function test_handle_query_starts_search_sets_enableAutofill() {
add_task(function test_handle_query_starts_search_sets_allowAutofill() {
let originalValue = Services.prefs.getBoolPref("browser.urlbar.autoFill");
Services.prefs.setBoolPref("browser.urlbar.autoFill", !originalValue);
@ -161,7 +161,7 @@ add_task(function test_handle_query_starts_search_sets_enableAutofill() {
"Should have called startQuery with two arguments");
assertContextMatches(fPM.startQuery.args[0][0], {
enableAutofill: !originalValue,
allowAutofill: !originalValue,
});
Assert.equal(fPM.startQuery.args[0][1], controller,
"Should have passed the controller as the second argument");

View File

@ -5,11 +5,11 @@
add_task(function test_constructor() {
Assert.throws(() => new UrlbarQueryContext(),
/Missing or empty enableAutofill provided to UrlbarQueryContext/,
/Missing or empty allowAutofill provided to UrlbarQueryContext/,
"Should throw with no arguments");
Assert.throws(() => new UrlbarQueryContext({
enableAutofill: true,
allowAutofill: true,
isPrivate: false,
maxResults: 1,
searchString: "foo",
@ -17,7 +17,7 @@ add_task(function test_constructor() {
"Should throw with a missing lastKey parameter");
Assert.throws(() => new UrlbarQueryContext({
enableAutofill: true,
allowAutofill: true,
isPrivate: false,
lastKey: "b",
searchString: "foo",
@ -25,7 +25,7 @@ add_task(function test_constructor() {
"Should throw with a missing maxResults parameter");
Assert.throws(() => new UrlbarQueryContext({
enableAutofill: true,
allowAutofill: true,
lastKey: "b",
maxResults: 1,
searchString: "foo",
@ -37,19 +37,19 @@ add_task(function test_constructor() {
lastKey: "b",
maxResults: 1,
searchString: "foo",
}), /Missing or empty enableAutofill provided to UrlbarQueryContext/,
"Should throw with a missing enableAutofill parameter");
}), /Missing or empty allowAutofill provided to UrlbarQueryContext/,
"Should throw with a missing allowAutofill parameter");
let qc = new UrlbarQueryContext({
enableAutofill: false,
allowAutofill: false,
isPrivate: true,
lastKey: "b",
maxResults: 1,
searchString: "foo",
});
Assert.strictEqual(qc.enableAutofill, false,
"Should have saved the correct value for enableAutofill");
Assert.strictEqual(qc.allowAutofill, false,
"Should have saved the correct value for allowAutofill");
Assert.strictEqual(qc.isPrivate, true,
"Should have saved the correct value for isPrivate");
Assert.equal(qc.lastKey, "b",

View File

@ -55,7 +55,10 @@ It is augmented as it progresses through the system, with various information:
.. code::
UrlbarQueryContext {
enableAutofill; // {boolean} Whether or not to include autofill results.
allowAutofill; // {boolean} If true, providers are allowed to return
// autofill results. Even if true, it's up to providers
// whether to include autofill results, but when false, no
// provider should include them.
isPrivate; // {boolean} Whether the search started in a private context.
lastKey; // {string} The last key pressed by the user. This can affect the
// behavior, for example by not autofilling again when the user

View File

@ -592,7 +592,7 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
%ifdef XP_UNIX
%ifndef XP_MACOSX
#customization-palette[whimsypong] > toolbarpaletteitem > toolbarspring {
#customization-palette[whimsypong] > toolbarpaletteitem[id^="wrapper-customizableui-special-spring"] {
font-size: 12px;
}
%endif

View File

@ -111,9 +111,17 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
unless(
anyOf(
MozKnownLiveCall,
// MOZ_KnownLive applied to a RefPtr or nsCOMPtr just returns that
// same RefPtr/nsCOMPtr type which causes us to have a conversion
// operator applied after the MOZ_KnownLive.
// MOZ_KnownLive applied to a smartptr just returns that
// same smartptr type which causes us to have a conversion
// operator applied after the MOZ_KnownLive. Allow that by
// allowing member calls on the result of MOZ_KnownLive, but only
// if the type is a known smartptr type. Otherwise we would think
// that things of the form "MOZ_KnownLive(someptr)->foo()" are
// live!
//
// This relies on member calls on smartptr types that return a
// refcounted pointer only returning the pointer the smartptr is
// keeping alive.
cxxMemberCallExpr(on(allOf(hasType(isSmartPtrToRefCounted()),
MozKnownLiveCall)))
)
@ -331,6 +339,6 @@ void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
<< CallRange;
diag(ParentFunction->getCanonicalDecl()->getLocation(),
NoteNonCanRunScriptParent, DiagnosticIDs::Note);
NoteNonCanRunScriptParent, DiagnosticIDs::Note);
}
}

View File

@ -282,3 +282,29 @@ struct AllowKnownLiveMemberArgs {
test2(MOZ_KnownLive(mRefCounted));
}
};
struct WeakPtrReturner : public RefCountedBase {
RefCountedBase* getWeakPtr() { return new RefCountedBase(); }
};
struct DisallowMemberCallsOnRandomKnownLive {
RefPtr<WeakPtrReturner> mWeakPtrReturner1;
WeakPtrReturner* mWeakPtrReturner2;
MOZ_CAN_RUN_SCRIPT void test_refptr_method() {
MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
}
MOZ_CAN_RUN_SCRIPT void test_refptr_function() {
test2(MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
}
MOZ_CAN_RUN_SCRIPT void test_raw_method() {
MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
}
MOZ_CAN_RUN_SCRIPT void test_raw_function() {
test2(MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
}
};

View File

@ -1198,7 +1198,8 @@ def check_have_64_bit(have_64_bit, compiler_have_64_bit):
def default_debug_flags(compiler_info, target):
# Debug info is ON by default.
if compiler_info.type == 'clang-cl':
return '-Z7'
# -fno-limit-debug-info works around https://llvm.org/pr38944
return '-Z7 -fno-limit-debug-info'
elif target.kernel == 'WINNT' and compiler_info.type == 'clang':
return '-g -gcodeview'
return '-g'

View File

@ -109,7 +109,6 @@ const AboutDebugging = {
async destroy() {
const width = this.getRoundedViewportWidth();
this.actions.recordTelemetryEvent("close_adbg", { width });
l10n.destroy();
const state = this.store.getState();
const currentRuntimeId = state.runtimes.selectedRuntimeId;

View File

@ -17,7 +17,7 @@ const Switch = createFactory(require("devtools/client/shared/vendor/react-router
const Redirect = createFactory(require("devtools/client/shared/vendor/react-router-dom").Redirect);
const Types = require("../types/index");
const { RUNTIMES } = require("../constants");
const { PAGE_TYPES, RUNTIMES } = require("../constants");
const ConnectPage = createFactory(require("./connect/ConnectPage"));
const RuntimePage = createFactory(require("./RuntimePage"));
@ -34,13 +34,11 @@ class App extends PureComponent {
// getString prop is injected by the withLocalization wrapper
getString: PropTypes.func.isRequired,
isScanningUsb: PropTypes.bool.isRequired,
networkEnabled: PropTypes.bool.isRequired,
networkLocations: PropTypes.arrayOf(Types.location).isRequired,
networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
selectedPage: Types.page,
selectedRuntimeId: PropTypes.string,
usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
wifiEnabled: PropTypes.bool.isRequired,
};
}
@ -51,34 +49,24 @@ class App extends PureComponent {
updateTitle() {
const { getString, selectedPage, selectedRuntimeId } = this.props;
const runtimeTitle = selectedRuntimeId ?
getString(
"about-debugging-page-title-with-runtime",
{ selectedPage, selectedRuntimeId }
)
: getString(
"about-debugging-page-title",
{ selectedPage }
);
const pageTitle = selectedPage === PAGE_TYPES.RUNTIME ?
getString("about-debugging-page-title-runtime-page", { selectedRuntimeId }) :
getString("about-debugging-page-title-setup-page");
document.title = runtimeTitle;
document.title = pageTitle;
}
renderConnect() {
const {
adbAddonStatus,
dispatch,
networkEnabled,
networkLocations,
wifiEnabled,
} = this.props;
return ConnectPage({
adbAddonStatus,
dispatch,
networkEnabled,
networkLocations,
wifiEnabled,
});
}
@ -182,13 +170,11 @@ const mapStateToProps = state => {
return {
adbAddonStatus: state.ui.adbAddonStatus,
isScanningUsb: state.ui.isScanningUsb,
networkEnabled: state.ui.networkEnabled,
networkLocations: state.ui.networkLocations,
networkRuntimes: state.runtimes.networkRuntimes,
selectedPage: state.ui.selectedPage,
selectedRuntimeId: state.runtimes.selectedRuntimeId,
usbRuntimes: state.runtimes.usbRuntimes,
wifiEnabled: state.ui.wifiEnabled,
};
};

View File

@ -62,14 +62,19 @@ class RuntimeInfo extends PureComponent {
deviceName
) : null,
runtimeId !== RUNTIMES.THIS_FIREFOX ?
dom.button(
Localized(
{
className: "default-button runtime-info__action qa-runtime-info__action",
onClick() {
dispatch(Actions.disconnectRuntime(runtimeId, true));
},
id: "about-debugging-runtime-disconnect-button",
},
"Disconnect"
dom.button(
{
className: "default-button runtime-info__action qa-runtime-info__action",
onClick() {
dispatch(Actions.disconnectRuntime(runtimeId, true));
},
},
"Disconnect"
)
) : null,
);
}

View File

@ -2,10 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.connect-page__disabled-section {
color: var(--grey-40);
}
.connect-page__breather {
margin-block-start: calc(var(--base-unit) * 6);
}

View File

@ -25,7 +25,7 @@ const ConnectSteps = createFactory(require("./ConnectSteps"));
const NetworkLocationsForm = createFactory(require("./NetworkLocationsForm"));
const NetworkLocationsList = createFactory(require("./NetworkLocationsList"));
const { PREFERENCES, PAGE_TYPES, RUNTIMES } = require("../../constants");
const { PAGE_TYPES, RUNTIMES } = require("../../constants");
const Types = require("../../types/index");
const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-usb-icon.svg";
@ -36,11 +36,7 @@ class ConnectPage extends PureComponent {
return {
adbAddonStatus: Types.adbAddonStatus,
dispatch: PropTypes.func.isRequired,
// Provided by wrapping the component with FluentReact.withLocalization.
getString: PropTypes.func.isRequired,
networkEnabled: PropTypes.bool.isRequired,
networkLocations: PropTypes.arrayOf(Types.location).isRequired,
wifiEnabled: PropTypes.bool.isRequired,
};
}
@ -180,41 +176,23 @@ class ConnectPage extends PureComponent {
}
renderNetwork() {
const { dispatch, networkEnabled, networkLocations } = this.props;
const { dispatch, networkLocations } = this.props;
return Localized(
{
id: "about-debugging-connect-network",
id: "about-debugging-setup-network",
attrs: { title: true },
},
ConnectSection(
{
className: "connect-page__breather",
icon: GLOBE_ICON_SRC,
title: "Network Location",
extraContent: networkEnabled
? dom.div(
{},
NetworkLocationsList({ dispatch, networkLocations }),
NetworkLocationsForm({ dispatch }),
)
: null,
},
networkEnabled
? null
: Localized(
{
id: "about-debugging-connect-network-disabled",
$pref: PREFERENCES.NETWORK_ENABLED,
},
dom.div(
{
className: "connect-page__disabled-section",
},
"about-debugging-connect-network-disabled"
)
),
)
ConnectSection({
className: "connect-page__breather",
icon: GLOBE_ICON_SRC,
title: "Network Location",
extraContent: dom.div(
{},
NetworkLocationsList({ dispatch, networkLocations }),
NetworkLocationsForm({ dispatch }),
),
})
);
}
@ -225,7 +203,7 @@ class ConnectPage extends PureComponent {
},
Localized(
{
id: "about-debugging-connect-title",
id: "about-debugging-setup-title",
},
dom.h1(
{
@ -243,12 +221,12 @@ class ConnectPage extends PureComponent {
"Configure the connection method you wish to remotely debug your device with."
)
),
Localized(
{
id: "about-debugging-setup-link-android-devices",
},
dom.p(
{},
dom.p(
{},
Localized(
{
id: "about-debugging-setup-link-android-devices",
},
dom.a(
{
href: "https://support.mozilla.org/kb/will-firefox-work-my-mobile-device#w_android-devices",

View File

@ -132,7 +132,7 @@ class ExtensionDetail extends PureComponent {
return Localized(
{
id: "about-debugging-extension-manifest-link",
id: "about-debugging-extension-manifest-url",
attrs: { label: true },
},
FieldPair(

View File

@ -48,6 +48,20 @@ class ServiceWorkerAction extends PureComponent {
});
}
_getStatusLocalizationId(status) {
switch (status) {
case SERVICE_WORKER_STATUSES.REGISTERING.toLowerCase():
return "about-debugging-worker-status-registering";
case SERVICE_WORKER_STATUSES.RUNNING.toLowerCase():
return "about-debugging-worker-status-running";
case SERVICE_WORKER_STATUSES.STOPPED.toLowerCase():
return "about-debugging-worker-status-stopped";
default:
// Assume status is stopped for unknown status value.
return "about-debugging-worker-status-stopped";
}
}
_renderStatus() {
const status = this.props.target.details.status.toLowerCase();
const statusClassName = status === SERVICE_WORKER_STATUSES.RUNNING.toLowerCase()
@ -55,8 +69,7 @@ class ServiceWorkerAction extends PureComponent {
return Localized(
{
id: "about-debugging-worker-status",
$status: status,
id: this._getStatusLocalizationId(status),
},
dom.span(
{

View File

@ -95,14 +95,10 @@ const PAGE_TYPES = {
};
const PREFERENCES = {
// Temporary preference without any default value until network locations are enabled.
NETWORK_ENABLED: "devtools.aboutdebugging.network",
// Preference that drives the display of the "Processes" debug target category.
PROCESS_DEBUGGING_ENABLED: "devtools.aboutdebugging.process-debugging",
// Preference that drives the display of system addons in about:debugging.
SHOW_SYSTEM_ADDONS: "devtools.aboutdebugging.showSystemAddons",
// Temporary preference without any default value until wifi is enabled.
WIFI_ENABLED: "devtools.aboutdebugging.wifi",
};
const RUNTIME_PREFERENCE = {

View File

@ -49,12 +49,9 @@ function configureStore() {
function getUiState() {
const collapsibilities = getDebugTargetCollapsibilities();
const locations = getNetworkLocations();
const networkEnabled = Services.prefs.getBoolPref(PREFERENCES.NETWORK_ENABLED, false);
const wifiEnabled = Services.prefs.getBoolPref(PREFERENCES.WIFI_ENABLED, false);
const showSystemAddons = Services.prefs.getBoolPref(PREFERENCES.SHOW_SYSTEM_ADDONS,
false);
return new UiState(locations, collapsibilities, networkEnabled, wifiEnabled,
showSystemAddons);
return new UiState(locations, collapsibilities, showSystemAddons);
}
exports.configureStore = configureStore;

View File

@ -7,26 +7,15 @@
const Services = require("Services");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const { L10nRegistry, FileSource } =
require("resource://gre/modules/L10nRegistry.jsm");
const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
class L10n {
async init() {
// XXX Until the strings for the updated about:debugging stabilize, we
// locate them outside the regular directory for locale resources so that
// they don't get picked up by localization tools.
if (!L10nRegistry.sources.has("aboutdebugging")) {
const temporarySource = new FileSource(
"aboutdebugging",
["en-US"],
"chrome://devtools/content/aboutdebugging-new/tmp-locale/{locale}/"
);
L10nRegistry.registerSource(temporarySource);
}
const locales = Services.locale.appLocalesAsBCP47;
const generator =
L10nRegistry.generateBundles(locales, ["aboutdebugging.ftl"]);
const generator = L10nRegistry.generateBundles(locales, [
"branding/brand.ftl",
"devtools/aboutdebugging.ftl",
]);
this._bundles = [];
for await (const bundle of generator) {
@ -51,10 +40,6 @@ class L10n {
// - add new arguments
return this._reactLocalization.getString.apply(this._reactLocalization, arguments);
}
destroy() {
L10nRegistry.removeSource("aboutdebugging");
}
}
// Export a singleton that will be shared by all aboutdebugging modules.

View File

@ -18,19 +18,16 @@ const {
} = require("../constants");
function UiState(locations = [], debugTargetCollapsibilities = {},
networkEnabled = false, wifiEnabled = false,
showSystemAddons = false) {
return {
adbAddonStatus: null,
debugTargetCollapsibilities,
isScanningUsb: false,
networkEnabled,
networkLocations: locations,
selectedPage: null,
showProfilerDialog: false,
showSystemAddons,
temporaryInstallError: null,
wifiEnabled,
};
}

View File

@ -26,7 +26,8 @@ add_task(async function() {
const connectLink = connectSidebarItem.querySelector(".js-sidebar-link");
ok(connectSidebarItem, "Found the Connect sidebar item");
const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
const thisFirefoxString = getThisFirefoxString(window);
const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
ok(thisFirefoxSidebarItem, "Found the ThisFirefox sidebar item");
ok(isSidebarItemSelected(thisFirefoxSidebarItem),

View File

@ -44,7 +44,8 @@ add_task(async function() {
await waitUntil(() => findDebugTargetByText(WORKER_NAME, document));
info("Go to This Firefox again");
const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
const thisFirefoxString = getThisFirefoxString(window);
const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
info("Click on the ThisFirefox item in the sidebar");
const requestsSuccess = waitForRequestsSuccess(window.AboutDebugging.store);

View File

@ -21,11 +21,13 @@ add_task(async function() {
const { document, tab, window } = await openAboutDebugging();
await selectThisFirefoxPage(document, window.AboutDebugging.store);
// Check that the selected sidebar item is "This Firefox"
// Check that the selected sidebar item is "This Firefox"/"This Nightly"/...
const selectedSidebarItem = document.querySelector(".js-sidebar-item-selected");
ok(selectedSidebarItem, "An item is selected in the sidebar");
is(selectedSidebarItem.textContent, "This Firefox",
"The selected sidebar item is This Firefox");
const thisFirefoxString = getThisFirefoxString(window);
is(selectedSidebarItem.textContent, thisFirefoxString,
"The selected sidebar item is " + thisFirefoxString);
const paneTitlesEls = document.querySelectorAll(".js-debug-target-pane-title");
is(paneTitlesEls.length, EXPECTED_TARGET_PANES.length,

View File

@ -41,7 +41,6 @@ registerCleanupFunction(async function() {
*/
async function enableNewAboutDebugging() {
await pushPref("devtools.aboutdebugging.new-enabled", true);
await pushPref("devtools.aboutdebugging.network", true);
}
async function openAboutDebugging({ enableWorkerUpdates } = {}) {
@ -113,8 +112,8 @@ async function reloadAboutDebugging(tab) {
const browser = tab.linkedBrowser;
const document = browser.contentDocument;
const window = browser.contentWindow;
info("wait for the initial about:debugging requests to be successful");
await waitForRequestsSuccess(window.AboutDebugging.store);
info("wait for the initial about:debugging requests to settle");
await waitForRequestsToSettle(window.AboutDebugging.store);
return document;
}
@ -289,3 +288,13 @@ async function openProfilerDialog(client, doc) {
info("Wait for the loadPerformanceProfiler callback to be executed on client-wrapper");
return onProfilerLoaded;
}
/**
* The "This Firefox" string depends on the brandShortName, which will be different
* depending on the channel where tests are running.
*/
function getThisFirefoxString(aboutDebuggingWindow) {
const loader = aboutDebuggingWindow.getBrowserLoaderForWindow();
const { l10n } = loader.require("devtools/client/aboutdebugging-new/src/modules/l10n");
return l10n.getString("about-debugging-this-firefox-runtime-name");
}

View File

@ -159,7 +159,6 @@ export type TabPayload = {
animationsActor: ActorId,
consoleActor: ActorId,
cssPropertiesActor: ActorId,
cssUsageActor: ActorId,
directorManagerActor: ActorId,
emulationActor: ActorId,
eventLoopLagActor: ActorId,

View File

@ -7,7 +7,7 @@
import * as firefox from "./firefox";
import * as chrome from "./chrome";
import { prefs, asyncStore, verifyPrefSchema } from "../utils/prefs";
import { asyncStore, verifyPrefSchema } from "../utils/prefs";
import { setupHelper } from "../utils/dbg";
import {
@ -19,16 +19,6 @@ import { initialBreakpointsState } from "../reducers/breakpoints";
import type { Panel } from "./firefox/types";
function loadFromPrefs(actions: Object) {
const { pauseOnExceptions, pauseOnCaughtExceptions } = prefs;
if (pauseOnExceptions || pauseOnCaughtExceptions) {
return actions.pauseOnExceptions(
pauseOnExceptions,
pauseOnCaughtExceptions
);
}
}
async function syncBreakpoints() {
const breakpoints = await asyncStore.pendingBreakpoints;
const breakpointValues = (Object.values(breakpoints): any);
@ -94,7 +84,6 @@ export async function onConnect(
const workers = bootstrapWorkers();
await client.onConnect(connection, actions);
await loadFromPrefs(actions);
syncBreakpoints();
syncXHRBreakpoints();
setupHelper({

View File

@ -968,7 +968,7 @@ function invokeInTab(fnc, ...args) {
fnc,
args
}) {
return content.wrappedJSObject[fnc](...args); // eslint-disable-line mozilla/no-cpows-in-tests, max-len
return content.wrappedJSObject[fnc](...args); // max-len
});
}

View File

@ -50,9 +50,6 @@ devtools.jar:
content/aboutdebugging/aboutdebugging.css (aboutdebugging/aboutdebugging.css)
content/aboutdebugging-new/index.html (aboutdebugging-new/index.html)
content/aboutdebugging-new/aboutdebugging.css (aboutdebugging-new/aboutdebugging.css)
# The following line is temporary until the strings for the new
# about:debugging feature stabilize.
content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl (aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl)
content/responsive.html/index.xhtml (responsive.html/index.xhtml)
content/dom/index.html (dom/index.html)
content/dom/main.js (dom/main.js)

View File

@ -2,15 +2,22 @@
# 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/.
### These strings are used inside the about:debugging panel which is available
### by setting the preference `devtools.aboutdebugging.new-enabled` to true.
### These strings are used inside the about:debugging UI.
# Display name of the runtime "This Firefox". Reused as the sidebar name for This Firefox
# (about-debugging-sidebar-this-firefox.name). Not displayed elsewhere in the application
# at the moment.
# This should the same string as the part outside of the parentheses in toolbox.properties
# toolbox.debugTargetInfo.runtimeLabel.thisFirefox. See 1520525.
about-debugging-this-firefox-runtime-name = This Firefox
# Page Title strings
# Page title (ie tab title) for the Setup page
about-debugging-page-title-setup-page = Debugging - Setup
# Page title (ie tab title) for the Runtime page
# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
about-debugging-page-title-runtime-page = Debugging - Runtime / { $selectedRuntimeId }
# Sidebar strings
# Display name of the runtime for the currently running instance of Firefox. Used in the
# Sidebar and in the Setup page.
about-debugging-this-firefox-runtime-name = This { -brand-shorter-name }
# Sidebar heading for selecting the currently running instance of Firefox
about-debugging-sidebar-this-firefox =
@ -56,21 +63,43 @@ about-debugging-sidebar-runtime-item-name =
about-debugging-sidebar-runtime-item-name-no-device =
.title = { $displayName }
# Temporary text displayed in a sidebar button to refresh USB devices. Temporary
# UI, do not localize.
# Text displayed in a sidebar button to refresh the list of USB devices. Clicking on it
# will attempt to update the list of devices displayed in the sidebar.
about-debugging-refresh-usb-devices-button = Refresh devices
# Setup Page strings
# Title of the Setup page.
about-debugging-connect-title = Setup
about-debugging-setup-title = Setup
# Introduction text in the Setup page to explain how to configure remote debugging.
about-debugging-setup-intro = Configure the connection method you wish to remotely debug your device with.
# Link displayed in the Setup page that leads to MDN page with list of supported devices.
# Temporarily leads to https://support.mozilla.org/en-US/kb/will-firefox-work-my-mobile-device#w_android-devices
about-debugging-setup-link-android-devices = View list of supported Android devices
# Explanatory text in the Setup page about what the 'This Firefox' page is for
about-debugging-setup-this-firefox = Use <a>This Firefox</a> to debug tags, extensions and service workers on this version of Firefox.
about-debugging-setup-this-firefox = Use <a>{ about-debugging-this-firefox-runtime-name }</a> to debug tabs, extensions and service workers on this version of { -brand-shorter-name }.
# Title of the heading Connect section of the Setup page.
about-debugging-setup-connect-heading = Connect a Device
# USB section of the Setup page
about-debugging-setup-usb-title = USB
about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to Firefox.
# Explanatory text displayed in the Setup page when USB debugging is disabled
about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to { -brand-shorter-name }.
# Text of the button displayed in the USB section of the setup page when USB debugging is disabled.
# Clicking on it will download components needed to debug USB Devices remotely.
about-debugging-setup-usb-enable-button = Enable USB Devices
# Text of the button displayed in the USB section of the setup page when USB debugging is enabled.
about-debugging-setup-usb-disable-button = Disable USB Devices
# Text of the button displayed in the USB section of the setup page while USB debugging
# components are downloaded and installed.
about-debugging-setup-usb-updating-button = Updating…
# USB section of the Setup page (USB status)
@ -90,14 +119,27 @@ about-debugging-setup-usb-step-enable-debug-firefox = Enable USB Debugging in Fi
# USB section step by step guide
about-debugging-setup-usb-step-plug-device = Connect the Android device to your computer.
# Network section of the Connect page
about-debugging-connect-network =
# Network section of the Setup page
about-debugging-setup-network =
.title = Network Location
# Temporary text displayed when network location support is turned off via preferences.
# { $pref } is the name of the preference that enables network locations
# Do not localize
about-debugging-connect-network-disabled = Network location support currently under development. You can enable it with the preference “{ $pref }”.
# Text of a button displayed after the network locations "Host" input.
# Clicking on it will add the new network location to the list.
about-debugging-network-locations-add-button = Add
# Text to display when there are no locations to show.
about-debugging-network-locations-empty-text = No network locations have been added yet.
# Text of the label for the text input that allows users to add new network locations in
# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
# the input's placeholder "localhost:6080".
about-debugging-network-locations-host-input-label = Host
# Text of a button displayed next to existing network locations in the Connect page.
# Clicking on it removes the network location from the list.
about-debugging-network-locations-remove-button = Remove
# Runtime Page strings
# Below are the titles for the various categories of debug targets that can be found
# on "runtime" pages of about:debugging.
@ -119,6 +161,9 @@ about-debugging-runtime-shared-workers =
# Title of the other workers category.
about-debugging-runtime-other-workers =
.name = Other Workers
# Title of the processes category.
about-debugging-runtime-processes =
.name = Processes
# Label of the button opening the performance profiler panel in runtime pages for remote
# runtimes.
@ -149,7 +194,40 @@ about-debugging-runtime-version-too-old-67-debugger = The Debugger panel may not
# { $localID } is the build ID of the current Firefox instance (same format)
# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
# { $localVersion } is the version of your current runtime (same format)
about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your desktop Firefox ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your { -brand-shorter-name } ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
# Displayed for runtime info in runtime pages.
# { $name } is brand name such as "Firefox Nightly"
# { $version } is version such as "64.0a1"
about-debugging-runtime-name = { $name } ({ $version })
# Text of a button displayed in Runtime pages for remote runtimes.
# Clicking on the button will close the connection to the runtime.
about-debugging-runtime-disconnect-button = Disconnect
# Text of the connection prompt button displayed in Runtime pages, when the preference
# "devtools.debugger.prompt-connection" is false on the target runtime.
about-debugging-connection-prompt-enable-button = Enable connection prompt
# Text of the connection prompt button displayed in Runtime pages, when the preference
# "devtools.debugger.prompt-connection" is true on the target runtime.
about-debugging-connection-prompt-disable-button = Disable connection prompt
# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
about-debugging-profiler-dialog-title = Performance Profiler
# Label of a checkbox displayed in the runtime page for "This Firefox".
# This checkbox will toggle preferences that enable local addon debugging.
# The "Learn more" link points to MDN.
# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
about-debugging-extension-debug-setting-label = Enable extension debugging. <a>Learn more</a>
# Clicking on the header of a debug target category will expand or collapse the debug
# target items in the category. This text is used as title attribute of the header,
# to describe this feature.
about-debugging-collapse-expand-debug-targets = Collapse / expand
# Debug Targets strings
# Displayed in the categories of "runtime" pages that don't have any debug target to
# show. Debug targets depend on the category (extensions, tabs, workers...).
@ -184,9 +262,10 @@ about-debugging-tmp-extension-install-message = Select manifest.json file or .xp
# This string is displayed as a message about the add-on having a temporaryID.
about-debugging-tmp-extension-temporary-id = This WebExtension has a temporary ID. <a>Learn more</a>
# Text of a link displayed for extensions in "runtime" pages.
# Clicking on the link should open the manifest file in a new tab.
about-debugging-extension-manifest-link = Manifest URL
# Text displayed for extensions in "runtime" pages, before displaying a link the extension's
# manifest URL.
about-debugging-extension-manifest-url =
.label = Manifest URL
# Text displayed for extensions in "runtime" pages, before displaying the extension's uuid.
# UUIDs look like b293e463-481e-5148-a487-5aaf7a130429
@ -200,23 +279,8 @@ about-debugging-extension-location =
# Text displayed for extensions in "runtime" pages, before displaying the extension's ID.
# For instance "geckoprofiler@mozilla.com" or "{ed26ddcb-5611-4512-a89a-51b8db81cfb2}".
about-debugging-extension-id = Extension ID
# Text of a button displayed after the network locations "Host" input.
# Clicking on it will add the new network location to the list.
about-debugging-network-locations-add-button = Add
# Text to display when there are no locations to show.
about-debugging-network-locations-empty-text = No network locations have been added yet.
# Text of the label for the text input that allows users to add new network locations in
# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
# the input's placeholder "localhost:6080".
about-debugging-network-locations-host-input-label = Host
# Text of a button displayed next to existing network locations in the Connect page.
# Clicking on it removes the network location from the list.
about-debugging-network-locations-remove-button = Remove
about-debugging-extension-id =
.label = Extension ID
# This string is displayed as a label of the button that pushes a test payload
# to a service worker.
@ -230,29 +294,25 @@ about-debugging-worker-action-start = Start
# This string is displayed as a label of the button that unregisters a service worker.
about-debugging-worker-action-unregister = Unregister
# Reused for the service worker fetch status labels.
# "Fetch" is an event type and should not be localized.
-worker-fetch-label = Fetch
# Displayed for service workers in runtime pages that listen to Fetch events.
about-debugging-worker-fetch-listening =
.label = { -worker-fetch-label }
.label = Fetch
.value = Listening for fetch events
# Displayed for service workers in runtime pages that do not listen to Fetch events.
about-debugging-worker-fetch-not-listening =
.label = { -worker-fetch-label }
.label = Fetch
.value = Not listening for fetch events
# Displayed for service workers in runtime pages, to indicate the status of a worker.
# For workers for which no registration could be found yet, they are considered as
# 'registering' (only active registrations are visible from about:debugging).
about-debugging-worker-status =
{ $status ->
[running] Running
*[stopped] Stopped
[registering] Registering
}
# Displayed for service workers in runtime pages that are currently running (service
# worker instance is active).
about-debugging-worker-status-running = Running
# Displayed for service workers in runtime pages that are registered but stopped.
about-debugging-worker-status-stopped = Stopped
# Displayed for service workers in runtime pages that are registering.
about-debugging-worker-status-registering = Registering
# Displayed for service workers in runtime pages, to label the scope of a worker
about-debugging-worker-scope =
@ -263,51 +323,10 @@ about-debugging-worker-scope =
about-debugging-worker-push-service =
.label = Push Service
# Displayed for runtime info in runtime pages.
# { $name } is brand name such as "Firefox Nightly"
# { $version } is version such as "64.0a1"
about-debugging-runtime-name = { $name } ({ $version })
# Text of the connection prompt button displayed in Runtime pages, when the preference
# "devtools.debugger.prompt-connection" is false on the target runtime.
about-debugging-connection-prompt-enable-button = Enable connection prompt
# Text of the connection prompt button displayed in Runtime pages, when the preference
# "devtools.debugger.prompt-connection" is true on the target runtime.
about-debugging-connection-prompt-disable-button = Disable connection prompt
# Title of the application displayed in the tab
-application-title = Debugging
# Page title of connect / runtime page
# Part of "about-debugging-page-title" string defined below
about-debugging-page-title-selected-page =
{ $selectedPage ->
[connect] Setup
*[runtime] Runtime
}
# Page title with the runtime displayed in the tab
# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
about-debugging-page-title-with-runtime = { -application-title } - { about-debugging-page-title-selected-page } / { $selectedRuntimeId }
# Page title without the runtime displayed in the tab
about-debugging-page-title = { -application-title } - { about-debugging-page-title-selected-page }
# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
about-debugging-profiler-dialog-title = Performance Profiler
# Label of a checkbox displayed in the runtime page for "This Firefox".
# This checkbox will toggle preferences that enable local addon debugging.
# The "Learn more" link points to MDN.
# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
about-debugging-extension-debug-setting-label = Enable extension debugging <a>Learn more</a>
# Clicking on the header of a debug target category will expand or collapse the debug
# target items in the category. This text is used as title attribute of the header,
# to describe this feature.
about-debugging-collapse-expand-debug-targets = Collapse / expand
# Displayed as name for the Main Process debug target in the Processes category. Only for
# remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
about-debugging-main-process-name = Main Process
about-debugging-main-process-description = Main Process for the target runtime
# Displayed as description for the Main Process debug target in the Processes category.
# Only for remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
about-debugging-main-process-description = Main Process for the target runtime

View File

@ -98,20 +98,6 @@ ToolboxStyleEditor.tooltip3=Stylesheet Editor (CSS) (%S)
# editor.
open.accesskey=l
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.label):
# This string is displayed in the title of the tab when the Web Audio Editor
# is displayed inside the developer tools window and in the Developer Tools Menu.
ToolboxWebAudioEditor1.label=Web Audio
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.panelLabel):
# This is used as the label for the toolbox panel.
ToolboxWebAudioEditor1.panelLabel=Web Audio Panel
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.tooltip):
# This string is displayed in the tooltip of the tab when the Web Audio Editor is
# displayed inside the developer tools window.
ToolboxWebAudioEditor1.tooltip=Web Audio context visualizer and audio node inspector
# LOCALIZATION NOTE (inspector.*)
# Used for the menuitem in the tool menu
inspector.label=Inspector

View File

@ -32,10 +32,6 @@ error-load=Style sheet could not be loaded.
# LOCALIZATION NOTE (error-save): This is shown when saving fails.
error-save=Style sheet could not be saved.
# LOCALIZATION NOTE (error-compressed): This is shown when we can't show
# coverage information because the css source is compressed.
error-compressed=Cant show coverage information for compressed stylesheets
# LOCALIZATION NOTE (importStyleSheet.title): This is the file picker title,
# when you import a style sheet into the Style Editor.
importStyleSheet.title=Import style sheet

View File

@ -341,10 +341,6 @@ pref("devtools.responsive.showUserAgentInput", false);
// Enable new about:debugging.
pref("devtools.aboutdebugging.new-enabled", false);
// Enable the network location feature.
pref("devtools.aboutdebugging.network", false);
// Enable the wifi feature.
pref("devtools.aboutdebugging.wifi", false);
// Show process debug targets.
pref("devtools.aboutdebugging.process-debugging", false);
// Stringified array of network locations that users can connect to.

View File

@ -706,7 +706,6 @@ function getChartsFromToolId(id) {
case "STORAGE":
case "STYLEEDITOR":
case "TOOLBOX":
case "WEBAUDIOEDITOR":
case "WEBCONSOLE":
case "WEBIDE":
timerHist = `DEVTOOLS_${id}_TIME_ACTIVE_SECONDS`;

View File

@ -80,7 +80,6 @@ const ITEM_NAME_MAX_LENGTH = 32;
class StorageUI {
constructor(front, target, panelWin, toolbox) {
EventEmitter.decorate(this);
this._target = target;
this._window = panelWin;
this._panelDoc = panelWin.document;
@ -601,7 +600,8 @@ class StorageUI {
}
try {
if (reason === REASON.POPULATE) {
if (reason === REASON.POPULATE ||
(reason === REASON.NEW_ROW && this.table.items.size === 0)) {
let subType = null;
// The indexedDB type could have sub-type data to fetch.
// If having names specified, then it means
@ -630,6 +630,8 @@ class StorageUI {
const {data} = await storageType.getStoreObjects(host, names, fetchOpts);
if (data.length) {
await this.populateTable(data, reason);
} else if (reason === REASON.POPULATE) {
await this.clearHeaders();
}
this.updateToolbar();
this.emit("store-objects-updated");
@ -653,9 +655,6 @@ class StorageUI {
this._addButton.hidden = false;
this._addButton.setAttribute("tooltiptext",
L10N.getFormatStr("storage.popupMenu.addItemLabel"));
} else {
this._addButton.hidden = true;
this._addButton.removeAttribute("tooltiptext");
}
}
@ -985,6 +984,8 @@ class StorageUI {
let names = null;
if (!host) {
// If selected item has no host then reset table headers
await this.clearHeaders();
return;
}
if (item.length > 2) {
@ -994,6 +995,13 @@ class StorageUI {
this.itemOffset = 0;
}
/**
* Clear the column headers in the storage table
*/
async clearHeaders() {
this.table.setColumns({}, null, {}, {});
}
/**
* Resets the column headers in the storage table with the pased object `data`
*
@ -1119,6 +1127,10 @@ class StorageUI {
this.sidebarToggledOpen = false;
event.stopPropagation();
event.preventDefault();
} else if (event.keyCode == KeyCodes.DOM_VK_BACK_SPACE && this.table.selectedRow) {
this.onRemoveItem();
event.stopPropagation();
event.preventDefault();
}
}
@ -1300,13 +1312,17 @@ class StorageUI {
onRemoveItem() {
const [, host, ...path] = this.tree.selectedItem;
const front = this.getCurrentFront();
const rowId = this.table.contextMenuRowId;
const uniqueId = this.table.uniqueId;
const rowId = this.table.contextMenuRowId || this.table.selectedRow[uniqueId];
const data = this.table.items.get(rowId);
let name = data[this.table.uniqueId];
if (path.length > 0) {
name = JSON.stringify([...path, name]);
}
front.removeItem(host, name);
return false;
}
/**

View File

@ -649,30 +649,6 @@ StyleEditorUI.prototype = {
showEditor.onShow();
this.emit("editor-selected", showEditor);
// Is there any CSS coverage markup to include?
const usage = await this._target.getFront("cssUsage");
if (usage == null) {
return;
}
const sheet = showEditor.styleSheet;
const {reports} = await usage.createEditorReportForSheet(sheet);
showEditor.removeAllUnusedRegions();
if (reports.length > 0) {
// Only apply if this file isn't compressed. We detect a
// compressed file if there are more rules than lines.
const editorText = showEditor.sourceEditor.getText();
const lineCount = editorText.split("\n").length;
const ruleCount = showEditor.styleSheet.ruleCount;
if (lineCount >= ruleCount) {
showEditor.addUnusedRegions(reports);
} else {
this.emit("error", { key: "error-compressed", level: "info" });
}
}
}.bind(this))().catch(console.error);
},
});

View File

@ -42,9 +42,6 @@ const CHECK_LINKED_SHEET_DELAY = 500;
// How many times to check for linked file changes
const MAX_CHECK_COUNT = 10;
// The classname used to show a line that is not used
const UNUSED_CLASS = "cm-unused-line";
// How much time should the mouse be still before the selector at that position
// gets highlighted?
const SELECTOR_HIGHLIGHT_TIMEOUT = 500;
@ -305,41 +302,6 @@ StyleSheetEditor.prototype = {
});
},
/**
* Add markup to a region. UNUSED_CLASS is added to specified lines
* @param region An object shaped like
* {
* start: { line: L1, column: C1 },
* end: { line: L2, column: C2 } // optional
* }
*/
addUnusedRegion: function(region) {
this.sourceEditor.addLineClass(region.start.line - 1, UNUSED_CLASS);
if (region.end) {
for (let i = region.start.line; i <= region.end.line; i++) {
this.sourceEditor.addLineClass(i - 1, UNUSED_CLASS);
}
}
},
/**
* As addUnusedRegion except that it takes an array of regions
*/
addUnusedRegions: function(regions) {
for (const region of regions) {
this.addUnusedRegion(region);
}
},
/**
* Remove all the unused markup regions added by addUnusedRegion
*/
removeAllUnusedRegions: function() {
for (let i = 0; i < this.sourceEditor.lineCount(); i++) {
this.sourceEditor.removeLineClass(i, UNUSED_CLASS);
}
},
/**
* Forward property-change event from stylesheet.
*

View File

@ -9,8 +9,6 @@
%editMenuStrings;
<!ENTITY % sourceEditorStrings SYSTEM "chrome://devtools/locale/sourceeditor.dtd">
%sourceEditorStrings;
<!ENTITY % csscoverageDTD SYSTEM "chrome://devtools-shared/locale/csscoverage.dtd">
%csscoverageDTD;
]>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
@ -169,60 +167,6 @@
</html:div> <!-- #splitview-templates -->
</box> <!-- .splitview-root -->
<box class="csscoverage-template" hidden="true">
<toolbar class="devtools-toolbar csscoverage-toolbar">
<button class="devtools-toolbarbutton csscoverage-toolbarbutton"
label="&csscoverage.backButton;"
onclick="${onback}"/>
</toolbar>
<!-- The data for this comes from CSSUsageActor.createPageReport -->
<html:div class="csscoverage-report-container">
<html:div class="csscoverage-report-content">
<html:div class="csscoverage-report-summary">
<html:div class="csscoverage-report-chart"/>
</html:div>
<html:div class="csscoverage-report-unused">
<html:h2>&csscoverage.unused;</html:h2>
<html:p>&csscoverage.noMatches;</html:p>
<html:div foreach="page in ${unused}">
<html:h3>${page.url}</html:h3>
<html:code foreach="rule in ${page.rules}"
href="${rule.url}"
class="csscoverage-list">${rule.selectorText}</html:code>
</html:div>
</html:div>
<html:div class="csscoverage-report-optimize">
<html:h2>&csscoverage.optimize.header;</html:h2>
<html:p>
&csscoverage.optimize.body1;
<html:code>&lt;link ...></html:code>
&csscoverage.optimize.body2;
<html:code>&lt;style>...</html:code>
&csscoverage.optimize.body3;
</html:p>
<html:div if="${preload.length == 0}">&csscoverage.optimize.bodyX;</html:div>
<html:div if="${preload.length > 0}">
<html:div foreach="page in ${preload}">
<html:h3>${page.url}</html:h3>
<html:textarea>&lt;style>
<html:loop foreach="rule in ${page.rules}"
onclick="${rule.onclick}">${rule.formattedCssText}</html:loop>&lt;/style></html:textarea>
</html:div>
</html:div>
<html:p>
&csscoverage.footer1;
<html:a target="_blank" href="&csscoverage.footer2a;">&csscoverage.footer3;</html:a>
&csscoverage.footer4;
</html:p>
</html:div>
<html:p>&#160;</html:p>
</html:div>
</html:div>
</box>
<box class="csscoverage-report" hidden="true">
</box>
</stack>
</window>

View File

@ -278,142 +278,3 @@ h3 {
-moz-box-flex: 0;
}
}
/* CSS coverage */
.csscoverage-report {
background-color: var(--theme-toolbar-background);
-moz-box-orient: horizontal;
}
.csscoverage-report-container {
height: 100vh;
padding: 0 10px;
overflow-x: hidden;
overflow-y: auto;
-moz-box-flex: 1;
}
.csscoverage-report-content {
margin: 20px auto;
-moz-column-width: 300px;
font-size: 13px;
-moz-user-select: text;
}
.csscoverage-report-summary,
.csscoverage-report-unused,
.csscoverage-report-optimize {
display: inline-block;
}
.csscoverage-report-unused,
.csscoverage-report-optimize {
flex: 1;
min-width: 0;
}
@media (max-width: 950px) {
.csscoverage-report-content {
display: block;
}
.csscoverage-report-summary {
display: block;
text-align: center;
}
}
.csscoverage-report h1 {
font-size: 120%;
}
.csscoverage-report h2 {
font-size: 110%;
}
.csscoverage-report h1,
.csscoverage-report h2,
.csscoverage-report h3 {
font-weight: bold;
margin: 10px 0;
}
.csscoverage-report code,
.csscoverage-report textarea {
font-family: var(--monospace-font-family);
font-size: inherit;
}
.csscoverage-list:after {
content: ', ';
}
.csscoverage-list:last-child:after {
display: none;
}
.csscoverage-report textarea {
width: 100%;
height: 100px;
}
.csscoverage-report a {
cursor: pointer;
text-decoration: underline;
}
.csscoverage-report > .csscoverage-toolbar {
border: none;
margin: 0;
padding: 0;
}
.csscoverage-report > .csscoverage-toolbarbutton {
min-width: 4em;
min-height: 100vh;
margin: 0;
padding: 0;
border-radius: 0;
border-top: none;
border-bottom: none;
border-inline-start: none;
}
.csscoverage-report .pie-table-chart-container {
-moz-box-orient: vertical;
text-align: start;
}
.chart-colored-blob[name="Used Preload"] {
fill: var(--theme-highlight-pink);
background: var(--theme-highlight-pink);
}
.chart-colored-blob[name=Used] {
fill: var(--theme-highlight-green);
background: var(--theme-highlight-green);
}
.chart-colored-blob[name=Unused] {
fill: var(--theme-highlight-lightorange);
background: var(--theme-highlight-lightorange);
}
/* Undo 'largest' customization */
.theme-dark .pie-chart-slice[largest] {
stroke-width: 1px;
stroke: rgba(0,0,0,0.2);
}
.theme-light .pie-chart-slice[largest] {
stroke-width: 1px;
stroke: rgba(255,255,255,0.8);
}
.csscoverage-report .pie-chart-slice {
cursor: default;
}
.csscoverage-report-chart {
margin: 0 20px;
}

View File

@ -1,715 +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";
const { Ci } = require("chrome");
const InspectorUtils = require("InspectorUtils");
const Services = require("Services");
const ChromeUtils = require("ChromeUtils");
const protocol = require("devtools/shared/protocol");
const { cssUsageSpec } = require("devtools/shared/specs/csscoverage");
loader.lazyRequireGetter(this, "prettifyCSS", "devtools/shared/inspector/css-logic", true);
const MAX_UNUSED_RULES = 10000;
/**
* Allow: let foo = l10n.lookup("csscoverageFoo");
*/
const l10n = exports.l10n = {
_URI: "chrome://devtools-shared/locale/csscoverage.properties",
lookup: function(msg) {
if (this._stringBundle == null) {
this._stringBundle = Services.strings.createBundle(this._URI);
}
return this._stringBundle.GetStringFromName(msg);
},
};
/**
* CSSUsage manages the collection of CSS usage data.
* The core of a CSSUsage is a JSON-able data structure called _knownRules
* which looks like this:
* This records the CSSStyleRules and their usage.
* The format is:
* Map({
* <CSS-URL>|<START-LINE>|<START-COLUMN>: {
* selectorText: <CSSStyleRule.selectorText>,
* test: <simplify(CSSStyleRule.selectorText)>,
* cssText: <CSSStyleRule.cssText>,
* isUsed: <TRUE|FALSE>,
* presentOn: Set([ <HTML-URL>, ... ]),
* preLoadOn: Set([ <HTML-URL>, ... ]),
* isError: <TRUE|FALSE>,
* }
* })
*
* For example:
* this._knownRules = Map({
* "http://eg.com/styles1.css|15|0": {
* selectorText: "p.quote:hover",
* test: "p.quote",
* cssText: "p.quote { color: red; }",
* isUsed: true,
* presentOn: Set([ "http://eg.com/page1.html", ... ]),
* preLoadOn: Set([ "http://eg.com/page1.html" ]),
* isError: false,
* }, ...
* });
*/
var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
initialize: function(conn, targetActor) {
protocol.Actor.prototype.initialize.call(this, conn);
this._targetActor = targetActor;
this._running = false;
this._onTabLoad = this._onTabLoad.bind(this);
this._onChange = this._onChange.bind(this);
this._notifyOn = Ci.nsIWebProgress.NOTIFY_STATE_ALL;
},
destroy: function() {
this._targetActor = undefined;
delete this._onTabLoad;
delete this._onChange;
protocol.Actor.prototype.destroy.call(this);
},
/**
* Begin recording usage data
* @param noreload It's best if we start by reloading the current page
* because that starts the test at a known point, but there could be reasons
* why we don't want to do that (e.g. the page contains state that will be
* lost across a reload)
*/
start: function(noreload) {
if (this._running) {
throw new Error(l10n.lookup("csscoverageRunningError"));
}
this._isOneShot = false;
this._visitedPages = new Set();
this._knownRules = new Map();
this._running = true;
this._tooManyUnused = false;
this._progressListener = {
QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference ]),
onStateChange: (progress, request, flags, status) => {
const isStop = flags & Ci.nsIWebProgressListener.STATE_STOP;
const isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
if (isStop && isWindow) {
this._onTabLoad(progress.DOMWindow.document);
}
},
destroy: () => {},
};
this._progress = this._targetActor.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
this._progress.addProgressListener(this._progressListener, this._notifyOn);
if (noreload) {
// If we're not starting by reloading the page, then pretend that onload
// has just happened.
this._onTabLoad(this._targetActor.window.document);
} else {
this._targetActor.window.location.reload();
}
this.emit("state-change", { isRunning: true });
},
/**
* Cease recording usage data
*/
stop: function() {
if (!this._running) {
throw new Error(l10n.lookup("csscoverageNotRunningError"));
}
this._progress.removeProgressListener(this._progressListener, this._notifyOn);
this._progress = undefined;
this._running = false;
this.emit("state-change", { isRunning: false });
},
/**
* Start/stop recording usage data depending on what we're currently doing.
*/
toggle: function() {
return this._running ? this.stop() : this.start();
},
/**
* Running start() quickly followed by stop() does a bunch of unnecessary
* work, so this cuts all that out
*/
oneshot: function() {
if (this._running) {
throw new Error(l10n.lookup("csscoverageRunningError"));
}
this._isOneShot = true;
this._visitedPages = new Set();
this._knownRules = new Map();
this._populateKnownRules(this._targetActor.window.document);
this._updateUsage(this._targetActor.window.document, false);
},
/**
* Called by the ProgressListener to simulate a "load" event
*/
_onTabLoad: function(document) {
this._populateKnownRules(document);
this._updateUsage(document, true);
this._observeMutations(document);
},
/**
* Setup a MutationObserver on the current document
*/
_observeMutations: function(document) {
const MutationObserver = document.defaultView.MutationObserver;
const observer = new MutationObserver(mutations => {
// It's possible that one of the mutations in this list adds a 'use' of
// a CSS rule, and another takes it away. See Bug 1010189
this._onChange(document);
});
observer.observe(document, {
attributes: true,
childList: true,
characterData: false,
subtree: true,
});
},
/**
* Event handler for whenever we think the page has changed in a way that
* means the CSS usage might have changed.
*/
_onChange: function(document) {
// Ignore changes pre 'load'
if (!this._visitedPages.has(getURL(document))) {
return;
}
this._updateUsage(document, false);
},
/**
* Called whenever we think the list of stylesheets might have changed so
* we can update the list of rules that we should be checking
*/
_populateKnownRules: function(document) {
const url = getURL(document);
this._visitedPages.add(url);
// Go through all the rules in the current sheets adding them to knownRules
// if needed and adding the current url to the list of pages they're on
for (const rule of getAllSelectorRules(document)) {
const ruleId = ruleToId(rule);
let ruleData = this._knownRules.get(ruleId);
if (ruleData == null) {
ruleData = {
selectorText: rule.selectorText,
cssText: rule.cssText,
test: getTestSelector(rule.selectorText),
isUsed: false,
presentOn: new Set(),
preLoadOn: new Set(),
isError: false,
};
this._knownRules.set(ruleId, ruleData);
}
ruleData.presentOn.add(url);
}
},
/**
* Update knownRules with usage information from the current page
*/
_updateUsage: function(document, isLoad) {
let qsaCount = 0;
// Update this._data with matches to say 'used at load time' by sheet X
const url = getURL(document);
for (const [ , ruleData ] of this._knownRules) {
// If it broke before, don't try again selectors don't change
if (ruleData.isError) {
continue;
}
// If it's used somewhere already, don't bother checking again unless
// this is a load event in which case we need to add preLoadOn
if (!isLoad && ruleData.isUsed) {
continue;
}
// Ignore rules that are not present on this page
if (!ruleData.presentOn.has(url)) {
continue;
}
qsaCount++;
if (qsaCount > MAX_UNUSED_RULES) {
console.error("Too many unused rules on " + url + " ");
this._tooManyUnused = true;
continue;
}
try {
const match = document.querySelector(ruleData.test);
if (match != null) {
ruleData.isUsed = true;
if (isLoad) {
ruleData.preLoadOn.add(url);
}
}
} catch (ex) {
ruleData.isError = true;
}
}
},
/**
* Returns a JSONable structure designed to help marking up the style editor,
* which describes the CSS selector usage.
* Example:
* [
* {
* selectorText: "p#content",
* usage: "unused|used",
* start: { line: 3, column: 0 },
* },
* ...
* ]
*/
createEditorReport: function(url) {
if (this._knownRules == null) {
return { reports: [] };
}
const reports = [];
for (const [ruleId, ruleData] of this._knownRules) {
const { url: ruleUrl, line, column } = deconstructRuleId(ruleId);
if (ruleUrl !== url || ruleData.isUsed) {
continue;
}
const ruleReport = {
selectorText: ruleData.selectorText,
start: { line: line, column: column },
};
if (ruleData.end) {
ruleReport.end = ruleData.end;
}
reports.push(ruleReport);
}
return { reports: reports };
},
/**
* Compute the stylesheet URL and delegate the report creation to createEditorReport.
* See createEditorReport documentation.
*
* @param {StyleSheetActor} stylesheetActor
* the stylesheet actor for which the coverage report should be generated.
*/
createEditorReportForSheet: function(stylesheetActor) {
const url = sheetToUrl(stylesheetActor.rawSheet);
return this.createEditorReport(url);
},
/**
* Returns a JSONable structure designed for the page report which shows
* the recommended changes to a page.
*
* "preload" means that a rule is used before the load event happens, which
* means that the page could by optimized by placing it in a <style> element
* at the top of the page, moving the <link> elements to the bottom.
*
* Example:
* {
* preload: [
* {
* url: "http://example.org/page1.html",
* shortUrl: "page1.html",
* rules: [
* {
* url: "http://example.org/style1.css",
* shortUrl: "style1.css",
* start: { line: 3, column: 4 },
* selectorText: "p#content",
* formattedCssText: "p#content {\n color: red;\n }\n"
* },
* ...
* ]
* }
* ],
* unused: [
* {
* url: "http://example.org/style1.css",
* shortUrl: "style1.css",
* rules: [ ... ]
* }
* ]
* }
*/
createPageReport: function() {
if (this._running) {
throw new Error(l10n.lookup("csscoverageRunningError"));
}
if (this._visitedPages == null) {
throw new Error(l10n.lookup("csscoverageNotRunError"));
}
if (this._isOneShot) {
throw new Error(l10n.lookup("csscoverageOneShotReportError"));
}
// Helper function to create a JSONable data structure representing a rule
const ruleToRuleReport = function(rule, ruleData) {
return {
url: rule.url,
shortUrl: rule.url.split("/").slice(-1)[0],
start: { line: rule.line, column: rule.column },
selectorText: ruleData.selectorText,
formattedCssText: prettifyCSS(ruleData.cssText),
};
};
// A count of each type of rule for the bar chart
const summary = { used: 0, unused: 0, preload: 0 };
// Create the set of the unused rules
const unusedMap = new Map();
for (const [ruleId, ruleData] of this._knownRules) {
const rule = deconstructRuleId(ruleId);
let rules = unusedMap.get(rule.url);
if (rules == null) {
rules = [];
unusedMap.set(rule.url, rules);
}
if (!ruleData.isUsed) {
const ruleReport = ruleToRuleReport(rule, ruleData);
rules.push(ruleReport);
} else {
summary.unused++;
}
}
const unused = [];
for (const [url, rules] of unusedMap) {
unused.push({
url: url,
shortUrl: url.split("/").slice(-1),
rules: rules,
});
}
// Create the set of rules that could be pre-loaded
const preload = [];
for (const url of this._visitedPages) {
const page = {
url: url,
shortUrl: url.split("/").slice(-1),
rules: [],
};
for (const [ruleId, ruleData] of this._knownRules) {
if (ruleData.preLoadOn.has(url)) {
const rule = deconstructRuleId(ruleId);
const ruleReport = ruleToRuleReport(rule, ruleData);
page.rules.push(ruleReport);
summary.preload++;
} else {
summary.used++;
}
}
if (page.rules.length > 0) {
preload.push(page);
}
}
return {
summary: summary,
preload: preload,
unused: unused,
};
},
/**
* For testing only. What pages did we visit.
*/
_testOnlyVisitedPages: function() {
return [...this._visitedPages];
},
});
exports.CSSUsageActor = CSSUsageActor;
/**
* Generator that filters the CSSRules out of _getAllRules so it only
* iterates over the CSSStyleRules
*/
function* getAllSelectorRules(document) {
for (const rule of getAllRules(document)) {
if (rule.type === CSSRule.STYLE_RULE && rule.selectorText !== "") {
yield rule;
}
}
}
/**
* Generator to iterate over the CSSRules in all the stylesheets the
* current document (i.e. it includes import rules, media rules, etc)
*/
function* getAllRules(document) {
// sheets is an array of the <link> and <style> element in this document
const sheets = getAllSheets(document);
for (let i = 0; i < sheets.length; i++) {
for (let j = 0; j < sheets[i].cssRules.length; j++) {
yield sheets[i].cssRules[j];
}
}
}
/**
* Get an array of all the stylesheets that affect this document. That means
* the <link> and <style> based sheets, and the @imported sheets (recursively)
* but not the sheets in nested frames.
*/
function getAllSheets(document) {
// sheets is an array of the <link> and <style> element in this document
let sheets = Array.slice(document.styleSheets);
// Add @imported sheets
for (let i = 0; i < sheets.length; i++) {
const subSheets = getImportedSheets(sheets[i]);
sheets = sheets.concat(...subSheets);
}
return sheets;
}
/**
* Recursively find @import rules in the given stylesheet.
* We're relying on the browser giving rule.styleSheet == null to resolve
* @import loops
*/
function getImportedSheets(stylesheet) {
let sheets = [];
for (let i = 0; i < stylesheet.cssRules.length; i++) {
const rule = stylesheet.cssRules[i];
// rule.styleSheet == null with duplicate @imports for the same URL.
if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet != null) {
sheets.push(rule.styleSheet);
const subSheets = getImportedSheets(rule.styleSheet);
sheets = sheets.concat(...subSheets);
}
}
return sheets;
}
/**
* Get a unique identifier for a rule. This is currently the string
* <CSS-URL>|<START-LINE>|<START-COLUMN>
* @see deconstructRuleId(ruleId)
*/
function ruleToId(rule) {
const line = InspectorUtils.getRelativeRuleLine(rule);
const column = InspectorUtils.getRuleColumn(rule);
return sheetToUrl(rule.parentStyleSheet) + "|" + line + "|" + column;
}
/**
* Convert a ruleId to an object with { url, line, column } properties
* @see ruleToId(rule)
*/
const deconstructRuleId = exports.deconstructRuleId = function(ruleId) {
const split = ruleId.split("|");
if (split.length > 3) {
const replace = split.slice(0, split.length - 3 + 1).join("|");
split.splice(0, split.length - 3 + 1, replace);
}
const [ url, line, column ] = split;
return {
url: url,
line: parseInt(line, 10),
column: parseInt(column, 10),
};
};
/**
* We're only interested in the origin and pathname, because changes to the
* username, password, hash, or query string probably don't significantly
* change the CSS usage properties of a page.
* @param document
*/
const getURL = exports.getURL = function(document) {
const url = new document.defaultView.URL(document.documentURI);
return url == "about:blank" ? "" : "" + url.origin + url.pathname;
};
/**
* Pseudo class handling constants:
* We split pseudo-classes into a number of categories so we can decide how we
* should match them. See getTestSelector for how we use these constants.
*
* @see http://dev.w3.org/csswg/selectors4/#overview
* @see https://developer.mozilla.org/en-US/docs/tag/CSS%20Pseudo-class
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
*/
/**
* Category 1: Pseudo-classes that depend on external browser/OS state
* This includes things like the time, locale, position of mouse/caret/window,
* contents of browser history, etc. These can be hard to mimic.
* Action: Remove from selectors
*/
const SEL_EXTERNAL = [
"active", "active-drop", "current", "dir", "focus", "future", "hover",
"invalid-drop", "lang", "past", "placeholder-shown", "target", "valid-drop",
"visited",
];
/**
* Category 2: Pseudo-classes that depend on user-input state
* These are pseudo-classes that arguably *should* be covered by unit tests but
* which probably aren't and which are unlikely to be covered by manual tests.
* We're currently stripping them out,
* Action: Remove from selectors (but consider future command line flag to
* enable them in the future. e.g. 'csscoverage start --strict')
*/
const SEL_FORM = [
"checked", "default", "disabled", "enabled", "fullscreen", "in-range",
"indeterminate", "invalid", "optional", "out-of-range", "required", "valid",
];
/**
* Category 3: Pseudo-elements
* querySelectorAll doesn't return matches with pseudo-elements because there
* is no element to match (they're pseudo) so we have to remove them all.
* (See http://codepen.io/joewalker/pen/sanDw for a demo)
* Action: Remove from selectors (including deprecated single colon versions)
*/
const SEL_ELEMENT = [
"after", "before", "first-letter", "first-line", "selection",
];
/**
* Category 4: Structural pseudo-classes
* This is a category defined by the spec (also called tree-structural and
* grid-structural) for selection based on relative position in the document
* tree that cannot be represented by other simple selectors or combinators.
* Action: Require a page-match
*/
const SEL_STRUCTURAL = [
"empty", "first-child", "first-of-type", "last-child", "last-of-type",
"nth-column", "nth-last-column", "nth-child", "nth-last-child",
"nth-last-of-type", "nth-of-type", "only-child", "only-of-type", "root",
];
/**
* Category 4a: Semi-structural pseudo-classes
* These are not structural according to the spec, but act nevertheless on
* information in the document tree.
* Action: Require a page-match
*/
const SEL_SEMI = [ "any-link", "link", "read-only", "read-write", "scope" ];
/**
* Category 5: Combining pseudo-classes
* has(), not() etc join selectors together in various ways. We take care when
* removing pseudo-classes to convert "not(:hover)" into "not(*)" and so on.
* With these changes the combining pseudo-classes should probably stand on
* their own.
* Action: Require a page-match
*/
const SEL_COMBINING = [ "not", "has", "matches" ];
/**
* Category 6: Media pseudo-classes
* Pseudo-classes that should be ignored because they're only relevant to
* media queries
* Action: Don't need removing from selectors as they appear in media queries
*/
const SEL_MEDIA = [ "blank", "first", "left", "right" ];
/**
* A test selector is a reduced form of a selector that we actually test
* against. This code strips out pseudo-elements and some pseudo-classes that
* we think should not have to match in order for the selector to be relevant.
*/
function getTestSelector(selector) {
let replacement = selector;
const replaceSelector = pseudo => {
replacement = replacement.replace(" :" + pseudo, " *")
.replace("(:" + pseudo, "(*")
.replace(":" + pseudo, "");
};
SEL_EXTERNAL.forEach(replaceSelector);
SEL_FORM.forEach(replaceSelector);
SEL_ELEMENT.forEach(replaceSelector);
// Pseudo elements work in : and :: forms
SEL_ELEMENT.forEach(pseudo => {
replacement = replacement.replace("::" + pseudo, "");
});
return replacement;
}
/**
* I've documented all known pseudo-classes above for 2 reasons: To allow
* checking logic and what might be missing, but also to allow a unit test
* that fetches the list of supported pseudo-classes and pseudo-elements from
* the platform and check that they were all represented here.
*/
exports.SEL_ALL = [
SEL_EXTERNAL, SEL_FORM, SEL_ELEMENT, SEL_STRUCTURAL, SEL_SEMI,
SEL_COMBINING, SEL_MEDIA,
].reduce(function(prev, curr) {
return prev.concat(curr);
}, []);
/**
* Find a URL for a given stylesheet
* @param {StyleSheet} stylesheet raw stylesheet
*/
const sheetToUrl = function(stylesheet) {
// For <link> elements
if (stylesheet.href) {
return stylesheet.href;
}
// For <style> elements
if (stylesheet.ownerNode) {
const document = stylesheet.ownerNode.ownerDocument;
const sheets = [...document.querySelectorAll("style")];
const index = sheets.indexOf(stylesheet.ownerNode);
return getURL(document) + " → <style> index " + index;
}
throw new Error("Unknown sheet source");
};

View File

@ -28,7 +28,6 @@ DevToolsModules(
'changes.js',
'common.js',
'css-properties.js',
'csscoverage.js',
'device.js',
'emulation.js',
'environment.js',
@ -72,9 +71,6 @@ with Files('breakpoint.js'):
with Files('css-properties.js'):
BUG_COMPONENT = ('DevTools', 'Inspector: Rules')
with Files('csscoverage.js'):
BUG_COMPONENT = ('DevTools', 'Graphics Commandline and Toolbar')
with Files('memory.js'):
BUG_COMPONENT = ('DevTools', 'Memory')

View File

@ -193,11 +193,6 @@ const ActorRegistry = {
constructor: "CssPropertiesActor",
type: { target: true },
});
this.registerModule("devtools/server/actors/csscoverage", {
prefix: "cssUsage",
constructor: "CSSUsageActor",
type: { target: true },
});
if ("nsIProfiler" in Ci &&
!Services.prefs.getBoolPref("devtools.performance.new-panel-enabled", false)) {
this.registerModule("devtools/server/actors/performance", {

View File

@ -1,105 +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";
const {cssUsageSpec} = require("devtools/shared/specs/csscoverage");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/shared/locales/csscoverage.properties");
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
/**
* Allow: let foo = l10n.lookup("csscoverageFoo");
*/
const l10n = exports.l10n = {
lookup: (msg) => L10N.getStr(msg),
};
/**
* Running more than one usage report at a time is probably bad for performance
* and it isn't particularly useful, and it's confusing from a notification POV
* so we only allow one.
*/
var isRunning = false;
var notification;
var target;
var chromeWindow;
/**
* Front for CSSUsageActor
*/
class CSSUsageFront extends FrontClassWithSpec(cssUsageSpec) {
constructor(client) {
super(client);
this.before("state-change", this._onStateChange.bind(this));
// Attribute name from which to retrieve the actorID out of the target actor's form
this.formAttributeName = "cssUsageActor";
}
_onStateChange(ev) {
isRunning = ev.isRunning;
ev.target = target;
if (isRunning) {
const gnb = chromeWindow.gNotificationBox;
notification = gnb.getNotificationWithValue("csscoverage-running");
if (notification == null) {
const notifyStop = reason => {
if (reason == "removed") {
this.stop();
}
};
const msg = l10n.lookup("csscoverageRunningReply");
notification = gnb.appendNotification(msg, "csscoverage-running",
"",
gnb.PRIORITY_INFO_HIGH,
null,
notifyStop);
}
} else {
if (notification) {
notification.close();
notification = undefined;
}
gDevTools.showToolbox(target, "styleeditor");
target = undefined;
}
}
/**
* Server-side start is above. Client-side start adds a notification box
*/
start(newChromeWindow, newTarget, noreload = false) {
target = newTarget;
chromeWindow = newChromeWindow;
return super.start(noreload);
}
/**
* Server-side start is above. Client-side start adds a notification box
*/
toggle(newChromeWindow, newTarget) {
target = newTarget;
chromeWindow = newChromeWindow;
return super.toggle();
}
/**
* We count STARTING and STOPPING as 'running'
*/
isRunning() {
return isRunning;
}
}
exports.CSSUsageFront = CSSUsageFront;
registerFront(CSSUsageFront);

View File

@ -17,7 +17,6 @@ DevToolsModules(
'animation.js',
'changes.js',
'css-properties.js',
'csscoverage.js',
'device.js',
'emulation.js',
'framerate.js',

View File

@ -1,47 +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/. -->
<!-- LOCALIZATION NOTE : FILE This file contains the CSS Coverage Report
- strings. See the 'csscoverage' command for more information, and
- devtools/client/styleeditor/index.xul for context -->
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
- keep it in English, or another language commonly spoken among web developers.
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!-- LOCALIZATION NOTE (csscoverage.backButton):
- Text on the button to go back to the main style editor -->
<!ENTITY csscoverage.backButton "Back">
<!-- LOCALIZATION NOTE (csscoverage.unused, csscoverage.noMatches):
- This is the heading and body text for the CSS usage part of the report -->
<!ENTITY csscoverage.unused "Unused Rules">
<!ENTITY csscoverage.noMatches "No matches found for the following rules:">
<!-- LOCALIZATION NOTE (csscoverage.optimize.header):
- This is the heading for the CSS optimization part of the report -->
<!ENTITY csscoverage.optimize.header "Optimizable Pages">
<!-- LOCALIZATION NOTE (csscoverage.preload1, csscoverage.preload2,
- csscoverage.preload3): These 3 are part of a paragraph with 1 and 2
- separated by a styled <link> tag and 2 and 3 separated by a styled
- <style> tag -->
<!ENTITY csscoverage.optimize.body1 "You can sometimes speed up loading by moving">
<!ENTITY csscoverage.optimize.body2 "tags to the bottom of the page and creating a new inline">
<!ENTITY csscoverage.optimize.body3 "element with the styles needed before the load event to the top. Here are the style blocks you need:">
<!-- LOCALIZATION NOTE (csscoverage.optimize.bodyX):
- This is what we say when we have no optimization suggestions -->
<!ENTITY csscoverage.optimize.bodyX "All rules are inlined.">
<!-- LOCALIZATION NOTE (csscoverage.footer1, csscoverage.footer2a,
- csscoverage.footer3, csscoverage.footer4): The text displayed at the
- bottom of the page, with 2a being the URL opened when the link text in 3
- is clicked -->
<!ENTITY csscoverage.footer1 "See">
<!ENTITY csscoverage.footer2a "https://developer.mozilla.org/docs/Tools/CSS_Coverage">
<!ENTITY csscoverage.footer3 "the MDN article on the CSS Coverage Tool">
<!ENTITY csscoverage.footer4 "for caveats in the generation of this report.">

View File

@ -1,32 +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/.
# LOCALIZATION NOTE These strings are used in the 'csscoverage' command and in
# the user interface that this command creates.
# LOCALIZATION NOTE (csscoverageDesc, csscoverageStartDesc2,
# csscoverageStopDesc2, csscoverageOneShotDesc2, csscoverageToggleDesc2,
# csscoverageReportDesc2): Short descriptions of the csscoverage commands
csscoverageDesc=Control CSS coverage analysis
csscoverageStartDesc2=Begin collecting CSS coverage data
csscoverageStopDesc2=Stop collecting CSS coverage data
csscoverageOneShotDesc2=Collect instantaneous CSS coverage data
csscoverageToggleDesc2=Toggle collecting CSS coverage data
csscoverageReportDesc2=Show CSS coverage report
csscoverageStartNoReloadDesc=Dont start with a page reload
csscoverageStartNoReloadManual=Its best if we start by reloading the current page because that starts the test at a known point, but there could be reasons why we dont want to do that (e.g. the page contains state that will be lost across a reload)
# LOCALIZATION NOTE (csscoverageRunningReply, csscoverageDoneReply): Text that
# describes the current state of the css coverage system
csscoverageRunningReply=Running CSS coverage analysis
csscoverageDoneReply=CSS Coverage analysis completed
# LOCALIZATION NOTE (csscoverageRunningError, csscoverageNotRunningError,
# csscoverageNotRunError): Error message that describe things that can go wrong
# with the css coverage system
csscoverageRunningError=CSS coverage analysis already running
csscoverageNotRunningError=CSS coverage analysis not running
csscoverageNotRunError=CSS coverage analysis has not been run
csscoverageNoRemoteError=Target does not support CSS Coverage
csscoverageOneShotReportError=CSS coverage report is not available for oneshot data. Please use start/stop.

View File

@ -1,42 +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";
const {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
const cssUsageSpec = generateActorSpec({
typeName: "cssUsage",
events: {
"state-change": {
type: "stateChange",
stateChange: Arg(0, "json"),
},
},
methods: {
start: {
request: { url: Arg(0, "boolean") },
},
stop: {},
toggle: {},
oneshot: {},
createEditorReport: {
request: { url: Arg(0, "string") },
response: { reports: RetVal("array:json") },
},
createEditorReportForSheet: {
request: { url: Arg(0, "stylesheet") },
response: { reports: RetVal("array:json") },
},
createPageReport: {
response: RetVal("json"),
},
_testOnlyVisitedPages: {
response: { value: RetVal("array:string") },
},
},
});
exports.cssUsageSpec = cssUsageSpec;

View File

@ -52,11 +52,6 @@ const Types = exports.__TypesForTests = [
spec: "devtools/shared/specs/css-properties",
front: "devtools/shared/fronts/css-properties",
},
{
types: ["cssUsage"],
spec: "devtools/shared/specs/csscoverage",
front: "devtools/shared/fronts/csscoverage",
},
{
types: ["device"],
spec: "devtools/shared/specs/device",

View File

@ -16,7 +16,6 @@ DevToolsModules(
'animation.js',
'changes.js',
'css-properties.js',
'csscoverage.js',
'device.js',
'emulation.js',
'environment.js',

View File

@ -17,6 +17,7 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/Preferences.h"
#include "mozilla/Unused.h"
@ -135,6 +136,8 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
nsTArray<PermissionRequest> mRequests;
private:
// Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::ipc::IPCResult Recvprompt() override;
virtual mozilla::ipc::IPCResult RecvNotifyVisibility(
const bool& aIsVisible) override;
@ -162,7 +165,8 @@ ContentPermissionRequestParent::~ContentPermissionRequestParent() {
mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
mProxy = new nsContentPermissionRequestProxy(this);
if (NS_FAILED(mProxy->Init(mRequests))) {
mProxy->Cancel();
RefPtr<nsContentPermissionRequestProxy> proxy(mProxy);
proxy->Cancel();
}
return IPC_OK();
}
@ -631,11 +635,14 @@ class RequestAllowEvent : public Runnable {
mAllow(allow),
mRequest(request) {}
// Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD Run() override {
// MOZ_KnownLive is OK, because we never drop the ref to mRequest.
if (mAllow) {
mRequest->Allow(JS::UndefinedHandleValue);
MOZ_KnownLive(mRequest)->Allow(JS::UndefinedHandleValue);
} else {
mRequest->Cancel();
MOZ_KnownLive(mRequest)->Cancel();
}
return NS_OK;
}
@ -931,12 +938,14 @@ RemotePermissionRequest::~RemotePermissionRequest() {
void RemotePermissionRequest::DoCancel() {
NS_ASSERTION(mRequest, "We need a request");
mRequest->Cancel();
nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
request->Cancel();
}
void RemotePermissionRequest::DoAllow(JS::HandleValue aChoices) {
NS_ASSERTION(mRequest, "We need a request");
mRequest->Allow(aChoices);
nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
request->Allow(aChoices);
}
// PContentPermissionRequestChild

View File

@ -220,7 +220,9 @@ class RemotePermissionRequest final
RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
nsPIDOMWindowInner* aWindow);
// It will be called when prompt dismissed.
// It will be called when prompt dismissed. MOZ_CAN_RUN_SCRIPT_BOUNDARY
// because we don't have MOZ_CAN_RUN_SCRIPT bits in IPC code yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvNotifyResult(
const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices);
@ -243,7 +245,9 @@ class RemotePermissionRequest final
private:
virtual ~RemotePermissionRequest();
MOZ_CAN_RUN_SCRIPT
void DoAllow(JS::HandleValue aChoices);
MOZ_CAN_RUN_SCRIPT
void DoCancel();
nsCOMPtr<nsIContentPermissionRequest> mRequest;

View File

@ -1,6 +1,7 @@
function handleRequest(request, response)
{
let [status, statusText, body] = request.queryString.split("&");
let [status, statusText, encodedBody] = request.queryString.split("&");
let body = decodeURIComponent(encodedBody);
response.setStatusLine(request.httpVersion, status, statusText);
response.setHeader("Content-Type", "text/xml", false);
response.setHeader("Content-Length", "" + body.length, false);

View File

@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=884693
const SERVER_URL = "http://mochi.test:8888/tests/dom/base/test/chrome/bug884693.sjs";
const INVALID_XML = "InvalidXML";
const XML_WITHOUT_ROOT = "<?xml version='1.0'?>";
let consoleService = Cc["@mozilla.org/consoleservice;1"].
getService(Ci.nsIConsoleService)
@ -63,7 +64,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=884693
then(() => { return runTest(205, "Reset Content", INVALID_XML, "", []); }).
then(() => { return runTest(304, "Not modified", "", "", []); }).
then(() => { return runTest(304, "Not modified", INVALID_XML, "", []); }).
then(() => { return runTest(200, "OK", "", "", ["no root element found"]); }).
then(() => { return runTest(200, "OK", "", "", []); }).
then(() => { return runTest(200, "OK", XML_WITHOUT_ROOT, XML_WITHOUT_ROOT, ["no root element found"]); }).
then(() => { return runTest(200, "OK", INVALID_XML, INVALID_XML, ["syntax error"]); }).
then(SimpleTest.finish);

View File

@ -553,8 +553,13 @@ void ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField) {
// subclass. This class is used in bindings to safely handle Fast* callbacks;
// it ensures that the callback is traced, and that if something is holding onto
// the callback when we're done with it HoldJSObjects is called.
//
// Since we effectively hold a ref to a refcounted thing (like RefPtr or
// OwningNonNull), we are also MOZ_IS_SMARTPTR_TO_REFCOUNTED for static analysis
// purposes.
template <typename T>
class MOZ_RAII RootedCallback : public JS::Rooted<T> {
class MOZ_RAII MOZ_IS_SMARTPTR_TO_REFCOUNTED RootedCallback
: public JS::Rooted<T> {
public:
explicit RootedCallback(JSContext* cx) : JS::Rooted<T>(cx), mCx(cx) {}

View File

@ -7321,7 +7321,7 @@ class CGCallGenerator(CGThing):
# If it's a refcounted object, let the static analysis know it's
# alive for the duration of the call.
if a.type.isGeckoInterface():
if a.type.isGeckoInterface() or a.type.isCallback():
arg = CGWrapper(arg, pre="MOZ_KnownLive(", post=")")
args.append(arg)
@ -10645,7 +10645,7 @@ class ClassMethod(ClassItem):
virtual=False, const=False, bodyInHeader=False,
templateArgs=None, visibility='public', body=None,
breakAfterReturnDecl="\n",
breakAfterSelf="\n", override=False):
breakAfterSelf="\n", override=False, canRunScript=False):
"""
override indicates whether to flag the method as override
"""
@ -10663,10 +10663,13 @@ class ClassMethod(ClassItem):
self.breakAfterReturnDecl = breakAfterReturnDecl
self.breakAfterSelf = breakAfterSelf
self.override = override
self.canRunScript = canRunScript;
ClassItem.__init__(self, name, visibility)
def getDecorators(self, declaring):
decorators = []
if self.canRunScript:
decorators.append('MOZ_CAN_RUN_SCRIPT')
if self.inline:
decorators.append('inline')
if declaring:
@ -14783,7 +14786,7 @@ class CGNativeMember(ClassMethod):
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
spiderMonkeyInterfacesAreStructs=True,
variadicIsSequence=False, resultNotAddRefed=False,
virtual=False, override=False):
virtual=False, override=False, canRunScript=False):
"""
If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
will be passed as JS::Handle<JSObject*>. If it's true they will be
@ -14813,7 +14816,8 @@ class CGNativeMember(ClassMethod):
breakAfterSelf=breakAfterSelf,
visibility=visibility,
virtual=virtual,
override=override)
override=override,
canRunScript=canRunScript)
def getReturnType(self, type, isMember):
return self.getRetvalInfo(type, isMember)[0]
@ -16227,17 +16231,21 @@ class CGCallback(CGClass):
return [ClassMethod(method.name, method.returnType, args,
bodyInHeader=True,
templateArgs=["typename T"],
body=bodyWithThis),
body=bodyWithThis,
canRunScript=method.canRunScript),
ClassMethod(method.name, method.returnType, argsWithoutThis,
bodyInHeader=True,
body=bodyWithoutThis),
body=bodyWithoutThis,
canRunScript=method.canRunScript),
ClassMethod(method.name, method.returnType, argsWithoutRv,
bodyInHeader=True,
templateArgs=["typename T"],
body=bodyWithThisWithoutRv),
body=bodyWithThisWithoutRv,
canRunScript=method.canRunScript),
ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
bodyInHeader=True,
body=bodyWithoutThisAndRv),
body=bodyWithoutThisAndRv,
canRunScript=method.canRunScript),
method]
def deps(self):
@ -16388,7 +16396,8 @@ class CallbackMember(CGNativeMember):
def __init__(self, sig, name, descriptorProvider, needThisHandling,
rethrowContentException=False,
spiderMonkeyInterfacesAreStructs=False,
wrapScope='CallbackKnownNotGray()'):
wrapScope='CallbackKnownNotGray()',
canRunScript=False):
"""
needThisHandling is True if we need to be able to accept a specified
thisObj, False otherwise.
@ -16422,7 +16431,8 @@ class CallbackMember(CGNativeMember):
extendedAttrs={},
passJSBitsAsNeeded=False,
visibility=visibility,
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
canRunScript=canRunScript)
# We have to do all the generation of our body now, because
# the caller relies on us throwing if we can't manage it.
self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
@ -16644,10 +16654,12 @@ class CallbackMember(CGNativeMember):
class CallbackMethod(CallbackMember):
def __init__(self, sig, name, descriptorProvider, needThisHandling,
rethrowContentException=False,
spiderMonkeyInterfacesAreStructs=False):
spiderMonkeyInterfacesAreStructs=False,
canRunScript=False):
CallbackMember.__init__(self, sig, name, descriptorProvider,
needThisHandling, rethrowContentException,
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
canRunScript=canRunScript)
def getRvalDecl(self):
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
@ -16680,7 +16692,8 @@ class CallCallback(CallbackMethod):
def __init__(self, callback, descriptorProvider):
self.callback = callback
CallbackMethod.__init__(self, callback.signatures()[0], "Call",
descriptorProvider, needThisHandling=True)
descriptorProvider, needThisHandling=True,
canRunScript=not callback.isRunScriptBoundary())
def getThisDecl(self):
return ""

View File

@ -4664,6 +4664,7 @@ class IDLCallback(IDLObjectWithScope):
self._treatNonCallableAsNull = False
self._treatNonObjectAsNull = False
self._isRunScriptBoundary = False
def isCallback(self):
return True
@ -4701,6 +4702,8 @@ class IDLCallback(IDLObjectWithScope):
self._treatNonCallableAsNull = True
elif attr.identifier() == "TreatNonObjectAsNull":
self._treatNonObjectAsNull = True
elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
self._isRunScriptBoundary = True
else:
unhandledAttrs.append(attr)
if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
@ -4712,6 +4715,9 @@ class IDLCallback(IDLObjectWithScope):
def _getDependentObjects(self):
return set([self._returnType] + self._arguments)
def isRunScriptBoundary(self):
return self._isRunScriptBoundary;
class IDLCallbackType(IDLType):
def __init__(self, location, callback):

View File

@ -28,6 +28,7 @@ class TestFunctions : public NonRefcountedDOMObject {
static Promise* PassThroughPromise(GlobalObject& aGlobal, Promise& aPromise);
MOZ_CAN_RUN_SCRIPT
static already_AddRefed<Promise> PassThroughCallbackPromise(
GlobalObject& aGlobal, PromiseReturner& aCallback, ErrorResult& aRv);

View File

@ -4,6 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
callback PlacesEventCallback = void (sequence<PlacesEvent> events);
[ChromeOnly, Exposed=Window,

View File

@ -8,6 +8,7 @@ interface nsISupports;
/**
* A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
*/
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
/**

View File

@ -5,6 +5,7 @@
interface URI;
interface WindowProxy;
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
callback WebExtensionLocalizeCallback = DOMString (DOMString unlocalizedText);
/**

View File

@ -47,7 +47,7 @@ JSObject* PositionError::WrapObject(JSContext* aCx,
void PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) {
nsAutoMicroTask mt;
if (aCallback.HasWebIDLCallback()) {
PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
RefPtr<PositionErrorCallback> callback = aCallback.GetWebIDLCallback();
if (callback) {
callback->Call(*this);

View File

@ -38,6 +38,7 @@ class PositionError final : public nsWrapperCache {
void GetMessage(nsAString& aMessage) const;
MOZ_CAN_RUN_SCRIPT
void NotifyCallback(const GeoPositionErrorCallback& callback);
private:

View File

@ -83,19 +83,24 @@ class nsGeolocationRequest final
int32_t aWatchId = 0);
// nsIContentPermissionRequest
NS_IMETHOD Cancel(void) override;
NS_IMETHOD Allow(JS::HandleValue choices) override;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Cancel(void) override;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Allow(JS::HandleValue choices) override;
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
void Shutdown();
// MOZ_CAN_RUN_SCRIPT_BOUNDARY is OK here because we're always called from a
// runnable. Ideally nsIRunnable::Run and its overloads would just be
// MOZ_CAN_RUN_SCRIPT and then we could be too...
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void SendLocation(nsIDOMGeoPosition* aLocation);
bool WantsHighAccuracy() {
return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;
}
void SetTimeoutTimer();
void StopTimeoutTimer();
MOZ_CAN_RUN_SCRIPT
void NotifyErrorAndShutdown(uint16_t);
using ContentPermissionRequestBase::GetPrincipal;
nsIPrincipal* GetPrincipal();
@ -124,7 +129,8 @@ class nsGeolocationRequest final
WeakPtr<nsGeolocationRequest> mRequest;
};
void Notify();
// Only called from a timer, so MOZ_CAN_RUN_SCRIPT_BOUNDARY ok for now.
MOZ_CAN_RUN_SCRIPT_BOUNDARY void Notify();
bool mIsWatchPositionRequest;
@ -332,7 +338,8 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) {
}
// Kick off the geo device, if it isn't already running
nsresult rv = gs->StartDevice(GetPrincipal());
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
nsresult rv = gs->StartDevice(principal);
if (NS_FAILED(rv)) {
// Location provider error
@ -410,7 +417,7 @@ void nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition) {
nsAutoMicroTask mt;
if (mCallback.HasWebIDLCallback()) {
PositionCallback* callback = mCallback.GetWebIDLCallback();
RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();
MOZ_ASSERT(callback);
callback->Call(*wrapped);
@ -942,13 +949,15 @@ Geolocation::NotifyError(uint16_t aErrorCode) {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
mPendingCallbacks[i - 1]->NotifyErrorAndShutdown(aErrorCode);
RefPtr<nsGeolocationRequest> request = mPendingCallbacks[i - 1];
request->NotifyErrorAndShutdown(aErrorCode);
// NotifyErrorAndShutdown() removes the request from the array
}
// notify everyone that is watching
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
RefPtr<nsGeolocationRequest> request = mWatchingCallbacks[i];
request->NotifyErrorAndShutdown(aErrorCode);
}
return NS_OK;

View File

@ -76,6 +76,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate,
CachedPositionAndAccuracy GetCachedPosition();
// Find and startup a geolocation device (gps, nmea, etc.)
MOZ_CAN_RUN_SCRIPT
nsresult StartDevice(nsIPrincipal* aPrincipal);
// Stop the started geolocation device (gps, nmea, etc.)
@ -132,6 +133,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
virtual JSObject* WrapObject(JSContext* aCtx,
JS::Handle<JSObject*> aGivenProto) override;
MOZ_CAN_RUN_SCRIPT
int32_t WatchPosition(PositionCallback& aCallback,
PositionErrorCallback* aErrorCallback,
const PositionOptions& aOptions, CallerType aCallerType,
@ -143,6 +145,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
void ClearWatch(int32_t aWatchId);
// A WatchPosition for C++ use. Returns -1 if we failed to actually watch.
MOZ_CAN_RUN_SCRIPT
int32_t WatchPosition(nsIDOMGeoPositionCallback* aCallback,
nsIDOMGeoPositionErrorCallback* aErrorCallback,
UniquePtr<PositionOptions>&& aOptions);
@ -186,6 +189,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
GeoPositionErrorCallback aErrorCallback,
UniquePtr<PositionOptions>&& aOptions,
CallerType aCallerType);
MOZ_CAN_RUN_SCRIPT
int32_t WatchPosition(GeoPositionCallback aCallback,
GeoPositionErrorCallback aErrorCallback,
UniquePtr<PositionOptions>&& aOptions,

View File

@ -5,7 +5,6 @@ async function idbCheckFunc() {
factory = indexedDB;
} catch (ex) {
// in a frame-script, we need to pierce "content"
// eslint-disable-next-line mozilla/no-cpows-in-tests
factory = content.indexedDB;
}
try {
@ -73,7 +72,6 @@ const workerScriptBlob = new Blob([workerScript]);
*/
async function workerCheckDeployer({ srcBlob, workerType }) {
let worker, port;
// eslint-disable-next-line mozilla/no-cpows-in-tests
const url = content.URL.createObjectURL(srcBlob);
if (workerType === "dedicated") {
worker = new content.Worker(url);

View File

@ -33,22 +33,6 @@ interface nsIBrowser : nsISupports
[array, size_is(linksCount)] in wstring links,
in nsIPrincipal aTriggeringPrincipal);
/**
* Flags for controlling the behavior of swapBrowsers
*/
/**
* The default options. This is used for swapping browsers between windows
*/
const unsigned long SWAP_DEFAULT = 0;
/**
* If this bit is set, swapping the browsers will not swap the permanentKey of
* the browsers. This is used when performing cross process loads by swapping
* browsers.
*/
const unsigned long SWAP_KEEP_PERMANENT_KEY = 0x1;
/**
* Swapping of frameloaders are usually initiated from a frameloader owner
* or other components operating on frameloader owners. This is done by calling
@ -61,7 +45,7 @@ interface nsIBrowser : nsISupports
* frameloader owners such as <xul:browser> can setup their properties and /
* or listeners properly on swapping.
*/
void swapBrowsers(in nsIBrowser aOtherBrowser, in unsigned long aFlags);
void swapBrowsers(in nsIBrowser aOtherBrowser);
/**
* Close the browser (usually means to remove a tab).

View File

@ -98,8 +98,9 @@ interface nsIContentPermissionRequest : nsISupports {
/**
* allow or cancel the request
*/
[can_run_script]
void cancel();
[can_run_script]
void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
};

View File

@ -376,6 +376,9 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
// in IPC code yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
mozilla::ipc::IPCResult RecvUpdateDictionaryList(

View File

@ -4001,6 +4001,7 @@ mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
return IPC_OK();
}
MOZ_CAN_RUN_SCRIPT
static int32_t AddGeolocationListener(
nsIDOMGeoPositionCallback* watcher,
nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {

View File

@ -989,10 +989,16 @@ class ContentParent final : public PContentParent,
const IPC::Principal& aPrincipal,
const ClonedMessageData& aData);
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
// in IPC code yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvAddGeolocationListener(
const IPC::Principal& aPrincipal, const bool& aHighAccuracy);
mozilla::ipc::IPCResult RecvRemoveGeolocationListener();
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
// in IPC code yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvSetGeolocationHigherAccuracy(const bool& aEnable);
mozilla::ipc::IPCResult RecvConsoleMessage(const nsString& aMessage);

View File

@ -50,7 +50,10 @@ ValueExtractor.prototype = {
const value = this.extractValue(spec);
let color;
if (InspectorUtils.isValidCSSColor(value)) {
color = value;
const rgba = InspectorUtils.colorToRGBA(value);
color = "#" + ((rgba.r << 16) |
(rgba.g << 8) |
rgba.b).toString(16);
} else if (value) {
this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidCSSColor",
[spec.property, value],

View File

@ -20,3 +20,106 @@ const data = {
manifestURL,
docURL,
};
const validThemeColors = [
["maroon", "#800000"],
["#f00", "#ff0000"],
["#ff0000", "#ff0000"],
["rgb(255,0,0)", "#ff0000"],
["rgb(255,0,0,1)", "#ff0000"],
["rgb(255,0,0,1.0)", "#ff0000"],
["rgb(255,0,0,100%)", "#ff0000"],
["rgb(255 0 0)", "#ff0000"],
["rgb(255 0 0 / 1)", "#ff0000"],
["rgb(255 0 0 / 1.0)", "#ff0000"],
["rgb(255 0 0 / 100%)", "#ff0000"],
["rgb(100%, 0%, 0%)", "#ff0000"],
["rgb(100%, 0%, 0%, 1)", "#ff0000"],
["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
["rgb(100% 0% 0%)", "#ff0000"],
["rgb(100% 0% 0% / 1)", "#ff0000"],
["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
["rgb(300,0,0)", "#ff0000"],
["rgb(300 0 0)", "#ff0000"],
["rgb(255,-10,0)", "#ff0000"],
["rgb(110%, 0%, 0%)", "#ff0000"],
["rgba(255,0,0)", "#ff0000"],
["rgba(255,0,0,1)", "#ff0000"],
["rgba(255 0 0 / 1)", "#ff0000"],
["rgba(100%,0%,0%,1)", "#ff0000"],
["rgba(0,0,255,0.5)", "#ff"],
["rgba(100%, 50%, 0%, 0.1)", "#ff8000"],
["hsl(120, 100%, 50%)", "#ff00"],
["hsl(120 100% 50%)", "#ff00"],
["hsl(120, 100%, 50%, 1.0)", "#ff00"],
["hsl(120 100% 50% / 1.0)", "#ff00"],
["hsla(120, 100%, 50%)", "#ff00"],
["hsla(120 100% 50%)", "#ff00"],
["hsla(120, 100%, 50%, 1.0)", "#ff00"],
["hsla(120 100% 50% / 1.0)", "#ff00"],
["hsl(120deg, 100%, 50%)", "#ff00"],
["hsl(133.33333333grad, 100%, 50%)", "#ff00"],
["hsl(2.0943951024rad, 100%, 50%)", "#ff00"],
["hsl(0.3333333333turn, 100%, 50%)", "#ff00"],
];
function setupManifest(key, value) {
const manifest = {};
manifest[key] = value;
data.jsonText = JSON.stringify(manifest);
}
function testValidColors(key) {
validThemeColors.forEach(item => {
const [manifest_color, parsed_color] = item;
setupManifest(key, manifest_color);
const result = processor.process(data);
is(result[key], parsed_color, `Expect ${key} to be returned for ${manifest_color}`);
});
// Trim tests
validThemeColors.forEach(item => {
const [manifest_color, parsed_color] = item;
const expandedThemeColor = `${seperators}${lineTerminators}${manifest_color}${lineTerminators}${seperators}`;
setupManifest(key, expandedThemeColor);
const result = processor.process(data);
is(result[key], parsed_color, `Expect trimmed ${key} to be returned for ${manifest_color}`);
});
}
const invalidThemeColors = [
"marooon",
"f000000",
"#ff00000",
"rgb(100, 0%, 0%)",
"rgb(255,0)",
"rbg(255,-10,0)",
"rgb(110, 0%, 0%)",
"(255,0,0) }",
"rgba(255)",
" rgb(100%,0%,0%) }",
"hsl(120, 100%, 50)",
"hsl(120, 100%, 50.0)",
"hsl 120, 100%, 50%",
"hsla{120, 100%, 50%, 1}",
];
function testInvalidColors(key) {
typeTests.forEach(type => {
setupManifest(key, type);
const result = processor.process(data);
is(result[key], undefined, `Expect non-string ${key} to be undefined: ${typeof type}.`);
});
invalidThemeColors.forEach(manifest_color => {
setupManifest(key, manifest_color);
const result = processor.process(data);
is(result[key], undefined, `Expect ${key} to be undefined: ${manifest_color}.`);
});
}

View File

@ -16,103 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1195018
**/
"use strict";
typeTests.forEach(type => {
data.jsonText = JSON.stringify({
background_color: type,
});
var result = processor.process(data);
is(result.background_color, undefined, `Expect non-string background_color to be undefined: ${typeof type}.`);
});
var validThemeColors = [
"maroon",
"#f00",
"#ff0000",
"rgb(255,0,0)",
"rgb(255,0,0,1)",
"rgb(255,0,0,1.0)",
"rgb(255,0,0,100%)",
"rgb(255 0 0)",
"rgb(255 0 0 / 1)",
"rgb(255 0 0 / 1.0)",
"rgb(255 0 0 / 100%)",
"rgb(100%, 0%, 0%)",
"rgb(100%, 0%, 0%, 1)",
"rgb(100%, 0%, 0%, 1.0)",
"rgb(100%, 0%, 0%, 100%)",
"rgb(100% 0% 0%)",
"rgb(100% 0% 0% / 1)",
"rgb(100%, 0%, 0%, 1.0)",
"rgb(100%, 0%, 0%, 100%)",
"rgb(300,0,0)",
"rgb(300 0 0)",
"rgb(255,-10,0)",
"rgb(110%, 0%, 0%)",
"rgba(255,0,0)",
"rgba(255,0,0,1)",
"rgba(255 0 0 / 1)",
"rgba(100%,0%,0%,1)",
"rgba(0,0,255,0.5)",
"rgba(100%, 50%, 0%, 0.1)",
"hsl(120, 100%, 50%)",
"hsl(120 100% 50%)",
"hsl(120, 100%, 50%, 1.0)",
"hsl(120 100% 50% / 1.0)",
"hsla(120, 100%, 50%)",
"hsla(120 100% 50%)",
"hsla(120, 100%, 50%, 1.0)",
"hsla(120 100% 50% / 1.0)",
"hsl(120deg, 100%, 50%)",
"hsl(133.33333333grad, 100%, 50%)",
"hsl(2.0943951024rad, 100%, 50%)",
"hsl(0.3333333333turn, 100%, 50%)",
];
validThemeColors.forEach(background_color => {
data.jsonText = JSON.stringify({
background_color,
});
var result = processor.process(data);
is(result.background_color, background_color, `Expect background_color to be returned: ${background_color}.`);
});
var invalidThemeColors = [
"marooon",
"f000000",
"#ff00000",
"rgb(100, 0%, 0%)",
"rgb(255,0)",
"rbg(255,-10,0)",
"rgb(110, 0%, 0%)",
"(255,0,0) }",
"rgba(255)",
" rgb(100%,0%,0%) }",
"hsl(120, 100%, 50)",
"hsl(120, 100%, 50.0)",
"hsl 120, 100%, 50%",
"hsla{120, 100%, 50%, 1}",
];
invalidThemeColors.forEach(background_color => {
data.jsonText = JSON.stringify({
background_color,
});
var result = processor.process(data);
is(result.background_color, undefined, `Expect background_color to be undefined: ${background_color}.`);
});
// Trim tests
validThemeColors.forEach(background_color => {
var expandedThemeColor = `${seperators}${lineTerminators}${background_color}${lineTerminators}${seperators}`;
data.jsonText = JSON.stringify({
background_color: expandedThemeColor,
});
var result = processor.process(data);
is(result.background_color, background_color, `Expect trimmed background_color to be returned.`);
});
testValidColors("background_color");
testInvalidColors("background_color");
</script>
</head>

View File

@ -16,103 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1195018
**/
"use strict";
typeTests.forEach(type => {
data.jsonText = JSON.stringify({
theme_color: type,
});
var result = processor.process(data);
is(result.theme_color, undefined, `Expect non-string theme_color to be undefined: ${typeof type}.`);
});
var validThemeColors = [
"maroon",
"#f00",
"#ff0000",
"rgb(255,0,0)",
"rgb(255,0,0,1)",
"rgb(255,0,0,1.0)",
"rgb(255,0,0,100%)",
"rgb(255 0 0)",
"rgb(255 0 0 / 1)",
"rgb(255 0 0 / 1.0)",
"rgb(255 0 0 / 100%)",
"rgb(100%, 0%, 0%)",
"rgb(100%, 0%, 0%, 1)",
"rgb(100%, 0%, 0%, 1.0)",
"rgb(100%, 0%, 0%, 100%)",
"rgb(100% 0% 0%)",
"rgb(100% 0% 0% / 1)",
"rgb(100%, 0%, 0%, 1.0)",
"rgb(100%, 0%, 0%, 100%)",
"rgb(300,0,0)",
"rgb(300 0 0)",
"rgb(255,-10,0)",
"rgb(110%, 0%, 0%)",
"rgba(255,0,0)",
"rgba(255,0,0,1)",
"rgba(255 0 0 / 1)",
"rgba(100%,0%,0%,1)",
"rgba(0,0,255,0.5)",
"rgba(100%, 50%, 0%, 0.1)",
"hsl(120, 100%, 50%)",
"hsl(120 100% 50%)",
"hsl(120, 100%, 50%, 1.0)",
"hsl(120 100% 50% / 1.0)",
"hsla(120, 100%, 50%)",
"hsla(120 100% 50%)",
"hsla(120, 100%, 50%, 1.0)",
"hsla(120 100% 50% / 1.0)",
"hsl(120deg, 100%, 50%)",
"hsl(133.33333333grad, 100%, 50%)",
"hsl(2.0943951024rad, 100%, 50%)",
"hsl(0.3333333333turn, 100%, 50%)",
];
validThemeColors.forEach(theme_color => {
data.jsonText = JSON.stringify({
theme_color,
});
var result = processor.process(data);
is(result.theme_color, theme_color, `Expect theme_color to be returned: ${theme_color}.`);
});
var invalidThemeColors = [
"marooon",
"f000000",
"#ff00000",
"rgb(100, 0%, 0%)",
"rgb(255,0)",
"rbg(255,-10,0)",
"rgb(110, 0%, 0%)",
"(255,0,0) }",
"rgba(255)",
" rgb(100%,0%,0%) }",
"hsl(120, 100%, 50)",
"hsl(120, 100%, 50.0)",
"hsl 120, 100%, 50%",
"hsla{120, 100%, 50%, 1}",
];
invalidThemeColors.forEach(theme_color => {
data.jsonText = JSON.stringify({
theme_color,
});
var result = processor.process(data);
is(result.theme_color, undefined, `Expect theme_color to be undefined: ${theme_color}.`);
});
// Trim tests
validThemeColors.forEach(theme_color => {
var expandedThemeColor = `${seperators}${lineTerminators}${theme_color}${lineTerminators}${seperators}`;
data.jsonText = JSON.stringify({
theme_color: expandedThemeColor,
});
var result = processor.process(data);
is(result.theme_color, theme_color, `Expect trimmed theme_color to be returned.`);
});
testValidColors("theme_color");
testInvalidColors("theme_color");
</script>
</head>

View File

@ -1677,12 +1677,10 @@ class PeerConnectionObserver {
}
onSetLocalDescriptionSuccess() {
this._dompc._syncTransceivers();
this._dompc._onSetLocalDescriptionSuccess();
}
onSetRemoteDescriptionSuccess() {
this._dompc._syncTransceivers();
this._dompc._processTrackAdditionsAndRemovals();
this._dompc._fireLegacyAddStreamEvents();
this._dompc._transceivers = this._dompc._transceivers.filter(t => !t.shouldRemove);

View File

@ -1101,7 +1101,6 @@ Result<Ok, nsresult> Sbgp::Parse(Box& aBox) {
uint32_t flags;
MOZ_TRY_VAR(flags, reader->ReadU32());
const uint8_t version = flags >> 24;
flags = flags & 0xffffff;
uint32_t type;
MOZ_TRY_VAR(type, reader->ReadU32());

View File

@ -6,6 +6,7 @@
#include "nsCOMPtr.h"
#include "nsIGeolocationProvider.h"
#include "mozilla/Attributes.h"
/*
* The CoreLocationObjects class contains the CoreLocation objects
@ -30,6 +31,10 @@ class CoreLocationLocationProvider : public nsIGeolocationProvider {
NS_DECL_NSIGEOLOCATIONPROVIDER
CoreLocationLocationProvider();
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we can't mark Objective-C methods as
// MOZ_CAN_RUN_SCRIPT as far as I can tell, and this method is called from
// Objective-C.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void NotifyError(uint16_t aErrorCode);
void Update(nsIDOMGeoPosition* aSomewhere);
void CreateMLSFallbackProvider();

View File

@ -224,7 +224,8 @@ void CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) {
}
}
void CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) {
mCallback->NotifyError(aErrorCode);
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
callback->NotifyError(aErrorCode);
}
void CoreLocationLocationProvider::CreateMLSFallbackProvider() {
if (mMLSFallbackProvider) {

View File

@ -9,6 +9,7 @@
#include "nsComponentManagerUtils.h"
#include "prtime.h"
#include "MLSFallback.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/PositionErrorBinding.h"
@ -40,7 +41,8 @@ WindowsLocationProvider::MLSUpdate::NotifyError(uint16_t aError) {
if (!mCallback) {
return NS_ERROR_FAILURE;
}
return mCallback->NotifyError(aError);
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
return callback->NotifyError(aError);
}
class LocationEvent final : public ILocationEvents {
@ -55,6 +57,7 @@ class LocationEvent final : public ILocationEvents {
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
// ILocationEvents interface
MOZ_CAN_RUN_SCRIPT_BOUNDARY
STDMETHODIMP OnStatusChanged(REFIID aReportType,
LOCATION_REPORT_STATUS aStatus) override;
STDMETHODIMP OnLocationChanged(REFIID aReportType,
@ -127,7 +130,8 @@ LocationEvent::OnStatusChanged(REFIID aReportType,
default:
return S_OK;
}
mCallback->NotifyError(err);
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
callback->NotifyError(err);
return S_OK;
}

Some files were not shown because too many files have changed in this diff Show More