Skip to content

Commit

Permalink
Bug 1845679 - Add an internal light-dark() function to allow defining…
Browse files Browse the repository at this point in the history
… colors reacting to color-scheme. r=dshin

This implement something like what's proposed in
w3c/csswg-drafts#7561, but the simplest
version possible, until issues are resolved.

This will allow the front-end to experiment with it and use it (and we
can update to the standard feature once there's a spec for it).

Differential Revision: https://phabricator.services.mozilla.com/D184680
  • Loading branch information
emilio committed Jul 27, 2023
1 parent b71ef85 commit 6fc6339
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
5 changes: 5 additions & 0 deletions style/gecko/media_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,11 @@ impl Device {
unsafe { bindings::Gecko_ComputeSystemColor(system_color, self.document(), color_scheme) }
}

/// Returns whether the used color-scheme for `color-scheme` should be dark.
pub(crate) fn is_dark_color_scheme(&self, color_scheme: &ColorScheme) -> bool {
unsafe { bindings::Gecko_IsDarkColorScheme(self.document(), color_scheme) }
}

/// Returns the default background color.
///
/// This is only for forced-colors/high-contrast, so looking at light colors
Expand Down
59 changes: 56 additions & 3 deletions style/values/specified/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl ColorMix {

let mut right_percentage = try_parse_percentage(input);

let right = Color::parse(context, input)?;
let right = Color::parse_internal(context, input, preserve_authored)?;

if right_percentage.is_none() {
right_percentage = try_parse_percentage(input);
Expand Down Expand Up @@ -130,11 +130,53 @@ pub enum Color {
System(SystemColor),
/// A color mix.
ColorMix(Box<ColorMix>),
/// A light-dark() color.
LightDark(Box<LightDark>),
/// Quirksmode-only rule for inheriting color from the body
#[cfg(feature = "gecko")]
InheritFromBodyQuirk,
}

/// A light-dark(<light-color>, <dark-color>) function.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem, ToCss)]
#[css(function, comma)]
pub struct LightDark {
light: Color,
dark: Color,
}

impl LightDark {
fn compute(&self, cx: &Context) -> ComputedColor {
let style_color_scheme = cx.style().get_inherited_ui().clone_color_scheme();
let dark = cx.device().is_dark_color_scheme(&style_color_scheme);
let used = if dark {
&self.dark
} else {
&self.light
};
used.to_computed_value(cx)
}

fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
preserve_authored: PreserveAuthored,
) -> Result<Self, ParseError<'i>> {
let enabled =
context.chrome_rules_enabled() || static_prefs::pref!("layout.css.light-dark.enabled");
if !enabled {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
input.expect_function_matching("light-dark")?;
input.parse_nested_block(|input| {
let light = Color::parse_internal(context, input, preserve_authored)?;
input.expect_comma()?;
let dark = Color::parse_internal(context, input, preserve_authored)?;
Ok(LightDark { light, dark })
})
}
}

impl From<AbsoluteColor> for Color {
#[inline]
fn from(value: AbsoluteColor) -> Self {
Expand Down Expand Up @@ -376,8 +418,7 @@ impl SystemColor {
use crate::gecko::values::convert_nscolor_to_absolute_color;
use crate::gecko_bindings::bindings;

// TODO: We should avoid cloning here most likely, though it's
// cheap-ish.
// TODO: We should avoid cloning here most likely, though it's cheap-ish.
let style_color_scheme = cx.style().get_inherited_ui().clone_color_scheme();
let color = cx.device().system_nscolor(*self, &style_color_scheme);
if color == bindings::NS_SAME_AS_FOREGROUND_COLOR {
Expand Down Expand Up @@ -574,6 +615,7 @@ impl<'a, 'b: 'a, 'i: 'a> ::cssparser::ColorParser<'i> for ColorParser<'a, 'b> {

/// Whether to preserve authored colors during parsing. That's useful only if we
/// plan to serialize the color back.
#[derive(Copy, Clone)]
enum PreserveAuthored {
No,
Yes,
Expand Down Expand Up @@ -645,6 +687,11 @@ impl Color {
return Ok(Color::ColorMix(Box::new(mix)));
}

if let Ok(ld) = input.try_parse(|i| LightDark::parse(context, i, preserve_authored))
{
return Ok(Color::LightDark(Box::new(ld)));
}

match e.kind {
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
Err(e.location.new_custom_error(StyleParseErrorKind::ValueError(
Expand Down Expand Up @@ -717,6 +764,7 @@ impl ToCss for Color {
Color::CurrentColor => cssparser::ToCss::to_css(&CSSParserColor::CurrentColor, dest),
Color::Absolute(ref absolute) => absolute.to_css(dest),
Color::ColorMix(ref mix) => mix.to_css(dest),
Color::LightDark(ref ld) => ld.to_css(dest),
#[cfg(feature = "gecko")]
Color::System(system) => system.to_css(dest),
#[cfg(feature = "gecko")]
Expand All @@ -732,6 +780,10 @@ impl Color {
Self::InheritFromBodyQuirk => false,
Self::CurrentColor | Color::System(..) => true,
Self::Absolute(ref absolute) => allow_transparent && absolute.color.alpha() == 0.0,
Self::LightDark(ref ld) => {
ld.light.honored_in_forced_colors_mode(allow_transparent) &&
ld.dark.honored_in_forced_colors_mode(allow_transparent)
},
Self::ColorMix(ref mix) => {
mix.left.honored_in_forced_colors_mode(allow_transparent) &&
mix.right.honored_in_forced_colors_mode(allow_transparent)
Expand Down Expand Up @@ -854,6 +906,7 @@ impl Color {
Some(match *self {
Color::CurrentColor => ComputedColor::CurrentColor,
Color::Absolute(ref absolute) => ComputedColor::Absolute(absolute.color),
Color::LightDark(ref ld) => ld.compute(context?),
Color::ColorMix(ref mix) => {
use crate::values::computed::percentage::Percentage;

Expand Down

0 comments on commit 6fc6339

Please sign in to comment.