henry pushed to branch tor-browser-140.4.0esr-15.0-1 at The Tor Project / Applications / Tor Browser

Commits:

4 changed files:

Changes:

  • browser/base/content/browser-fullScreenAndPointerLock.js
    ... ... @@ -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
       },
    

  • browser/themes/shared/tabbrowser/content-area.css
    ... ... @@ -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);
    

  • toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
    ... ... @@ -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) {
    

  • toolkit/components/resistfingerprinting/content/letterboxing.css
    ... ... @@ -7,30 +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;
    
    21
    -
    
    22
    -  /* Re-styling for Tor Browser. */
    
    23
    -  /* stylelint-disable declaration-block-no-duplicate-custom-properties */
    
    24
    -  --letterboxing-bgcolor: light-dark(#F0F0F4, #52525E);
    
    25
    -  --letterboxing-gradient-color1: light-dark(
    
    26
    -    rgba(0, 219, 222, 0.02),
    
    27
    -    rgba(0, 219, 222, 0.06)
    
    28
    -  );
    
    29
    -  --letterboxing-gradient-color2: light-dark(
    
    30
    -    rgba(252, 0, 255, 0.02),
    
    31
    -    rgba(252, 0, 255, 0.06)
    
    32
    -  );
    
    33
    -  /* stylelint-enable declaration-block-no-duplicate-custom-properties */
    
    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
    +  }
    
    34 110
     
    
    35 111
       .browserContainer {
    
    36 112
         /*
    
    ... ... @@ -39,101 +115,71 @@
    39 115
          * doesn't get notified on horizontal shrinking.
    
    40 116
          */
    
    41 117
         overflow: hidden;
    
    42
    -    background: var(--letterboxing-bgcolor);
    
    43 118
       }
    
    44 119
     
    
    45
    -  .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
    
    46
    -    box-shadow: 0 4px 8px 0 var(--letterboxing-shadow-color);
    
    47
    -    border-radius: var(--letterboxing-border-radius);
    
    48
    -    border-top-left-radius: var(--letterboxing-border-top-radius);
    
    49
    -    border-top-right-radius: var(--letterboxing-border-top-radius);
    
    50
    -    width: var(--letterboxing-width) !important;
    
    51
    -    height: var(--letterboxing-height) !important;
    
    52
    -    background: var(--letterboxing-gradient-color2);
    
    120
    +  &.letterboxing-vcenter {
    
    121
    +    --letterboxing-border-radius-top: var(--letterboxing-border-radius);
    
    122
    +    --letterboxing-vertical-alignment: center;
    
    53 123
       }
    
    54 124
     }
    
    55 125
     
    
    56
    -:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
    
    57
    -  > .browserStack:not(.exclude-letterboxing) {
    
    58
    -  place-content: start center;
    
    59
    -}
    
    60
    -
    
    61
    -.browserDecorator {
    
    62
    -  display: none;
    
    63
    -  pointer-events: none;
    
    64
    -  background: transparent;
    
    65
    -  position: relative;
    
    66
    -  z-index: 1;
    
    67
    -}
    
    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
    +  }
    
    68 130
     
    
    69
    -.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
    
    70
    -  --letterboxing-border-top-radius: var(--letterboxing-border-radius);
    
    71
    -  --letterboxing-vertical-alignment: center;
    
    72
    -}
    
    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
    +    }
    
    73 139
     
    
    74
    -.letterboxing.letterboxing-gradient .browserContainer {
    
    75
    -  background: linear-gradient(283deg, var(--letterboxing-gradient-color1) 0%, var(--letterboxing-gradient-color2) 100%), var(--letterboxing-bgcolor);
    
    76
    -}
    
    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
    +    }
    
    77 152
     
    
    78
    -:root:not([inDOMFullscreen]) .letterboxing .browserContainer:not(.responsive-mode)
    
    79
    -  > .browserStack:not(.exclude-letterboxing)
    
    80
    -  > .browserDecorator {
    
    81
    -  display: initial;
    
    82
    -  visibility: var(--letterboxing-decorator-visibility);
    
    83
    -  border-radius: var(--letterboxing-border-radius);
    
    84
    -  border-top-left-radius: var(--letterboxing-border-top-radius);
    
    85
    -  border-top-right-radius: var(--letterboxing-border-top-radius);
    
    86
    -  box-shadow: var(--letterboxing-border-color) 0 0 .1px inset, var(--letterboxing-border-color) 0 0 .1px;
    
    87
    -  border: .1px solid var(--letterboxing-border-color);
    
    88
    -  outline: .1px solid var(--letterboxing-bgcolor);
    
    89
    -  height: calc(var(--letterboxing-height) + 1px);
    
    90
    -  top: -1px;
    
    91
    -}
    
    153
    +    #statuspanel:not([mirror]) #statuspanel-label {
    
    154
    +      border-end-start-radius: var(--letterboxing-border-radius);
    
    155
    +    }
    
    92 156
     
    
    93
    -.letterboxing-vcenter .browserDecorator {
    
    94
    -  height: auto !important;
    
    95
    -  top: 0 !important;
    
    96
    -}
    
    157
    +    #statuspanel[mirror] #statuspanel-label {
    
    158
    +      border-end-end-radius: var(--letterboxing-border-radius);
    
    159
    +    }
    
    160
    +  }
    
    97 161
     
    
    98
    -/*
    
    99
    -  Align status bar with content.
    
    100
    -  TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
    
    101
    -*/
    
    102
    -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
    
    103
    -  > #statuspanel:not([hidden]) {
    
    104
    -  position: relative;
    
    105
    -  place-self: end left;
    
    106
    -  left: 0;
    
    107
    -  right: 0;
    
    108
    -  z-index: 2;
    
    109
    -  --letterboxing-status-left-radius: var(--letterboxing-border-radius);
    
    110
    -  --letterboxing-status-right-radius: 0;
    
    111
    -}
    
    112
    -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
    
    113
    -  > #statuspanel:not([mirror]):-moz-locale-dir(rtl),
    
    114
    -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
    
    115
    -  > #statuspanel[mirror]:-moz-locale-dir(ltr) {
    
    116
    -  left: 0;
    
    117
    -  right: 0;
    
    118
    -  --letterboxing-status-right-radius: var(--letterboxing-border-radius);
    
    119
    -  --letterboxing-status-left-radius: 0;
    
    120
    -  justify-self: right;
    
    121
    -}
    
    162
    +  #statuspanel {
    
    163
    +    position: relative;
    
    164
    +    place-self: end start;
    
    165
    +    z-index: 2;
    
    122 166
     
    
    123
    -.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
    
    124
    -#statuspanel-label {
    
    125
    -  border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
    
    126
    -  margin: 0;
    
    127
    -  border: 1px solid var(--letterboxing-border-color);
    
    128
    -  max-width: calc(var(--letterboxing-width) * .5);
    
    129
    -}
    
    167
    +    &[mirror] {
    
    168
    +      justify-self: end;
    
    169
    +    }
    
    170
    +  }
    
    130 171
     
    
    131
    -browser:fullscreen {
    
    132
    -  --letterboxing-border-top-radius: 0;
    
    133
    -  --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
    +  }
    
    134 177
     }
    
    135 178
     
    
    136
    -:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
    
    137
    -  > .browserStack:not(.exclude-letterboxing) {
    
    138
    -  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;
    
    139 185
     }