commit 5a27116efe6fcd2ddc657c3fb64bd183192b83fa
parent 9982432f5c46351e0e5c6f4b4e28f8948b6245bd
Author: hackademix <giorgio@maone.net>
Date: Sun, 11 Dec 2022 13:28:57 +0100
BB 32308: Use direct browser sizing for letterboxing.
Bug 30556: align letterboxing with 200x100 new win width stepping
Diffstat:
5 files changed, 500 insertions(+), 30 deletions(-)
diff --git a/browser/app/profile/001-base-profile.js b/browser/app/profile/001-base-profile.js
@@ -521,6 +521,10 @@ pref("security.remote_settings.intermediates.enabled", false);
pref("dom.use_components_shim", false);
// Enable letterboxing
pref("privacy.resistFingerprinting.letterboxing", true);
+// tor-browser#41917: Center letterboxed area vertically
+pref("privacy.resistFingerprinting.letterboxing.vcenter", true);
+// tor-browser#41917: Letterboxing gradient background
+pref("privacy.resistFingerprinting.letterboxing.gradient", true);
// tor-browser#43402: Avoid a resize from the skeleton to the newwin size.
// Should be fixed in ESR-140 with Bug 1448423.
pref("browser.startup.blankWindow", false);
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -2453,6 +2453,10 @@
stack.className = "browserStack";
stack.appendChild(b);
+ let decorator = document.createXULElement("hbox");
+ decorator.className = "browserDecorator";
+ stack.appendChild(decorator);
+
let browserContainer = document.createXULElement("vbox");
browserContainer.className = "browserContainer";
browserContainer.appendChild(stack);
diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css
@@ -422,6 +422,11 @@ split-view-footer {
position: absolute;
inset: 0;
+ /* Override the <stack> `grid-area: 1 / 1` rule with an `auto` placement.
+ * Otherwise the .dialogStack start edges are placed relative to the
+ * center-aligned grid items, rather than the grid's padding area. */
+ grid-area: auto;
+
/* Hide tab-modal dialogs when a window-modal one is up. */
:root[window-modal-open] .browserStack > &,
/* For some printing use cases we need to visually hide the dialog before
diff --git a/toolkit/components/resistfingerprinting/RFPHelper.sys.mjs b/toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
@@ -15,12 +15,21 @@ const kPrefLetterboxingDimensions =
"privacy.resistFingerprinting.letterboxing.dimensions";
const kPrefLetterboxingTesting =
"privacy.resistFingerprinting.letterboxing.testing";
+const kPrefLetterboxingVcenter =
+ "privacy.resistFingerprinting.letterboxing.vcenter";
const kTopicDOMWindowOpened = "domwindowopened";
const kTopicDOMWindowClosed = "domwindowclosed";
+const kTopicFullscreenNavToolbox = "fullscreen-nav-toolbox";
+
+const kPrefVerticalTabs = "sidebar.verticalTabs";
+
const lazy = {};
+ChromeUtils.defineESModuleGetters(lazy, {
+ Color: "resource://gre/modules/Color.sys.mjs",
+});
ChromeUtils.defineLazyGetter(lazy, "logConsole", () =>
console.createInstance({
prefix: "RFPHelper",
@@ -56,6 +65,10 @@ class _RFPHelper {
// Add unconditional observers
Services.prefs.addObserver(kPrefResistFingerprinting, this);
Services.prefs.addObserver(kPrefLetterboxing, this);
+ Services.prefs.addObserver(kPrefLetterboxingVcenter, this);
+ Services.prefs.addObserver(kPrefVerticalTabs, this);
+ Services.obs.addObserver(this, kTopicFullscreenNavToolbox);
+
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_letterboxingDimensions",
@@ -87,7 +100,10 @@ class _RFPHelper {
// Remove unconditional observers
Services.prefs.removeObserver(kPrefResistFingerprinting, this);
+ Services.prefs.removeObserver(kPrefLetterboxingVcenter, this);
Services.prefs.removeObserver(kPrefLetterboxing, this);
+ Services.prefs.removeObserver(kPrefVerticalTabs, this);
+ Services.obs.removeObserver(this, kTopicFullscreenNavToolbox);
// Remove the RFP observers, swallowing exceptions if they weren't present
this._removeLanguagePrefObservers();
}
@@ -109,6 +125,15 @@ class _RFPHelper {
case kTopicDOMWindowClosed:
this._handleDOMWindowClosed(subject);
break;
+ case kTopicFullscreenNavToolbox:
+ // The `subject` is the gNavToolbox.
+ // Record whether the toobox has been hidden when the browser (not
+ // content) is in fullscreen.
+ subject.ownerGlobal.gBrowser.tabbox.classList.toggle(
+ "letterboxing-nav-toolbox-hidden",
+ data === "hidden"
+ );
+ break;
default:
break;
}
@@ -123,6 +148,13 @@ class _RFPHelper {
resizeObserver.observe(browser.parentElement);
break;
}
+ case "nativethemechange":
+ // NOTE: "nativethemechange" seems to always be sent after
+ // "windowlwthemeupdate". So all the lwtheme CSS properties should be
+ // set to the new theme's values already, so we don't need to wait for
+ // windowlwthemeupdate.
+ this._updateLetterboxingColors(aMessage.currentTarget, true);
+ break;
default:
break;
}
@@ -138,8 +170,14 @@ class _RFPHelper {
this._handleSpoofEnglishChanged();
break;
case kPrefLetterboxing:
+ case kPrefLetterboxingVcenter:
this._handleLetterboxingPrefChanged();
break;
+ case kPrefVerticalTabs:
+ if (this.letterboxingEnabled) {
+ forEachWindow(win => this._updateLetterboxingColors(win));
+ }
+ break;
default:
break;
}
@@ -346,7 +384,7 @@ class _RFPHelper {
// If not already cached on the document object, traverse the CSSOM and
// find the rule applying the default letterboxing styles to browsers
// preemptively in order to beat race conditions on tab/window creation
- return (document._letterboxingMarginsRule ||= (() => {
+ return (document._letterboxingDefaultRule ||= (() => {
const LETTERBOX_CSS_SELECTOR = ".letterboxing";
const LETTERBOX_CSS_URL =
"chrome://global/content/resistfingerprinting/letterboxing.css";
@@ -553,26 +591,22 @@ class _RFPHelper {
if (lastRoundedSize) {
// Check whether the letterboxing margin is less than the border radius,
- // and if so flatten the borders.
- let borderRadius = parseInt(
- win
- .getComputedStyle(browserContainer)
- .getPropertyValue("--letterboxing-border-radius")
+ // and if so do not show an outline.
+ const gapVertical = parentHeight - lastRoundedSize.height;
+ const gapHorizontal = parentWidth - lastRoundedSize.width;
+ browserParent.classList.toggle(
+ "letterboxing-show-outline",
+ gapVertical >= this._letterboxingBorderRadius ||
+ gapHorizontal >= this._letterboxingBorderRadius
+ );
+ // When the Letterboxing area is top-aligned, only show the sidebar corner
+ // if there is enough horizontal space.
+ // The factor of 4 is from the horizontal centre-alignment and wanting
+ // enough space for twice the corner radius.
+ browserParent.classList.toggle(
+ "letterboxing-show-sidebar-corner",
+ gapHorizontal >= 4 * this._letterboxingBorderRadius
);
- if (
- borderRadius &&
- parentWidth - lastRoundedSize.width < borderRadius &&
- parentHeight - lastRoundedSize.height < borderRadius
- ) {
- borderRadius = 0;
- } else {
- borderRadius = "";
- }
- styleChanges.queueIfNeeded(browserParent, {
- "--letterboxing-decorator-visibility":
- borderRadius === 0 ? "hidden" : "",
- "--letterboxing-border-radius": borderRadius,
- });
}
// If the size of the content is already quantized, we do nothing.
@@ -605,12 +639,31 @@ class _RFPHelper {
_resetContentSize(aBrowser) {
aBrowser.parentElement.classList.add("exclude-letterboxing");
+ aBrowser.parentElement.classList.remove(
+ "letterboxing-show-outline",
+ "letterboxing-show-sidebar-corner"
+ );
}
_updateSizeForTabsInWindow(aWindow) {
let tabBrowser = aWindow.gBrowser;
- tabBrowser.tabpanels?.classList.add("letterboxing");
+ tabBrowser.tabbox.classList.add("letterboxing");
+ tabBrowser.tabbox.classList.toggle(
+ "letterboxing-vcenter",
+ Services.prefs.getBoolPref(kPrefLetterboxingVcenter, false)
+ );
+ if (this._letterboxingBorderRadius === undefined && tabBrowser.tabbox) {
+ // Cache the value since it is not expected to change in a session for any
+ // window.
+ this._letterboxingBorderRadius = Math.ceil(
+ parseFloat(
+ aWindow
+ .getComputedStyle(tabBrowser.tabbox)
+ .getPropertyValue("--letterboxing-border-radius")
+ )
+ );
+ }
for (let tab of tabBrowser.tabs) {
let browser = tab.linkedBrowser;
@@ -619,7 +672,7 @@ class _RFPHelper {
// We need to add this class late because otherwise new windows get
// maximized.
aWindow.setTimeout(() => {
- tabBrowser.tabpanels?.classList.add("letterboxing-ready");
+ tabBrowser.tabbox.classList.add("letterboxing-ready");
});
}
@@ -639,6 +692,247 @@ class _RFPHelper {
this._resizeObservers.set(aWindow, resizeObserver);
// Rounding the content viewport.
this._updateSizeForTabsInWindow(aWindow);
+
+ this._updateLetterboxingColors(aWindow, true);
+ aWindow.addEventListener("nativethemechange", this);
+ }
+
+ /**
+ * Convert a CSS property to its RGBA value.
+ *
+ * @param {Window} win - The window for the element.
+ * @param {CSSStyleDeclaration} style - The computed style for the element we
+ * want to grab the color from.
+ * @param {string} property - The name of the property we want.
+ *
+ * @returns {InspectorRGBATuple} - The RGBA color. The "r", "g", "b" fields
+ * are relative to the 0-255 color range. The "a" field is in the 0-1 range.
+ */
+ _convertToRGBA(win, style, property) {
+ let cssColor = style.getPropertyValue(property);
+ if (!cssColor) {
+ lazy.logConsole.error(`Missing color "${property}"`);
+ return { r: 0, g: 0, b: 0, a: 0 };
+ }
+ const currentColorRegex =
+ /(^|[^a-zA-Z0-9_-])currentColor($|[^a-zA-Z0-9_-])/g;
+ if (currentColorRegex.test(cssColor)) {
+ const currentColor = style.color;
+ cssColor = cssColor.replace(currentColorRegex, (_, pre, post) => {
+ return pre + currentColor + post;
+ });
+ lazy.logConsole.debug(
+ "Replaced currentColor.",
+ property,
+ currentColor,
+ cssColor
+ );
+ }
+ /* Can drop the document argument after bugzilla bug 1973684 (142). */
+ const colorRGBA = win.InspectorUtils.colorToRGBA(cssColor, win.document);
+ if (!colorRGBA) {
+ lazy.logConsole.error(
+ `Failed to convert "${property}" color (${cssColor}) to RGBA`
+ );
+ return { r: 0, g: 0, b: 0, a: 0 };
+ }
+ return colorRGBA;
+ }
+
+ /**
+ * Compose two colors with alpha values on top of each other.
+ *
+ * @param {InspectorRGBATuple} topRGBA - The color to place on the top.
+ * @param {InspectorRGBATuple} bottomRGBA - The color to place on the bottom.
+ *
+ * @returns {InspectorRGBATuple} - The composed color.
+ */
+ _composeRGBA(topRGBA, bottomRGBA) {
+ const topA = Math.max(0, Math.min(1, topRGBA.a));
+ const bottomA = Math.max(0, Math.min(1, bottomRGBA.a));
+ const a = topA + bottomA - topA * bottomA; // Should be 1 if either is 1.
+ if (a === 0) {
+ return { r: 0, g: 0, b: 0, a };
+ }
+ const ret = { a };
+ for (const field of ["r", "g", "b"]) {
+ ret[field] =
+ (topRGBA[field] * topA + bottomRGBA[field] * bottomA * (1 - topA)) / a;
+ }
+ return ret;
+ }
+
+ /**
+ * Calculate the urlbar's container opaque background color, removing any
+ * transparency.
+ *
+ * @param {Window} win - The window to calculate the color for.
+ * @param {CSSStyleDeclaration} style - The computed style for the #nav-bar
+ * element.
+ *
+ * @returns {InspectorRGBATuple} - The calculated color, which will be opaque.
+ */
+ _calculateUrlbarContainerColor(win, style) {
+ let colorRGBA;
+ if (!Services.prefs.getBoolPref(kPrefVerticalTabs)) {
+ lazy.logConsole.debug("Toolbar background used.");
+ colorRGBA = this._convertToRGBA(win, style, "--toolbar-bgcolor");
+ if (colorRGBA.a === 1) {
+ return colorRGBA;
+ }
+ } else {
+ // The urlbar only has the toolbox colour.
+ colorRGBA = { r: 0, g: 0, b: 0, a: 0 };
+ }
+ let toolboxHasBackgroundImage = false;
+ const isLwTheme = win.document.documentElement.hasAttribute("lwtheme");
+ if (isLwTheme) {
+ for (const prop of ["--lwt-header-image", "--lwt-additional-images"]) {
+ const headerImage = style.getPropertyValue(prop);
+ if (headerImage && headerImage !== "none") {
+ // The theme sets a background image behind the urlbar. No easy way to
+ // derive a single colour from this.
+ toolboxHasBackgroundImage = true;
+ lazy.logConsole.debug(
+ "Toolbox has background image.",
+ prop,
+ headerImage
+ );
+ break;
+ }
+ }
+ }
+ if (!toolboxHasBackgroundImage) {
+ lazy.logConsole.debug("Toolbox background used.");
+ colorRGBA = this._composeRGBA(
+ colorRGBA,
+ this._convertToRGBA(win, style, "--toolbox-bgcolor")
+ );
+ if (colorRGBA.a === 1) {
+ return colorRGBA;
+ }
+ }
+
+ // Determine whether the urlbar is dark.
+ // At this point, the urlbar background has some transparency, likely on top
+ // of an image.
+ // We use the theme's text colour to figure out whether the urlbar
+ // background is overall meant to be light or dark. Unlike the urlbar, we
+ // expect this colour to be (almost) opaque.
+ const textRGBA = this._convertToRGBA(win, style, "--toolbar-field-color");
+ const textColor = new lazy.Color(textRGBA.r, textRGBA.g, textRGBA.b);
+ if (textColor.relativeLuminance >= 0.5) {
+ // Light text, so assume it has a dark background.
+ // Combine with a generic opaque dark colour. Copied from "frame" for the
+ // built-in dark theme.
+ lazy.logConsole.debug("Generic dark background used.");
+ const darkFrameRGBA = { r: 28, g: 27, b: 34, a: 1 };
+ return this._composeRGBA(colorRGBA, darkFrameRGBA);
+ }
+ // Combine with an opaque light colour. Copied from "frame" for the built-in
+ // light theme.
+ lazy.logConsole.debug("Generic light background used.");
+ const lightFrameRGBA = { r: 234, g: 234, b: 237, a: 1 };
+ return this._composeRGBA(colorRGBA, lightFrameRGBA);
+ }
+
+ /**
+ * Update the Letterboxing colors and related classes, or clear them if
+ * Letterboxing is not enabled.
+ *
+ * @param {Window} win - The window to update the colors for.
+ * @param {boolean} letterboxingEnabled - Whether Letterboxing is enabled.
+ */
+ _updateLetterboxingColors(win, letterboxingEnabled) {
+ let urlbarBackgroundRGBA;
+ let urlbarTextRGBA;
+ let contentSeparatorRGBA;
+ let urlbarBackgroundDark = false;
+ let lowBackgroundOutlineContrast = false;
+
+ if (letterboxingEnabled) {
+ // Want the effective colour of various elements without any alpha values
+ // so they can be used consistently.
+ const navbarStyle = win.getComputedStyle(
+ win.document.getElementById("nav-bar")
+ );
+ const containerRGBA = this._calculateUrlbarContainerColor(
+ win,
+ navbarStyle
+ );
+ urlbarBackgroundRGBA = this._composeRGBA(
+ this._convertToRGBA(
+ win,
+ navbarStyle,
+ "--toolbar-field-background-color"
+ ),
+ containerRGBA
+ );
+ urlbarTextRGBA = this._composeRGBA(
+ this._convertToRGBA(win, navbarStyle, "--toolbar-field-color"),
+ urlbarBackgroundRGBA
+ );
+ /* Separator between the urlbar container #nav-bar and the tabbox. */
+ const tabboxStyle = win.getComputedStyle(win.gBrowser.tabbox);
+ contentSeparatorRGBA = this._composeRGBA(
+ this._convertToRGBA(
+ win,
+ tabboxStyle,
+ "--chrome-content-separator-color"
+ ),
+ containerRGBA
+ );
+ const bgColor = new lazy.Color(
+ urlbarBackgroundRGBA.r,
+ urlbarBackgroundRGBA.g,
+ urlbarBackgroundRGBA.b
+ );
+ const outlineColor = new lazy.Color(
+ contentSeparatorRGBA.r,
+ contentSeparatorRGBA.g,
+ contentSeparatorRGBA.b
+ );
+ const contrastRatio = bgColor.contrastRatio(outlineColor);
+ lazy.logConsole.debug(
+ "Outline-background contrast ratio.",
+ contrastRatio
+ );
+ urlbarBackgroundDark = bgColor.relativeLuminance < 0.5;
+ /* Very low contrast ratio. For reference the default light theme has
+ * a contrast ratio of ~1.1. */
+ lowBackgroundOutlineContrast = contrastRatio < 1.05;
+ }
+ for (const { name, colorRGBA } of [
+ {
+ name: "--letterboxing-urlbar-text-color",
+ colorRGBA: urlbarTextRGBA,
+ },
+ {
+ name: "--letterboxing-urlbar-background-color",
+ colorRGBA: urlbarBackgroundRGBA,
+ },
+ {
+ name: "--letterboxing-content-separator-color",
+ colorRGBA: contentSeparatorRGBA,
+ },
+ ]) {
+ if (letterboxingEnabled) {
+ win.gBrowser.tabbox.style.setProperty(
+ name,
+ `rgb(${colorRGBA.r}, ${colorRGBA.g}, ${colorRGBA.b})`
+ );
+ } else {
+ win.gBrowser.tabbox.style.removeProperty(name);
+ }
+ }
+ win.gBrowser.tabbox.classList.toggle(
+ "letterboxing-urlbar-background-dark",
+ urlbarBackgroundDark
+ );
+ win.gBrowser.tabbox.classList.toggle(
+ "letterboxing-low-background-outline-contrast",
+ lowBackgroundOutlineContrast
+ );
}
_attachAllWindows() {
@@ -670,13 +964,16 @@ class _RFPHelper {
aWindow.removeEventListener("TabOpen", this);
// revert tabpanel's style to default
- tabBrowser.tabpanels?.classList.remove("letterboxing");
+ tabBrowser.tabbox.classList.remove("letterboxing");
// and restore default size on each browser element
for (let tab of tabBrowser.tabs) {
let browser = tab.linkedBrowser;
this._resetContentSize(browser);
}
+
+ aWindow.removeEventListener("nativethemechange", this);
+ this._updateLetterboxingColors(aWindow, false);
}
_detachAllWindows() {
diff --git a/toolkit/components/resistfingerprinting/content/letterboxing.css b/toolkit/components/resistfingerprinting/content/letterboxing.css
@@ -7,9 +7,109 @@
* RFPHelper.sys.mjs (LETTERBOX_CSS_SELECTOR and LETTERBOX_CSS_URL,
* respectively), where --letterboxing-width & --letterboxing-height are
* actually set.
+ * Keep this block first and separate to the rules that do not necessarily
+ * require --letterboxing-width or --letterboxing-height.
*/
.letterboxing {
- --letterboxing-bgcolor: var(--tabpanel-background-color);
+ .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
+ width: var(--letterboxing-width) !important;
+ height: var(--letterboxing-height) !important;
+ }
+}
+
+/* stylelint-disable stylelint-plugin-mozilla/use-border-color-tokens */
+/* stylelint-disable stylelint-plugin-mozilla/use-border-radius-tokens */
+
+#tabbrowser-tabbox.letterboxing {
+ --letterboxing-bgcolor: var(--background-color-canvas);
+ /* Match the border radius used for the sidebar. */
+ --letterboxing-border-radius: var(--border-radius-medium);
+ --letterboxing-border-radius-top: 0;
+ --letterboxing-vertical-alignment: start;
+ --letterboxing-shadow: none;
+ --letterboxing-outline-color: var(--border-color);
+ --letterboxing-outline-width: 1px;
+
+ @media not ((prefers-contrast) or (forced-colors)) {
+ /* Match the #sidebar outline width. */
+ --letterboxing-outline-width: 0.5px;
+ --letterboxing-shadow-color: rgba(58, 57, 68, 0.2);
+ --letterboxing-shadow: 0 2px 14px 0 var(--letterboxing-shadow-color);
+
+ /* Match the effective urlbar background colour. */
+ --letterboxing-bgcolor: var(--letterboxing-urlbar-background-color);
+ /* Match the effective colour of the separator between the urlbar container
+ * and the content. */
+ --letterboxing-outline-color: var(--letterboxing-content-separator-color);
+
+ &.letterboxing-urlbar-background-dark {
+ --letterboxing-shadow-color: #15141a;
+ }
+
+ &.letterboxing-low-background-outline-contrast {
+ /* The default content separator colour has insufficient contrast. */
+ --letterboxing-outline-color: color-mix(in srgb, var(--letterboxing-content-separator-color) 90%, black);
+
+ &.letterboxing-urlbar-background-dark {
+ /* Lighten the colour. */
+ --letterboxing-outline-color: color-mix(in srgb, var(--letterboxing-content-separator-color) 90%, white);
+ }
+ }
+ }
+
+ @media (prefers-contrast) and (not (forced-colors)) {
+ :root[lwtheme] & {
+ /* User with prefers-contrast coming from the system settings, but also an
+ * installed theme. */
+ --letterboxing-bgcolor: var(--letterboxing-urlbar-background-color);
+ /* Presumably a user with prefers-contrast and a custom theme has chosen
+ * a theme where the contrast between the urlbar and the text is
+ * sufficiently high or low. */
+ --letterboxing-outline-color: var(--letterboxing-urlbar-text-color);
+ }
+ }
+
+ background: var(--letterboxing-bgcolor);
+
+ &:has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-outline) {
+ /* Letterboxing outline is visible for the current tab. Replace the usual
+ * outline to match the Letterboxing outline. For most scenarios, this
+ * should be mostly the same colour as when Letterboxing is not visible. But
+ * it may make a difference for some theme combinations. */
+ outline-color: var(--letterboxing-outline-color);
+ outline-width: var(--letterboxing-outline-width);
+ }
+
+ #tabbrowser-tabpanels {
+ /* Override the --tabpanel-background-color.
+ * Also, make sure this remains transparent, otherwise it will overlap the
+ * parent's corner's border-radius due to it's "position: relative" rule. */
+ /* TODO: FIX this for newtab pages. tor-browser#44085 */
+ background: transparent;
+ }
+
+ /* stylelint-disable-next-line media-query-no-invalid */
+ @media -moz-pref("sidebar.revamp") {
+ :root:not([inDOMFullscreen]) &[sidebar-shown]:not(.letterboxing-nav-toolbox-hidden):is(
+ /* When the Letterboxing area is aligned to the top, show the rounded
+ * corner if there is enough vertical space between the sidebar and the
+ * browser element, which is not rounded at the top. */
+ :not(.letterboxing-vcenter):has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-sidebar-corner),
+ /* When the Letterboxing area is aligned to the centre, show the rounded
+ * corner if the Letterboxing border is shown. */
+ .letterboxing-vcenter:has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-outline)
+ ) {
+ /* stylelint-disable-next-line media-query-no-invalid */
+ @media -moz-pref("sidebar.position_start") {
+ border-start-start-radius: var(--letterboxing-border-radius);
+ }
+
+ /* stylelint-disable-next-line media-query-no-invalid */
+ @media not -moz-pref("sidebar.position_start") {
+ border-start-end-radius: var(--letterboxing-border-radius);
+ }
+ }
+ }
.browserContainer {
/*
@@ -18,15 +118,75 @@
* doesn't get notified on horizontal shrinking.
*/
overflow: hidden;
- background: var(--letterboxing-bgcolor);
}
- .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
- width: var(--letterboxing-width) !important;
- height: var(--letterboxing-height) !important;
+ &.letterboxing-vcenter {
+ --letterboxing-border-radius-top: var(--letterboxing-border-radius);
+ --letterboxing-vertical-alignment: center;
+ }
+}
+
+.browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
+ :root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready & {
+ place-content: var(--letterboxing-vertical-alignment) center;
+ }
+
+ :root:not([inDOMFullscreen]) .letterboxing &.letterboxing-show-outline {
+ browser {
+ /* We use clip-path rather than border-radius because border-radius on its
+ * own leads to rendering artefacts in the corners (tested with GNOME).
+ * See tor-browser#44214 (comment 3262962). */
+ /* TODO: Use border-radius once bugzilla bug 1991874 is resolved. */
+ clip-path: rect(
+ auto auto auto auto round var(--letterboxing-border-radius-top) var(--letterboxing-border-radius-top) var(--letterboxing-border-radius)
+ var(--letterboxing-border-radius)
+ );
+ }
+
+ .browserDecorator {
+ /* Need a separate browserDecorator element because the clip-path on the
+ * browser would exclude the outline and box-shadow. */
+ /* TODO: Move these rules to the browser element once bugzilla bug 1991874
+ * is resolved, and drop browserDecorator. */
+ display: block;
+ border-radius: var(--letterboxing-border-radius-top) var(--letterboxing-border-radius-top) var(--letterboxing-border-radius)
+ var(--letterboxing-border-radius);
+ /* NOTE: The top outline will not be visible when this is aligned to the
+ * top. */
+ outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color);
+ box-shadow: var(--letterboxing-shadow);
+ }
+
+ #statuspanel:not([mirror]) #statuspanel-label {
+ border-end-start-radius: var(--letterboxing-border-radius);
+ }
+
+ #statuspanel[mirror] #statuspanel-label {
+ border-end-end-radius: var(--letterboxing-border-radius);
+ }
+ }
+
+ #statuspanel {
+ position: relative;
+ place-self: end start;
+ z-index: 2;
+
+ &[mirror] {
+ justify-self: end;
+ }
+ }
+
+ #statuspanel-label {
+ margin: 0;
+ outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color);
+ max-width: calc(var(--letterboxing-width) * 0.5);
}
}
-:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
- place-content: start center;
+.browserDecorator {
+ display: none;
+ pointer-events: none;
+ background: transparent;
+ position: relative;
+ z-index: 1;
}