Bug 1782623 - Set select color-scheme based on child background. r=dholbert

This makes us use light or dark select popups on supported platforms
based on the background of the select element, which allows us to use
the right scrollbar color.

Depends on D153424

Differential Revision: https://phabricator.services.mozilla.com/D153425
This commit is contained in:
Emilio Cobos Álvarez 2022-08-02 15:49:13 +00:00
parent f6eb8c21a5
commit 4fc9841344
7 changed files with 43 additions and 21 deletions

View File

@ -107,7 +107,7 @@ const gSelects = {
" option { color: white; }" +
"</style></head>" +
"<body><select id='one'>" +
' <option>{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 0)"}</option>' +
' <option>{"colorScheme": "dark", "color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 0)"}</option>' +
' <option selected="true">{"end": "true"}</option>' +
"</select></body></html>",
@ -231,8 +231,8 @@ const gSelects = {
select { background-color: #fff; }
option { color: #2b2b2b; background-color: #fff; }
</style></head><body><select id='one'>
<option>{"color": "rgb(43, 43, 43)", "backgroundColor": "rgb(255, 255, 255)"}</option>
<option>{"color": "rgb(43, 43, 43)", "backgroundColor": "rgb(255, 255, 255)"}</option>
<option>{"colorScheme": "light", "color": "rgb(43, 43, 43)", "backgroundColor": "rgb(255, 255, 255)"}</option>
<option>{"colorScheme": "light", "color": "rgb(43, 43, 43)", "backgroundColor": "rgb(255, 255, 255)"}</option>
<option selected="true">{"end": "true"}</option>
</select></body></html>
`,
@ -298,6 +298,7 @@ function computeLabels(tab) {
let any = false;
for (let color of Object.keys(expected)) {
if (
color != "colorScheme" &&
color.toLowerCase().includes("color") &&
!expected[color].startsWith("rgb")
) {
@ -719,7 +720,6 @@ add_task(
'#ContentSelectDropdown .ContentSelectDropdown-item-1:not([_moz-menuactive="true"])',
"#ContentSelectDropdown .ContentSelectDropdown-item-2",
'#ContentSelectDropdown .ContentSelectDropdown-item-2:not([_moz-menuactive="true"])',
"#ContentSelectDropdown > menupopup",
'#ContentSelectDropdown > menupopup > :is(menuitem, menucaption):not([_moz-menuactive="true"])',
'#ContentSelectDropdown > menupopup > :is(menuitem, menucaption)[_moz-menuactive="true"]',
].sort();

View File

@ -51,6 +51,7 @@
#include "mozilla/ipc/UtilityProcessHost.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "IOActivityMonitor.h"
#include "nsNativeTheme.h"
#include "nsThreadUtils.h"
#include "mozJSModuleLoader.h"
#include "mozilla/ProfilerLabels.h"
@ -1707,4 +1708,13 @@ void ChromeUtils::GetFormAutofillConfidences(
FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
aRv);
}
bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
if (!f) {
return false;
}
return nsNativeTheme::IsDarkBackground(f);
}
} // namespace mozilla::dom

View File

@ -276,6 +276,8 @@ class ChromeUtils {
static void GetFormAutofillConfidences(
GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv);
static bool IsDarkBackground(GlobalObject&, Element&);
};
} // namespace dom

View File

@ -632,6 +632,11 @@ partial namespace ChromeUtils {
[Throws]
sequence<FormAutofillConfidences> getFormAutofillConfidences(sequence<Element> elements);
/**
* Returns whether the background of the element is dark.
*/
boolean isDarkBackground(Element element);
};
/*

View File

@ -130,6 +130,7 @@ SelectContentHelper.prototype = {
options,
rect,
selectedIndex: this.element.selectedIndex,
isDarkBackground: ChromeUtils.isDarkBackground(this.element),
style: supportedStyles(computedStyles, SUPPORTED_SELECT_PROPERTIES),
defaultStyle: supportedStyles(defaultStyles, SUPPORTED_SELECT_PROPERTIES),
});

View File

@ -84,6 +84,7 @@ var SelectParentHelper = {
* @param {Array<Object>} uniqueItemStyles
* @param {Number} selectedIndex
* @param {Number} zoom
* @param {Boolean} isDarkBackground
* @param {Object} uaStyle
* @param {Object} selectStyle
*/
@ -93,18 +94,24 @@ var SelectParentHelper = {
uniqueItemStyles,
selectedIndex,
zoom,
isDarkBackground,
uaStyle,
selectStyle
) {
let doc = menulist.ownerDocument;
// Clear the current contents of the popup
menulist.menupopup.textContent = "";
let menupopup = menulist.menupopup;
menupopup.textContent = "";
let stylesheet = menulist.querySelector("#ContentSelectDropdownStylesheet");
if (stylesheet) {
stylesheet.remove();
}
menupopup.setAttribute("style", "");
menupopup.style.colorScheme = isDarkBackground ? "dark" : "light";
stylesheet = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
stylesheet.setAttribute("id", "ContentSelectDropdownStylesheet");
stylesheet.hidden = true;
@ -140,7 +147,6 @@ var SelectParentHelper = {
);
}
let addedRule = false;
for (let property of SUPPORTED_SELECT_PROPERTIES) {
let shouldSkip = (function() {
if (property == "direction") {
@ -160,10 +166,6 @@ var SelectParentHelper = {
if (shouldSkip) {
continue;
}
if (!addedRule) {
sheet.insertRule("#ContentSelectDropdown > menupopup {}", 0);
addedRule = true;
}
let value = selectStyle[property];
if (property == "scrollbar-width") {
// This needs to actually apply to the relevant scrollbox, because
@ -173,7 +175,7 @@ var SelectParentHelper = {
if (property == "color") {
property = "--panel-color";
}
sheet.cssRules[0].style.setProperty(property, value);
menupopup.style.setProperty(property, value);
}
// Some webpages set the <select> backgroundColor to transparent,
// but they don't intend to change the popup to transparent.
@ -182,19 +184,18 @@ var SelectParentHelper = {
// We intentionally use the parsed color to prevent color
// values like `url(..)` being injected into the
// `background-image` property.
let parsedColor = sheet.cssRules[0].style["background-color"];
sheet.cssRules[0].style.setProperty(
let parsedColor = menupopup.style.backgroundColor;
menupopup.style.setProperty(
"--content-select-background-image",
`linear-gradient(${parsedColor}, ${parsedColor})`
);
// Always drop the background color to avoid messing with the custom
// shadow on Windows 10 styling.
sheet.cssRules[0].style["background-color"] = "";
menupopup.style.backgroundColor = "";
// If the background is set, we also make sure we set the color, to
// prevent contrast issues.
sheet.cssRules[0].style.setProperty("--panel-color", selectStyle.color);
}
if (addedRule) {
menupopup.style.setProperty("--panel-color", selectStyle.color);
sheet.insertRule(
`#ContentSelectDropdown > menupopup > :is(menuitem, menucaption):not([_moz-menuactive="true"]) {
color: inherit;
@ -436,6 +437,7 @@ var SelectParentHelper = {
options.uniqueStyles,
selectedIndex,
this._currentZoom,
msg.data.isDarkBackground,
msg.data.defaultStyle,
msg.data.style
);
@ -785,6 +787,7 @@ class SelectParent extends JSWindowActorParent {
// We only want to apply the full zoom. The text zoom is already
// applied in the font-size.
this.manager.browsingContext.fullZoom,
data.isDarkBackground,
data.defaultStyle,
data.style
);

View File

@ -23,9 +23,6 @@ menupopup {
appearance: auto;
-moz-default-appearance: menupopup;
/* Native menus are always light */
color-scheme: light;
/* We set the background-color / border here so that it doesn't interfere with native styling. */
background-color: Menu;
border: 1px solid ThreeDShadow;
@ -38,7 +35,6 @@ menupopup {
menupopup {
/* Disable the default appearance so we can override the native styling. */
appearance: none;
color-scheme: unset;
/* Prevent any background or border around the outside of the shadow. */
background-color: transparent;
@ -124,6 +120,11 @@ menulist > menupopup {
}
@media not (-moz-windows-non-native-menus) {
menupopup {
/* Native menus are always light */
color-scheme: light !important;
}
/* For Win10, the popup itself needs to have a transparent background because
otherwise the background color would appear behind the drop shadow. */
menulist > menupopup {