diff --git a/Tests/LibWeb/Text/expected/css/font-face-src-local-serialization.txt b/Tests/LibWeb/Text/expected/css/font-face-src-local-serialization.txt
new file mode 100644
index 00000000000..491578a7596
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/font-face-src-local-serialization.txt
@@ -0,0 +1 @@
+@font-face { font-family: "a1"; src: local("xyz"); unicode-range: "U+0-10ffff"; }
diff --git a/Tests/LibWeb/Text/input/css/font-face-src-local-serialization.html b/Tests/LibWeb/Text/input/css/font-face-src-local-serialization.html
new file mode 100644
index 00000000000..6e1505b29ab
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/font-face-src-local-serialization.html
@@ -0,0 +1,10 @@
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/CSSFontFaceRule.cpp b/Userland/Libraries/LibWeb/CSS/CSSFontFaceRule.cpp
index 9e486ab9046..4fa5945cbdf 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSFontFaceRule.cpp
+++ b/Userland/Libraries/LibWeb/CSS/CSSFontFaceRule.cpp
@@ -62,8 +62,11 @@ DeprecatedString 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.
serialize_a_comma_separated_list(builder, m_font_face.sources(), [&](StringBuilder& builder, FontFace::Source source) -> void {
- // FIXME: Serialize locals once we support those
- serialize_a_url(builder, source.url.to_deprecated_string());
+ if (source.local_or_url.has()) {
+ serialize_a_url(builder, source.local_or_url.get().to_deprecated_string());
+ } else {
+ builder.appendff("local({})", source.local_or_url.get());
+ }
// NOTE: No spec currently exists for format()
if (source.format.has_value()) {
diff --git a/Userland/Libraries/LibWeb/CSS/FontFace.h b/Userland/Libraries/LibWeb/CSS/FontFace.h
index 04a112a2d01..eb46b3de307 100644
--- a/Userland/Libraries/LibWeb/CSS/FontFace.h
+++ b/Userland/Libraries/LibWeb/CSS/FontFace.h
@@ -16,7 +16,7 @@ namespace Web::CSS {
class FontFace {
public:
struct Source {
- AK::URL url;
+ Variant local_or_url;
// FIXME: Do we need to keep this around, or is it only needed to discard unwanted formats during parsing?
Optional format;
};
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index 5f76228272b..384a02f4e40 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -4453,7 +4453,14 @@ Vector Parser::parse_font_face_src(TokenStream
continue;
}
- // FIXME: Implement `local()`.
+ if (first.is_function() && first.function().name().equals_ignoring_ascii_case("local"sv)) {
+ if (first.function().values().is_empty()) {
+ continue;
+ }
+ supported_sources.empend(first.function().values().first().to_string(), Optional {});
+ continue;
+ }
+
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (failed to parse url from: {}); discarding.", first.to_debug_string());
return {};
}
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
index 64128d288ba..253fbef348d 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
@@ -2827,7 +2827,9 @@ void StyleComputer::load_fonts_from_sheet(CSSStyleSheet const& sheet)
Vector urls;
for (auto& source : font_face.sources()) {
// FIXME: These should be loaded relative to the stylesheet URL instead of the document URL.
- urls.append(m_document->parse_url(source.url.to_deprecated_string()));
+ if (source.local_or_url.has())
+ urls.append(m_document->parse_url(source.local_or_url.get().to_deprecated_string()));
+ // FIXME: Handle local()
}
if (urls.is_empty())
diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp
index e7164462122..023d7468c71 100644
--- a/Userland/Libraries/LibWeb/Dump.cpp
+++ b/Userland/Libraries/LibWeb/Dump.cpp
@@ -654,7 +654,10 @@ void dump_font_face_rule(StringBuilder& builder, CSS::CSSFontFaceRule const& rul
builder.append("sources:\n"sv);
for (auto const& source : font_face.sources()) {
indent(builder, indent_levels + 2);
- builder.appendff("url={}, format={}\n", source.url, source.format.value_or("???"_string));
+ if (source.local_or_url.has())
+ builder.appendff("url={}, format={}\n", source.local_or_url.get(), source.format.value_or("???"_string));
+ else
+ builder.appendff("local={}\n", source.local_or_url.get());
}
indent(builder, indent_levels + 1);