LibWeb/CSS: Add FontSourceStyleValue

This will be used by the `@font { src: ... }` descriptor once we parse
descriptors as style values.
This commit is contained in:
Sam Atkins 2025-04-02 17:01:16 +01:00
parent ceeaf352c8
commit 790923e7c5
8 changed files with 186 additions and 0 deletions

View file

@ -164,6 +164,7 @@ set(SOURCES
CSS/StyleValues/EasingStyleValue.cpp
CSS/StyleValues/EdgeStyleValue.cpp
CSS/StyleValues/FilterValueListStyleValue.cpp
CSS/StyleValues/FontSourceStyleValue.cpp
CSS/StyleValues/GridAutoFlowStyleValue.cpp
CSS/StyleValues/GridTemplateAreaStyleValue.cpp
CSS/StyleValues/GridTrackPlacementStyleValue.cpp

View file

@ -33,6 +33,7 @@
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
#include <LibWeb/CSS/StyleValues/FitContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
#include <LibWeb/CSS/StyleValues/FontSourceStyleValue.h>
#include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
@ -196,6 +197,12 @@ FlexStyleValue const& CSSStyleValue::as_flex() const
return static_cast<FlexStyleValue const&>(*this);
}
FontSourceStyleValue const& CSSStyleValue::as_font_source() const
{
VERIFY(is_font_source());
return static_cast<FontSourceStyleValue const&>(*this);
}
FrequencyStyleValue const& CSSStyleValue::as_frequency() const
{
VERIFY(is_frequency());

View file

@ -106,6 +106,7 @@ public:
FilterValueList,
FitContent,
Flex,
FontSource,
FontVariant,
Frequency,
GridAutoFlow,
@ -228,6 +229,10 @@ public:
FlexStyleValue const& as_flex() const;
FlexStyleValue& as_flex() { return const_cast<FlexStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_flex()); }
bool is_font_source() const { return type() == Type::FontSource; }
FontSourceStyleValue const& as_font_source() const;
FontSourceStyleValue& as_font_source() { return const_cast<FontSourceStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_font_source()); }
bool is_frequency() const { return type() == Type::Frequency; }
FrequencyStyleValue const& as_frequency() const;
FrequencyStyleValue& as_frequency() { return const_cast<FrequencyStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_frequency()); }

View file

@ -341,6 +341,7 @@ private:
RefPtr<PositionStyleValue> parse_position_value(TokenStream<ComponentValue>&, PositionParsingMode = PositionParsingMode::Normal);
RefPtr<CSSStyleValue> parse_filter_value_list_value(TokenStream<ComponentValue>&);
RefPtr<StringStyleValue> parse_opentype_tag_value(TokenStream<ComponentValue>&);
RefPtr<FontSourceStyleValue> parse_font_source_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_angle_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_angle_percentage_value(TokenStream<ComponentValue>&);

View file

@ -16,6 +16,7 @@
#include <AK/GenericLexer.h>
#include <AK/TemporaryChange.h>
#include <LibURL/URL.h>
#include <LibWeb/CSS/FontFace.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
@ -39,6 +40,7 @@
#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/FitContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
#include <LibWeb/CSS/StyleValues/FontSourceStyleValue.h>
#include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
@ -3655,6 +3657,67 @@ RefPtr<StringStyleValue> Parser::parse_opentype_tag_value(TokenStream<ComponentV
return string_value;
}
RefPtr<FontSourceStyleValue> Parser::parse_font_source_value(TokenStream<ComponentValue>& tokens)
{
// <font-src> = <url> [ format(<font-format>)]? [ tech( <font-tech>#)]? | local(<family-name>)
auto transaction = tokens.begin_transaction();
tokens.discard_whitespace();
// local(<family-name>)
if (tokens.next_token().is_function("local"sv)) {
auto const& function = tokens.consume_a_token().function();
TokenStream function_tokens { function.value };
if (auto family_name = parse_family_name_value(function_tokens)) {
transaction.commit();
return FontSourceStyleValue::create(FontSourceStyleValue::Local { family_name.release_nonnull() }, {});
}
return nullptr;
}
// <url> [ format(<font-format>)]? [ tech( <font-tech>#)]?
auto url = parse_url_function(tokens);
if (!url.has_value() || !url->is_valid())
return nullptr;
Optional<FlyString> format;
tokens.discard_whitespace();
// [ format(<font-format>)]?
if (tokens.next_token().is_function("format"sv)) {
auto const& function = tokens.consume_a_token().function();
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
TokenStream format_tokens { function.value };
format_tokens.discard_whitespace();
auto const& format_name_token = format_tokens.consume_a_token();
FlyString format_name;
if (format_name_token.is(Token::Type::Ident)) {
format_name = format_name_token.token().ident();
} else if (format_name_token.is(Token::Type::String)) {
format_name = format_name_token.token().string();
} else {
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: font source invalid (`format()` parameter not an ident or string; is: {}); discarding.", format_name_token.to_debug_string());
return nullptr;
}
if (!font_format_is_supported(format_name)) {
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: font source format({}) not supported; skipping.", format_name);
return nullptr;
}
format = move(format_name);
}
tokens.discard_whitespace();
// FIXME: [ tech( <font-tech>#)]?
transaction.commit();
return FontSourceStyleValue::create(url.release_value(), move(format));
}
NonnullRefPtr<CSSStyleValue> Parser::resolve_unresolved_style_value(ParsingParams const& context, DOM::Element& element, Optional<PseudoElement> pseudo_element, PropertyID property_id, UnresolvedStyleValue const& unresolved)
{
// Unresolved always contains a var() or attr(), unless it is a custom property's value, in which case we shouldn't be trying

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/Serialize.h>
#include <LibWeb/CSS/StyleValues/FontSourceStyleValue.h>
namespace Web::CSS {
FontSourceStyleValue::FontSourceStyleValue(Source source, Optional<FlyString> format)
: StyleValueWithDefaultOperators(Type::FontSource)
, m_source(move(source))
, m_format(move(format))
{
}
FontSourceStyleValue::~FontSourceStyleValue() = default;
String FontSourceStyleValue::to_string(SerializationMode) const
{
// <font-src> = <url> [ format(<font-format>)]? [ tech( <font-tech>#)]? | local(<family-name>)
return m_source.visit(
[](Local const& local) {
// local(<family-name>)
StringBuilder builder;
serialize_a_local(builder, local.name->to_string(SerializationMode::Normal));
return builder.to_string_without_validation();
},
[this](URL::URL const& url) {
// <url> [ format(<font-format>)]? [ tech( <font-tech>#)]?
// FIXME: tech()
StringBuilder builder;
serialize_a_url(builder, url.to_string());
if (m_format.has_value()) {
builder.append(" format("sv);
serialize_an_identifier(builder, *m_format);
builder.append(")"sv);
}
return builder.to_string_without_validation();
});
}
bool FontSourceStyleValue::properties_equal(FontSourceStyleValue const& other) const
{
bool sources_equal = m_source.visit(
[&other](Local const& local) {
if (auto* other_local = other.m_source.get_pointer<Local>()) {
return local.name == other_local->name;
}
return false;
},
[&other](URL::URL const& url) {
if (auto* other_url = other.m_source.get_pointer<URL::URL>()) {
return url == *other_url;
}
return false;
});
return sources_equal
&& m_format == other.m_format;
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/FlyString.h>
#include <LibWeb/CSS/CSSStyleValue.h>
namespace Web::CSS {
class FontSourceStyleValue final : public StyleValueWithDefaultOperators<FontSourceStyleValue> {
public:
struct Local {
NonnullRefPtr<CSSStyleValue> name;
};
using Source = Variant<Local, URL::URL>;
static ValueComparingNonnullRefPtr<FontSourceStyleValue> create(Source source, Optional<FlyString> format)
{
return adopt_ref(*new (nothrow) FontSourceStyleValue(move(source), move(format)));
}
virtual ~FontSourceStyleValue() override;
Source const& source() const { return m_source; }
Optional<FlyString> const& format() const { return m_format; }
virtual String to_string(SerializationMode) const override;
bool properties_equal(FontSourceStyleValue const&) const;
private:
FontSourceStyleValue(Source source, Optional<FlyString> format);
Source m_source;
Optional<FlyString> m_format;
};
}

View file

@ -198,6 +198,7 @@ class FlexOrCalculated;
class FlexStyleValue;
class FontFace;
class FontFaceSet;
class FontSourceStyleValue;
class Frequency;
class FrequencyOrCalculated;
class FrequencyPercentage;