summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-07-21 15:39:40 +0100
committerAndreas Kling <kling@serenityos.org>2021-07-22 23:09:01 +0200
commit82f3228dd20659d7060df6bb10f92deca7df61a9 (patch)
treedb11512f5c53d04901d5a29b3b8f3d2f1e51f8b2 /Userland
parenta44d7670ab937783e233f7d9a3ef73a39fcd8720 (diff)
downloadserenity-82f3228dd20659d7060df6bb10f92deca7df61a9.zip
LibWeb: Resolve CSS font property from value list
The font property now resolves into its various parts: - font-family - font-weight - font-size - font-style - line-height The font-variant and font-stretch parts are left unparsed since LibWeb doesn't know how to render those. Added `fonts.html` as a test for various forms of `font` declarations, based on the examples in the spec.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Identifiers.json11
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleResolver.cpp213
2 files changed, 222 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Identifiers.json b/Userland/Libraries/LibWeb/CSS/Identifiers.json
index 29490eead7..2c95fe7b54 100644
--- a/Userland/Libraries/LibWeb/CSS/Identifiers.json
+++ b/Userland/Libraries/LibWeb/CSS/Identifiers.json
@@ -76,6 +76,7 @@
"context-menu",
"copy",
"crosshair",
+ "cursive",
"dashed",
"decimal",
"decimal-leading-zero",
@@ -85,6 +86,7 @@
"double",
"e-resize",
"ew-resize",
+ "fantasy",
"fixed",
"flex",
"flex-start",
@@ -100,6 +102,7 @@
"inline-block",
"inset",
"inside",
+ "italic",
"justify",
"large",
"larger",
@@ -112,6 +115,7 @@
"lower-latin",
"lower-roman",
"medium",
+ "monospace",
"move",
"ne-resize",
"nesw-resize",
@@ -125,6 +129,7 @@
"ns-resize",
"nw-resize",
"nwse-resize",
+ "oblique",
"outset",
"outside",
"overline",
@@ -143,7 +148,9 @@
"row",
"row-resize",
"row-reverse",
+ "sans-serif",
"scroll",
+ "serif",
"se-resize",
"small",
"smaller",
@@ -166,6 +173,10 @@
"table-row",
"table-row-group",
"text",
+ "ui-monospace",
+ "ui-rounded",
+ "ui-sans-serif",
+ "ui-serif",
"underline",
"uppercase",
"upper-alpha",
diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
index fd641b4cdc..0a059fb50d 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
@@ -296,6 +296,98 @@ static inline bool is_flex_basis(StyleValue const& value)
return false;
}
+static inline bool is_font_family(StyleValue const& value)
+{
+ if (value.is_builtin_or_dynamic())
+ return true;
+ if (value.is_string())
+ return true;
+ switch (value.to_identifier()) {
+ case ValueID::Cursive:
+ case ValueID::Fantasy:
+ case ValueID::Monospace:
+ case ValueID::Serif:
+ case ValueID::SansSerif:
+ case ValueID::UiMonospace:
+ case ValueID::UiRounded:
+ case ValueID::UiSerif:
+ case ValueID::UiSansSerif:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool is_font_size(StyleValue const& value)
+{
+ if (value.is_builtin_or_dynamic())
+ return true;
+ if (value.is_length())
+ return true;
+ switch (value.to_identifier()) {
+ case ValueID::XxSmall:
+ case ValueID::XSmall:
+ case ValueID::Small:
+ case ValueID::Medium:
+ case ValueID::Large:
+ case ValueID::XLarge:
+ case ValueID::XxLarge:
+ case ValueID::XxxLarge:
+ case ValueID::Smaller:
+ case ValueID::Larger:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool is_font_style(StyleValue const& value)
+{
+ // FIXME: Handle angle parameter to `oblique`: https://www.w3.org/TR/css-fonts-4/#font-style-prop
+ if (value.is_builtin_or_dynamic())
+ return true;
+ switch (value.to_identifier()) {
+ case ValueID::Normal:
+ case ValueID::Italic:
+ case ValueID::Oblique:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool is_font_weight(StyleValue const& value)
+{
+ if (value.is_builtin_or_dynamic())
+ return true;
+ if (value.is_numeric()) {
+ auto weight = static_cast<NumericStyleValue const&>(value).value();
+ return (weight >= 1 && weight <= 1000);
+ }
+ switch (value.to_identifier()) {
+ case ValueID::Normal:
+ case ValueID::Bold:
+ case ValueID::Bolder:
+ case ValueID::Lighter:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool is_line_height(StyleValue const& value)
+{
+ if (value.is_builtin_or_dynamic())
+ return true;
+ if (value.is_numeric())
+ return true;
+ if (value.is_length())
+ return true;
+ if (value.to_identifier() == ValueID::Normal)
+ return true;
+ return false;
+}
+
static inline bool is_line_style(StyleValue const& value)
{
if (value.is_builtin_or_dynamic())
@@ -1308,7 +1400,6 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
return;
}
- // FIXME: parse other values as well
if (property_id == CSS::PropertyID::Font) {
// FIXME: Remove string parsing once DeprecatedCSSParser is gone.
if (value.is_string()) {
@@ -1334,7 +1425,125 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
return;
}
- // FIXME: Handle this as a ValueListStyleValue.
+ if (value.is_value_list()) {
+ auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
+
+ RefPtr<StyleValue> font_style_value;
+ RefPtr<StyleValue> font_weight_value;
+ RefPtr<StyleValue> font_size_value;
+ RefPtr<StyleValue> line_height_value;
+ RefPtr<StyleValue> font_family_value;
+ // FIXME: Implement font-stretch and font-variant.
+
+ for (size_t i = 0; i < parts.size(); ++i) {
+ auto value = Parser::parse_css_value(context, property_id, parts[i]);
+ if (!value)
+ return;
+
+ if (is_font_style(*value)) {
+ if (font_style_value)
+ return;
+ font_style_value = move(value);
+ continue;
+ }
+ if (is_font_weight(*value)) {
+ if (font_weight_value)
+ return;
+ font_weight_value = move(value);
+ continue;
+ }
+ if (is_font_size(*value)) {
+ if (font_size_value)
+ return;
+ font_size_value = move(value);
+
+ // Consume `/ line-height` if present
+ if (i + 2 < parts.size()) {
+ auto solidus_part = parts[i + 1];
+ if (!(solidus_part.is(Token::Type::Delim) && solidus_part.token().delim() == "/"sv))
+ break;
+ auto line_height = Parser::parse_css_value(context, property_id, parts[i + 2]);
+ if (!(line_height && is_line_height(*line_height)))
+ return;
+ line_height_value = move(line_height);
+ i += 2;
+ }
+
+ // Consume font-family
+ // FIXME: Handle multiple font-families separated by commas, for fallback purposes.
+ if (i + 1 < parts.size()) {
+ auto& font_family_part = parts[i + 1];
+ auto font_family = Parser::parse_css_value(context, property_id, font_family_part);
+ if (!font_family) {
+ // Single-word font-families may not be quoted. We convert it to a String for convenience.
+ if (font_family_part.is(Token::Type::Ident))
+ font_family = StringStyleValue::create(font_family_part.token().ident());
+ else
+ return;
+ } else if (!is_font_family(*font_family)) {
+ dbgln("*** Unable to parse '{}' as a font-family.", font_family_part.to_debug_string());
+ return;
+ }
+
+ font_family_value = move(font_family);
+ }
+ break;
+ }
+
+ return;
+ }
+
+ if (!font_size_value || !font_family_value)
+ return;
+
+ style.set_property(CSS::PropertyID::FontSize, *font_size_value);
+ style.set_property(CSS::PropertyID::FontFamily, *font_family_value);
+
+ if (font_style_value)
+ style.set_property(CSS::PropertyID::FontStyle, *font_style_value);
+ if (font_weight_value)
+ style.set_property(CSS::PropertyID::FontWeight, *font_weight_value);
+ if (line_height_value)
+ style.set_property(CSS::PropertyID::LineHeight, *line_height_value);
+
+ return;
+ }
+
+ if (value.is_inherit()) {
+ style.set_property(CSS::PropertyID::FontSize, value);
+ style.set_property(CSS::PropertyID::FontFamily, value);
+ style.set_property(CSS::PropertyID::FontStyle, value);
+ style.set_property(CSS::PropertyID::FontVariant, value);
+ style.set_property(CSS::PropertyID::FontWeight, value);
+ style.set_property(CSS::PropertyID::LineHeight, value);
+ // FIXME: Implement font-stretch
+ return;
+ }
+
+ // FIXME: Handle system fonts. (caption, icon, menu, message-box, small-caption, status-bar)
+
+ return;
+ }
+
+ if (property_id == CSS::PropertyID::FontFamily) {
+ if (value.is_value_list()) {
+ auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
+ // FIXME: Handle multiple font-families separated by commas, for fallback purposes.
+ for (auto& part : parts) {
+ auto value = Parser::parse_css_value(context, property_id, part);
+ if (!value)
+ return;
+ if (is_font_family(*value))
+ style.set_property(CSS::PropertyID::FontFamily, *value);
+ break;
+ }
+ return;
+ }
+
+ if (is_font_family(value)) {
+ style.set_property(CSS::PropertyID::FontFamily, value);
+ return;
+ }
return;
}