henry pushed to branch base-browser-140.4.0esr-15.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
a8d9aeef
by Henry Wilkes at 2025-10-15T18:01:07+01:00
-
73862bbd
by Henry Wilkes at 2025-10-15T18:01:08+01:00
-
09abf933
by Henry Wilkes at 2025-10-15T18:01:09+01:00
-
943bae35
by Henry Wilkes at 2025-10-15T18:01:09+01:00
-
9b4b135b
by Henry Wilkes at 2025-10-15T18:01:10+01:00
-
4d9307d1
by Henry Wilkes at 2025-10-15T18:01:11+01:00
-
e4d77eb2
by Henry Wilkes at 2025-10-15T18:01:12+01:00
-
261e8522
by Henry Wilkes at 2025-10-15T18:01:12+01:00
-
2282a161
by Henry Wilkes at 2025-10-15T18:01:13+01:00
-
f48a8536
by Henry Wilkes at 2025-10-15T18:01:14+01:00
-
26d1b64a
by Henry Wilkes at 2025-10-15T18:01:15+01:00
-
940d5e2c
by Henry Wilkes at 2025-10-15T18:01:15+01:00
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/themes/shared/tabbrowser/content-area.css
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
- toolkit/components/resistfingerprinting/content/letterboxing.css
Changes:
... | ... | @@ -879,7 +879,13 @@ var FullScreen = { |
879 | 879 | }
|
880 | 880 | |
881 | 881 | this._isChromeCollapsed = false;
|
882 | - Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "shown");
|
|
882 | + // Need a subject to know which window this applies to.
|
|
883 | + // Base browser patch can be dropped after bugzilla bug 1992036.
|
|
884 | + Services.obs.notifyObservers(
|
|
885 | + gNavToolbox,
|
|
886 | + "fullscreen-nav-toolbox",
|
|
887 | + "shown"
|
|
888 | + );
|
|
883 | 889 | },
|
884 | 890 | |
885 | 891 | hideNavToolbox(aAnimate = false) {
|
... | ... | @@ -943,7 +949,13 @@ var FullScreen = { |
943 | 949 | gNavToolbox.style.marginTop =
|
944 | 950 | -gNavToolbox.getBoundingClientRect().height + "px";
|
945 | 951 | this._isChromeCollapsed = true;
|
946 | - Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "hidden");
|
|
952 | + // Need a subject to know which window this applies to.
|
|
953 | + // Base browser patch can be dropped after bugzilla bug 1880918.
|
|
954 | + Services.obs.notifyObservers(
|
|
955 | + gNavToolbox,
|
|
956 | + "fullscreen-nav-toolbox",
|
|
957 | + "hidden"
|
|
958 | + );
|
|
947 | 959 | |
948 | 960 | MousePosTracker.removeListener(this);
|
949 | 961 | },
|
... | ... | @@ -242,13 +242,17 @@ |
242 | 242 | }
|
243 | 243 | }
|
244 | 244 | |
245 | -#statuspanel[type=letterboxingStatus] > #statuspanel-label,
|
|
246 | -#statuspanel[previoustype=letterboxingStatus][inactive] > #statuspanel-label {
|
|
245 | +#statuspanel:is([type=letterboxingStatus], [previoustype=letterboxingStatus][inactive]) > #statuspanel-label {
|
|
247 | 246 | background-image: url("chrome://browser/skin/window.svg");
|
248 | 247 | background-size: 1em;
|
249 | 248 | background-repeat: no-repeat;
|
250 | - background-position-x: .5em;
|
|
251 | 249 | background-position-y: center;
|
250 | + background-position-x: left .5em;
|
|
251 | + |
|
252 | + &:-moz-locale-dir(rtl) {
|
|
253 | + background-position-x: right .5em;
|
|
254 | + }
|
|
255 | + |
|
252 | 256 | padding-inline-start: 2em;
|
253 | 257 | -moz-context-properties: fill;
|
254 | 258 | fill: var(--color-accent-primary);
|
... | ... | @@ -18,8 +18,6 @@ const kPrefLetterboxingTesting = |
18 | 18 | "privacy.resistFingerprinting.letterboxing.testing";
|
19 | 19 | const kPrefLetterboxingVcenter =
|
20 | 20 | "privacy.resistFingerprinting.letterboxing.vcenter";
|
21 | -const kPrefLetterboxingGradient =
|
|
22 | - "privacy.resistFingerprinting.letterboxing.gradient";
|
|
23 | 21 | const kPrefLetterboxingDidForceSize =
|
24 | 22 | "privacy.resistFingerprinting.letterboxing.didForceSize";
|
25 | 23 | const kPrefLetterboxingRememberSize =
|
... | ... | @@ -28,10 +26,17 @@ const kPrefLetterboxingRememberSize = |
28 | 26 | const kTopicDOMWindowOpened = "domwindowopened";
|
29 | 27 | const kTopicDOMWindowClosed = "domwindowclosed";
|
30 | 28 | |
29 | +const kTopicFullscreenNavToolbox = "fullscreen-nav-toolbox";
|
|
30 | + |
|
31 | 31 | const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
|
32 | 32 | |
33 | +const kPrefVerticalTabs = "sidebar.verticalTabs";
|
|
34 | + |
|
33 | 35 | const lazy = {};
|
34 | 36 | |
37 | +ChromeUtils.defineESModuleGetters(lazy, {
|
|
38 | + Color: "resource://gre/modules/Color.sys.mjs",
|
|
39 | +});
|
|
35 | 40 | ChromeUtils.defineLazyGetter(lazy, "logConsole", () =>
|
36 | 41 | console.createInstance({
|
37 | 42 | prefix: "RFPHelper",
|
... | ... | @@ -155,7 +160,8 @@ class _RFPHelper { |
155 | 160 | Services.prefs.addObserver(kPrefResistFingerprinting, this);
|
156 | 161 | Services.prefs.addObserver(kPrefLetterboxing, this);
|
157 | 162 | Services.prefs.addObserver(kPrefLetterboxingVcenter, this);
|
158 | - Services.prefs.addObserver(kPrefLetterboxingGradient, this);
|
|
163 | + Services.prefs.addObserver(kPrefVerticalTabs, this);
|
|
164 | + Services.obs.addObserver(this, kTopicFullscreenNavToolbox);
|
|
159 | 165 | |
160 | 166 | XPCOMUtils.defineLazyPreferenceGetter(
|
161 | 167 | this,
|
... | ... | @@ -188,9 +194,10 @@ class _RFPHelper { |
188 | 194 | |
189 | 195 | // Remove unconditional observers
|
190 | 196 | Services.prefs.removeObserver(kPrefResistFingerprinting, this);
|
191 | - Services.prefs.removeObserver(kPrefLetterboxingGradient, this);
|
|
192 | 197 | Services.prefs.removeObserver(kPrefLetterboxingVcenter, this);
|
193 | 198 | Services.prefs.removeObserver(kPrefLetterboxing, this);
|
199 | + Services.prefs.removeObserver(kPrefVerticalTabs, this);
|
|
200 | + Services.obs.removeObserver(this, kTopicFullscreenNavToolbox);
|
|
194 | 201 | // Remove the RFP observers, swallowing exceptions if they weren't present
|
195 | 202 | this._removeLanguagePrefObservers();
|
196 | 203 | }
|
... | ... | @@ -212,6 +219,15 @@ class _RFPHelper { |
212 | 219 | case kTopicDOMWindowClosed:
|
213 | 220 | this._handleDOMWindowClosed(subject);
|
214 | 221 | break;
|
222 | + case kTopicFullscreenNavToolbox:
|
|
223 | + // The `subject` is the gNavToolbox.
|
|
224 | + // Record whether the toobox has been hidden when the browser (not
|
|
225 | + // content) is in fullscreen.
|
|
226 | + subject.ownerGlobal.gBrowser.tabbox.classList.toggle(
|
|
227 | + "letterboxing-nav-toolbox-hidden",
|
|
228 | + data === "hidden"
|
|
229 | + );
|
|
230 | + break;
|
|
215 | 231 | default:
|
216 | 232 | break;
|
217 | 233 | }
|
... | ... | @@ -226,6 +242,13 @@ class _RFPHelper { |
226 | 242 | resizeObserver.observe(browser.parentElement);
|
227 | 243 | break;
|
228 | 244 | }
|
245 | + case "nativethemechange":
|
|
246 | + // NOTE: "nativethemechange" seems to always be sent after
|
|
247 | + // "windowlwthemeupdate". So all the lwtheme CSS properties should be
|
|
248 | + // set to the new theme's values already, so we don't need to wait for
|
|
249 | + // windowlwthemeupdate.
|
|
250 | + this._updateLetterboxingColors(aMessage.currentTarget, true);
|
|
251 | + break;
|
|
229 | 252 | default:
|
230 | 253 | break;
|
231 | 254 | }
|
... | ... | @@ -245,9 +268,13 @@ class _RFPHelper { |
245 | 268 | Services.prefs.clearUserPref(kPrefLetterboxingDidForceSize);
|
246 | 269 | // fall-through
|
247 | 270 | case kPrefLetterboxingVcenter:
|
248 | - case kPrefLetterboxingGradient:
|
|
249 | 271 | this._handleLetterboxingPrefChanged();
|
250 | 272 | break;
|
273 | + case kPrefVerticalTabs:
|
|
274 | + if (this.letterboxingEnabled) {
|
|
275 | + forEachWindow(win => this._updateLetterboxingColors(win));
|
|
276 | + }
|
|
277 | + break;
|
|
251 | 278 | default:
|
252 | 279 | break;
|
253 | 280 | }
|
... | ... | @@ -452,7 +479,7 @@ class _RFPHelper { |
452 | 479 | // If not already cached on the document object, traverse the CSSOM and
|
453 | 480 | // find the rule applying the default letterboxing styles to browsers
|
454 | 481 | // preemptively in order to beat race conditions on tab/window creation
|
455 | - return (document._letterboxingMarginsRule ||= (() => {
|
|
482 | + return (document._letterboxingDefaultRule ||= (() => {
|
|
456 | 483 | const LETTERBOX_CSS_SELECTOR = ".letterboxing";
|
457 | 484 | const LETTERBOX_CSS_URL =
|
458 | 485 | "chrome://global/content/resistfingerprinting/letterboxing.css";
|
... | ... | @@ -688,26 +715,22 @@ class _RFPHelper { |
688 | 715 | |
689 | 716 | if (lastRoundedSize) {
|
690 | 717 | // Check whether the letterboxing margin is less than the border radius,
|
691 | - // and if so flatten the borders.
|
|
692 | - let borderRadius = parseInt(
|
|
693 | - win
|
|
694 | - .getComputedStyle(browserContainer)
|
|
695 | - .getPropertyValue("--letterboxing-border-radius")
|
|
718 | + // and if so do not show an outline.
|
|
719 | + const gapVertical = parentHeight - lastRoundedSize.height;
|
|
720 | + const gapHorizontal = parentWidth - lastRoundedSize.width;
|
|
721 | + browserParent.classList.toggle(
|
|
722 | + "letterboxing-show-outline",
|
|
723 | + gapVertical >= this._letterboxingBorderRadius ||
|
|
724 | + gapHorizontal >= this._letterboxingBorderRadius
|
|
725 | + );
|
|
726 | + // When the Letterboxing area is top-aligned, only show the sidebar corner
|
|
727 | + // if there is enough horizontal space.
|
|
728 | + // The factor of 4 is from the horizontal centre-alignment and wanting
|
|
729 | + // enough space for twice the corner radius.
|
|
730 | + browserParent.classList.toggle(
|
|
731 | + "letterboxing-show-sidebar-corner",
|
|
732 | + gapHorizontal >= 4 * this._letterboxingBorderRadius
|
|
696 | 733 | );
|
697 | - if (
|
|
698 | - borderRadius &&
|
|
699 | - parentWidth - lastRoundedSize.width < borderRadius &&
|
|
700 | - parentHeight - lastRoundedSize.height < borderRadius
|
|
701 | - ) {
|
|
702 | - borderRadius = 0;
|
|
703 | - } else {
|
|
704 | - borderRadius = "";
|
|
705 | - }
|
|
706 | - styleChanges.queueIfNeeded(browserParent, {
|
|
707 | - "--letterboxing-decorator-visibility":
|
|
708 | - borderRadius === 0 ? "hidden" : "",
|
|
709 | - "--letterboxing-border-radius": borderRadius,
|
|
710 | - });
|
|
711 | 734 | if (win.gBrowser.selectedBrowser == aBrowser) {
|
712 | 735 | const updateStatus = async args => {
|
713 | 736 | win.XULBrowserWindow.letterboxingStatus = args
|
... | ... | @@ -769,20 +792,31 @@ class _RFPHelper { |
769 | 792 | |
770 | 793 | _resetContentSize(aBrowser) {
|
771 | 794 | aBrowser.parentElement.classList.add("exclude-letterboxing");
|
795 | + aBrowser.parentElement.classList.remove(
|
|
796 | + "letterboxing-show-outline",
|
|
797 | + "letterboxing-show-sidebar-corner"
|
|
798 | + );
|
|
772 | 799 | }
|
773 | 800 | |
774 | 801 | _updateSizeForTabsInWindow(aWindow) {
|
775 | 802 | let tabBrowser = aWindow.gBrowser;
|
776 | 803 | |
777 | - tabBrowser.tabpanels?.classList.add("letterboxing");
|
|
778 | - tabBrowser.tabpanels?.classList.toggle(
|
|
804 | + tabBrowser.tabbox.classList.add("letterboxing");
|
|
805 | + tabBrowser.tabbox.classList.toggle(
|
|
779 | 806 | "letterboxing-vcenter",
|
780 | 807 | Services.prefs.getBoolPref(kPrefLetterboxingVcenter, false)
|
781 | 808 | );
|
782 | - tabBrowser.tabpanels?.classList.toggle(
|
|
783 | - "letterboxing-gradient",
|
|
784 | - Services.prefs.getBoolPref(kPrefLetterboxingGradient, false)
|
|
785 | - );
|
|
809 | + if (this._letterboxingBorderRadius === undefined && tabBrowser.tabbox) {
|
|
810 | + // Cache the value since it is not expected to change in a session for any
|
|
811 | + // window.
|
|
812 | + this._letterboxingBorderRadius = Math.ceil(
|
|
813 | + parseFloat(
|
|
814 | + aWindow
|
|
815 | + .getComputedStyle(tabBrowser.tabbox)
|
|
816 | + .getPropertyValue("--letterboxing-border-radius")
|
|
817 | + )
|
|
818 | + );
|
|
819 | + }
|
|
786 | 820 | |
787 | 821 | for (let tab of tabBrowser.tabs) {
|
788 | 822 | let browser = tab.linkedBrowser;
|
... | ... | @@ -791,7 +825,7 @@ class _RFPHelper { |
791 | 825 | // We need to add this class late because otherwise new windows get
|
792 | 826 | // maximized.
|
793 | 827 | aWindow.setTimeout(() => {
|
794 | - tabBrowser.tabpanels?.classList.add("letterboxing-ready");
|
|
828 | + tabBrowser.tabbox.classList.add("letterboxing-ready");
|
|
795 | 829 | if (!aWindow._rfpOriginalSize) {
|
796 | 830 | this._recordWindowSize(aWindow);
|
797 | 831 | }
|
... | ... | @@ -869,6 +903,247 @@ class _RFPHelper { |
869 | 903 | this._resizeObservers.set(aWindow, resizeObserver);
|
870 | 904 | // Rounding the content viewport.
|
871 | 905 | this._updateSizeForTabsInWindow(aWindow);
|
906 | + |
|
907 | + this._updateLetterboxingColors(aWindow, true);
|
|
908 | + aWindow.addEventListener("nativethemechange", this);
|
|
909 | + }
|
|
910 | + |
|
911 | + /**
|
|
912 | + * Convert a CSS property to its RGBA value.
|
|
913 | + *
|
|
914 | + * @param {Window} win - The window for the element.
|
|
915 | + * @param {CSSStyleDeclaration} style - The computed style for the element we
|
|
916 | + * want to grab the color from.
|
|
917 | + * @param {string} property - The name of the property we want.
|
|
918 | + *
|
|
919 | + * @returns {InspectorRGBATuple} - The RGBA color. The "r", "g", "b" fields
|
|
920 | + * are relative to the 0-255 color range. The "a" field is in the 0-1 range.
|
|
921 | + */
|
|
922 | + _convertToRGBA(win, style, property) {
|
|
923 | + let cssColor = style.getPropertyValue(property);
|
|
924 | + if (!cssColor) {
|
|
925 | + lazy.logConsole.error(`Missing color "${property}"`);
|
|
926 | + return { r: 0, g: 0, b: 0, a: 0 };
|
|
927 | + }
|
|
928 | + const currentColorRegex =
|
|
929 | + /(^|[^a-zA-Z0-9_-])currentColor($|[^a-zA-Z0-9_-])/g;
|
|
930 | + if (currentColorRegex.test(cssColor)) {
|
|
931 | + const currentColor = style.color;
|
|
932 | + cssColor = cssColor.replace(currentColorRegex, (_, pre, post) => {
|
|
933 | + return pre + currentColor + post;
|
|
934 | + });
|
|
935 | + lazy.logConsole.debug(
|
|
936 | + "Replaced currentColor.",
|
|
937 | + property,
|
|
938 | + currentColor,
|
|
939 | + cssColor
|
|
940 | + );
|
|
941 | + }
|
|
942 | + /* Can drop the document argument after bugzilla bug 1973684 (142). */
|
|
943 | + const colorRGBA = win.InspectorUtils.colorToRGBA(cssColor, win.document);
|
|
944 | + if (!colorRGBA) {
|
|
945 | + lazy.logConsole.error(
|
|
946 | + `Failed to convert "${property}" color (${cssColor}) to RGBA`
|
|
947 | + );
|
|
948 | + return { r: 0, g: 0, b: 0, a: 0 };
|
|
949 | + }
|
|
950 | + return colorRGBA;
|
|
951 | + }
|
|
952 | + |
|
953 | + /**
|
|
954 | + * Compose two colors with alpha values on top of each other.
|
|
955 | + *
|
|
956 | + * @param {InspectorRGBATuple} topRGBA - The color to place on the top.
|
|
957 | + * @param {InspectorRGBATuple} bottomRGBA - The color to place on the bottom.
|
|
958 | + *
|
|
959 | + * @returns {InspectorRGBATuple} - The composed color.
|
|
960 | + */
|
|
961 | + _composeRGBA(topRGBA, bottomRGBA) {
|
|
962 | + const topA = Math.max(0, Math.min(1, topRGBA.a));
|
|
963 | + const bottomA = Math.max(0, Math.min(1, bottomRGBA.a));
|
|
964 | + const a = topA + bottomA - topA * bottomA; // Should be 1 if either is 1.
|
|
965 | + if (a === 0) {
|
|
966 | + return { r: 0, g: 0, b: 0, a };
|
|
967 | + }
|
|
968 | + const ret = { a };
|
|
969 | + for (const field of ["r", "g", "b"]) {
|
|
970 | + ret[field] =
|
|
971 | + (topRGBA[field] * topA + bottomRGBA[field] * bottomA * (1 - topA)) / a;
|
|
972 | + }
|
|
973 | + return ret;
|
|
974 | + }
|
|
975 | + |
|
976 | + /**
|
|
977 | + * Calculate the urlbar's container opaque background color, removing any
|
|
978 | + * transparency.
|
|
979 | + *
|
|
980 | + * @param {Window} win - The window to calculate the color for.
|
|
981 | + * @param {CSSStyleDeclaration} style - The computed style for the #nav-bar
|
|
982 | + * element.
|
|
983 | + *
|
|
984 | + * @returns {InspectorRGBATuple} - The calculated color, which will be opaque.
|
|
985 | + */
|
|
986 | + _calculateUrlbarContainerColor(win, style) {
|
|
987 | + let colorRGBA;
|
|
988 | + if (!Services.prefs.getBoolPref(kPrefVerticalTabs)) {
|
|
989 | + lazy.logConsole.debug("Toolbar background used.");
|
|
990 | + colorRGBA = this._convertToRGBA(win, style, "--toolbar-bgcolor");
|
|
991 | + if (colorRGBA.a === 1) {
|
|
992 | + return colorRGBA;
|
|
993 | + }
|
|
994 | + } else {
|
|
995 | + // The urlbar only has the toolbox colour.
|
|
996 | + colorRGBA = { r: 0, g: 0, b: 0, a: 0 };
|
|
997 | + }
|
|
998 | + let toolboxHasBackgroundImage = false;
|
|
999 | + const isLwTheme = win.document.documentElement.hasAttribute("lwtheme");
|
|
1000 | + if (isLwTheme) {
|
|
1001 | + for (const prop of ["--lwt-header-image", "--lwt-additional-images"]) {
|
|
1002 | + const headerImage = style.getPropertyValue(prop);
|
|
1003 | + if (headerImage && headerImage !== "none") {
|
|
1004 | + // The theme sets a background image behind the urlbar. No easy way to
|
|
1005 | + // derive a single colour from this.
|
|
1006 | + toolboxHasBackgroundImage = true;
|
|
1007 | + lazy.logConsole.debug(
|
|
1008 | + "Toolbox has background image.",
|
|
1009 | + prop,
|
|
1010 | + headerImage
|
|
1011 | + );
|
|
1012 | + break;
|
|
1013 | + }
|
|
1014 | + }
|
|
1015 | + }
|
|
1016 | + if (!toolboxHasBackgroundImage) {
|
|
1017 | + lazy.logConsole.debug("Toolbox background used.");
|
|
1018 | + colorRGBA = this._composeRGBA(
|
|
1019 | + colorRGBA,
|
|
1020 | + this._convertToRGBA(win, style, "--toolbox-bgcolor")
|
|
1021 | + );
|
|
1022 | + if (colorRGBA.a === 1) {
|
|
1023 | + return colorRGBA;
|
|
1024 | + }
|
|
1025 | + }
|
|
1026 | + |
|
1027 | + // Determine whether the urlbar is dark.
|
|
1028 | + // At this point, the urlbar background has some transparency, likely on top
|
|
1029 | + // of an image.
|
|
1030 | + // We use the theme's text colour to figure out whether the urlbar
|
|
1031 | + // background is overall meant to be light or dark. Unlike the urlbar, we
|
|
1032 | + // expect this colour to be (almost) opaque.
|
|
1033 | + const textRGBA = this._convertToRGBA(win, style, "--toolbar-field-color");
|
|
1034 | + const textColor = new lazy.Color(textRGBA.r, textRGBA.g, textRGBA.b);
|
|
1035 | + if (textColor.relativeLuminance >= 0.5) {
|
|
1036 | + // Light text, so assume it has a dark background.
|
|
1037 | + // Combine with a generic opaque dark colour. Copied from "frame" for the
|
|
1038 | + // built-in dark theme.
|
|
1039 | + lazy.logConsole.debug("Generic dark background used.");
|
|
1040 | + const darkFrameRGBA = { r: 28, g: 27, b: 34, a: 1 };
|
|
1041 | + return this._composeRGBA(colorRGBA, darkFrameRGBA);
|
|
1042 | + }
|
|
1043 | + // Combine with an opaque light colour. Copied from "frame" for the built-in
|
|
1044 | + // light theme.
|
|
1045 | + lazy.logConsole.debug("Generic light background used.");
|
|
1046 | + const lightFrameRGBA = { r: 234, g: 234, b: 237, a: 1 };
|
|
1047 | + return this._composeRGBA(colorRGBA, lightFrameRGBA);
|
|
1048 | + }
|
|
1049 | + |
|
1050 | + /**
|
|
1051 | + * Update the Letterboxing colors and related classes, or clear them if
|
|
1052 | + * Letterboxing is not enabled.
|
|
1053 | + *
|
|
1054 | + * @param {Window} win - The window to update the colors for.
|
|
1055 | + * @param {boolean} letterboxingEnabled - Whether Letterboxing is enabled.
|
|
1056 | + */
|
|
1057 | + _updateLetterboxingColors(win, letterboxingEnabled) {
|
|
1058 | + let urlbarBackgroundRGBA;
|
|
1059 | + let urlbarTextRGBA;
|
|
1060 | + let contentSeparatorRGBA;
|
|
1061 | + let urlbarBackgroundDark = false;
|
|
1062 | + let lowBackgroundOutlineContrast = false;
|
|
1063 | + |
|
1064 | + if (letterboxingEnabled) {
|
|
1065 | + // Want the effective colour of various elements without any alpha values
|
|
1066 | + // so they can be used consistently.
|
|
1067 | + const navbarStyle = win.getComputedStyle(
|
|
1068 | + win.document.getElementById("nav-bar")
|
|
1069 | + );
|
|
1070 | + const containerRGBA = this._calculateUrlbarContainerColor(
|
|
1071 | + win,
|
|
1072 | + navbarStyle
|
|
1073 | + );
|
|
1074 | + urlbarBackgroundRGBA = this._composeRGBA(
|
|
1075 | + this._convertToRGBA(
|
|
1076 | + win,
|
|
1077 | + navbarStyle,
|
|
1078 | + "--toolbar-field-background-color"
|
|
1079 | + ),
|
|
1080 | + containerRGBA
|
|
1081 | + );
|
|
1082 | + urlbarTextRGBA = this._composeRGBA(
|
|
1083 | + this._convertToRGBA(win, navbarStyle, "--toolbar-field-color"),
|
|
1084 | + urlbarBackgroundRGBA
|
|
1085 | + );
|
|
1086 | + /* Separator between the urlbar container #nav-bar and the tabbox. */
|
|
1087 | + const tabboxStyle = win.getComputedStyle(win.gBrowser.tabbox);
|
|
1088 | + contentSeparatorRGBA = this._composeRGBA(
|
|
1089 | + this._convertToRGBA(
|
|
1090 | + win,
|
|
1091 | + tabboxStyle,
|
|
1092 | + "--chrome-content-separator-color"
|
|
1093 | + ),
|
|
1094 | + containerRGBA
|
|
1095 | + );
|
|
1096 | + const bgColor = new lazy.Color(
|
|
1097 | + urlbarBackgroundRGBA.r,
|
|
1098 | + urlbarBackgroundRGBA.g,
|
|
1099 | + urlbarBackgroundRGBA.b
|
|
1100 | + );
|
|
1101 | + const outlineColor = new lazy.Color(
|
|
1102 | + contentSeparatorRGBA.r,
|
|
1103 | + contentSeparatorRGBA.g,
|
|
1104 | + contentSeparatorRGBA.b
|
|
1105 | + );
|
|
1106 | + const contrastRatio = bgColor.contrastRatio(outlineColor);
|
|
1107 | + lazy.logConsole.debug(
|
|
1108 | + "Outline-background contrast ratio.",
|
|
1109 | + contrastRatio
|
|
1110 | + );
|
|
1111 | + urlbarBackgroundDark = bgColor.relativeLuminance < 0.5;
|
|
1112 | + /* Very low contrast ratio. For reference the default light theme has
|
|
1113 | + * a contrast ratio of ~1.1. */
|
|
1114 | + lowBackgroundOutlineContrast = contrastRatio < 1.05;
|
|
1115 | + }
|
|
1116 | + for (const { name, colorRGBA } of [
|
|
1117 | + {
|
|
1118 | + name: "--letterboxing-urlbar-text-color",
|
|
1119 | + colorRGBA: urlbarTextRGBA,
|
|
1120 | + },
|
|
1121 | + {
|
|
1122 | + name: "--letterboxing-urlbar-background-color",
|
|
1123 | + colorRGBA: urlbarBackgroundRGBA,
|
|
1124 | + },
|
|
1125 | + {
|
|
1126 | + name: "--letterboxing-content-separator-color",
|
|
1127 | + colorRGBA: contentSeparatorRGBA,
|
|
1128 | + },
|
|
1129 | + ]) {
|
|
1130 | + if (letterboxingEnabled) {
|
|
1131 | + win.gBrowser.tabbox.style.setProperty(
|
|
1132 | + name,
|
|
1133 | + `rgb(${colorRGBA.r}, ${colorRGBA.g}, ${colorRGBA.b})`
|
|
1134 | + );
|
|
1135 | + } else {
|
|
1136 | + win.gBrowser.tabbox.style.removeProperty(name);
|
|
1137 | + }
|
|
1138 | + }
|
|
1139 | + win.gBrowser.tabbox.classList.toggle(
|
|
1140 | + "letterboxing-urlbar-background-dark",
|
|
1141 | + urlbarBackgroundDark
|
|
1142 | + );
|
|
1143 | + win.gBrowser.tabbox.classList.toggle(
|
|
1144 | + "letterboxing-low-background-outline-contrast",
|
|
1145 | + lowBackgroundOutlineContrast
|
|
1146 | + );
|
|
872 | 1147 | }
|
873 | 1148 | |
874 | 1149 | _detachWindow(aWindow) {
|
... | ... | @@ -886,7 +1161,7 @@ class _RFPHelper { |
886 | 1161 | aWindow.removeEventListener("TabOpen", this);
|
887 | 1162 | |
888 | 1163 | // revert tabpanel's style to default
|
889 | - tabBrowser.tabpanels?.classList.remove("letterboxing");
|
|
1164 | + tabBrowser.tabbox.classList.remove("letterboxing");
|
|
890 | 1165 | |
891 | 1166 | // and restore default size on each browser element
|
892 | 1167 | for (let tab of tabBrowser.tabs) {
|
... | ... | @@ -896,6 +1171,9 @@ class _RFPHelper { |
896 | 1171 | aWindow.removeEventListener("dblclick", this._onWindowDoubleClick);
|
897 | 1172 | delete aWindow.shrinkToLetterbox;
|
898 | 1173 | aWindow.removeEventListener("sizemodechange", windowResizeHandler);
|
1174 | + |
|
1175 | + aWindow.removeEventListener("nativethemechange", this);
|
|
1176 | + this._updateLetterboxingColors(aWindow, false);
|
|
899 | 1177 | }
|
900 | 1178 | |
901 | 1179 | _handleDOMWindowOpened(win) {
|
... | ... | @@ -7,17 +7,106 @@ |
7 | 7 | * RFPHelper.sys.mjs (LETTERBOX_CSS_SELECTOR and LETTERBOX_CSS_URL,
|
8 | 8 | * respectively), where --letterboxing-width & --letterboxing-height are
|
9 | 9 | * actually set.
|
10 | + * Keep this block first and separate to the rules that do not necessarily
|
|
11 | + * require --letterboxing-width or --letterboxing-height.
|
|
10 | 12 | */
|
11 | 13 | .letterboxing {
|
12 | - --letterboxing-bgcolor: var(--tabpanel-background-color);
|
|
13 | - --letterboxing-border-radius: 8px;
|
|
14 | - --letterboxing-border-top-radius: 0;
|
|
14 | + .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
|
|
15 | + width: var(--letterboxing-width) !important;
|
|
16 | + height: var(--letterboxing-height) !important;
|
|
17 | + }
|
|
18 | +}
|
|
19 | + |
|
20 | +#tabbrowser-tabbox.letterboxing {
|
|
21 | + --letterboxing-bgcolor: var(--background-color-canvas);
|
|
22 | + /* Match the border radius used for the sidebar. */
|
|
23 | + --letterboxing-border-radius: var(--border-radius-medium);
|
|
24 | + --letterboxing-border-radius-top: 0;
|
|
15 | 25 | --letterboxing-vertical-alignment: start;
|
16 | - --letterboxing-shadow-color: rgba(12, 12, 13, 0.10);
|
|
17 | - --letterboxing-gradient-color1: var(--letterboxing-bgcolor);
|
|
18 | - --letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
|
|
19 | - --letterboxing-border-color: var(--letterboxing-bgcolor);
|
|
20 | - --letterboxing-decorator-visibility: visible;
|
|
26 | + --letterboxing-shadow: none;
|
|
27 | + --letterboxing-outline-color: var(--border-color);
|
|
28 | + --letterboxing-outline-width: 1px;
|
|
29 | + |
|
30 | + @media not ((prefers-contrast) or (forced-colors)) {
|
|
31 | + /* Match the #sidebar outline width. */
|
|
32 | + --letterboxing-outline-width: 0.5px;
|
|
33 | + --letterboxing-shadow-color: rgba(58, 57, 68, 0.20);
|
|
34 | + --letterboxing-shadow: 0 2px 14px 0 var(--letterboxing-shadow-color);
|
|
35 | + |
|
36 | + /* Match the effective urlbar background colour. */
|
|
37 | + --letterboxing-bgcolor: var(--letterboxing-urlbar-background-color);
|
|
38 | + /* Match the effective colour of the separator between the urlbar container
|
|
39 | + * and the content. */
|
|
40 | + --letterboxing-outline-color: var(--letterboxing-content-separator-color);
|
|
41 | + |
|
42 | + &.letterboxing-urlbar-background-dark {
|
|
43 | + --letterboxing-shadow-color: #15141a;
|
|
44 | + }
|
|
45 | + |
|
46 | + &.letterboxing-low-background-outline-contrast {
|
|
47 | + /* The default content separator colour has insufficient contrast. */
|
|
48 | + --letterboxing-outline-color: color-mix(in srgb, var(--letterboxing-content-separator-color) 90%, black);
|
|
49 | + |
|
50 | + &.letterboxing-urlbar-background-dark {
|
|
51 | + /* Lighten the colour. */
|
|
52 | + --letterboxing-outline-color: color-mix(in srgb, var(--letterboxing-content-separator-color) 90%, white);
|
|
53 | + }
|
|
54 | + }
|
|
55 | + }
|
|
56 | + |
|
57 | + @media (prefers-contrast) and (not (forced-colors)) {
|
|
58 | + :root[lwtheme] & {
|
|
59 | + /* User with prefers-contrast coming from the system settings, but also an
|
|
60 | + * installed theme. */
|
|
61 | + --letterboxing-bgcolor: var(--letterboxing-urlbar-background-color);
|
|
62 | + /* Presumably a user with prefers-contrast and a custom theme has chosen
|
|
63 | + * a theme where the contrast between the urlbar and the text is
|
|
64 | + * sufficiently high or low. */
|
|
65 | + --letterboxing-outline-color: var(--letterboxing-urlbar-text-color);
|
|
66 | + }
|
|
67 | + }
|
|
68 | + |
|
69 | + background: var(--letterboxing-bgcolor);
|
|
70 | + |
|
71 | + &:has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-outline) {
|
|
72 | + /* Letterboxing outline is visible for the current tab. Replace the usual
|
|
73 | + * outline to match the Letterboxing outline. For most scenarios, this
|
|
74 | + * should be mostly the same colour as when Letterboxing is not visible. But
|
|
75 | + * it may make a difference for some theme combinations. */
|
|
76 | + outline-color: var(--letterboxing-outline-color);
|
|
77 | + outline-width: var(--letterboxing-outline-width);
|
|
78 | + }
|
|
79 | + |
|
80 | + #tabbrowser-tabpanels {
|
|
81 | + /* Override the --tabpanel-background-color.
|
|
82 | + * Also, make sure this remains transparent, otherwise it will overlap the
|
|
83 | + * parent's corner's border-radius due to it's "position: relative" rule. */
|
|
84 | + /* TODO: FIX this for newtab pages. tor-browser#44085 */
|
|
85 | + background: transparent;
|
|
86 | + }
|
|
87 | + |
|
88 | + /* stylelint-disable-next-line media-query-no-invalid */
|
|
89 | + @media -moz-pref("sidebar.revamp") {
|
|
90 | + :root:not([inDOMFullscreen]) &[sidebar-shown]:not(.letterboxing-nav-toolbox-hidden):is(
|
|
91 | + /* When the Letterboxing area is aligned to the top, show the rounded
|
|
92 | + * corner if there is enough vertical space between the sidebar and the
|
|
93 | + * browser element, which is not rounded at the top. */
|
|
94 | + :not(.letterboxing-vcenter):has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-sidebar-corner),
|
|
95 | + /* When the Letterboxing area is aligned to the centre, show the rounded
|
|
96 | + * corner if the Letterboxing border is shown. */
|
|
97 | + .letterboxing-vcenter:has(.deck-selected .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing).letterboxing-show-outline)
|
|
98 | + ) {
|
|
99 | + /* stylelint-disable-next-line media-query-no-invalid */
|
|
100 | + @media -moz-pref("sidebar.position_start") {
|
|
101 | + border-start-start-radius: var(--letterboxing-border-radius);
|
|
102 | + }
|
|
103 | + |
|
104 | + /* stylelint-disable-next-line media-query-no-invalid */
|
|
105 | + @media not -moz-pref("sidebar.position_start") {
|
|
106 | + border-start-end-radius: var(--letterboxing-border-radius);
|
|
107 | + }
|
|
108 | + }
|
|
109 | + }
|
|
21 | 110 | |
22 | 111 | .browserContainer {
|
23 | 112 | /*
|
... | ... | @@ -26,101 +115,71 @@ |
26 | 115 | * doesn't get notified on horizontal shrinking.
|
27 | 116 | */
|
28 | 117 | overflow: hidden;
|
29 | - background: var(--letterboxing-bgcolor);
|
|
30 | 118 | }
|
31 | 119 | |
32 | - .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
|
|
33 | - box-shadow: 0 4px 8px 0 var(--letterboxing-shadow-color);
|
|
34 | - border-radius: var(--letterboxing-border-radius);
|
|
35 | - border-top-left-radius: var(--letterboxing-border-top-radius);
|
|
36 | - border-top-right-radius: var(--letterboxing-border-top-radius);
|
|
37 | - width: var(--letterboxing-width) !important;
|
|
38 | - height: var(--letterboxing-height) !important;
|
|
39 | - background: var(--letterboxing-gradient-color2);
|
|
120 | + &.letterboxing-vcenter {
|
|
121 | + --letterboxing-border-radius-top: var(--letterboxing-border-radius);
|
|
122 | + --letterboxing-vertical-alignment: center;
|
|
40 | 123 | }
|
41 | 124 | }
|
42 | 125 | |
43 | -:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
|
|
44 | - > .browserStack:not(.exclude-letterboxing) {
|
|
45 | - place-content: start center;
|
|
46 | -}
|
|
47 | - |
|
48 | -.browserDecorator {
|
|
49 | - display: none;
|
|
50 | - pointer-events: none;
|
|
51 | - background: transparent;
|
|
52 | - position: relative;
|
|
53 | - z-index: 1;
|
|
54 | -}
|
|
126 | +.browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
|
|
127 | + :root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready & {
|
|
128 | + place-content: var(--letterboxing-vertical-alignment) center;
|
|
129 | + }
|
|
55 | 130 | |
56 | -.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
|
|
57 | - --letterboxing-border-top-radius: var(--letterboxing-border-radius);
|
|
58 | - --letterboxing-vertical-alignment: center;
|
|
59 | -}
|
|
131 | + :root:not([inDOMFullscreen]) .letterboxing &.letterboxing-show-outline {
|
|
132 | + browser {
|
|
133 | + /* We use clip-path rather than border-radius because border-radius on its
|
|
134 | + * own leads to rendering artefacts in the corners (tested with GNOME).
|
|
135 | + * See tor-browser#44214 (comment 3262962). */
|
|
136 | + /* TODO: Use border-radius once bugzilla bug 1991874 is resolved. */
|
|
137 | + 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));
|
|
138 | + }
|
|
60 | 139 | |
61 | -.letterboxing.letterboxing-gradient .browserContainer {
|
|
62 | - background: linear-gradient(283deg, var(--letterboxing-gradient-color1) 0%, var(--letterboxing-gradient-color2) 100%), var(--letterboxing-bgcolor);
|
|
63 | -}
|
|
140 | + .browserDecorator {
|
|
141 | + /* Need a separate browserDecorator element because the clip-path on the
|
|
142 | + * browser would exclude the outline and box-shadow. */
|
|
143 | + /* TODO: Move these rules to the browser element once bugzilla bug 1991874
|
|
144 | + * is resolved, and drop browserDecorator. */
|
|
145 | + display: block;
|
|
146 | + border-radius: var(--letterboxing-border-radius-top) var(--letterboxing-border-radius-top) var(--letterboxing-border-radius) var(--letterboxing-border-radius);
|
|
147 | + /* NOTE: The top outline will not be visible when this is aligned to the
|
|
148 | + * top. */
|
|
149 | + outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color);
|
|
150 | + box-shadow: var(--letterboxing-shadow);
|
|
151 | + }
|
|
64 | 152 | |
65 | -:root:not([inDOMFullscreen]) .letterboxing .browserContainer:not(.responsive-mode)
|
|
66 | - > .browserStack:not(.exclude-letterboxing)
|
|
67 | - > .browserDecorator {
|
|
68 | - display: initial;
|
|
69 | - visibility: var(--letterboxing-decorator-visibility);
|
|
70 | - border-radius: var(--letterboxing-border-radius);
|
|
71 | - border-top-left-radius: var(--letterboxing-border-top-radius);
|
|
72 | - border-top-right-radius: var(--letterboxing-border-top-radius);
|
|
73 | - box-shadow: var(--letterboxing-border-color) 0 0 .1px inset, var(--letterboxing-border-color) 0 0 .1px;
|
|
74 | - border: .1px solid var(--letterboxing-border-color);
|
|
75 | - outline: .1px solid var(--letterboxing-bgcolor);
|
|
76 | - height: calc(var(--letterboxing-height) + 1px);
|
|
77 | - top: -1px;
|
|
78 | -}
|
|
153 | + #statuspanel:not([mirror]) #statuspanel-label {
|
|
154 | + border-end-start-radius: var(--letterboxing-border-radius);
|
|
155 | + }
|
|
79 | 156 | |
80 | -.letterboxing-vcenter .browserDecorator {
|
|
81 | - height: auto !important;
|
|
82 | - top: 0 !important;
|
|
83 | -}
|
|
157 | + #statuspanel[mirror] #statuspanel-label {
|
|
158 | + border-end-end-radius: var(--letterboxing-border-radius);
|
|
159 | + }
|
|
160 | + }
|
|
84 | 161 | |
85 | -/*
|
|
86 | - Align status bar with content.
|
|
87 | - TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
|
|
88 | -*/
|
|
89 | -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
|
|
90 | - > #statuspanel:not([hidden]) {
|
|
91 | - position: relative;
|
|
92 | - place-self: end left;
|
|
93 | - left: 0;
|
|
94 | - right: 0;
|
|
95 | - z-index: 2;
|
|
96 | - --letterboxing-status-left-radius: var(--letterboxing-border-radius);
|
|
97 | - --letterboxing-status-right-radius: 0;
|
|
98 | -}
|
|
99 | -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
|
|
100 | - > #statuspanel:not([mirror]):-moz-locale-dir(rtl),
|
|
101 | -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
|
|
102 | - > #statuspanel[mirror]:-moz-locale-dir(ltr) {
|
|
103 | - left: 0;
|
|
104 | - right: 0;
|
|
105 | - --letterboxing-status-right-radius: var(--letterboxing-border-radius);
|
|
106 | - --letterboxing-status-left-radius: 0;
|
|
107 | - justify-self: right;
|
|
108 | -}
|
|
162 | + #statuspanel {
|
|
163 | + position: relative;
|
|
164 | + place-self: end start;
|
|
165 | + z-index: 2;
|
|
109 | 166 | |
110 | -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
|
|
111 | -#statuspanel-label {
|
|
112 | - border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
|
|
113 | - margin: 0;
|
|
114 | - border: 1px solid var(--letterboxing-border-color);
|
|
115 | - max-width: calc(var(--letterboxing-width) * .5);
|
|
116 | -}
|
|
167 | + &[mirror] {
|
|
168 | + justify-self: end;
|
|
169 | + }
|
|
170 | + }
|
|
117 | 171 | |
118 | -browser:fullscreen {
|
|
119 | - --letterboxing-border-top-radius: 0;
|
|
120 | - --letterboxing-border-radius: 0;
|
|
172 | + #statuspanel-label {
|
|
173 | + margin: 0;
|
|
174 | + outline: var(--letterboxing-outline-width) solid var(--letterboxing-outline-color);
|
|
175 | + max-width: calc(var(--letterboxing-width) * .5);
|
|
176 | + }
|
|
121 | 177 | }
|
122 | 178 | |
123 | -:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
|
|
124 | - > .browserStack:not(.exclude-letterboxing) {
|
|
125 | - place-content: var(--letterboxing-vertical-alignment) center;
|
|
179 | +.browserDecorator {
|
|
180 | + display: none;
|
|
181 | + pointer-events: none;
|
|
182 | + background: transparent;
|
|
183 | + position: relative;
|
|
184 | + z-index: 1;
|
|
126 | 185 | } |