فهرست منبع

LibWeb: Parse `src: local(...)` in CSS @font-face rules

Note that we don't load the local font as specified, but at least we no
longer reject such src properties in the CSS parser.

This makes the custom fonts used on http://apple.com/ actually load. :^)
Andreas Kling 1 سال پیش
والد
کامیت
13e2ca6b59

+ 1 - 0
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"; }

+ 10 - 0
Tests/LibWeb/Text/input/css/font-face-src-local-serialization.html

@@ -0,0 +1,10 @@
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        let style = document.createElement("style");
+        style.innerText = "@font-face { font-family: 'a1'; src: local('xyz'); }";
+        document.head.appendChild(style);
+        let sheet = style.sheet;
+        println(sheet.cssRules[0].cssText);
+    });
+</script>

+ 5 - 2
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.
         // 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 {
         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<AK::URL>()) {
+                serialize_a_url(builder, source.local_or_url.get<AK::URL>().to_deprecated_string());
+            } else {
+                builder.appendff("local({})", source.local_or_url.get<String>());
+            }
 
 
             // NOTE: No spec currently exists for format()
             // NOTE: No spec currently exists for format()
             if (source.format.has_value()) {
             if (source.format.has_value()) {

+ 1 - 1
Userland/Libraries/LibWeb/CSS/FontFace.h

@@ -16,7 +16,7 @@ namespace Web::CSS {
 class FontFace {
 class FontFace {
 public:
 public:
     struct Source {
     struct Source {
-        AK::URL url;
+        Variant<String, AK::URL> local_or_url;
         // FIXME: Do we need to keep this around, or is it only needed to discard unwanted formats during parsing?
         // FIXME: Do we need to keep this around, or is it only needed to discard unwanted formats during parsing?
         Optional<FlyString> format;
         Optional<FlyString> format;
     };
     };

+ 8 - 1
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -4453,7 +4453,14 @@ Vector<FontFace::Source> Parser::parse_font_face_src(TokenStream<ComponentValue>
             continue;
             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<FlyString> {});
+            continue;
+        }
+
         dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (failed to parse url from: {}); discarding.", first.to_debug_string());
         dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (failed to parse url from: {}); discarding.", first.to_debug_string());
         return {};
         return {};
     }
     }

+ 3 - 1
Userland/Libraries/LibWeb/CSS/StyleComputer.cpp

@@ -2827,7 +2827,9 @@ void StyleComputer::load_fonts_from_sheet(CSSStyleSheet const& sheet)
         Vector<AK::URL> urls;
         Vector<AK::URL> urls;
         for (auto& source : font_face.sources()) {
         for (auto& source : font_face.sources()) {
             // FIXME: These should be loaded relative to the stylesheet URL instead of the document URL.
             // 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<AK::URL>())
+                urls.append(m_document->parse_url(source.local_or_url.get<AK::URL>().to_deprecated_string()));
+            // FIXME: Handle local()
         }
         }
 
 
         if (urls.is_empty())
         if (urls.is_empty())

+ 4 - 1
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);
     builder.append("sources:\n"sv);
     for (auto const& source : font_face.sources()) {
     for (auto const& source : font_face.sources()) {
         indent(builder, indent_levels + 2);
         indent(builder, indent_levels + 2);
-        builder.appendff("url={}, format={}\n", source.url, source.format.value_or("???"_string));
+        if (source.local_or_url.has<AK::URL>())
+            builder.appendff("url={}, format={}\n", source.local_or_url.get<AK::URL>(), source.format.value_or("???"_string));
+        else
+            builder.appendff("local={}\n", source.local_or_url.get<AK::String>());
     }
     }
 
 
     indent(builder, indent_levels + 1);
     indent(builder, indent_levels + 1);