diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 899c3eb259076..fe8e5c4eaca6e 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -138,6 +138,7 @@ set(SOURCES CSS/StyleValues/CSSKeywordValue.cpp CSS/StyleValues/CSSLabLike.cpp CSS/StyleValues/CSSLCHLike.cpp + CSS/StyleValues/CSSLightDark.cpp CSS/StyleValues/CSSRGB.cpp CSS/StyleValues/DisplayStyleValue.cpp CSS/StyleValues/EasingStyleValue.cpp diff --git a/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Libraries/LibWeb/CSS/Parser/Parser.cpp index a6ba66a60a1b2..a48357c2f07c3 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -3491,6 +3492,39 @@ RefPtr Parser::parse_color_function(TokenStream& alpha.release_nonnull()); } +// https://drafts.csswg.org/css-color-5/#funcdef-light-dark +RefPtr Parser::parse_light_dark_color_value(TokenStream& outer_tokens) +{ + auto transaction = outer_tokens.begin_transaction(); + outer_tokens.discard_whitespace(); + + auto const& function_token = outer_tokens.consume_a_token(); + if (!function_token.is_function("light-dark"sv)) + return {}; + + auto inner_tokens = TokenStream { function_token.function().value }; + inner_tokens.discard_whitespace(); + + auto light = parse_color_value(inner_tokens); + if (!light) + return {}; + inner_tokens.discard_whitespace(); + + if (!inner_tokens.consume_a_token().is(Token::Type::Comma)) + return {}; + + auto dark = parse_color_value(inner_tokens); + if (!dark) + return {}; + inner_tokens.discard_whitespace(); + + if (inner_tokens.has_next_token()) + return {}; + + transaction.commit(); + return CSSLightDark::create(light, dark); +} + // https://www.w3.org/TR/css-color-4/#color-syntax RefPtr Parser::parse_color_value(TokenStream& tokens) { @@ -3522,6 +3556,8 @@ RefPtr Parser::parse_color_value(TokenStream& tok return oklab; if (auto oklch = parse_oklch_color_value(tokens)) return oklch; + if (auto light_dark = parse_light_dark_color_value(tokens)) + return light_dark; auto transaction = tokens.begin_transaction(); tokens.discard_whitespace(); diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index e9901d3221244..f3821349c0703 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -291,6 +291,7 @@ class Parser { RefPtr parse_lch_color_value(TokenStream&); RefPtr parse_oklch_color_value(TokenStream&); RefPtr parse_color_function(TokenStream&); + RefPtr parse_light_dark_color_value(TokenStream&); RefPtr parse_color_value(TokenStream&); RefPtr parse_color_scheme_value(TokenStream&); RefPtr parse_counter_value(TokenStream&); diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.h b/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.h index 225a4e8fb4d6c..39ddf3e2df42f 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.h @@ -39,6 +39,7 @@ class CSSColorValue : public CSSStyleValue { Rec2020, XYZD50, XYZD65, + LightDark, // This is used by CSSLightDark for light-dark(..., ...). }; ColorType color_type() const { return m_color_type; } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp new file mode 100644 index 0000000000000..ed171eef8d45f --- /dev/null +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, Ladybird contributors + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CSSLightDark.h" +#include + +namespace Web::CSS { + +Color CSSLightDark::to_color(Optional node) const +{ + if (node.has_value() && node.value().computed_values().color_scheme() == PreferredColorScheme::Dark) + return m_properties.dark->to_color(node); + + return m_properties.light->to_color(node); +} + +bool CSSLightDark::equals(CSSStyleValue const& other) const +{ + if (type() != other.type()) + return false; + auto const& other_color = other.as_color(); + if (color_type() != other_color.color_type()) + return false; + auto const& other_light_dark = verify_cast(other_color); + return m_properties == other_light_dark.m_properties; +} + +String CSSLightDark::to_string(SerializationMode mode) const +{ + // FIXME: We don't have enough information to determine the computed value here. + return MUST(String::formatted("light-dark({}, {})", m_properties.light->to_string(mode), m_properties.dark->to_string(mode))); +} + +} diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h new file mode 100644 index 0000000000000..19d8935a55a69 --- /dev/null +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Ladybird contributors + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +// https://drafts.csswg.org/css-color-5/#funcdef-light-dark +class CSSLightDark final : public CSSColorValue { +public: + virtual ~CSSLightDark() override = default; + + static ValueComparingNonnullRefPtr create(RefPtr light, RefPtr dark) + { + return AK::adopt_ref(*new (nothrow) CSSLightDark(move(light), move(dark))); + } + + virtual bool equals(CSSStyleValue const&) const override; + virtual Color to_color(Optional) const override; + virtual String to_string(SerializationMode) const override; + +private: + CSSLightDark(RefPtr light, RefPtr dark) + : CSSColorValue(CSSColorValue::ColorType::LightDark) + , m_properties { .light = move(light), .dark = move(dark) } + { + } + + struct Properties { + RefPtr light; + RefPtr dark; + bool operator==(Properties const&) const = default; + }; + + Properties m_properties; +}; + +} // Web::CSS diff --git a/Tests/LibWeb/Screenshot/expected/color-scheme-ref.html b/Tests/LibWeb/Screenshot/expected/color-scheme-ref.html new file mode 100644 index 0000000000000..4208be37a46fe --- /dev/null +++ b/Tests/LibWeb/Screenshot/expected/color-scheme-ref.html @@ -0,0 +1,10 @@ + + diff --git a/Tests/LibWeb/Screenshot/images/color-scheme-ref.png b/Tests/LibWeb/Screenshot/images/color-scheme-ref.png new file mode 100644 index 0000000000000..283645ae512ff Binary files /dev/null and b/Tests/LibWeb/Screenshot/images/color-scheme-ref.png differ diff --git a/Tests/LibWeb/Screenshot/input/color-scheme.html b/Tests/LibWeb/Screenshot/input/color-scheme.html new file mode 100644 index 0000000000000..e4577196b0b32 --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/color-scheme.html @@ -0,0 +1,69 @@ + + +
+
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
+
+
+
+
+
+
+
+
light-dark(red,green)
+
+
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
a
+
+
+
+
+
+
+
+
+
light-dark(red,green)
+
+