LibWeb: Serialize more @font-face descriptors

Adapt the existing `font-face-src-local-serialization.html` test into a
more general test for these.
This commit is contained in:
Sam Atkins 2024-10-02 14:18:08 +01:00 committed by Sam Atkins
commit c497e5f850
Notes: github-actions[bot] 2024-10-02 15:37:27 +00:00
5 changed files with 105 additions and 19 deletions

View file

@ -0,0 +1,7 @@
@font-face { font-family: "a1"; src: local("xyz"); unicode-range: "U+0-10ffff"; }
@font-face { font-family: "b1"; unicode-range: "U+0-10ffff"; font-feature-settings: "aaaa", "bbbb" 0, "yyyy" 3, "zzzz"; }
@font-face { font-family: "b2"; unicode-range: "U+0-10ffff"; font-feature-settings: "aaaa" 3; }
@font-face { font-family: "c1"; unicode-range: "U+0-10ffff"; font-width: 62.5%; }
@font-face { font-family: "c2"; unicode-range: "U+0-10ffff"; font-width: 50%; }
@font-face { font-family: "c3"; unicode-range: "U+0-10ffff"; font-width: 62.5%; }
@font-face { font-family: "c4"; unicode-range: "U+0-10ffff"; font-width: 50%; }

View file

@ -1 +0,0 @@
@font-face { font-family: "a1"; src: local("xyz"); unicode-range: "U+0-10ffff"; }

View file

@ -0,0 +1,30 @@
<script src="../include.js"></script>
<script>
test(() => {
let testCases = [
// src
// - local()
"@font-face { font-family: 'a1'; src: local('xyz'); }",
// font-feature-settings is sorted by tag
"@font-face { font-family: 'b1'; font-feature-settings: 'bbbb' 0, 'aaaa', 'zzzz' 1, 'yyyy' 3; }",
// font-feature-settings deduplicates tags, keeping the last value
"@font-face { font-family: 'b2'; font-feature-settings: 'aaaa', 'aaaa' 0, 'aaaa' 3; }",
// font-width
"@font-face { font-family: 'c1'; font-width: extra-condensed; }",
"@font-face { font-family: 'c2'; font-width: 50%; }",
// - font-stretch is a legacy alias for font-width
"@font-face { font-family: 'c3'; font-stretch: extra-condensed; }",
"@font-face { font-family: 'c4'; font-stretch: 50%; }",
];
for (let testCase of testCases) {
let style = document.createElement("style");
style.innerText = testCase;
document.head.appendChild(style);
let sheet = style.sheet;
println(sheet.cssRules[0].cssText);
style.remove();
}
});
</script>

View file

@ -1,10 +0,0 @@
<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>

View file

@ -5,6 +5,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/Font/Font.h>
#include <LibGfx/Font/FontStyleMapping.h>
#include <LibWeb/Bindings/CSSFontFaceRulePrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
@ -92,15 +93,74 @@ String CSSFontFaceRule::serialized() const
// followed by the result of performing serialize a <'font-variant'>,
// followed by the string ";", i.e., SEMICOLON (U+003B).
// FIXME: 8. If rules associated font-feature-settings descriptor is present, a single SPACE (U+0020),
// followed by the string "font-feature-settings:", followed by a single SPACE (U+0020),
// followed by the result of performing serialize a <'font-feature-settings'>,
// followed by the string ";", i.e., SEMICOLON (U+003B).
// 8. If rules associated font-feature-settings descriptor is present, a single SPACE (U+0020),
// followed by the string "font-feature-settings:", followed by a single SPACE (U+0020),
// followed by the result of performing serialize a <'font-feature-settings'>,
// followed by the string ";", i.e., SEMICOLON (U+003B).
if (m_font_face.font_feature_settings().has_value()) {
auto const& feature_settings = m_font_face.font_feature_settings().value();
builder.append(" font-feature-settings: "sv);
// NOTE: We sort the tags during parsing, so they're already in the correct order.
bool first = true;
for (auto const& [key, value] : feature_settings) {
if (first) {
first = false;
} else {
builder.append(", "sv);
}
// FIXME: 9. If rules associated font-stretch descriptor is present, a single SPACE (U+0020),
// followed by the string "font-stretch:", followed by a single SPACE (U+0020),
// followed by the result of performing serialize a <'font-stretch'>,
// followed by the string ";", i.e., SEMICOLON (U+003B).
serialize_a_string(builder, key);
// NOTE: 1 is the default value, so don't serialize it.
if (value != 1)
builder.appendff(" {}", value);
}
builder.append(";"sv);
}
// 9. If rules associated font-stretch descriptor is present, a single SPACE (U+0020),
// followed by the string "font-stretch:", followed by a single SPACE (U+0020),
// followed by the result of performing serialize a <'font-stretch'>,
// followed by the string ";", i.e., SEMICOLON (U+003B).
// NOTE: font-stretch is now an alias for font-width, so we use that instead.
if (m_font_face.width().has_value()) {
builder.append(" font-width: "sv);
// NOTE: font-width is supposed to always be serialized as a percentage.
// Right now, it's stored as a Gfx::FontWidth value, so we have to lossily convert it back.
float percentage = 100.0f;
switch (m_font_face.width().value()) {
case Gfx::FontWidth::UltraCondensed:
percentage = 50.0f;
break;
case Gfx::FontWidth::ExtraCondensed:
percentage = 62.5f;
break;
case Gfx::FontWidth::Condensed:
percentage = 75.0f;
break;
case Gfx::FontWidth::SemiCondensed:
percentage = 87.5f;
break;
case Gfx::FontWidth::Normal:
percentage = 100.0f;
break;
case Gfx::FontWidth::SemiExpanded:
percentage = 112.5f;
break;
case Gfx::FontWidth::Expanded:
percentage = 125.0f;
break;
case Gfx::FontWidth::ExtraExpanded:
percentage = 150.0f;
break;
case Gfx::FontWidth::UltraExpanded:
percentage = 200.0f;
break;
default:
break;
}
builder.appendff("{}%", percentage);
builder.append(";"sv);
}
// 10. If rules associated font-weight descriptor is present, a single SPACE (U+0020),
// followed by the string "font-weight:", followed by a single SPACE (U+0020),