1
0
Fork 0
firefox/browser/themes/ToolbarIconColor.sys.mjs
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

138 lines
4.5 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Module is used set the "brighttext" attribute to `true` or remove it
* based on calculating a luminance value from the current toolbar color.
* This causes items like icons on the toolbar to contrast in brightness
* enough to be visible, depending on the current theme/coloring of the browser
* window. Calculated luminance values are cached in `state.toolbarLuminanceCache`. */
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
// Track individual windowstates using WeakMap
const _windowStateMap = new WeakMap();
export const ToolbarIconColor = {
init(window) {
if (_windowStateMap.has(window)) {
return;
}
const state = {
active: false,
fullscreen: false,
customtitlebar: false,
toolbarLuminanceCache: new Map(),
};
_windowStateMap.set(window, state);
window.addEventListener("nativethemechange", this);
window.addEventListener("activate", this);
window.addEventListener("deactivate", this);
window.addEventListener("toolbarvisibilitychange", this);
window.addEventListener("windowlwthemeupdate", this);
// If the window isn't active now, we assume that it has never been active
// before and will soon become active such that inferFromText will be
// called from the initial activate event.
if (Services.focus.activeWindow == window) {
this.inferFromText("activate", window);
}
},
uninit(window) {
const state = _windowStateMap.get(window);
if (!state) {
return;
}
window.removeEventListener("nativethemechange", this);
window.removeEventListener("activate", this);
window.removeEventListener("deactivate", this);
window.removeEventListener("toolbarvisibilitychange", this);
window.removeEventListener("windowlwthemeupdate", this);
_windowStateMap.delete(window);
},
handleEvent(event) {
const window = event.target.ownerGlobal;
switch (event.type) {
case "activate":
case "deactivate":
case "nativethemechange":
case "windowlwthemeupdate":
this.inferFromText(event.type, window);
break;
case "toolbarvisibilitychange":
this.inferFromText(event.type, window, event.visible);
break;
}
},
inferFromText(reason, window, reasonValue) {
const state = _windowStateMap.get(window);
if (!state) {
return;
}
switch (reason) {
case "activate": // falls through
case "deactivate":
state.active = reason === "activate";
break;
case "fullscreen":
state.fullscreen = reasonValue;
break;
case "nativethemechange":
case "windowlwthemeupdate":
// theme change, we'll need to recalculate all color values
state.toolbarLuminanceCache.clear();
break;
case "toolbarvisibilitychange":
// toolbar changes dont require reset of the cached color values
break;
case "customtitlebar":
state.customtitlebar = reasonValue;
break;
}
let toolbarSelector = ".browser-toolbar:not([collapsed=true])";
if (AppConstants.platform == "macosx") {
toolbarSelector += ":not([type=menubar])";
}
// The getComputedStyle calls and setting the brighttext are separated in
// two loops to avoid flushing layout and making it dirty repeatedly.
let cachedLuminances = state.toolbarLuminanceCache;
let luminances = new Map();
for (let toolbar of window.document.querySelectorAll(toolbarSelector)) {
// toolbars *should* all have ids, but guard anyway to avoid blowing up
let cacheKey = toolbar.id && toolbar.id + JSON.stringify(state);
// lookup cached luminance value for this toolbar in this window state
let luminance = cacheKey && cachedLuminances.get(cacheKey);
if (isNaN(luminance)) {
let { r, g, b } = InspectorUtils.colorToRGBA(
window.getComputedStyle(toolbar).color
);
luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
if (cacheKey) {
cachedLuminances.set(cacheKey, luminance);
}
}
luminances.set(toolbar, luminance);
}
const luminanceThreshold = 127; // In between 0 and 255
for (let [toolbar, luminance] of luminances) {
if (luminance <= luminanceThreshold) {
toolbar.removeAttribute("brighttext");
} else {
toolbar.setAttribute("brighttext", "true");
}
}
},
};