Loading browser/base/content/browser-fullScreenAndPointerLock.js +14 −2 Original line number Diff line number Diff line Loading @@ -879,7 +879,13 @@ var FullScreen = { } this._isChromeCollapsed = false; Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "shown"); // Need a subject to know which window this applies to. // Base browser patch can be dropped after bugzilla bug 1992036. Services.obs.notifyObservers( gNavToolbox, "fullscreen-nav-toolbox", "shown" ); }, hideNavToolbox(aAnimate = false) { Loading Loading @@ -943,7 +949,13 @@ var FullScreen = { gNavToolbox.style.marginTop = -gNavToolbox.getBoundingClientRect().height + "px"; this._isChromeCollapsed = true; Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "hidden"); // Need a subject to know which window this applies to. // Base browser patch can be dropped after bugzilla bug 1880918. Services.obs.notifyObservers( gNavToolbox, "fullscreen-nav-toolbox", "hidden" ); MousePosTracker.removeListener(this); }, Loading toolkit/components/resistfingerprinting/RFPHelper.sys.mjs +288 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,15 @@ const kPrefLetterboxingVcenter = 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", Loading Loading @@ -54,6 +61,8 @@ class _RFPHelper { 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, Loading Loading @@ -88,6 +97,8 @@ class _RFPHelper { 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(); } Loading @@ -109,6 +120,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; } Loading @@ -123,6 +143,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; } Loading @@ -141,6 +168,11 @@ class _RFPHelper { case kPrefLetterboxingVcenter: this._handleLetterboxingPrefChanged(); break; case kPrefVerticalTabs: if (this.letterboxingEnabled) { forEachWindow(win => this._updateLetterboxingColors(win)); } break; default: break; } Loading Loading @@ -556,6 +588,14 @@ class _RFPHelper { 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 the size of the content is already quantized, we do nothing. Loading Loading @@ -588,7 +628,10 @@ class _RFPHelper { _resetContentSize(aBrowser) { aBrowser.parentElement.classList.add("exclude-letterboxing"); aBrowser.parentElement.classList.remove("letterboxing-show-outline"); aBrowser.parentElement.classList.remove( "letterboxing-show-outline", "letterboxing-show-sidebar-corner" ); } _updateSizeForTabsInWindow(aWindow) { Loading Loading @@ -638,6 +681,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() { Loading Loading @@ -676,6 +960,9 @@ class _RFPHelper { let browser = tab.linkedBrowser; this._resetContentSize(browser); } aWindow.removeEventListener("nativethemechange", this); this._updateLetterboxingColors(aWindow, false); } _detachAllWindows() { Loading toolkit/components/resistfingerprinting/content/letterboxing.css +103 −20 Original line number Diff line number Diff line Loading @@ -18,12 +18,95 @@ } #tabbrowser-tabbox.letterboxing { --letterboxing-bgcolor: var(--tabpanel-background-color); --letterboxing-border-radius: 8px; --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-color: rgba(12, 12, 13, 0.10); --letterboxing-border-color: var(--letterboxing-bgcolor); --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.20); --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 { /* Loading @@ -32,7 +115,6 @@ * doesn't get notified on horizontal shrinking. */ overflow: hidden; background: var(--letterboxing-bgcolor); } &.letterboxing-vcenter { Loading @@ -42,29 +124,30 @@ } .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) { .letterboxing & browser { box-shadow: 0 4px 8px 0 var(--letterboxing-shadow-color); } :root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready & { place-content: var(--letterboxing-vertical-alignment) center; } :root:not([inDOMFullscreen]) .letterboxing &.letterboxing-show-outline { browser { border-radius: var(--letterboxing-border-radius); border-top-left-radius: var(--letterboxing-border-radius-top); border-top-right-radius: var(--letterboxing-border-radius-top); /* 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 { display: initial; border-radius: var(--letterboxing-border-radius); border-top-left-radius: var(--letterboxing-border-radius-top); border-top-right-radius: var(--letterboxing-border-radius-top); box-shadow: var(--letterboxing-border-color) 0 0 .1px inset, var(--letterboxing-border-color) 0 0 .1px; border: .1px solid var(--letterboxing-border-color); outline: .1px solid var(--letterboxing-bgcolor); /* 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 { Loading @@ -88,7 +171,7 @@ #statuspanel-label { margin: 0; border: 1px solid var(--letterboxing-border-color); outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color); max-width: calc(var(--letterboxing-width) * .5); } } Loading Loading
browser/base/content/browser-fullScreenAndPointerLock.js +14 −2 Original line number Diff line number Diff line Loading @@ -879,7 +879,13 @@ var FullScreen = { } this._isChromeCollapsed = false; Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "shown"); // Need a subject to know which window this applies to. // Base browser patch can be dropped after bugzilla bug 1992036. Services.obs.notifyObservers( gNavToolbox, "fullscreen-nav-toolbox", "shown" ); }, hideNavToolbox(aAnimate = false) { Loading Loading @@ -943,7 +949,13 @@ var FullScreen = { gNavToolbox.style.marginTop = -gNavToolbox.getBoundingClientRect().height + "px"; this._isChromeCollapsed = true; Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "hidden"); // Need a subject to know which window this applies to. // Base browser patch can be dropped after bugzilla bug 1880918. Services.obs.notifyObservers( gNavToolbox, "fullscreen-nav-toolbox", "hidden" ); MousePosTracker.removeListener(this); }, Loading
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs +288 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,15 @@ const kPrefLetterboxingVcenter = 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", Loading Loading @@ -54,6 +61,8 @@ class _RFPHelper { 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, Loading Loading @@ -88,6 +97,8 @@ class _RFPHelper { 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(); } Loading @@ -109,6 +120,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; } Loading @@ -123,6 +143,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; } Loading @@ -141,6 +168,11 @@ class _RFPHelper { case kPrefLetterboxingVcenter: this._handleLetterboxingPrefChanged(); break; case kPrefVerticalTabs: if (this.letterboxingEnabled) { forEachWindow(win => this._updateLetterboxingColors(win)); } break; default: break; } Loading Loading @@ -556,6 +588,14 @@ class _RFPHelper { 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 the size of the content is already quantized, we do nothing. Loading Loading @@ -588,7 +628,10 @@ class _RFPHelper { _resetContentSize(aBrowser) { aBrowser.parentElement.classList.add("exclude-letterboxing"); aBrowser.parentElement.classList.remove("letterboxing-show-outline"); aBrowser.parentElement.classList.remove( "letterboxing-show-outline", "letterboxing-show-sidebar-corner" ); } _updateSizeForTabsInWindow(aWindow) { Loading Loading @@ -638,6 +681,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() { Loading Loading @@ -676,6 +960,9 @@ class _RFPHelper { let browser = tab.linkedBrowser; this._resetContentSize(browser); } aWindow.removeEventListener("nativethemechange", this); this._updateLetterboxingColors(aWindow, false); } _detachAllWindows() { Loading
toolkit/components/resistfingerprinting/content/letterboxing.css +103 −20 Original line number Diff line number Diff line Loading @@ -18,12 +18,95 @@ } #tabbrowser-tabbox.letterboxing { --letterboxing-bgcolor: var(--tabpanel-background-color); --letterboxing-border-radius: 8px; --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-color: rgba(12, 12, 13, 0.10); --letterboxing-border-color: var(--letterboxing-bgcolor); --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.20); --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 { /* Loading @@ -32,7 +115,6 @@ * doesn't get notified on horizontal shrinking. */ overflow: hidden; background: var(--letterboxing-bgcolor); } &.letterboxing-vcenter { Loading @@ -42,29 +124,30 @@ } .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) { .letterboxing & browser { box-shadow: 0 4px 8px 0 var(--letterboxing-shadow-color); } :root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready & { place-content: var(--letterboxing-vertical-alignment) center; } :root:not([inDOMFullscreen]) .letterboxing &.letterboxing-show-outline { browser { border-radius: var(--letterboxing-border-radius); border-top-left-radius: var(--letterboxing-border-radius-top); border-top-right-radius: var(--letterboxing-border-radius-top); /* 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 { display: initial; border-radius: var(--letterboxing-border-radius); border-top-left-radius: var(--letterboxing-border-radius-top); border-top-right-radius: var(--letterboxing-border-radius-top); box-shadow: var(--letterboxing-border-color) 0 0 .1px inset, var(--letterboxing-border-color) 0 0 .1px; border: .1px solid var(--letterboxing-border-color); outline: .1px solid var(--letterboxing-bgcolor); /* 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 { Loading @@ -88,7 +171,7 @@ #statuspanel-label { margin: 0; border: 1px solid var(--letterboxing-border-color); outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color); max-width: calc(var(--letterboxing-width) * .5); } } Loading