tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6e07030e5f86a3f1e512c72b55967f06c5bcf479
parent 805fffea427c8d3be92e8465828bfd361043a33b
Author: Carlos Jeurissen <carlos-mozilla@jeurissen.co>
Date:   Tue,  6 Jan 2026 15:42:15 +0000

Bug 1994948 - prefer theme_icons.dark for default themes r=robwu,desktop-theme-reviewers,jsudiaman,emilio

Swaps the internal "dark" and "light" property names to match the conventions of dark/light scheme, and now uses theme_icons.dark instead of default_icon for default light themes.

Differential Revision: https://phabricator.services.mozilla.com/D270302

Diffstat:
Mbrowser/components/extensions/parent/ext-browserAction.js | 46+++++++++++++++++++++++++---------------------
Mbrowser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js | 17+++++++++--------
Mbrowser/components/extensions/test/browser/browser_ext_browserAction_theme_icons.js | 174+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mbrowser/components/sidebar/browser-sidebar.js | 2++
Mbrowser/themes/shared/addons/unified-extensions.css | 11++---------
Mtoolkit/components/extensions/ExtensionParent.sys.mjs | 9+++++----
6 files changed, 128 insertions(+), 131 deletions(-)

diff --git a/browser/components/extensions/parent/ext-browserAction.js b/browser/components/extensions/parent/ext-browserAction.js @@ -913,37 +913,41 @@ this.browserAction = class extends ExtensionAPIPersistent { } getIconData(icons) { - let getIcon = (icon, theme) => { + const getIcon = (icon, theme) => { if (typeof icon === "object") { return IconDetails.escapeUrl(icon[theme]); } return IconDetails.escapeUrl(icon); }; - let getStyle = (name, icon1x, icon2x) => { - return ` - --webextension-${name}: image-set( - url("${getIcon(icon1x, "default")}"), - url("${getIcon(icon2x, "default")}") 2x - ); - --webextension-${name}-light: image-set( - url("${getIcon(icon1x, "light")}"), - url("${getIcon(icon2x, "light")}") 2x - ); - --webextension-${name}-dark: image-set( - url("${getIcon(icon1x, "dark")}"), - url("${getIcon(icon2x, "dark")}") 2x - ); - `; + const getBackgroundImage = (icon1x, icon2x = icon1x) => { + const image1x = `url("${icon1x}")`; + if (icon2x === icon1x) { + return image1x; + } + + const image2x = `url("${icon2x}")`; + return `image-set(${image1x} 1dppx, ${image2x} 2dppx);`; + }; + + const getStyle = (cssVarName, icon1x, icon2x) => { + return `${cssVarName}: ${getBackgroundImage( + getIcon(icon1x, "light"), + getIcon(icon2x, "light") + )}; + ${cssVarName}-dark: ${getBackgroundImage( + getIcon(icon1x, "dark"), + getIcon(icon2x, "dark") + )};`; }; - let icon16 = IconDetails.getPreferredIcon(icons, this.extension, 16).icon; - let icon32 = IconDetails.getPreferredIcon(icons, this.extension, 32).icon; - let icon64 = IconDetails.getPreferredIcon(icons, this.extension, 64).icon; + const icon16 = IconDetails.getPreferredIcon(icons, this.extension, 16).icon; + const icon32 = IconDetails.getPreferredIcon(icons, this.extension, 32).icon; + const icon64 = IconDetails.getPreferredIcon(icons, this.extension, 64).icon; return ` - ${getStyle("menupanel-image", icon32, icon64)} - ${getStyle("toolbar-image", icon16, icon32)} + ${getStyle("--webextension-menupanel-image", icon32, icon64)} + ${getStyle("--webextension-toolbar-image", icon16, icon32)} `; } diff --git a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js @@ -3,16 +3,17 @@ "use strict"; function testHiDpiImage(button, images1x, images2x, prop) { - let image = getRawListStyleImage(button); + const image = getRawListStyleImage(button); info(image); info(button.outerHTML); - let image1x = images1x[prop]; - let image2x = images2x[prop]; - is( - image, - `image-set(url("${image1x}") 1dppx, url("${image2x}") 2dppx)`, - prop - ); + const image1x = images1x[prop]; + const image2x = images2x[prop]; + const backgroundImage = + image1x === image2x && prop === "browserActionImageURL" + ? `url("${image1x}")` + : `image-set(url("${image1x}") 1dppx, url("${image2x}") 2dppx)`; + + is(image, backgroundImage, prop); } // Test that various combinations of icon details specs, for both paths diff --git a/browser/components/extensions/test/browser/browser_ext_browserAction_theme_icons.js b/browser/components/extensions/test/browser/browser_ext_browserAction_theme_icons.js @@ -17,21 +17,25 @@ const TOOLBAR_MAPPING = { tabstrip: "TabsToolbar", }; +const DEFAULT_ICON = "default.png"; +const LIGHT_THEME_ICON = "black.png"; +const DARK_THEME_ICON = "white.png"; + async function testBrowserAction(extension, expectedIcon) { - let browserActionWidget = getBrowserActionWidget(extension); + const browserActionWidget = getBrowserActionWidget(extension); await promiseAnimationFrame(); - let browserActionButton = browserActionWidget + const browserActionButton = browserActionWidget .forWindow(window) .node.querySelector(".unified-extensions-item-action-button"); - let image = getListStyleImage(browserActionButton); + const image = getListStyleImage(browserActionButton); ok( - image.includes(expectedIcon), + image?.includes(expectedIcon), `Expected browser action icon (${image}) to be ${expectedIcon}` ); } async function testStaticTheme(options) { - let { + const { themeData, themeIcons, withDefaultIcon, @@ -39,7 +43,7 @@ async function testStaticTheme(options) { defaultArea = "navbar", } = options; - let manifest = { + const manifest = { browser_action: { theme_icons: themeIcons, default_area: defaultArea, @@ -47,17 +51,17 @@ async function testStaticTheme(options) { }; if (withDefaultIcon) { - manifest.browser_action.default_icon = "default.png"; + manifest.browser_action.default_icon = DEFAULT_ICON; } - let extension = ExtensionTestUtils.loadExtension({ manifest }); + const extension = ExtensionTestUtils.loadExtension({ manifest }); await extension.startup(); // Ensure we show the menupanel at least once. This makes sure that the // elements we're going to query the style of are in the flat tree. if (defaultArea == "menupanel") { - let shown = BrowserTestUtils.waitForPopupEvent( + const shown = BrowserTestUtils.waitForPopupEvent( window.gUnifiedExtensions.panel, "shown" ); @@ -66,17 +70,15 @@ async function testStaticTheme(options) { } // Confirm that the browser action has the correct default icon before a theme is loaded. - let toolbarId = TOOLBAR_MAPPING[defaultArea]; - let expectedDefaultIcon; + const toolbarId = TOOLBAR_MAPPING[defaultArea]; + // Some platforms have dark toolbars by default, take it in account when picking the default icon. - if ( - toolbarId && - document.getElementById(toolbarId).hasAttribute("brighttext") - ) { - expectedDefaultIcon = "light.png"; - } else { - expectedDefaultIcon = withDefaultIcon ? "default.png" : "dark.png"; - } + const hasDarkToolbar = + toolbarId && document.getElementById(toolbarId).hasAttribute("brighttext"); + const expectedDefaultIcon = hasDarkToolbar + ? DARK_THEME_ICON + : LIGHT_THEME_ICON; + if (Services.appinfo.nativeMenubar) { ok( !document.getElementById("toolbar-menubar").hasAttribute("brighttext"), @@ -85,7 +87,7 @@ async function testStaticTheme(options) { } await testBrowserAction(extension, expectedDefaultIcon); - let theme = ExtensionTestUtils.loadExtension({ + const theme = ExtensionTestUtils.loadExtension({ manifest: { theme: { colors: themeData, @@ -96,13 +98,7 @@ async function testStaticTheme(options) { await theme.startup(); // Confirm that the correct icon is used when the theme is loaded. - if (expectedIcon == "dark") { - // The dark icon should be used if the area is light. - await testBrowserAction(extension, "dark.png"); - } else { - // The light icon should be used if the area is dark. - await testBrowserAction(extension, "light.png"); - } + await testBrowserAction(extension, expectedIcon); await theme.unload(); @@ -115,11 +111,11 @@ async function testStaticTheme(options) { add_task(async function browseraction_theme_icons_light_theme() { await testStaticTheme({ themeData: LIGHT_THEME_COLORS, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -127,16 +123,16 @@ add_task(async function browseraction_theme_icons_light_theme() { }); await testStaticTheme({ themeData: LIGHT_THEME_COLORS, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -147,11 +143,11 @@ add_task(async function browseraction_theme_icons_light_theme() { add_task(async function browseraction_theme_icons_dark_theme() { await testStaticTheme({ themeData: DARK_THEME_COLORS, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -159,16 +155,16 @@ add_task(async function browseraction_theme_icons_dark_theme() { }); await testStaticTheme({ themeData: DARK_THEME_COLORS, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -177,7 +173,7 @@ add_task(async function browseraction_theme_icons_dark_theme() { }); add_task(async function browseraction_theme_icons_different_toolbars() { - let themeData = { + const themeData = { frame: "#000", tab_background_text: "#fff", toolbar: "#fff", @@ -185,11 +181,11 @@ add_task(async function browseraction_theme_icons_different_toolbars() { }; await testStaticTheme({ themeData, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -197,28 +193,28 @@ add_task(async function browseraction_theme_icons_different_toolbars() { }); await testStaticTheme({ themeData, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], }); await testStaticTheme({ themeData, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, defaultArea: "tabstrip", themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -226,17 +222,17 @@ add_task(async function browseraction_theme_icons_different_toolbars() { }); await testStaticTheme({ themeData, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, defaultArea: "tabstrip", themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -244,17 +240,17 @@ add_task(async function browseraction_theme_icons_different_toolbars() { }); add_task(async function browseraction_theme_icons_overflow_panel() { - let themeData = { + const themeData = { popup: "#000", popup_text: "#fff", }; await testStaticTheme({ themeData, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -262,16 +258,16 @@ add_task(async function browseraction_theme_icons_overflow_panel() { }); await testStaticTheme({ themeData, - expectedIcon: "dark", + expectedIcon: LIGHT_THEME_ICON, themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -279,12 +275,12 @@ add_task(async function browseraction_theme_icons_overflow_panel() { await testStaticTheme({ themeData, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, defaultArea: "menupanel", themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 19, }, ], @@ -292,17 +288,17 @@ add_task(async function browseraction_theme_icons_overflow_panel() { }); await testStaticTheme({ themeData, - expectedIcon: "light", + expectedIcon: DARK_THEME_ICON, defaultArea: "menupanel", themeIcons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -310,7 +306,7 @@ add_task(async function browseraction_theme_icons_overflow_panel() { }); add_task(async function browseraction_theme_icons_dynamic_theme() { - let themeExtension = ExtensionTestUtils.loadExtension({ + const themeExtension = ExtensionTestUtils.loadExtension({ manifest: { permissions: ["theme"], }, @@ -328,20 +324,20 @@ add_task(async function browseraction_theme_icons_dynamic_theme() { await themeExtension.startup(); - let extension = ExtensionTestUtils.loadExtension({ + const extension = ExtensionTestUtils.loadExtension({ manifest: { browser_action: { - default_icon: "default.png", + default_icon: DEFAULT_ICON, default_area: "navbar", theme_icons: [ { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 16, }, { - light: "light.png", - dark: "dark.png", + dark: LIGHT_THEME_ICON, + light: DARK_THEME_ICON, size: 32, }, ], @@ -352,27 +348,27 @@ add_task(async function browseraction_theme_icons_dynamic_theme() { await extension.startup(); // Confirm that the browser action has the default icon before a theme is set. - await testBrowserAction(extension, "default.png"); + await testBrowserAction(extension, LIGHT_THEME_ICON); // Update the theme to a light theme. themeExtension.sendMessage("update-theme", LIGHT_THEME_COLORS); await themeExtension.awaitMessage("theme-updated"); // Confirm that the dark icon is used for the light theme. - await testBrowserAction(extension, "dark.png"); + await testBrowserAction(extension, LIGHT_THEME_ICON); // Update the theme to a dark theme. themeExtension.sendMessage("update-theme", DARK_THEME_COLORS); await themeExtension.awaitMessage("theme-updated"); // Confirm that the light icon is used for the dark theme. - await testBrowserAction(extension, "light.png"); + await testBrowserAction(extension, DARK_THEME_ICON); // Unload the theme. await themeExtension.unload(); - // Confirm that the default icon is used when the theme is unloaded. - await testBrowserAction(extension, "default.png"); + // Confirm that the light icon is used when the theme is unloaded. + await testBrowserAction(extension, LIGHT_THEME_ICON); await extension.unload(); }); diff --git a/browser/components/sidebar/browser-sidebar.js b/browser/components/sidebar/browser-sidebar.js @@ -1764,6 +1764,8 @@ var SidebarController = { sidebar.label = label; const updateAttributes = el => { + // TODO Bug 1996762 - Add support for dark-theme sidebar icons + // --webextension-menuitem-image-dark is used in dark themes el.style.setProperty("--webextension-menuitem-image", sidebar.icon); el.setAttribute("label", sidebar.label); }; diff --git a/browser/themes/shared/addons/unified-extensions.css b/browser/themes/shared/addons/unified-extensions.css @@ -119,20 +119,13 @@ unified-extensions-item { list-style-image: var(--webextension-toolbar-image, inherit); toolbar[brighttext] & { - list-style-image: var(--webextension-toolbar-image-light, inherit); - } - :root[lwtheme] toolbar:not([brighttext]) & { + /* separate image used for dark toolbars */ list-style-image: var(--webextension-toolbar-image-dark, inherit); } toolbaritem:is([overflowedItem="true"], [cui-areatype="panel"]) > .unified-extensions-item-row-wrapper > & { list-style-image: var(--webextension-menupanel-image, inherit); - /* TODO: This feels a bit odd, why do we have three images? It feels we - * should probably have only two (light/dark), and choose based on - * prefers-color-scheme + lwt-popup */ :root[lwt-popup="dark"] & { - list-style-image: var(--webextension-menupanel-image-light, inherit); - } - :root[lwt-popup="light"] & { + /* separate image used for dark toolbars */ list-style-image: var(--webextension-menupanel-image-dark, inherit); } } diff --git a/toolkit/components/extensions/ExtensionParent.sys.mjs b/toolkit/components/extensions/ExtensionParent.sys.mjs @@ -2151,15 +2151,16 @@ let IconDetails = { if (themeIcons) { themeIcons.forEach(({ size, light, dark }) => { - let lightURL = baseURI.resolve(light); - let darkURL = baseURI.resolve(dark); + // light and dark are reversed. theme_icons specifies + // the color of the icon instead of the toolbar color + const lightURL = baseURI.resolve(dark); + const darkURL = baseURI.resolve(light); this._checkURL(lightURL, extension); this._checkURL(darkURL, extension); - let defaultURL = result[size] || result[19]; // always fallback to default first result[size] = { - default: defaultURL || darkURL, // Fallback to the dark url if no default is specified. + default: lightURL, // TODO bug 2008737: Remove default property. light: lightURL, dark: darkURL, };