diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
index b5de02bb3bce6..6c823eeaab81b 100644
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -2429,20 +2429,10 @@ void DocAccessible::ContentRemoved(nsIContent* aContentNode) {
}
bool DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement) {
- if (!aElement->HasID()) return false;
-
- AttrRelProviders* list = GetRelProviders(
- aElement->AsElement(), nsDependentAtomString(aElement->GetID()));
- if (list) {
- for (uint32_t idx = 0; idx < list->Length(); idx++) {
- if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
- LocalAccessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
- if (owner) {
- mNotificationController->ScheduleRelocation(owner);
- return true;
- }
- }
- }
+ RelatedAccIterator owners(mDoc, aElement, nsGkAtoms::aria_owns);
+ if (Accessible* owner = owners.Next()) {
+ mNotificationController->ScheduleRelocation(owner->AsLocal());
+ return true;
}
return false;
diff --git a/accessible/tests/browser/caching_granularity/browser_viewport_domain.js b/accessible/tests/browser/caching_granularity/browser_viewport_domain.js
index d1ab65f6f9489..92290bf66ec15 100644
--- a/accessible/tests/browser/caching_granularity/browser_viewport_domain.js
+++ b/accessible/tests/browser/caching_granularity/browser_viewport_domain.js
@@ -8,8 +8,9 @@
addAccessibleTask(
`
test
`,
async function (browser, docAcc) {
- // On Linux, the viewport cache is populated on the DocAccessible without
- // explicitly requesting it and is present once the document has loaded.
+ // On Linux and macOS, inconsistently, the viewport cache is populated on
+ // the DocAccessible without explicitly requesting it and is present once
+ // the document has loaded.
await testCachingPerPlatform(docAcc, "viewport", () => {
docAcc.getState({}, {});
});
diff --git a/accessible/tests/browser/caching_granularity/head.js b/accessible/tests/browser/caching_granularity/head.js
index 9bd55281da7e1..b4633b157d565 100644
--- a/accessible/tests/browser/caching_granularity/head.js
+++ b/accessible/tests/browser/caching_granularity/head.js
@@ -123,7 +123,8 @@ async function testCachingPerPlatform(accessible, attribute, queryCb) {
attribute == "layout-guess" ||
attribute == "language" ||
attribute == "text" ||
- attribute == "style")
+ attribute == "style" ||
+ attribute == "viewport")
) {
// These attributes work on macOS, but aren't consistent. Events may happen
// before document load complete that cause caching before the test starts.
diff --git a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
index 62ff3f5b83bf6..df1dcacfb2838 100644
--- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
@@ -544,3 +544,65 @@ customElements.define("custom-listbox",
await onReorder;
}
);
+
+/**
+ * Test insertion of relocated by ID child after initial load
+ */
+addAccessibleTask(
+ ``,
+ async function (browser, accDoc) {
+ const a = findAccessibleChildByID(accDoc, "a");
+ is(a.children.length, 0, "'a' has no children");
+ const waitFor = {
+ expected: [
+ [EVENT_SHOW, "b"],
+ [EVENT_INNER_REORDER, a],
+ [EVENT_REORDER, accDoc],
+ ],
+ };
+ await contentSpawnMutation(browser, waitFor, function () {
+ const b = content.document.createElement("div");
+ b.id = "b";
+ content.document.body.appendChild(b);
+ });
+ is(getAccessibleDOMNodeID(a.firstChild), "b", "'a' owns relocated child");
+ }
+);
+
+/**
+ * Test insertion of relocated by child element reflection after initial load
+ */
+addAccessibleTask(``, async function (browser, accDoc) {
+ const a = findAccessibleChildByID(accDoc, "a");
+ is(a.children.length, 0, "'a' has no children");
+
+ // Create div and add it to a's ariaOwnsElements.
+ // The refresh ticks called in contentSpawnMutation
+ // will cause a relocation to be scheduled and performed.
+ // Nothing will happen because 'b' is not parented yet.
+ let waitFor = {
+ unexpected: [
+ [EVENT_SHOW, "b"],
+ [EVENT_INNER_REORDER, a],
+ [EVENT_REORDER, accDoc],
+ ],
+ };
+ await contentSpawnMutation(browser, waitFor, function () {
+ content.b = content.document.createElement("div");
+ content.b.id = "b";
+ content.document.getElementById("a").ariaOwnsElements = [content.b];
+ });
+
+ // Parent 'b'. It should relocate into 'a'.
+ waitFor = {
+ expected: [
+ [EVENT_SHOW, "b"],
+ [EVENT_INNER_REORDER, a],
+ [EVENT_REORDER, accDoc],
+ ],
+ };
+ await contentSpawnMutation(browser, waitFor, function () {
+ content.document.body.appendChild(content.b);
+ });
+ is(getAccessibleDOMNodeID(a.firstChild), "b", "'a' owns relocated child");
+});
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index f54a1538503b3..2fc549e65c98c 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -39,7 +39,6 @@ ChromeUtils.defineESModuleGetters(this, {
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
ExtensionsUI: "resource:///modules/ExtensionsUI.sys.mjs",
HomePage: "resource:///modules/HomePage.sys.mjs",
- isProductURL: "chrome://global/content/shopping/ShoppingProduct.mjs",
LightweightThemeConsumer:
"resource://gre/modules/LightweightThemeConsumer.sys.mjs",
LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
@@ -3600,14 +3599,8 @@ var XULBrowserWindow = {
},
// Properties used to cache security state used to update the UI
- _state: null,
- _lastLocation: null,
_event: null,
_lastLocationForEvent: null,
- // _isSecureContext can change without the state/location changing, due to security
- // error pages that intercept certain loads. For example this happens sometimes
- // with the the HTTPS-Only Mode error page (more details in bug 1656027)
- _isSecureContext: null,
// This is called in multiple ways:
// 1. Due to the nsIWebProgressListener.onContentBlockingEvent notification.
@@ -3654,41 +3647,23 @@ var XULBrowserWindow = {
// 3. Called directly during this object's initializations.
// aRequest will be null always in case 2 and 3, and sometimes in case 1.
onSecurityChange(aWebProgress, aRequest, aState, _aIsSimulated) {
- // Don't need to do anything if the data we use to update the UI hasn't
- // changed
- let uri = gBrowser.currentURI;
- let spec = uri.spec;
- let isSecureContext = gBrowser.securityUI.isSecureContext;
- if (
- this._state == aState &&
- this._lastLocation == spec &&
- this._isSecureContext === isSecureContext
- ) {
- // Switching to a tab of the same URL doesn't change most security
- // information, but tab specific permissions may be different.
- gIdentityHandler.refreshIdentityBlock();
- return;
- }
- this._state = aState;
- this._lastLocation = spec;
- this._isSecureContext = isSecureContext;
-
// Make sure the "https" part of the URL is striked out or not,
// depending on the current mixed active content blocking state.
gURLBar.formatValue();
// Update the identity panel, making sure we use the precursorPrincipal's
// URI where appropriate, for example about:blank windows.
+ let uri = gBrowser.currentURI;
let uriOverride = this._securityURIOverride(gBrowser.selectedBrowser);
if (uriOverride) {
uri = uriOverride;
- this._state |= Ci.nsIWebProgressListener.STATE_IDENTITY_ASSOCIATED;
+ aState |= Ci.nsIWebProgressListener.STATE_IDENTITY_ASSOCIATED;
}
try {
uri = Services.io.createExposableURI(uri);
} catch (e) {}
- gIdentityHandler.updateIdentity(this._state, uri);
+ gIdentityHandler.updateIdentity(aState, uri);
},
// simulate all change notifications after switching tabs
diff --git a/browser/base/content/browser.js.globals b/browser/base/content/browser.js.globals
index 746081f1d52a7..3c08424945429 100644
--- a/browser/base/content/browser.js.globals
+++ b/browser/base/content/browser.js.globals
@@ -128,7 +128,6 @@
"E10SUtils",
"ExtensionsUI",
"HomePage",
- "isProductURL",
"LightweightThemeConsumer",
"LoginHelper",
"LoginManagerParent",
diff --git a/browser/base/content/test/performance/browser_preferences_usage.js b/browser/base/content/test/performance/browser_preferences_usage.js
index 46d17a2f7bc6d..4ad2f8c1f5418 100644
--- a/browser/base/content/test/performance/browser_preferences_usage.js
+++ b/browser/base/content/test/performance/browser_preferences_usage.js
@@ -156,8 +156,7 @@ add_task(async function navigate_around() {
// Disable bfcache so that we can measure more accurately the number of
// pref accesses in the child processes.
// If bfcache is enabled on Fission
- // dom.ipc.keepProcessesAlive.webIsolated.perOrigin and
- // security.sandbox.content.force-namespace are accessed only a couple of
+ // security.sandbox.content.force-namespace is accessed only a couple of
// times.
["browser.sessionhistory.max_total_viewers", 0],
],
@@ -183,12 +182,6 @@ add_task(async function navigate_around() {
min: 50,
max: 51,
};
- // This pref is only accessed in automation to speed up tests.
- knownProblematicPrefs["dom.ipc.keepProcessesAlive.webIsolated.perOrigin"] =
- {
- min: 50,
- max: 51,
- };
if (AppConstants.platform == "linux") {
// The following sandbox pref is covered by
// https://bugzilla.mozilla.org/show_bug.cgi?id=1600189
diff --git a/browser/base/content/test/static/browser.toml b/browser/base/content/test/static/browser.toml
index 4e8a0ebe063c7..8798e6276ec63 100644
--- a/browser/base/content/test/static/browser.toml
+++ b/browser/base/content/test/static/browser.toml
@@ -24,6 +24,8 @@ skip-if = ["os == 'win' && msix"] # Permafail on MSIX packages due to it running
["browser_parsable_script.js"]
skip-if = ["ccov && os == 'linux'"] # https://bugzilla.mozilla.org/show_bug.cgi?id=1608081
+["browser_glean_metrics_exist.js"]
+
["browser_sentence_case_strings.js"]
["browser_title_case_menus.js"]
diff --git a/browser/base/content/test/static/browser_glean_metrics_exist.js b/browser/base/content/test/static/browser_glean_metrics_exist.js
new file mode 100644
index 0000000000000..755af762d736a
--- /dev/null
+++ b/browser/base/content/test/static/browser_glean_metrics_exist.js
@@ -0,0 +1,259 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* This list allows pre-existing or 'unfixable' JS issues to remain, while we
+ * detect newly occurring issues in shipping JS. It is a list of regexes
+ * matching files which have errors:
+ */
+
+requestLongerTimeout(2);
+
+const kAllowlist = new Set([
+ /browser\/content\/browser\/places\/controller.js$/,
+]);
+
+// Normally we would use reflect.sys.mjs to get Reflect.parse. However, if
+// we do that, then all the AST data is allocated in reflect.sys.mjs's
+// zone. That exposes a bug in our GC. The GC collects reflect.sys.mjs's
+// zone but not the zone in which our test code lives (since no new
+// data is being allocated in it). The cross-compartment wrappers in
+// our zone that point to the AST data never get collected, and so the
+// AST data itself is never collected. We need to GC both zones at
+// once to fix the problem.
+const init = Cc["@mozilla.org/jsreflect;1"].createInstance();
+init();
+
+/**
+ * Check if an error should be ignored due to matching one of the allowlist
+ * objects.
+ *
+ * @param uri the uri to check against the allowlist
+ * @return true if the uri should be skipped, false otherwise.
+ */
+function uriIsAllowed(uri) {
+ for (let allowlistItem of kAllowlist) {
+ if (allowlistItem.test(uri.spec)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function recursivelyCheckForGleanCalls(obj, parent = null) {
+ if (!obj) {
+ return;
+ }
+
+ if (Array.isArray(obj)) {
+ for (let item of obj) {
+ recursivelyCheckForGleanCalls(item, { obj, parent });
+ }
+ return;
+ }
+
+ for (let key in obj) {
+ if (key == "loc") {
+ continue;
+ }
+ if (typeof obj[key] == "object") {
+ recursivelyCheckForGleanCalls(obj[key], { obj, parent });
+ }
+ }
+
+ if (obj.type != "Identifier" || obj.name != "Glean") {
+ return;
+ }
+
+ function getMemberName(object, child) {
+ if (
+ object.type == "MemberExpression" &&
+ !object.computed &&
+ object.object === child &&
+ object.property.type == "Identifier"
+ ) {
+ return object.property.name;
+ }
+ return "";
+ }
+
+ let cat = getMemberName(parent.obj, obj);
+ if (cat) {
+ if (Glean.hasOwnProperty(cat)) {
+ ok(true, `The category ${cat} should exist in the global Glean object`);
+ } else {
+ record(
+ false,
+ `The category ${cat} should exist in the global Glean object`,
+ undefined,
+ `${obj.loc.source}:${obj.loc.start.line}`
+ );
+ return;
+ }
+
+ let name = getMemberName(parent.parent.obj, parent.obj);
+ if (name) {
+ if (Glean[cat].hasOwnProperty(name)) {
+ ok(true, `The metric ${name} should exist in the Glean.${cat} object`);
+ } else {
+ record(
+ false,
+ `The metric ${name} should exist in the Glean.${cat} object`,
+ undefined,
+ `${obj.loc.source}:${obj.loc.start.line}`,
+ // Object metrics are not supported yet in artifact builds (see bug 1883857),
+ // so we expect some failures.
+ Services.prefs.getBoolPref("telemetry.fog.artifact_build", false)
+ ? "fail"
+ : undefined
+ );
+ return;
+ }
+
+ let methodOrLabel = getMemberName(
+ parent.parent.parent.obj,
+ parent.parent.obj
+ );
+ if (methodOrLabel) {
+ if (methodOrLabel in Glean[cat][name]) {
+ ok(true, `${methodOrLabel} should exist in Glean.${cat}.${name}`);
+ } else {
+ record(
+ false,
+ `${methodOrLabel} should exist in Glean.${cat}.${name}`,
+ undefined,
+ `${obj.loc.source}:${obj.loc.start.line}`
+ );
+ return;
+ }
+
+ let object = Glean[cat][name];
+ let method = methodOrLabel;
+ if (typeof Glean[cat][name][methodOrLabel] == "object") {
+ method = getMemberName(
+ parent.parent.parent.parent.obj,
+ parent.parent.parent.obj
+ );
+ if (!method) {
+ return;
+ }
+ object = Glean[cat][name][methodOrLabel];
+ }
+
+ if (method in object) {
+ ok(true, `${method} exists`);
+ is(
+ typeof object[method],
+ "function",
+ `${method} should be a function`
+ );
+ } else {
+ record(
+ false,
+ `${method} should exist`,
+ undefined,
+ `${obj.loc.source}:${obj.loc.start.line}`
+ );
+ }
+ }
+ }
+ }
+}
+
+function parsePromise(uri, parseTarget) {
+ return new Promise(resolve => {
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", uri, true);
+ xhr.onreadystatechange = function () {
+ if (this.readyState == this.DONE) {
+ let scriptText = this.responseText;
+ if (!scriptText.includes("Glean.")) {
+ resolve();
+ return;
+ }
+
+ try {
+ info(`Checking ${parseTarget} ${uri}`);
+ let parseOpts = {
+ source: uri,
+ target: parseTarget,
+ };
+ recursivelyCheckForGleanCalls(
+ Reflect.parse(scriptText, parseOpts).body
+ );
+ } catch (ex) {
+ let errorMsg = "Script error reading " + uri + ": " + ex;
+ ok(false, errorMsg);
+ }
+ resolve();
+ }
+ };
+ xhr.onerror = error => {
+ ok(false, "XHR error reading " + uri + ": " + error);
+ resolve();
+ };
+ xhr.overrideMimeType("application/javascript");
+ xhr.send(null);
+ });
+}
+
+add_task(async function checkAllTheJS() {
+ // In debug builds, even on a fast machine, collecting the file list may take
+ // more than 30 seconds, and parsing all files may take four more minutes.
+ // For this reason, this test must be explictly requested in debug builds by
+ // using the "--setpref parse=" argument to mach. You can specify:
+ // - A case-sensitive substring of the file name to test (slow).
+ // - A single absolute URI printed out by a previous run (fast).
+ // - An empty string to run the test on all files (slowest).
+ let parseRequested = Services.prefs.prefHasUserValue("parse");
+ let parseValue = parseRequested && Services.prefs.getCharPref("parse");
+ if (SpecialPowers.isDebugBuild) {
+ if (!parseRequested) {
+ ok(
+ true,
+ "Test disabled on debug build. To run, execute: ./mach" +
+ " mochitest-browser --setpref parse=" +
+ " browser/base/content/test/general/browser_parsable_script.js"
+ );
+ return;
+ }
+ // Request a 15 minutes timeout (30 seconds * 30) for debug builds.
+ requestLongerTimeout(30);
+ }
+
+ let uris;
+ // If an absolute URI is specified on the command line, use it immediately.
+ if (parseValue && parseValue.includes(":")) {
+ uris = [NetUtil.newURI(parseValue)];
+ } else {
+ let appDir = Services.dirsvc.get("GreD", Ci.nsIFile);
+ // This asynchronously produces a list of URLs (sadly, mostly sync on our
+ // test infrastructure because it runs against jarfiles there, and
+ // our zipreader APIs are all sync)
+ let startTimeMs = Date.now();
+ info("Collecting URIs");
+ uris = await generateURIsFromDirTree(appDir, [".js", ".jsm", ".mjs"]);
+ info("Collected URIs in " + (Date.now() - startTimeMs) + "ms");
+
+ // Apply the filter specified on the command line, if any.
+ if (parseValue) {
+ uris = uris.filter(uri => {
+ if (uri.spec.includes(parseValue)) {
+ return true;
+ }
+ info("Not checking filtered out " + uri.spec);
+ return false;
+ });
+ }
+ }
+
+ // We create an array of promises so we can parallelize all our parsing
+ // and file loading activity:
+ await PerfTestHelpers.throttledMapPromises(uris, uri => {
+ if (uriIsAllowed(uri)) {
+ info("Not checking allowlisted " + uri.spec);
+ return undefined;
+ }
+ return parsePromise(uri.spec, uriIsESModule(uri) ? "module" : "script");
+ });
+ ok(true, "All files parsed");
+});
diff --git a/browser/base/content/test/static/browser_parsable_script.js b/browser/base/content/test/static/browser_parsable_script.js
index 71a2930ddc117..ef97d32ccde11 100644
--- a/browser/base/content/test/static/browser_parsable_script.js
+++ b/browser/base/content/test/static/browser_parsable_script.js
@@ -12,17 +12,6 @@ const kAllowlist = new Set([
/browser\/content\/browser\/places\/controller.js$/,
]);
-const kESModuleList = new Set([
- /browser\/lockwise-card.js$/,
- /browser\/monitor-card.js$/,
- /browser\/proxy-card.js$/,
- /browser\/vpn-card.js$/,
- /toolkit\/content\/global\/certviewer\/components\/.*\.js$/,
- /toolkit\/content\/global\/certviewer\/.*\.js$/,
- /toolkit\/content\/global\/ml\/transformers.*\.js$/,
- /chrome\/pdfjs\/content\/web\/.*\.js$/,
-]);
-
// Normally we would use reflect.sys.mjs to get Reflect.parse. However, if
// we do that, then all the AST data is allocated in reflect.sys.mjs's
// zone. That exposes a bug in our GC. The GC collects reflect.sys.mjs's
@@ -50,25 +39,6 @@ function uriIsAllowed(uri) {
return false;
}
-/**
- * Check if a URI should be parsed as an ES module.
- *
- * @param uri the uri to check against the ES module list
- * @return true if the uri should be parsed as a module, otherwise parse it as a script.
- */
-function uriIsESModule(uri) {
- if (uri.filePath.endsWith(".mjs")) {
- return true;
- }
-
- for (let allowlistItem of kESModuleList) {
- if (allowlistItem.test(uri.spec)) {
- return true;
- }
- }
- return false;
-}
-
function parsePromise(uri, parseTarget) {
let promise = new Promise(resolve => {
let xhr = new XMLHttpRequest();
diff --git a/browser/base/content/test/static/head.js b/browser/base/content/test/static/head.js
index 317ad430af164..b507eeaf5b3a2 100644
--- a/browser/base/content/test/static/head.js
+++ b/browser/base/content/test/static/head.js
@@ -21,6 +21,36 @@ var { PerfTestHelpers } = ChromeUtils.importESModule(
"resource://testing-common/PerfTestHelpers.sys.mjs"
);
+const kESModuleList = new Set([
+ /browser\/lockwise-card.js$/,
+ /browser\/monitor-card.js$/,
+ /browser\/proxy-card.js$/,
+ /browser\/vpn-card.js$/,
+ /toolkit\/content\/global\/certviewer\/components\/.*\.js$/,
+ /toolkit\/content\/global\/certviewer\/.*\.js$/,
+ /toolkit\/content\/global\/ml\/transformers.*\.js$/,
+ /chrome\/pdfjs\/content\/web\/.*\.js$/,
+]);
+
+/**
+ * Check if a URI should be parsed as an ES module.
+ *
+ * @param uri the uri to check against the ES module list
+ * @return true if the uri should be parsed as a module, otherwise parse it as a script.
+ */
+function uriIsESModule(uri) {
+ if (uri.filePath.endsWith(".mjs")) {
+ return true;
+ }
+
+ for (let allowlistItem of kESModuleList) {
+ if (allowlistItem.test(uri.spec)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Returns a promise that is resolved with a list of files that have one of the
* extensions passed, represented by their nsIURI objects, which exist inside
diff --git a/browser/components/backup/resources/BackupResource.sys.mjs b/browser/components/backup/resources/BackupResource.sys.mjs
index d33af63f4e2eb..9d82d17a9828f 100644
--- a/browser/components/backup/resources/BackupResource.sys.mjs
+++ b/browser/components/backup/resources/BackupResource.sys.mjs
@@ -10,8 +10,22 @@ ChromeUtils.defineESModuleGetters(lazy, {
Sqlite: "resource://gre/modules/Sqlite.sys.mjs",
BackupError: "resource:///modules/backup/BackupError.mjs",
ERRORS: "chrome://browser/content/backup/backup-constants.mjs",
+ PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
});
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "isBrowsingHistoryEnabled",
+ "places.history.enabled",
+ true
+);
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "isSanitizeOnShutdownEnabled",
+ "privacy.sanitize.sanitizeOnShutdown",
+ false
+);
+
// Convert from bytes to kilobytes (not kibibytes).
export const BYTES_IN_KB = 1000;
@@ -225,6 +239,20 @@ export class BackupResource {
}
}
+ /**
+ * Returns true if the browser is configured in such a way that backing up
+ * things related to browsing history is allowed. Otherwise, returns false.
+ *
+ * @returns {boolean}
+ */
+ static canBackupHistory() {
+ return (
+ !lazy.PrivateBrowsingUtils.permanentPrivateBrowsing &&
+ !lazy.isSanitizeOnShutdownEnabled &&
+ lazy.isBrowsingHistoryEnabled
+ );
+ }
+
constructor() {}
/**
diff --git a/browser/components/backup/resources/CookiesBackupResource.sys.mjs b/browser/components/backup/resources/CookiesBackupResource.sys.mjs
index fb7298d4a94f3..875d513746bfb 100644
--- a/browser/components/backup/resources/CookiesBackupResource.sys.mjs
+++ b/browser/components/backup/resources/CookiesBackupResource.sys.mjs
@@ -21,6 +21,10 @@ export class CookiesBackupResource extends BackupResource {
profilePath = PathUtils.profileDir,
_isEncrypting = false
) {
+ if (!BackupResource.canBackupHistory()) {
+ return null;
+ }
+
await BackupResource.copySqliteDatabases(profilePath, stagingPath, [
"cookies.sqlite",
]);
diff --git a/browser/components/backup/resources/FormHistoryBackupResource.sys.mjs b/browser/components/backup/resources/FormHistoryBackupResource.sys.mjs
index a5d6d7c1ea243..d179d92fc7011 100644
--- a/browser/components/backup/resources/FormHistoryBackupResource.sys.mjs
+++ b/browser/components/backup/resources/FormHistoryBackupResource.sys.mjs
@@ -21,6 +21,10 @@ export class FormHistoryBackupResource extends BackupResource {
profilePath = PathUtils.profileDir,
_isEncrypting = false
) {
+ if (!BackupResource.canBackupHistory()) {
+ return null;
+ }
+
await BackupResource.copySqliteDatabases(profilePath, stagingPath, [
"formhistory.sqlite",
]);
diff --git a/browser/components/backup/resources/PlacesBackupResource.sys.mjs b/browser/components/backup/resources/PlacesBackupResource.sys.mjs
index 23538c605a25f..b01b8d44cfa11 100644
--- a/browser/components/backup/resources/PlacesBackupResource.sys.mjs
+++ b/browser/components/backup/resources/PlacesBackupResource.sys.mjs
@@ -4,28 +4,13 @@
import { BackupResource } from "resource:///modules/backup/BackupResource.sys.mjs";
import { MeasurementUtils } from "resource:///modules/backup/MeasurementUtils.sys.mjs";
-import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.sys.mjs",
- PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
});
-XPCOMUtils.defineLazyPreferenceGetter(
- lazy,
- "isBrowsingHistoryEnabled",
- "places.history.enabled",
- true
-);
-XPCOMUtils.defineLazyPreferenceGetter(
- lazy,
- "isSanitizeOnShutdownEnabled",
- "privacy.sanitize.sanitizeOnShutdown",
- false
-);
-
const BOOKMARKS_BACKUP_FILENAME = "bookmarks.jsonlz4";
/**
@@ -49,16 +34,11 @@ export class PlacesBackupResource extends BackupResource {
profilePath = PathUtils.profileDir,
_isEncrypting = false
) {
- let canBackupHistory =
- !lazy.PrivateBrowsingUtils.permanentPrivateBrowsing &&
- !lazy.isSanitizeOnShutdownEnabled &&
- lazy.isBrowsingHistoryEnabled;
-
/**
* Do not backup places.sqlite and favicons.sqlite if users have history disabled, want history cleared on shutdown or are using permanent private browsing mode.
* Instead, export all existing bookmarks to a compressed JSON file that we can read when restoring the backup.
*/
- if (!canBackupHistory) {
+ if (!BackupResource.canBackupHistory()) {
let bookmarksBackupFile = PathUtils.join(
stagingPath,
BOOKMARKS_BACKUP_FILENAME
diff --git a/browser/components/backup/resources/PreferencesBackupResource.sys.mjs b/browser/components/backup/resources/PreferencesBackupResource.sys.mjs
index 65aaa5a8c7997..728409e089140 100644
--- a/browser/components/backup/resources/PreferencesBackupResource.sys.mjs
+++ b/browser/components/backup/resources/PreferencesBackupResource.sys.mjs
@@ -39,12 +39,14 @@ export class PreferencesBackupResource extends BackupResource {
];
await BackupResource.copyFiles(profilePath, stagingPath, simpleCopyFiles);
- const sqliteDatabases = ["permissions.sqlite", "content-prefs.sqlite"];
- await BackupResource.copySqliteDatabases(
- profilePath,
- stagingPath,
- sqliteDatabases
- );
+ if (BackupResource.canBackupHistory()) {
+ const sqliteDatabases = ["permissions.sqlite", "content-prefs.sqlite"];
+ await BackupResource.copySqliteDatabases(
+ profilePath,
+ stagingPath,
+ sqliteDatabases
+ );
+ }
// prefs.js is a special case - we have a helper function to flush the
// current prefs state to disk off of the main thread.
diff --git a/browser/components/backup/tests/xpcshell/head.js b/browser/components/backup/tests/xpcshell/head.js
index 76af09cf2d4dd..0962927890a65 100644
--- a/browser/components/backup/tests/xpcshell/head.js
+++ b/browser/components/backup/tests/xpcshell/head.js
@@ -36,6 +36,13 @@ const { MockRegistrar } = ChromeUtils.importESModule(
"resource://testing-common/MockRegistrar.sys.mjs"
);
+const { PrivateBrowsingUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/PrivateBrowsingUtils.sys.mjs"
+);
+
+const HISTORY_ENABLED_PREF = "places.history.enabled";
+const SANITIZE_ON_SHUTDOWN_PREF = "privacy.sanitize.sanitizeOnShutdown";
+
let gFakeOSKeyStore;
add_setup(async () => {
diff --git a/browser/components/backup/tests/xpcshell/test_CookiesBackupResource.js b/browser/components/backup/tests/xpcshell/test_CookiesBackupResource.js
index 1690580437fdd..26d924c3f2c11 100644
--- a/browser/components/backup/tests/xpcshell/test_CookiesBackupResource.js
+++ b/browser/components/backup/tests/xpcshell/test_CookiesBackupResource.js
@@ -104,6 +104,119 @@ add_task(async function test_backup() {
sandbox.restore();
});
+/**
+ * Tests that the backup method does not copy the cookie database if the
+ * browser is configured to not save history - either while running, or to
+ * clear it at shutdown.
+ */
+add_task(async function test_backup_no_saved_history() {
+ let cookiesBackupResource = new CookiesBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "CookiesBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "CookiesBackupResource-staging-test"
+ );
+
+ let sandbox = sinon.createSandbox();
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+
+ // First, we'll try with browsing history in general being disabled.
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false);
+
+ let manifestEntry = await cookiesBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with remember history disabled"
+ );
+
+ // Now verify that the sanitize shutdown pref also prevents us from backing
+ // up cookies
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true);
+
+ fakeConnection.backup.resetHistory();
+ manifestEntry = await cookiesBackupResource.backup(stagingPath, sourcePath);
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with sanitize shutdown enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+ Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
+ Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
+});
+
+/**
+ * Tests that the backup method correctly skips backing up cookies when
+ * permanent private browsing mode is enabled.
+ */
+add_task(async function test_backup_private_browsing() {
+ let sandbox = sinon.createSandbox();
+
+ let cookiesBackupResource = new CookiesBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "CookiesBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "CookiesBackupResource-staging-test"
+ );
+
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+ sandbox.stub(PrivateBrowsingUtils, "permanentPrivateBrowsing").value(true);
+
+ let manifestEntry = await cookiesBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with permanent private browsing enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+});
+
/**
* Test that the recover method correctly copies items from the recovery
* directory into the destination profile directory.
diff --git a/browser/components/backup/tests/xpcshell/test_FormHistoryBackupResource.js b/browser/components/backup/tests/xpcshell/test_FormHistoryBackupResource.js
index 93434daa9c728..124eb63f427ef 100644
--- a/browser/components/backup/tests/xpcshell/test_FormHistoryBackupResource.js
+++ b/browser/components/backup/tests/xpcshell/test_FormHistoryBackupResource.js
@@ -108,6 +108,122 @@ add_task(async function test_backup() {
sandbox.restore();
});
+/**
+ * Tests that the backup method does not copy the form history database if the
+ * browser is configured to not save history - either while running, or to
+ * clear it at shutdown.
+ */
+add_task(async function test_backup_no_saved_history() {
+ let formHistoryBackupResource = new FormHistoryBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "FormHistoryBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "FormHistoryBackupResource-staging-test"
+ );
+
+ let sandbox = sinon.createSandbox();
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+
+ // First, we'll try with browsing history in general being disabled.
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false);
+
+ let manifestEntry = await formHistoryBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with remember history disabled"
+ );
+
+ // Now verify that the sanitize shutdown pref also prevents us from backing
+ // up form history
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true);
+
+ fakeConnection.backup.resetHistory();
+ manifestEntry = await formHistoryBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with sanitize shutdown enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+ Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
+ Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
+});
+
+/**
+ * Tests that the backup method correctly skips backing up form history when
+ * permanent private browsing mode is enabled.
+ */
+add_task(async function test_backup_private_browsing() {
+ let sandbox = sinon.createSandbox();
+
+ let formHistoryBackupResource = new FormHistoryBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "FormHistoryBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "FormHistoryBackupResource-staging-test"
+ );
+
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+ sandbox.stub(PrivateBrowsingUtils, "permanentPrivateBrowsing").value(true);
+
+ let manifestEntry = await formHistoryBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ null,
+ "Should have gotten back a null ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with permanent private browsing enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+});
+
/**
* Test that the recover method correctly copies items from the recovery
* directory into the destination profile directory.
diff --git a/browser/components/backup/tests/xpcshell/test_PlacesBackupResource.js b/browser/components/backup/tests/xpcshell/test_PlacesBackupResource.js
index 0ffa91b36e8f5..b9ba78e32cb93 100644
--- a/browser/components/backup/tests/xpcshell/test_PlacesBackupResource.js
+++ b/browser/components/backup/tests/xpcshell/test_PlacesBackupResource.js
@@ -9,12 +9,6 @@ const { BookmarkJSONUtils } = ChromeUtils.importESModule(
const { PlacesBackupResource } = ChromeUtils.importESModule(
"resource:///modules/backup/PlacesBackupResource.sys.mjs"
);
-const { PrivateBrowsingUtils } = ChromeUtils.importESModule(
- "resource://gre/modules/PrivateBrowsingUtils.sys.mjs"
-);
-
-const HISTORY_ENABLED_PREF = "places.history.enabled";
-const SANITIZE_ON_SHUTDOWN_PREF = "privacy.sanitize.sanitizeOnShutdown";
registerCleanupFunction(() => {
/**
diff --git a/browser/components/backup/tests/xpcshell/test_PreferencesBackupResource.js b/browser/components/backup/tests/xpcshell/test_PreferencesBackupResource.js
index de8ca3a16fb7d..80bc20d53e4e5 100644
--- a/browser/components/backup/tests/xpcshell/test_PreferencesBackupResource.js
+++ b/browser/components/backup/tests/xpcshell/test_PreferencesBackupResource.js
@@ -151,6 +151,125 @@ add_task(async function test_backup() {
sandbox.restore();
});
+/**
+ * Tests that the backup method does not copy the permissions or content prefs
+ * databases if the browser is configured to not save history - either while
+ * running, or to clear it at shutdown.
+ */
+add_task(async function test_backup_no_saved_history() {
+ let preferencesBackupResource = new PreferencesBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "PreferencesBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "PreferencesBackupResource-staging-test"
+ );
+
+ let sandbox = sinon.createSandbox();
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+
+ // First, we'll try with browsing history in general being disabled.
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false);
+
+ let manifestEntry = await preferencesBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ { profilePath: sourcePath },
+ "PreferencesBackupResource.backup should return the original profile path " +
+ "in its ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with remember history disabled"
+ );
+
+ // Now verify that the sanitize shutdown pref also prevents us from backing
+ // up site permissions and preferences
+ Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true);
+ Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true);
+
+ fakeConnection.backup.resetHistory();
+ manifestEntry = await preferencesBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ { profilePath: sourcePath },
+ "PreferencesBackupResource.backup should return the original profile path " +
+ "in its ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with sanitize shutdown enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+ Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
+ Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
+});
+
+/**
+ * Tests that the backup method correctly skips backing up the permissions and
+ * content prefs databases if permanent private browsing mode is enabled.
+ */
+add_task(async function test_backup_private_browsing() {
+ let sandbox = sinon.createSandbox();
+
+ let preferencesBackupResource = new PreferencesBackupResource();
+ let sourcePath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "PreferencesBackupResource-source-test"
+ );
+ let stagingPath = await IOUtils.createUniqueDirectory(
+ PathUtils.tempDir,
+ "PreferencesBackupResource-staging-test"
+ );
+
+ let fakeConnection = {
+ backup: sandbox.stub().resolves(true),
+ close: sandbox.stub().resolves(true),
+ };
+ sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
+ sandbox.stub(PrivateBrowsingUtils, "permanentPrivateBrowsing").value(true);
+
+ let manifestEntry = await preferencesBackupResource.backup(
+ stagingPath,
+ sourcePath
+ );
+ Assert.deepEqual(
+ manifestEntry,
+ { profilePath: sourcePath },
+ "PreferencesBackupResource.backup should return the original profile path " +
+ "in its ManifestEntry"
+ );
+
+ Assert.ok(
+ fakeConnection.backup.notCalled,
+ "No sqlite connections should have been made with permanent private browsing enabled"
+ );
+
+ await maybeRemovePath(stagingPath);
+ await maybeRemovePath(sourcePath);
+
+ sandbox.restore();
+});
+
/**
* Test that the recover method correctly copies items from the recovery
* directory into the destination profile directory.
diff --git a/browser/components/extensions/test/browser/browser_ext_browserAction_area.js b/browser/components/extensions/test/browser/browser_ext_browserAction_area.js
index 90ed744a78c54..bad9f9191c2ee 100644
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_area.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_area.js
@@ -9,7 +9,7 @@ var browserAreas = {
personaltoolbar: CustomizableUI.AREA_BOOKMARKS,
};
-async function testInArea(area) {
+async function testInArea(area, fallbackDefaultArea = null) {
let manifest = {
browser_action: {
browser_style: true,
@@ -24,17 +24,17 @@ async function testInArea(area) {
await extension.startup();
let widget = getBrowserActionWidget(extension);
let placement = CustomizableUI.getPlacementOfWidget(widget.id);
- let fallbackDefaultArea = CustomizableUI.AREA_ADDONS;
+ let expectedArea = fallbackDefaultArea ?? browserAreas[area];
is(
placement && placement.area,
- browserAreas[area] || fallbackDefaultArea,
+ expectedArea,
`widget located in correct area`
);
await extension.unload();
}
add_task(async function testBrowserActionDefaultArea() {
- await testInArea();
+ await testInArea(null, CustomizableUI.AREA_ADDONS);
});
add_task(async function testBrowserActionInToolbar() {
@@ -124,3 +124,41 @@ add_task(async function testPolicyOverridesBrowserActionToMenuPanel() {
);
await extension.unload();
});
+
+add_task(async function testBrowserActionWithVerticalTabs() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["sidebar.verticalTabs", true]],
+ });
+
+ await testInArea("tabstrip", CustomizableUI.AREA_ADDONS);
+ // Make sure other areas aren't affected.
+ await testInArea(null, CustomizableUI.AREA_ADDONS);
+ await testInArea("menupanel");
+ await testInArea("navbar");
+ await testInArea("personaltoolbar");
+
+ await SpecialPowers.popPrefEnv();
+
+ // Test action is still placed in tabstrip when sidebar.verticalTabs is not
+ // set to true anymore.
+ await testInArea("tabstrip");
+});
+
+add_task(async function testBrowserActionWithPersonalToolbarNeverShown() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.toolbars.bookmarks.visibility", "never"]],
+ });
+
+ await testInArea("personaltoolbar", CustomizableUI.AREA_ADDONS);
+ // Make sure other areas aren't affected.
+ await testInArea(null, CustomizableUI.AREA_ADDONS);
+ await testInArea("menupanel");
+ await testInArea("navbar");
+ await testInArea("tabstrip");
+
+ await SpecialPowers.popPrefEnv();
+
+ // Test action is still placed in personaltoolbar if the bookmark.visibility
+ // pref is flipped back to its default value ('newtab').
+ await testInArea("personaltoolbar");
+});
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss
index c9aef577fcedb..b7f3e9f77e6fe 100644
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss
@@ -31,6 +31,7 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
height: 100%;
width: 100%;
background: linear-gradient(90deg, rgba(255, 255, 255, 0%) 0%, var(--newtab-background-color-secondary) 50%, rgba(255, 255, 255, 0%) 100%);
+ z-index: 2;
@media (prefers-reduced-motion: no-preference) {
animation: loading 1.5s infinite;
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx
index 0e4edf2ad839b..008f2e2bd5a29 100644
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx
@@ -20,40 +20,51 @@ function ListFeed({ type, firstVisibleTimestamp, recs }) {
role="menu"
aria-labelledby="list-feed-title"
>
- {recs.map(rec => (
-
- ))}
+ {recs.map(rec => {
+ if (!rec || rec.placeholder) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ })}
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss
index 364081c204375..3316374c89d77 100644
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss
@@ -20,9 +20,8 @@
.icon-trending {
margin-inline-end: var(--space-small);
- -moz-context-properties: stroke;
- stroke: currentColor;
transform: none;
+ fill: var(--newtab-text-primary-color);
}
}
@@ -31,12 +30,36 @@
padding-inline-start: 0;
margin: 0;
}
+
+ .ds-card.placeholder.list-card-placeholder {
+ box-shadow: unset;
+ padding-inline-end: var(--space-large);
+ padding-block: var(--space-large) var(--space-small);
+
+ .placeholder-image {
+ height: 75px;
+ width: 75px;
+ position: absolute;
+ border-radius: var(--border-radius-medium);
+ inset-inline-end: var(--space-large);
+ }
+
+ .placeholder-label {
+ margin-bottom: unset;
+ }
+
+ .placeholder-header, .placeholder-description {
+ width: 60%;
+ height: 20px;
+ }
+ }
}
+
.ds-card-grid .list-feed-content .ds-card.list-feed-card {
// overrides when using the DSCard component
background-color: var(--newtab-background-color-secondary);
- border-block-start: 1px solid var(--color-gray-50);
+ border-block-start: 1px solid light-dark(var(--color-gray-70), var(--color-gray-50));
border-radius: 0;
box-shadow: none;
flex-direction: row-reverse;
diff --git a/browser/components/newtab/css/activity-stream.css b/browser/components/newtab/css/activity-stream.css
index 9a4f0dbdc8a43..f96a9027bbaa9 100644
--- a/browser/components/newtab/css/activity-stream.css
+++ b/browser/components/newtab/css/activity-stream.css
@@ -4814,6 +4814,7 @@ main section {
height: 100%;
width: 100%;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--newtab-background-color-secondary) 50%, rgba(255, 255, 255, 0) 100%);
+ z-index: 2;
}
@media (prefers-reduced-motion: no-preference) {
.ds-card.placeholder-seen::before {
@@ -6092,19 +6093,37 @@ main section {
}
.list-feed .list-feed-title .icon-trending {
margin-inline-end: var(--space-small);
- -moz-context-properties: stroke;
- stroke: currentColor;
transform: none;
+ fill: var(--newtab-text-primary-color);
}
.list-feed .list-feed-content {
list-style: none;
padding-inline-start: 0;
margin: 0;
}
+.list-feed .ds-card.placeholder.list-card-placeholder {
+ box-shadow: unset;
+ padding-inline-end: var(--space-large);
+ padding-block: var(--space-large) var(--space-small);
+}
+.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-image {
+ height: 75px;
+ width: 75px;
+ position: absolute;
+ border-radius: var(--border-radius-medium);
+ inset-inline-end: var(--space-large);
+}
+.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-label {
+ margin-bottom: unset;
+}
+.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-header, .list-feed .ds-card.placeholder.list-card-placeholder .placeholder-description {
+ width: 60%;
+ height: 20px;
+}
.ds-card-grid .list-feed-content .ds-card.list-feed-card {
background-color: var(--newtab-background-color-secondary);
- border-block-start: 1px solid var(--color-gray-50);
+ border-block-start: 1px solid light-dark(var(--color-gray-70), var(--color-gray-50));
border-radius: 0;
box-shadow: none;
flex-direction: row-reverse;
diff --git a/browser/components/sidebar/browser-sidebar.js b/browser/components/sidebar/browser-sidebar.js
index 372bc9eb79baf..ea2579705c7c2 100644
--- a/browser/components/sidebar/browser-sidebar.js
+++ b/browser/components/sidebar/browser-sidebar.js
@@ -1519,7 +1519,8 @@ var SidebarController = {
toggleTabstrip() {
let toVerticalTabs = CustomizableUI.verticalTabsEnabled;
- let arrowScrollbox = gBrowser.tabContainer.arrowScrollbox;
+ let tabStrip = gBrowser.tabContainer;
+ let arrowScrollbox = tabStrip.arrowScrollbox;
let currentScrollOrientation = arrowScrollbox.getAttribute("orient");
if (
@@ -1530,7 +1531,6 @@ var SidebarController = {
return;
}
- let tabStrip = gBrowser.tabContainer;
if (toVerticalTabs) {
this.toggleExpanded(this._sidebarMain.expanded);
arrowScrollbox.setAttribute("orient", "vertical");
@@ -1544,16 +1544,6 @@ var SidebarController = {
let verticalToolbar = document.getElementById(
CustomizableUI.AREA_VERTICAL_TABSTRIP
);
- let indicatorTabs = gBrowser.visibleTabs.filter(tab => {
- return (
- tab.hasAttribute("soundplaying") ||
- tab.hasAttribute("muted") ||
- tab.hasAttribute("activemedia-blocked")
- );
- });
- for (const indicatorTab of indicatorTabs) {
- tabStrip.updateTabIndicatorAttr(indicatorTab);
- }
verticalToolbar.toggleAttribute("visible", toVerticalTabs);
},
};
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index 1f91d92efbe3d..2f6b9b16d3ce7 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -2751,7 +2751,8 @@
let animate =
!skipAnimation &&
!pinned &&
- this.tabContainer.getAttribute("overflow") != "true" &&
+ !this.tabContainer.verticalMode &&
+ !this.tabContainer.overflowing &&
!gReduceMotion;
let uriInfo = this._determineURIToLoad(uriString, createLazyBrowser);
@@ -4160,6 +4161,7 @@
}
let lockTabSizing =
+ !this.tabContainer.verticalMode &&
!aTab.pinned &&
!aTab.hidden &&
aTab._fullyOpen &&
@@ -4177,6 +4179,7 @@
isLastTab ||
aTab.pinned ||
aTab.hidden ||
+ this.tabContainer.verticalMode ||
this._removingTabs.size >
3 /* don't want lots of concurrent animations */ ||
!aTab.hasAttribute(
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
index a00e4abd30784..6f8f017a07d14 100644
--- a/browser/components/tabbrowser/content/tabs.js
+++ b/browser/components/tabbrowser/content/tabs.js
@@ -115,14 +115,13 @@
"_tabMinWidthPref",
"browser.tabs.tabMinWidth",
null,
- (pref, prevValue, newValue) => (this._tabMinWidth = newValue),
+ (pref, prevValue, newValue) => this.#updateTabMinWidth(newValue),
newValue => {
const LIMIT = 50;
return Math.max(newValue, LIMIT);
}
);
-
- this._tabMinWidth = this._tabMinWidthPref;
+ this.#updateTabMinWidth(this._tabMinWidthPref);
CustomizableUI.addListener(this);
this._updateNewTabVisibility();
@@ -158,6 +157,19 @@
}
this._positionPinnedTabs();
+ this.#updateTabMinWidth();
+
+ let indicatorTabs = gBrowser.visibleTabs.filter(tab => {
+ return (
+ tab.hasAttribute("soundplaying") ||
+ tab.hasAttribute("muted") ||
+ tab.hasAttribute("activemedia-blocked")
+ );
+ });
+ for (const indicatorTab of indicatorTabs) {
+ this.updateTabIndicatorAttr(indicatorTab);
+ }
+
super.attributeChangedCallback(name, oldValue, newValue);
}
@@ -1326,8 +1338,16 @@
return node.before(tab);
}
- set _tabMinWidth(val) {
- this.style.setProperty("--tab-min-width", val + "px");
+ #updateTabMinWidth(val) {
+ const minWidthVariable = "--tab-min-width";
+ if (this.verticalMode) {
+ this.style.removeProperty(minWidthVariable);
+ } else {
+ this.style.setProperty(
+ minWidthVariable,
+ (val ?? this._tabMinWidthPref) + "px"
+ );
+ }
}
get _isCustomizing() {
@@ -1474,6 +1494,10 @@
* Try to keep the active tab's close button under the mouse cursor
*/
_lockTabSizing(aTab, aTabWidth) {
+ if (this.verticalMode) {
+ return;
+ }
+
let tabs = this._getVisibleTabs();
if (!tabs.length) {
return;
diff --git a/browser/locales/l10n-changesets.json b/browser/locales/l10n-changesets.json
index 19183daf49ef1..72a6f2b8c577f 100644
--- a/browser/locales/l10n-changesets.json
+++ b/browser/locales/l10n-changesets.json
@@ -16,7 +16,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"af": {
"pin": false,
@@ -35,7 +35,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"an": {
"pin": false,
@@ -54,7 +54,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ar": {
"pin": false,
@@ -73,7 +73,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ast": {
"pin": false,
@@ -92,7 +92,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"az": {
"pin": false,
@@ -111,7 +111,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"be": {
"pin": false,
@@ -130,7 +130,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"bg": {
"pin": false,
@@ -149,7 +149,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"bn": {
"pin": false,
@@ -168,7 +168,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"bo": {
"pin": false,
@@ -187,7 +187,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"br": {
"pin": false,
@@ -206,7 +206,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"brx": {
"pin": false,
@@ -225,7 +225,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"bs": {
"pin": false,
@@ -244,7 +244,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ca": {
"pin": false,
@@ -263,7 +263,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ca-valencia": {
"pin": false,
@@ -282,7 +282,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"cak": {
"pin": false,
@@ -301,7 +301,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ckb": {
"pin": false,
@@ -320,7 +320,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"cs": {
"pin": false,
@@ -339,7 +339,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"cy": {
"pin": false,
@@ -358,7 +358,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"da": {
"pin": false,
@@ -377,7 +377,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"de": {
"pin": false,
@@ -396,7 +396,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"dsb": {
"pin": false,
@@ -415,7 +415,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"el": {
"pin": false,
@@ -434,7 +434,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"en-CA": {
"pin": false,
@@ -453,7 +453,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"en-GB": {
"pin": false,
@@ -472,7 +472,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"eo": {
"pin": false,
@@ -491,7 +491,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"es-AR": {
"pin": false,
@@ -510,7 +510,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"es-CL": {
"pin": false,
@@ -529,7 +529,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"es-ES": {
"pin": false,
@@ -548,7 +548,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"es-MX": {
"pin": false,
@@ -567,7 +567,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"et": {
"pin": false,
@@ -586,7 +586,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"eu": {
"pin": false,
@@ -605,7 +605,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"fa": {
"pin": false,
@@ -624,7 +624,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ff": {
"pin": false,
@@ -643,7 +643,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"fi": {
"pin": false,
@@ -662,7 +662,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"fr": {
"pin": false,
@@ -681,7 +681,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"fur": {
"pin": false,
@@ -700,7 +700,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"fy-NL": {
"pin": false,
@@ -719,7 +719,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ga-IE": {
"pin": false,
@@ -738,7 +738,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"gd": {
"pin": false,
@@ -757,7 +757,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"gl": {
"pin": false,
@@ -776,7 +776,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"gn": {
"pin": false,
@@ -795,7 +795,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"gu-IN": {
"pin": false,
@@ -814,7 +814,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"he": {
"pin": false,
@@ -833,7 +833,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hi-IN": {
"pin": false,
@@ -852,7 +852,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hr": {
"pin": false,
@@ -871,7 +871,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hsb": {
"pin": false,
@@ -890,7 +890,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hu": {
"pin": false,
@@ -909,7 +909,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hy-AM": {
"pin": false,
@@ -928,7 +928,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"hye": {
"pin": false,
@@ -947,7 +947,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ia": {
"pin": false,
@@ -966,7 +966,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"id": {
"pin": false,
@@ -985,7 +985,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"is": {
"pin": false,
@@ -1004,7 +1004,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"it": {
"pin": false,
@@ -1023,7 +1023,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ja": {
"pin": false,
@@ -1040,7 +1040,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ja-JP-mac": {
"pin": false,
@@ -1048,7 +1048,7 @@
"macosx64",
"macosx64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ka": {
"pin": false,
@@ -1067,7 +1067,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"kab": {
"pin": false,
@@ -1086,7 +1086,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"kk": {
"pin": false,
@@ -1105,7 +1105,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"km": {
"pin": false,
@@ -1124,7 +1124,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"kn": {
"pin": false,
@@ -1143,7 +1143,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ko": {
"pin": false,
@@ -1162,7 +1162,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"lij": {
"pin": false,
@@ -1181,7 +1181,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"lo": {
"pin": false,
@@ -1200,7 +1200,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"lt": {
"pin": false,
@@ -1219,7 +1219,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ltg": {
"pin": false,
@@ -1238,7 +1238,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"lv": {
"pin": false,
@@ -1257,7 +1257,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"meh": {
"pin": false,
@@ -1276,7 +1276,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"mk": {
"pin": false,
@@ -1295,7 +1295,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"mr": {
"pin": false,
@@ -1314,7 +1314,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ms": {
"pin": false,
@@ -1333,7 +1333,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"my": {
"pin": false,
@@ -1352,7 +1352,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"nb-NO": {
"pin": false,
@@ -1371,7 +1371,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ne-NP": {
"pin": false,
@@ -1390,7 +1390,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"nl": {
"pin": false,
@@ -1409,7 +1409,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"nn-NO": {
"pin": false,
@@ -1428,7 +1428,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"oc": {
"pin": false,
@@ -1447,7 +1447,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"pa-IN": {
"pin": false,
@@ -1466,7 +1466,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"pl": {
"pin": false,
@@ -1485,7 +1485,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"pt-BR": {
"pin": false,
@@ -1504,7 +1504,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"pt-PT": {
"pin": false,
@@ -1523,7 +1523,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"rm": {
"pin": false,
@@ -1542,7 +1542,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ro": {
"pin": false,
@@ -1561,7 +1561,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ru": {
"pin": false,
@@ -1580,7 +1580,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sat": {
"pin": false,
@@ -1599,7 +1599,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sc": {
"pin": false,
@@ -1618,7 +1618,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"scn": {
"pin": false,
@@ -1637,7 +1637,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sco": {
"pin": false,
@@ -1656,7 +1656,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"si": {
"pin": false,
@@ -1675,7 +1675,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sk": {
"pin": false,
@@ -1694,7 +1694,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"skr": {
"pin": false,
@@ -1713,7 +1713,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sl": {
"pin": false,
@@ -1732,7 +1732,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"son": {
"pin": false,
@@ -1751,7 +1751,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sq": {
"pin": false,
@@ -1770,7 +1770,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sr": {
"pin": false,
@@ -1789,7 +1789,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"sv-SE": {
"pin": false,
@@ -1808,7 +1808,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"szl": {
"pin": false,
@@ -1827,7 +1827,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ta": {
"pin": false,
@@ -1846,7 +1846,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"te": {
"pin": false,
@@ -1865,7 +1865,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"tg": {
"pin": false,
@@ -1884,7 +1884,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"th": {
"pin": false,
@@ -1903,7 +1903,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"tl": {
"pin": false,
@@ -1922,7 +1922,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"tr": {
"pin": false,
@@ -1941,7 +1941,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"trs": {
"pin": false,
@@ -1960,7 +1960,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"uk": {
"pin": false,
@@ -1979,7 +1979,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"ur": {
"pin": false,
@@ -1998,7 +1998,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"uz": {
"pin": false,
@@ -2017,7 +2017,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"vi": {
"pin": false,
@@ -2036,7 +2036,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"wo": {
"pin": false,
@@ -2055,7 +2055,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"xh": {
"pin": false,
@@ -2074,7 +2074,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"zh-CN": {
"pin": false,
@@ -2093,7 +2093,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
},
"zh-TW": {
"pin": false,
@@ -2112,6 +2112,6 @@
"win64-aarch64-devedition",
"win64-devedition"
],
- "revision": "d1fe24b183ee549d27146a0d7481b3517ddda6f2"
+ "revision": "370cbff9cfa983022555ca3939fb09f722772498"
}
}
\ No newline at end of file
diff --git a/browser/themes/shared/browser-shared.css b/browser/themes/shared/browser-shared.css
index e4b6f2821cf3a..a437ca50aa485 100644
--- a/browser/themes/shared/browser-shared.css
+++ b/browser/themes/shared/browser-shared.css
@@ -70,6 +70,7 @@ body {
--urlbar-search-mode-picker-persisted-background-color: color-mix(in srgb, currentColor 14%, transparent);
--urlbar-search-mode-picker-persisted-background-color-hover: color-mix(in srgb, currentColor 28%, transparent);
--urlbar-search-mode-picker-persisted-background-color-active: color-mix(in srgb, currentColor 35%, transparent);
+ --urlbar-searchmodeswitcher-spacing: 6px;
--pocket-icon-fill: #ef4056;
diff --git a/browser/themes/shared/sidebar.css b/browser/themes/shared/sidebar.css
index 126bbfc73f4c9..9b9ab3420444b 100644
--- a/browser/themes/shared/sidebar.css
+++ b/browser/themes/shared/sidebar.css
@@ -73,6 +73,9 @@
.sidebar-splitter {
--splitter-width: 4px;
+ /* Ensure the splitter is painted on top of the sidebar box it overlaps.
+ Otherwise, the user may be unable to drag the splitter to resize the sidebar. */
+ z-index: 1;
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.revamp") or (not (-moz-platform: linux)) {
diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css
index 2cde31d8cf2f3..b447bcf90f964 100644
--- a/browser/themes/shared/tabbrowser/tabs.css
+++ b/browser/themes/shared/tabbrowser/tabs.css
@@ -11,9 +11,10 @@
&[uidensity=touch] {
--tab-min-height: 41px;
}
- --collapsed-tab-width: 40px;
- --inline-tab-padding: var(--space-medium);
+ --tab-collapsed-width: 40px;
+ --tab-inline-padding: var(--space-medium);
--tab-border-radius: 4px;
+ --tab-overflow-clip-margin: 2px;
--tab-shadow-max-size: 6px;
--tab-block-margin: 4px;
--tab-icon-end-margin: 5.5px;
@@ -50,24 +51,32 @@
}
#tabbrowser-tabs {
- --tab-min-width: 76px;
- --tab-overflow-pinned-tabs-width: 0px;
- padding-inline: var(--tab-overflow-pinned-tabs-width) 0;
/* Use a bigger flex value than the searchbar to prevent it from
* taking all the toolbar space. */
flex: 1000 1000;
- &[orient="horizontal"][positionpinnedtabs] > #tabbrowser-arrowscrollbox::part(scrollbox) {
- /* Add padding to match the shadow's blur radius so the
- shadow doesn't get clipped when either the first or
- last tab is selected */
- padding-inline: var(--tab-shadow-max-size);
- }
+ &[orient="horizontal"] {
+ --tab-overflow-pinned-tabs-width: 0px;
+ padding-inline: var(--tab-overflow-pinned-tabs-width) 0;
+
+ --tab-min-width: 76px;
+ :root[uidensity="touch"] & {
+ /* Touch mode needs additional space for the close button. */
+ --tab-min-width: 86px;
+ }
+
+ &[positionpinnedtabs] > #tabbrowser-arrowscrollbox::part(scrollbox) {
+ /* Add padding to match the shadow's blur radius so the
+ shadow doesn't get clipped when either the first or
+ last tab is selected */
+ padding-inline: var(--tab-shadow-max-size);
+ }
- /* Make it easier to drag tabs by expanding the drag area downwards. */
- &[movingtab] {
- padding-bottom: 15px;
- margin-bottom: -15px;
+ /* Make it easier to drag tabs by expanding the drag area downwards. */
+ &[movingtab] {
+ padding-bottom: 15px;
+ margin-bottom: -15px;
+ }
}
}
@@ -103,16 +112,15 @@
border-radius: 0;
border-width: 0;
margin: 0;
- padding: 0 2px;
+ padding: 0 var(--tab-overflow-clip-margin);
align-items: stretch;
/* Needed so that overflowing content overflows towards the end rather than
getting centered. That prevents tab opening animation from looking off at
the start, see bug 1759221. */
justify-content: flex-start;
overflow: clip;
- /* Needed to avoid clipping the tab-background shadow, which has a 4px blur
- * (we only have 2px padding in the inline direction) */
- overflow-clip-margin: 2px;
+ /* Needed to avoid clipping the tab-background shadow, which has a 4px blur. */
+ overflow-clip-margin: var(--tab-overflow-clip-margin);
&:not([pinned]) {
flex: 100 100;
@@ -120,11 +128,6 @@
min-width: var(--tab-min-width);
transition: min-width 100ms ease-out,
max-width 100ms ease-out;
-
- :root[uidensity=touch] & {
- /* Touch mode needs additional space for the close button. */
- min-width: calc(var(--tab-min-width) + 10px);
- }
}
&:not([pinned], [fadein]) {
@@ -158,7 +161,7 @@
}
.tab-content {
- padding: 0 var(--inline-tab-padding);
+ padding: 0 var(--tab-inline-padding);
&:not([pinned]) {
min-width: 0;
@@ -515,7 +518,7 @@
.tab-close-button {
-moz-context-properties: fill, fill-opacity;
- margin-inline-end: calc(var(--inline-tab-padding) / -2);
+ margin-inline-end: calc(var(--tab-inline-padding) / -2);
width: 24px;
height: 24px;
padding: 6px;
@@ -805,7 +808,8 @@ tab-group {
font: message-box; /* match .tabbrowser-tab on macOS */
min-height: var(--tab-min-height);
border-radius: var(--border-radius-medium);
- padding: 0 var(--inline-tab-padding);
+ padding: 0 var(--tab-inline-padding);
+ margin-inline: var(--tab-overflow-clip-margin);
#tabbrowser-tabs[orient="horizontal"] > &,
#tabbrowser-tabs[orient="vertical"]:not([expanded]) > & > .toolbarbutton-text {
@@ -826,7 +830,7 @@ tab-group {
#vertical-tabs {
overflow: hidden;
display: none;
- padding-inline: var(--space-medium);
+ padding-inline: calc(var(--space-medium) - var(--tab-overflow-clip-margin));
padding-block-start: var(--space-medium);
&[visible] {
@@ -836,7 +840,7 @@ tab-group {
#vertical-pinned-tabs-container {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(var(--collapsed-tab-width), auto));
+ grid-template-columns: repeat(auto-fit, minmax(var(--tab-collapsed-width), auto));
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
@@ -867,16 +871,23 @@ tab-group {
}
#tabbrowser-tabs[orient="vertical"] {
- overflow: hidden;
+ --tab-min-width: unset;
+
+ min-height: 0;
display: flex;
flex-direction: column;
align-content: flex-start;
grid-gap: var(--space-small);
+ padding: 0; /* override tabbox.css on macOS */
&[overflow] {
border-bottom: var(--tabstrip-inner-border);
}
+ .tabbrowser-tab {
+ flex: none;
+ }
+
.tab-close-button {
display: none;
}
@@ -893,9 +904,7 @@ tab-group {
&:not([expanded]) {
.tabbrowser-tab {
- min-width: inherit;
- width: var(--collapsed-tab-width);
- flex: none;
+ width: var(--tab-collapsed-width);
}
.tab-label-container {
@@ -907,10 +916,7 @@ tab-group {
--tab-icon-end-margin: 7.5px;
.tabbrowser-tab {
- min-width: calc(100% - var(--space-medium));
- flex: none;
max-width: none;
- padding: 0;
&:is(:hover, [selected]):not([pinned]) .tab-close-button {
display: flex;
diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css
index 4b563e0f58f32..0e7f2b526879f 100644
--- a/browser/themes/shared/urlbar-searchbar.css
+++ b/browser/themes/shared/urlbar-searchbar.css
@@ -472,7 +472,8 @@
display: none;
}
-#urlbar-search-mode-indicator-close {
+#urlbar-search-mode-indicator-close,
+#searchmode-switcher-close {
background: url(chrome://global/skin/icons/close.svg) no-repeat center;
background-size: round(62.5%, 2px);
width: round(max(16px, 1em), 2px);
@@ -1116,11 +1117,17 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
}
#urlbar-searchmode-switcher {
+ appearance: none;
display: none;
- background-color: var(--toolbar-field-background-color);
- border-radius: var(--toolbarbutton-border-radius);
- margin-inline: 0 var(--urlbar-icon-padding);
- padding-block: 0;
+ background-color: var(--urlbar-box-bgcolor);
+ border-radius: var(--urlbar-icon-border-radius);
+ margin: 0;
+ margin-inline-end: var(--urlbar-icon-padding);
+ padding-inline: var(--urlbar-searchmodeswitcher-spacing);
+
+ #urlbar[focused] & {
+ background-color: var(--urlbar-box-focus-bgcolor);
+ }
&:focus-visible {
outline: var(--focus-outline);
@@ -1151,19 +1158,19 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
}
#searchmode-switcher-icon {
- width: calc(var(--urlbar-min-height) - 2px - 2 * var(--urlbar-container-padding));
- height: calc(var(--urlbar-min-height) - 2px - 2 * var(--urlbar-container-padding));
+ width: 16px;
+ height: 16px;
border-radius: var(--urlbar-icon-border-radius);
- padding: var(--urlbar-icon-padding);
-moz-context-properties: fill;
fill: var(--text-color-deemphasized);
}
#searchmode-switcher-chicklet {
- background-color: var(--toolbar-field-background-color);
+ background-color: var(--urlbar-box-bgcolor);
border-start-end-radius: var(--toolbarbutton-border-radius);
- border-end-end-radius: var(--toolbarbutton-border-radius);
+ border-end-end-radius: var(--urlbar-icon-border-radius);
align-items: center;
+ height: 100%;
margin-inline-end: var(--urlbar-icon-padding);
display: none;
@@ -1173,10 +1180,18 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
display: inline-flex;
}
}
+
+ #urlbar[focused] & {
+ background-color: var(--urlbar-box-focus-bgcolor);
+ }
+
+ #urlbar[persistsearchterms] & {
+ background-color: var(--urlbar-search-mode-picker-persisted-background-color);
+ }
}
#searchmode-switcher-title {
- margin-inline-start: 0;
+ margin: 0;
align-items: center;
&:empty {
@@ -1185,10 +1200,9 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
}
#searchmode-switcher-close {
- list-style-image: url("chrome://global/skin/icons/close-12.svg");
+ appearance: none;
pointer-events: all;
- -moz-context-properties: fill;
- fill: var(--text-color-deemphasized);
+ margin-inline: var(--urlbar-searchmodeswitcher-spacing);
#urlbar[searchmode] & {
display: inline-flex;
@@ -1196,6 +1210,8 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
}
#searchmode-switcher-dropmarker {
+ margin-inline-start: var(--urlbar-searchmodeswitcher-spacing);
+
#urlbar[searchmode] & {
display: none;
}
diff --git a/build.gradle b/build.gradle
index 01592592613f9..a350a8ad187cd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ buildscript {
ksp_plugin = Versions.ksp_plugin
// Used in mobile/android/fenix/app/build.gradle
- protobuf_plugin = FenixVersions.protobuf_plugin
+ protobuf_plugin = Versions.protobuf_plugin
}
dependencies {
diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure
index 1c6a6a6b6f728..19ef32d97a41d 100644
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -2865,6 +2865,13 @@ def security_hardening_cflags(
if debug:
flags.extend(trivial_auto_var_init)
+ if (c_compiler.type == "clang" and c_compiler.version >= "16") or (
+ c_compiler.type == "gcc" and c_compiler.version >= "13"
+ ):
+ # Cannot use level 3 because we have many uses of the [0] GNU syntax.
+ # Cannot use level 2 because sqlite3 and icu use the [1] GNU syntax.
+ flags.append("-fstrict-flex-arrays=1")
+
# ASLR ------------------------------------------------
# ASLR (dynamicbase) is enabled by default in clang-cl; but the
# mingw-clang build requires it to be explicitly enabled
diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h
index f97170b145e97..5400c9f2254c1 100644
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -81,8 +81,6 @@ class nsScriptSecurityManager final : public nsIScriptSecurityManager {
bool aFromPrivateWindow,
uint64_t aInnerWindowID = 0);
- static uint32_t HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
-
static bool GetStrictFileOriginPolicy() { return sStrictFileOriginPolicy; }
void DeactivateDomainPolicy();
diff --git a/devtools/client/inspector/fonts/fonts.js b/devtools/client/inspector/fonts/fonts.js
index cde47bc93823e..f134a8e632fb6 100644
--- a/devtools/client/inspector/fonts/fonts.js
+++ b/devtools/client/inspector/fonts/fonts.js
@@ -118,7 +118,6 @@ class FontInspector {
this.update = this.update.bind(this);
this.updateFontVariationSettings =
this.updateFontVariationSettings.bind(this);
- this.onResourceAvailable = this.onResourceAvailable.bind(this);
this.init();
}
@@ -185,11 +184,6 @@ class FontInspector {
// @see ToolSidebar.onSidebarTabSelected()
this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
- this.inspector.toolbox.resourceCommand.watchResources(
- [this.inspector.toolbox.resourceCommand.TYPES.DOCUMENT_EVENT],
- { onAvailable: this.onResourceAvailable }
- );
-
// Listen for theme changes as the color of the previews depend on the theme
gDevTools.on("theme-switched", this.onThemeChanged);
}
@@ -330,12 +324,6 @@ class FontInspector {
this.ruleView.off("property-value-updated", this.onRulePropertyUpdated);
gDevTools.off("theme-switched", this.onThemeChanged);
- this.inspector.toolbox.resourceCommand.unwatchResources(
- [this.inspector.toolbox.resourceCommand.TYPES.DOCUMENT_EVENT],
- { onAvailable: this.onResourceAvailable }
- );
-
- this.fontsHighlighter = null;
this.document = null;
this.inspector = null;
this.node = null;
@@ -348,21 +336,6 @@ class FontInspector {
this.writers = null;
}
- onResourceAvailable(resources) {
- for (const resource of resources) {
- if (
- resource.resourceType ===
- this.inspector.commands.resourceCommand.TYPES.DOCUMENT_EVENT &&
- resource.name === "will-navigate" &&
- resource.targetFront.isTopLevel
- ) {
- // Reset the fontsHighlighter so the next call to `onToggleFontHighlight` will
- // re-create it from the inspector front tied to the new document.
- this.fontsHighlighter = null;
- }
- }
- }
-
/**
* Get all expected CSS font properties and values from the node's matching rules and
* fallback to computed style. Skip CSS Custom Properties, `calc()` and keyword values.
@@ -896,32 +869,24 @@ class FontInspector {
* just to the current element selection.
*/
async onToggleFontHighlight(font, show, isForCurrentElement = true) {
- if (!this.fontsHighlighter) {
- try {
- this.fontsHighlighter =
- await this.inspector.inspectorFront.getHighlighterByType(
- HIGHLIGHTER_TYPES.FONTS
- );
- } catch (e) {
- // the FontsHighlighter won't be available when debugging a XUL document.
- // Silently fail here and prevent any future calls to the function.
- this.onToggleFontHighlight = () => {};
- return;
- }
- }
-
try {
if (show) {
const node = isForCurrentElement
- ? this.node
+ ? this.inspector.selection.nodeFront
: this.node.walkerFront.rootNode;
- await this.fontsHighlighter.show(node, {
- CSSFamilyName: font.CSSFamilyName,
- name: font.name,
- });
+ await this.inspector.highlighters.showHighlighterTypeForNode(
+ HIGHLIGHTER_TYPES.FONTS,
+ node,
+ {
+ CSSFamilyName: font.CSSFamilyName,
+ name: font.name,
+ }
+ );
} else {
- await this.fontsHighlighter.hide();
+ await this.inspector.highlighters.hideHighlighterType(
+ HIGHLIGHTER_TYPES.FONTS
+ );
}
} catch (e) {
// Silently handle protocol errors here, because these might be called during
diff --git a/devtools/client/inspector/fonts/test/browser_fontinspector_reveal-in-page.js b/devtools/client/inspector/fonts/test/browser_fontinspector_reveal-in-page.js
index a4cfb4533afaf..e6a39795bf090 100644
--- a/devtools/client/inspector/fonts/test/browser_fontinspector_reveal-in-page.js
+++ b/devtools/client/inspector/fonts/test/browser_fontinspector_reveal-in-page.js
@@ -11,16 +11,20 @@ add_task(async function () {
// events simulation will fail.
await pushPref("devtools.toolbox.footer.height", 500);
- const { view } = await openFontInspectorForURL(TEST_URI);
- await testFontHighlighting(view);
+ const { inspector, view } = await openFontInspectorForURL(TEST_URI);
+ await testFontHighlighting(view, inspector);
info("Check that highlighting still works after reloading the page");
await reloadBrowser();
- await testFontHighlighting(view);
+ await testFontHighlighting(view, inspector);
+
+ info("Check that highlighting works for iframe nodes");
+ await testFontHighlightingInIframe(view, inspector);
});
-async function testFontHighlighting(view) {
+async function testFontHighlighting(view, inspector) {
+ await selectNode("body", inspector);
// The number of window selection change events we expect to get as we hover over each
// font in the list. Waiting for those events is how we know that text-runs were
// highlighted in the page.
@@ -68,7 +72,10 @@ async function testFontHighlighting(view) {
// Simulating a mouse over event on the font name and expecting a selectionchange.
const nameEl = fontEls[i];
- let onEvents = waitForNSelectionEvents(expectedEvents);
+ let onEvents = waitForNSelectionEvents(
+ gBrowser.selectedBrowser,
+ expectedEvents
+ );
EventUtils.synthesizeMouse(
nameEl,
2,
@@ -82,7 +89,7 @@ async function testFontHighlighting(view) {
// Simulating a mouse out event on the font name and expecting a selectionchange.
const otherEl = viewDoc.querySelector("body");
- onEvents = waitForNSelectionEvents(1);
+ onEvents = waitForNSelectionEvents(gBrowser.selectedBrowser, 1);
EventUtils.synthesizeMouse(
otherEl,
2,
@@ -96,24 +103,80 @@ async function testFontHighlighting(view) {
}
}
-async function waitForNSelectionEvents(numberOfTimes) {
- await SpecialPowers.spawn(
- gBrowser.selectedBrowser,
- [numberOfTimes],
- async function (n) {
- const win = content.wrappedJSObject;
-
- await new Promise(resolve => {
- let received = 0;
- win.document.addEventListener("selectionchange", function listen() {
- received++;
-
- if (received === n) {
- win.document.removeEventListener("selectionchange", listen);
- resolve();
- }
- });
- });
+async function testFontHighlightingInIframe(view, inspector) {
+ await selectNodeInFrames(["iframe", "div"], inspector);
+
+ const viewDoc = view.document;
+
+ // Wait for the view to have all the expected used fonts.
+ const fontEls = await waitFor(() => {
+ const els = getUsedFontsEls(viewDoc);
+
+ if (!els.length) {
+ return false;
}
+
+ return [...els];
+ });
+
+ is(fontEls.length, 1, "There's only one font used in the iframe document");
+ ok(
+ // On Linux, Times New Roman does not exist. Liberation Serif is used instead.
+ ["Times New Roman", "Liberation Serif"].includes(fontEls[0].innerText),
+ "The expected font is displayed"
);
+
+ const iframeBrowsingContext = await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [],
+ () => content.document.querySelector("iframe").browsingContext
+ );
+
+ info(`Mousing over and out of the font in the list`);
+
+ // Simulating a mouse over event on the font name and expecting a selectionchange.
+ const nameEl = fontEls[0];
+ let onEvents = waitForNSelectionEvents(iframeBrowsingContext, 1);
+ EventUtils.synthesizeMouse(
+ nameEl,
+ 2,
+ 2,
+ { type: "mouseover" },
+ viewDoc.defaultView
+ );
+ await onEvents;
+
+ ok(true, `A selectionchange events detected on mouseover`);
+
+ // Simulating a mouse out event on the font name and expecting a selectionchange.
+ const otherEl = viewDoc.querySelector("body");
+ onEvents = waitForNSelectionEvents(iframeBrowsingContext, 1);
+ EventUtils.synthesizeMouse(
+ otherEl,
+ 2,
+ 2,
+ { type: "mouseover" },
+ viewDoc.defaultView
+ );
+ await onEvents;
+
+ ok(true, "1 selectionchange events detected on mouseout");
+}
+
+async function waitForNSelectionEvents(browser, numberOfTimes) {
+ await SpecialPowers.spawn(browser, [numberOfTimes], async function (n) {
+ const win = content.wrappedJSObject;
+
+ await new Promise(resolve => {
+ let received = 0;
+ win.document.addEventListener("selectionchange", function listen() {
+ received++;
+
+ if (received === n) {
+ win.document.removeEventListener("selectionchange", listen);
+ resolve();
+ }
+ });
+ });
+ });
}
diff --git a/devtools/client/inspector/fonts/test/doc_browser_fontinspector.html b/devtools/client/inspector/fonts/test/doc_browser_fontinspector.html
index 27e24e2fd0513..b761bc43f73d9 100644
--- a/devtools/client/inspector/fonts/test/doc_browser_fontinspector.html
+++ b/devtools/client/inspector/fonts/test/doc_browser_fontinspector.html
@@ -57,7 +57,7 @@
DIV
NESTED SPAN
-
+
NORMAL DIV
BOLD DIV
800 DIV
diff --git a/devtools/client/netmonitor/test/browser.toml b/devtools/client/netmonitor/test/browser.toml
index 957cbfec1c967..39537e79fb05c 100644
--- a/devtools/client/netmonitor/test/browser.toml
+++ b/devtools/client/netmonitor/test/browser.toml
@@ -512,6 +512,8 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_net_throttle.js"]
+["browser_net_throttling_cached.js"]
+
["browser_net_throttling_profiles.js"]
["browser_net_timeline_ticks.js"]
diff --git a/devtools/client/netmonitor/test/browser_net_throttling_cached.js b/devtools/client/netmonitor/test/browser_net_throttling_cached.js
new file mode 100644
index 0000000000000..fb40a92c2e566
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_throttling_cached.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ profiles,
+ PROFILE_CONSTANTS,
+} = require("resource://devtools/client/shared/components/throttling/profiles.js");
+
+const offlineProfile = profiles.find(
+ profile => profile.id === PROFILE_CONSTANTS.OFFLINE
+);
+
+const CACHED_URL = STATUS_CODES_SJS + "?sts=ok&cached&test_cached";
+
+add_task(async function () {
+ const { monitor } = await initNetMonitor(SIMPLE_URL, { requestCount: 1 });
+ const { connector } = monitor.panelWin;
+ const { updateNetworkThrottling } = connector;
+
+ // Throttle the network before entering the content process
+ await pushPref("devtools.cache.disabled", false);
+ await updateNetworkThrottling(true, offlineProfile);
+
+ // Clear the cache beforehand
+ Services.cache2.clear();
+
+ // The request is blocked since the profile is offline
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [CACHED_URL],
+ async url => {
+ try {
+ await content.fetch(url);
+ ok(false, "Should not load since profile is offline");
+ } catch (err) {
+ is(err.name, "TypeError", "Should fail since profile is offline");
+ }
+ }
+ );
+
+ // Disable throttling
+ await pushPref("devtools.cache.disabled", false);
+ await updateNetworkThrottling(false);
+
+ // Fetch to prime the cache
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [CACHED_URL],
+ async url => {
+ await content.fetch(url);
+ }
+ );
+
+ // Set profile to offline again
+ await pushPref("devtools.cache.disabled", false);
+ await updateNetworkThrottling(true, offlineProfile);
+
+ // Check that cached resource loaded
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [CACHED_URL],
+ async url => {
+ await content.fetch(url);
+ }
+ );
+
+ await teardown(monitor);
+});
diff --git a/devtools/docs/user/index.rst b/devtools/docs/user/index.rst
index 681c1c140a665..5893371b95f02 100644
--- a/devtools/docs/user/index.rst
+++ b/devtools/docs/user/index.rst
@@ -265,7 +265,7 @@ If you want to help improve the developer tools, these resources will get you st
* - `Get Involved `_
- Our community website explains how to get involved.
- * - `bugs.firefox-dev.tools `_
+ * - `codetribute.mozilla.org `_
- A tool helping to find bugs to work on.
* - :ref:`Read source docs `
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
index dc65224fd9db8..cd4d788c654ae 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -109,6 +109,11 @@ struct ParamTraits
: public mozilla::dom::WebIDLEnumSerializer<
mozilla::dom::PrefersColorSchemeOverride> {};
+template <>
+struct ParamTraits
+ : public mozilla::dom::WebIDLEnumSerializer<
+ mozilla::dom::ForcedColorsOverride> {};
+
template <>
struct ParamTraits
: public ContiguousEnumSerializer<
@@ -2851,6 +2856,15 @@ void BrowsingContext::DidSet(FieldIndex,
PresContextAffectingFieldChanged();
}
+void BrowsingContext::DidSet(FieldIndex,
+ dom::ForcedColorsOverride aOldValue) {
+ MOZ_ASSERT(IsTop());
+ if (ForcedColorsOverride() == aOldValue) {
+ return;
+ }
+ PresContextAffectingFieldChanged();
+}
+
void BrowsingContext::DidSet(FieldIndex,
nsString&& aOldValue) {
MOZ_ASSERT(IsTop());
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index 3e869d779e6cd..e566841106c94 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -240,6 +240,8 @@ struct EmbedderColorSchemes {
FIELD(MediumOverride, nsString) \
/* DevTools override for prefers-color-scheme */ \
FIELD(PrefersColorSchemeOverride, dom::PrefersColorSchemeOverride) \
+ /* DevTools override for forced-colors */ \
+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \
/* prefers-color-scheme override based on the color-scheme style of our \
* embedder element. */ \
FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \
@@ -940,6 +942,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return GetPrefersColorSchemeOverride();
}
+ dom::ForcedColorsOverride ForcedColorsOverride() const {
+ return GetForcedColorsOverride();
+ }
+
bool IsInBFCache() const;
bool AllowJavascript() const { return GetAllowJavascript(); }
@@ -1099,6 +1105,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return IsTop();
}
+ bool CanSet(FieldIndex, dom::ForcedColorsOverride,
+ ContentParent*) {
+ return IsTop();
+ }
+
void DidSet(FieldIndex, bool aOldValue);
void DidSet(FieldIndex,
@@ -1107,6 +1118,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void DidSet(FieldIndex,
dom::PrefersColorSchemeOverride aOldValue);
+ void DidSet(FieldIndex,
+ dom::ForcedColorsOverride aOldValue);
+
template
void WalkPresContexts(Callback&&);
void PresContextAffectingFieldChanged();
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 3a5787b6b8174..9eface9e97e6a 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1329,7 +1329,20 @@ void nsDocShell::FirePageHideShowNonRecursive(bool aShow) {
mEODForCurrentDocument = false;
mIsRestoringDocument = true;
mLoadGroup->AddRequest(channel, nullptr);
- SetCurrentURI(doc->GetDocumentURI(), channel,
+ nsCOMPtr uri;
+ if (doc->FragmentDirective()) {
+ // If we have fragment directives, then we've mutated the document
+ // uri. Set the current URI from session history instead.
+ if (mozilla::SessionHistoryInParent()) {
+ uri = mActiveEntry ? mActiveEntry->GetURI() : nullptr;
+ } else if (mOSHE) {
+ uri = mOSHE->GetURI();
+ }
+ }
+ if (!uri) {
+ uri = doc->GetDocumentURI();
+ }
+ SetCurrentURI(uri, channel,
/* aFireOnLocationChange */ true,
/* aIsInitialAboutBlank */ false,
/* aLocationFlags */ 0);
diff --git a/docshell/test/browser/browser.toml b/docshell/test/browser/browser.toml
index b604c16e5e54c..758397bf80d73 100644
--- a/docshell/test/browser/browser.toml
+++ b/docshell/test/browser/browser.toml
@@ -78,6 +78,8 @@ support-files = [
"file_backforward_restore_scroll.html^headers^",
]
+["browser_backforward_text_fragment_restore_urlbar.js"]
+
["browser_backforward_userinteraction.js"]
support-files = ["dummy_iframe_page.html"]
skip-if = ["os == 'linux' && bits == 64 && !debug"] # Bug 1607713
diff --git a/docshell/test/browser/browser_backforward_text_fragment_restore_urlbar.js b/docshell/test/browser/browser_backforward_text_fragment_restore_urlbar.js
new file mode 100644
index 0000000000000..472a4c0b3bca5
--- /dev/null
+++ b/docshell/test/browser/browser_backforward_text_fragment_restore_urlbar.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const ROOT = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://mochi.test:8888"
+);
+
+const URL = `${ROOT}/dummy_page.html#:~:text=dummy`;
+
+function waitForPageShow(browser) {
+ return BrowserTestUtils.waitForContentEvent(browser, "pageshow", true);
+}
+
+add_task(async function test_fragment_restore_urlbar() {
+ await BrowserTestUtils.withNewTab("https://example.com", async browser => {
+ let loaded = BrowserTestUtils.browserLoaded(browser, false);
+ BrowserTestUtils.startLoadingURIString(browser, URL);
+ await loaded;
+
+ // Go back in history.
+ let change = waitForPageShow(browser);
+ browser.goBack();
+ await change;
+ change = waitForPageShow(browser);
+ // Go forward in history.
+ browser.goForward();
+ await change;
+ is(gURLBar.inputField.value, URL, "URL should have text directive");
+ });
+});
diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp
index 65bc5987dd80c..3318268bff10b 100644
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -214,10 +214,17 @@ static Directionality GetDirectionFromText(const Text* aTextNode,
}
/**
- * Compute auto direction aRoot should have based on descendants
- * https://html.spec.whatwg.org/#auto-directionality step 3
+ * Compute auto direction for aRoot. If aCanExcludeRoot is true and aRoot
+ * establishes its own directionality, return early.
+ * https://html.spec.whatwg.org/#contained-text-auto-directionality
*/
-Directionality WalkDescendantsAndGetDirectionFromText(nsINode* aRoot) {
+Directionality ContainedTextAutoDirectionality(nsINode* aRoot,
+ bool aCanExcludeRoot) {
+ MOZ_ASSERT_IF(aCanExcludeRoot, aRoot->IsElement());
+ if (aCanExcludeRoot && EstablishesOwnDirection(aRoot->AsElement())) {
+ return Directionality::Unset;
+ }
+
nsIContent* child = aRoot->GetFirstChild();
while (child) {
if (child->IsElement() && EstablishesOwnDirection(child->AsElement())) {
@@ -225,7 +232,7 @@ Directionality WalkDescendantsAndGetDirectionFromText(nsINode* aRoot) {
continue;
}
- // Step 3.2. If descendant is a slot element whose root is a shadow root,
+ // Step 1.2. If descendant is a slot element whose root is a shadow root,
// then return the directionality of that shadow root's host.
if (auto* slot = HTMLSlotElement::FromNode(child)) {
if (const ShadowRoot* sr = slot->GetContainingShadow()) {
@@ -235,8 +242,8 @@ Directionality WalkDescendantsAndGetDirectionFromText(nsINode* aRoot) {
}
}
- // Step 3.3-5. If descendant is a Text node, return its
- // text node directionality if it is not null
+ // Step 1.3-5. If descendant is a Text node, return its
+ // text node directionality.
if (auto* text = Text::FromNode(child)) {
Directionality textNodeDir = GetDirectionFromText(text);
if (textNodeDir != Directionality::Unset) {
@@ -276,22 +283,8 @@ Directionality ComputeAutoDirectionFromAssignedNodes(
Element* assignedElement = Element::FromNode(assignedNode);
MOZ_ASSERT(assignedElement);
- // Step 2.1.3.2. Set childDirection to the auto directionality of child.
- // Need to perform parts of the auto directionality algorithm here, as
- // ComputeAutoDirectionality does not implement the whole algorithm.
- if (Maybe maybe =
- GetValueIfFormAssociatedElement(assignedElement)) {
- const nsAutoString& value = maybe.value();
- childDirection =
- GetDirectionFromText(value.BeginReading(), value.Length());
- if (childDirection == Directionality::Unset && !value.IsEmpty()) {
- childDirection = Directionality::Ltr;
- }
- }
- // Now recursively call into the remainder of auto directionality.
- if (ParticipatesInAutoDirection(assignedElement)) {
- childDirection = ComputeAutoDirectionality(assignedElement, aNotify);
- }
+ // Step 2.1.3.2.
+ childDirection = ContainedTextAutoDirectionality(assignedElement, true);
}
// Step 2.1.4. If childDirection is not null, then return childDirection.
@@ -329,7 +322,7 @@ static Directionality ComputeAutoDirectionality(Element* aElement,
}
// Step 3. find first text or slot that determines the direction
- Directionality nodeDir = WalkDescendantsAndGetDirectionFromText(aElement);
+ Directionality nodeDir = ContainedTextAutoDirectionality(aElement, false);
if (nodeDir != Directionality::Unset) {
return nodeDir;
}
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index d1b89b13258c9..ad128a0ac398b 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8914,9 +8914,9 @@ void nsContentUtils::FirePageHideEventForFrameLoaderSwap(
MOZ_DIAGNOSTIC_ASSERT(aItem);
MOZ_DIAGNOSTIC_ASSERT(aChromeEventHandler);
- RefPtr doc = aItem->GetDocument();
- NS_ASSERTION(doc, "What happened here?");
- doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup);
+ if (RefPtr doc = aItem->GetDocument()) {
+ doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup);
+ }
int32_t childCount = 0;
aItem->GetInProcessChildCount(&childCount);
diff --git a/dom/base/test/useractivation/test_popup_blocker_mouse_event.html b/dom/base/test/useractivation/test_popup_blocker_mouse_event.html
index fd94150f1ef7a..7a35d862a87a6 100644
--- a/dom/base/test/useractivation/test_popup_blocker_mouse_event.html
+++ b/dom/base/test/useractivation/test_popup_blocker_mouse_event.html
@@ -11,6 +11,8 @@
+
+