LibWeb/CSS: Make @font-face src parsing more forgiving

As noted in the spec, an invalid (or unsupported) font source should not
make the `src` declaration invalid.
This commit is contained in:
Sam Atkins 2025-04-15 10:58:14 +01:00
parent d616ab0d95
commit 90deecad3d
4 changed files with 54 additions and 37 deletions

View file

@ -9,6 +9,7 @@
#include <LibWeb/CSS/StyleValues/FontSourceStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/StringStyleValue.h>
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
#include <LibWeb/CSS/StyleValues/UnicodeRangeStyleValue.h>
#include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
@ -61,10 +62,27 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_descriptor_valu
switch (value_type) {
case DescriptorMetadata::ValueType::FamilyName:
return parse_family_name_value(tokens);
case DescriptorMetadata::ValueType::FontSrcList:
return parse_comma_separated_value_list(tokens, [this](auto& tokens) -> RefPtr<CSSStyleValue> {
return parse_font_source_value(tokens);
});
case DescriptorMetadata::ValueType::FontSrcList: {
// "If a component value is parsed correctly and is of a font format or font tech that the UA
// supports, add it to the list of supported sources. If parsing a component value results in a
// parsing error or its format or tech are unsupported, do not add it to the list of supported
// sources.
// If there are no supported entries at the end of this process, the value for the src descriptor
// is a parse error.
// These parsing rules allow for graceful fallback of fonts for user agents which dont support a
// particular font tech or font format."
// https://drafts.csswg.org/css-fonts-4/#font-face-src-parsing
auto source_lists = parse_a_comma_separated_list_of_component_values(tokens);
StyleValueVector valid_sources;
for (auto const& source_list : source_lists) {
TokenStream source_tokens { source_list };
if (auto font_source = parse_font_source_value(source_tokens); font_source && !source_tokens.has_next_token())
valid_sources.append(font_source.release_nonnull());
}
if (valid_sources.is_empty())
return nullptr;
return StyleValueList::create(move(valid_sources), StyleValueList::Separator::Comma);
}
case DescriptorMetadata::ValueType::OptionalDeclarationValue:
// `component_values` already has what we want. Just skip through its tokens so code below knows we consumed them.
while (tokens.has_next_token())

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 35 tests
21 Pass
14 Fail
30 Pass
5 Fail
Pass Check that src: url("foo.ttf") is valid
Pass Check that src: url("foo.ttf"), url("bar.ttf") is valid
Pass Check that src: url("foo.ttf") format() is invalid
@ -30,12 +30,12 @@ Pass Check that src: url("foo.ttf") format(initial) is invalid
Pass Check that src: url("foo.ttf") format(none) is invalid
Pass Check that src: url("foo.ttf") format(normal) is invalid
Pass Check that src: url("foo.ttf") format(xyzzy) is invalid
Fail Check that src: url("foo.ttf") format("embedded-opentype"), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(embedded-opentype), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format("svg"), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(svg), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(xyzz 200px), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(xyzz), url("bar.html") is valid
Fail Check that src: url("foo.ttf") dummy(xyzzy), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(), url("bar.html") is valid
Fail Check that src: url("foo.ttf") format(none), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format("embedded-opentype"), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(embedded-opentype), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format("svg"), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(svg), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(xyzz 200px), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(xyzz), url("bar.html") is valid
Pass Check that src: url("foo.ttf") dummy(xyzzy), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(), url("bar.html") is valid
Pass Check that src: url("foo.ttf") format(none), url("bar.html") is valid

View file

@ -2,20 +2,19 @@ Harness status: OK
Found 17 tests
5 Pass
12 Fail
Fail Check that src: local(inherit), url(foo.ttf) is valid
Fail Check that src: local("myfont"), local(unset) is valid
Fail Check that src: local(), url(foo.ttf) is valid
Fail Check that src: local(12px monospace), url(foo.ttf) is valid
Fail Check that src: local("myfont") format(opentype), url(foo.ttf) is valid
Fail Check that src: url(not a valid url/bar.ttf), url(foo.ttf) is valid
Fail Check that src: url(foo.ttf) format(bad), url(foo.ttf) is valid
Fail Check that src: url(foo.ttf) tech(unknown), url(foo.ttf) is valid
Fail Check that src: url(foo.ttf) tech(color-COLRv0) otherfunc(othervalue), url(foo.ttf) is valid
Fail Check that src: url(foo.ttf), url(something.ttf) format(broken) is valid
Fail Check that src: /* an empty component */, url(foo.ttf) is valid
Fail Check that src: local(""), url(foo.ttf), unparseable-garbage, local("another font name") is valid
17 Pass
Pass Check that src: local(inherit), url(foo.ttf) is valid
Pass Check that src: local("myfont"), local(unset) is valid
Pass Check that src: local(), url(foo.ttf) is valid
Pass Check that src: local(12px monospace), url(foo.ttf) is valid
Pass Check that src: local("myfont") format(opentype), url(foo.ttf) is valid
Pass Check that src: url(not a valid url/bar.ttf), url(foo.ttf) is valid
Pass Check that src: url(foo.ttf) format(bad), url(foo.ttf) is valid
Pass Check that src: url(foo.ttf) tech(unknown), url(foo.ttf) is valid
Pass Check that src: url(foo.ttf) tech(color-COLRv0) otherfunc(othervalue), url(foo.ttf) is valid
Pass Check that src: url(foo.ttf), url(something.ttf) format(broken) is valid
Pass Check that src: /* an empty component */, url(foo.ttf) is valid
Pass Check that src: local(""), url(foo.ttf), unparseable-garbage, local("another font name") is valid
Pass Check that src: local(), local(initial) is invalid
Pass Check that src: local("textfont") format(opentype), local("emoji") tech(color-COLRv0) is invalid
Pass Check that src: local(), /*empty*/, url(should be quoted.ttf), junk is invalid

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 39 tests
22 Pass
17 Fail
28 Pass
11 Fail
Pass Check that src: url("foo.ttf") is valid
Pass Check that src: url("foo.ttf") tech() is invalid
Fail Check that src: url("foo.ttf") tech(features-opentype) is valid
@ -33,13 +33,13 @@ Pass Check that src: url("foo.ttf") tech(xyzzy, features-opentype) is invalid
Pass Check that src: url("foo.ttf") tech(features-opentype, xyzzy) is invalid
Fail Check that src: url("foo.ttf") format(opentype) tech(features-opentype) is valid
Pass Check that src: url("foo.ttf") tech(features-opentype) format(opentype) is invalid
Fail Check that src: url("foo.ttf") tech(incremental), url("bar.html") is valid
Fail Check that src: url("foo.ttf") tech(incremental, color-SVG, features-graphite, features-aat), url("bar.html") is valid
Fail Check that src: url("foo.ttf") tech(color-SVG, features-graphite), url("bar.html") is valid
Fail Check that src: url("foo.ttf") tech(color-SVG), url("bar.html") is valid
Fail Check that src: url("foo.ttf") tech(features-graphite), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(incremental), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(incremental, color-SVG, features-graphite, features-aat), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(color-SVG, features-graphite), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(color-SVG), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(features-graphite), url("bar.html") is valid
Pass Check that src: url("foo.ttf") dummy("opentype") tech(variations) is invalid
Pass Check that src: url("foo.ttf") dummy("opentype") dummy(variations) is invalid
Pass Check that src: url("foo.ttf") format(opentype) tech(features-opentype) dummy(something) is invalid
Fail Check that src: url("foo.ttf") format(dummy), url("foo.ttf") tech(variations) is valid
Fail Check that src: url("foo.ttf") tech(color), url("bar.html") is valid
Pass Check that src: url("foo.ttf") tech(color), url("bar.html") is valid