mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibWeb/CSS: Start parsing the color()
function
This is really bare bone as we only support the `xyz-d50` color space for the moment. It makes us pass the following WPT tests: - css/css-color/predefined-016.html - css/css-color/xyz-d50-001.html - css/css-color/xyz-d50-002.html
This commit is contained in:
parent
a6794627b0
commit
48bbebc636
Notes:
github-actions[bot]
2024-10-28 22:33:33 +00:00
Author: https://github.com/LucasChollet Commit: https://github.com/LadybirdBrowser/ladybird/commit/48bbebc6365 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2003
7 changed files with 166 additions and 0 deletions
|
@ -7,6 +7,7 @@ source_set("StyleValues") {
|
|||
"BackgroundSizeStyleValue.cpp",
|
||||
"BasicShapeStyleValue.cpp",
|
||||
"BorderRadiusStyleValue.cpp",
|
||||
"CSSColor.cpp",
|
||||
"CSSColorValue.cpp",
|
||||
"CSSHSL.cpp",
|
||||
"CSSHWB.cpp",
|
||||
|
|
|
@ -115,6 +115,7 @@ set(SOURCES
|
|||
CSS/StyleValues/ContentStyleValue.cpp
|
||||
CSS/StyleValues/CounterDefinitionsStyleValue.cpp
|
||||
CSS/StyleValues/CounterStyleValue.cpp
|
||||
CSS/StyleValues/CSSColor.cpp
|
||||
CSS/StyleValues/CSSColorValue.cpp
|
||||
CSS/StyleValues/CSSHSL.cpp
|
||||
CSS/StyleValues/CSSHWB.cpp
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BasicShapeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSColor.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSColorValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSHSL.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSHWB.h>
|
||||
|
@ -3387,6 +3388,66 @@ RefPtr<CSSStyleValue> Parser::parse_oklch_color_value(TokenStream<ComponentValue
|
|||
return CSSOKLCH::create(l.release_nonnull(), c.release_nonnull(), h.release_nonnull(), alpha.release_nonnull());
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-color-4/#funcdef-color
|
||||
RefPtr<CSSStyleValue> Parser::parse_color_function(TokenStream<ComponentValue>& outer_tokens)
|
||||
{
|
||||
// color() = color( <colorspace-params> [ / [ <alpha-value> | none ] ]? )
|
||||
// <colorspace-params> = [ <predefined-rgb-params> | <xyz-params>]
|
||||
// <predefined-rgb-params> = <predefined-rgb> [ <number> | <percentage> | none ]{3}
|
||||
// <predefined-rgb> = srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020
|
||||
// <xyz-params> = <xyz-space> [ <number> | <percentage> | none ]{3}
|
||||
// <xyz-space> = xyz | xyz-d50 | xyz-d65
|
||||
|
||||
auto transaction = outer_tokens.begin_transaction();
|
||||
outer_tokens.discard_whitespace();
|
||||
|
||||
auto const& function_token = outer_tokens.consume_a_token();
|
||||
if (!function_token.is_function("color"sv))
|
||||
return {};
|
||||
|
||||
auto inner_tokens = TokenStream { function_token.function().value };
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
auto maybe_color_space = inner_tokens.consume_a_token();
|
||||
inner_tokens.discard_whitespace();
|
||||
if (!any_of(CSSColor::s_supported_color_space, [&](auto supported) { return maybe_color_space.is_ident(supported); }))
|
||||
return {};
|
||||
|
||||
auto const& color_space = maybe_color_space.token().ident();
|
||||
|
||||
auto c1 = parse_number_percentage_value(inner_tokens);
|
||||
if (!c1)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
auto c2 = parse_number_percentage_value(inner_tokens);
|
||||
if (!c2)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
auto c3 = parse_number_percentage_value(inner_tokens);
|
||||
if (!c3)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
RefPtr<CSSStyleValue> alpha;
|
||||
if (inner_tokens.has_next_token()) {
|
||||
alpha = parse_solidus_and_alpha_value(inner_tokens);
|
||||
if (!alpha || inner_tokens.has_next_token())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!alpha)
|
||||
alpha = NumberStyleValue::create(1);
|
||||
|
||||
transaction.commit();
|
||||
return CSSColor::create(color_space.to_ascii_lowercase(),
|
||||
c1.release_nonnull(),
|
||||
c2.release_nonnull(),
|
||||
c3.release_nonnull(),
|
||||
alpha.release_nonnull());
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-color-4/#color-syntax
|
||||
RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
@ -3401,6 +3462,9 @@ RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tok
|
|||
}
|
||||
|
||||
// Functions
|
||||
if (auto color = parse_color_function(tokens))
|
||||
return color;
|
||||
|
||||
if (auto rgb = parse_rgb_color_value(tokens))
|
||||
return rgb;
|
||||
if (auto hsl = parse_hsl_color_value(tokens))
|
||||
|
|
|
@ -254,6 +254,7 @@ private:
|
|||
RefPtr<CSSStyleValue> parse_lab_color_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue> parse_oklab_color_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue> parse_oklch_color_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue> parse_color_function(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue> parse_color_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue> parse_counter_value(TokenStream<ComponentValue>&);
|
||||
enum class AllowReversed {
|
||||
|
|
58
Userland/Libraries/LibWeb/CSS/StyleValues/CSSColor.cpp
Normal file
58
Userland/Libraries/LibWeb/CSS/StyleValues/CSSColor.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Lucas Chollet <lucas.chollet@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "CSSColor.h"
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibWeb/CSS/Serialize.h>
|
||||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueComparingNonnullRefPtr<CSSColor> CSSColor::create(StringView color_space, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingRefPtr<CSSStyleValue> alpha)
|
||||
{
|
||||
VERIFY(any_of(s_supported_color_space, [=](auto supported) { return color_space == supported; }));
|
||||
|
||||
if (!alpha)
|
||||
alpha = NumberStyleValue::create(1);
|
||||
|
||||
if (color_space == "xyz-d50")
|
||||
return adopt_ref(*new (nothrow) CSSColor(ColorType::XYZD50, move(c1), move(c2), move(c3), alpha.release_nonnull()));
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool CSSColor::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_lab_like = verify_cast<CSSColor>(other_color);
|
||||
return m_properties == other_lab_like.m_properties;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-color-4/#serializing-color-function-values
|
||||
String CSSColor::to_string() const
|
||||
{
|
||||
// FIXME: Do this properly, taking unresolved calculated values into account.
|
||||
return serialize_a_srgb_value(to_color({}));
|
||||
}
|
||||
|
||||
Color CSSColor::to_color(Optional<Layout::NodeWithStyle const&>) const
|
||||
{
|
||||
auto const c1 = resolve_with_reference_value(m_properties.channels[0], 100).value_or(0);
|
||||
auto const c2 = resolve_with_reference_value(m_properties.channels[1], 100).value_or(0);
|
||||
auto const c3 = resolve_with_reference_value(m_properties.channels[2], 100).value_or(0);
|
||||
auto const alpha_val = resolve_alpha(m_properties.alpha).value_or(1);
|
||||
|
||||
if (color_type() == ColorType::XYZD50)
|
||||
return Color::from_xyz50(c1, c2, c3, alpha_val);
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
} // Web::CSS
|
40
Userland/Libraries/LibWeb/CSS/StyleValues/CSSColor.h
Normal file
40
Userland/Libraries/LibWeb/CSS/StyleValues/CSSColor.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Lucas Chollet <lucas.chollet@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/StyleValues/CSSColorValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#csscolor
|
||||
class CSSColor final : public CSSColorValue {
|
||||
public:
|
||||
virtual ~CSSColor() override = default;
|
||||
|
||||
static ValueComparingNonnullRefPtr<CSSColor> create(StringView color_space, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingRefPtr<CSSStyleValue> alpha = {});
|
||||
|
||||
virtual bool equals(CSSStyleValue const&) const override;
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>) const override;
|
||||
virtual String to_string() const override;
|
||||
|
||||
static constexpr Array s_supported_color_space = { "xyz-d50"sv };
|
||||
|
||||
private:
|
||||
CSSColor(ColorType color_type, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(color_type)
|
||||
, m_properties { .channels = { move(c1), move(c2), move(c3) }, .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
||||
struct Properties {
|
||||
Array<ValueComparingNonnullRefPtr<CSSStyleValue>, 3> channels;
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue> alpha;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
};
|
||||
|
||||
} // Web::CSS
|
|
@ -29,6 +29,7 @@ public:
|
|||
Lab,
|
||||
OKLab,
|
||||
OKLCH,
|
||||
XYZD50,
|
||||
};
|
||||
ColorType color_type() const { return m_color_type; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue