LibWeb/CSS: Parse local() font sources more correctly

There were several issues with the previous parsing code, like ignoring
trailing tokens, not handling whitespace, and not requiring the value
to be a `<family-name>`. So, fix all that.

Also correct the serialization code, which didn't call
`serialize_a_string()` previously.
This commit is contained in:
Sam Atkins 2025-03-24 17:20:08 +00:00 committed by Andreas Kling
parent 93a2c9946f
commit 285fbc8f1c
Notes: github-actions[bot] 2025-03-25 07:54:56 +00:00
2 changed files with 30 additions and 7 deletions

View file

@ -65,11 +65,15 @@ String CSSFontFaceRule::serialized() const
// 2. The result of invoking serialize a comma-separated list on performing serialize a URL or serialize a LOCAL for each source on the source list. // 2. The result of invoking serialize a comma-separated list on performing serialize a URL or serialize a LOCAL for each source on the source list.
serialize_a_comma_separated_list(builder, m_font_face.sources(), [&](StringBuilder& builder, ParsedFontFace::Source source) -> void { serialize_a_comma_separated_list(builder, m_font_face.sources(), [&](StringBuilder& builder, ParsedFontFace::Source source) -> void {
if (source.local_or_url.has<URL::URL>()) { source.local_or_url.visit(
serialize_a_url(builder, source.local_or_url.get<URL::URL>().to_string()); [&builder](URL::URL const& url) {
} else { serialize_a_url(builder, url.to_string());
builder.appendff("local({})", source.local_or_url.get<FlyString>()); },
} [&builder](FlyString const& local) {
// https://drafts.csswg.org/cssom-1/#serialize-a-local
// To serialize a LOCAL means to create a string represented by "local(", followed by the serialization of the LOCAL as a string, followed by ")".
builder.appendff("local({})", serialize_a_string(local));
});
// NOTE: No spec currently exists for format() // NOTE: No spec currently exists for format()
if (source.format.has_value()) { if (source.format.has_value()) {

View file

@ -28,6 +28,7 @@
#include <LibWeb/CSS/Parser/Parser.h> #include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/PropertyName.h> #include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/StyleValues/CSSKeywordValue.h> #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h> #include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h> #include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
#include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h> #include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h>
@ -669,10 +670,28 @@ Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& compo
auto const& first = source_tokens.consume_a_token(); auto const& first = source_tokens.consume_a_token();
if (first.is_function("local"sv)) { if (first.is_function("local"sv)) {
// local(<family-name>)
if (first.function().value.is_empty()) { if (first.function().value.is_empty()) {
continue; dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (`local()` syntax is invalid: no arguments); discarding.");
return {};
} }
supported_sources.empend(FlyString { first.function().value.first().to_string() }, Optional<FlyString> {});
TokenStream function_tokens { first.function().value };
function_tokens.discard_whitespace();
auto font_family = parse_family_name_value(function_tokens);
function_tokens.discard_whitespace();
if (!font_family || function_tokens.has_next_token()) {
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (`local()` syntax is invalid: `{}`); discarding.", first.function().original_source_text());
return {};
}
if (font_family->is_string())
supported_sources.empend(font_family->as_string().string_value(), Optional<FlyString> {});
else if (font_family->is_custom_ident())
supported_sources.empend(font_family->as_custom_ident().custom_ident(), Optional<FlyString> {});
else
VERIFY_NOT_REACHED();
continue; continue;
} }