From 468b2a5ace28424f57e52cc69f57d1f3a36fcee2 Mon Sep 17 00:00:00 2001
From: implicitfield <114500360+implicitfield@users.noreply.github.com>
Date: Sun, 19 Nov 2023 15:34:55 +0400
Subject: [PATCH] LibWeb: Support `size` attribute on `font` elements
---
.../Layout/expected/font-size-legacy.txt | 14 +++
.../LibWeb/Layout/input/font-size-legacy.html | 1 +
.../Libraries/LibWeb/HTML/HTMLFontElement.cpp | 92 +++++++++++++++++++
3 files changed, 107 insertions(+)
create mode 100644 Tests/LibWeb/Layout/expected/font-size-legacy.txt
create mode 100644 Tests/LibWeb/Layout/input/font-size-legacy.html
diff --git a/Tests/LibWeb/Layout/expected/font-size-legacy.txt b/Tests/LibWeb/Layout/expected/font-size-legacy.txt
new file mode 100644
index 00000000000..8b6f6732544
--- /dev/null
+++ b/Tests/LibWeb/Layout/expected/font-size-legacy.txt
@@ -0,0 +1,14 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+ BlockContainer at (0,0) content-size 800x33.46875 [BFC] children: not-inline
+ BlockContainer
at (8,8) content-size 784x17.46875 children: inline
+ line 0 width: 24.109375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 4, rect: [8,11 24.109375x13.09375]
+ "text"
+ InlineNode
+ TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x33.46875]
+ PaintableWithLines (BlockContainer) [8,8 784x17.46875]
+ InlinePaintable (InlineNode)
+ TextPaintable (TextNode<#text>)
diff --git a/Tests/LibWeb/Layout/input/font-size-legacy.html b/Tests/LibWeb/Layout/input/font-size-legacy.html
new file mode 100644
index 00000000000..0a7225b1138
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/font-size-legacy.html
@@ -0,0 +1 @@
+text
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFontElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLFontElement.cpp
index 7ca976c4f39..c22f3552dca 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLFontElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLFontElement.cpp
@@ -4,16 +4,100 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include
#include
+#include
+#include
#include
#include
#include
#include
+#include
namespace Web::HTML {
JS_DEFINE_ALLOCATOR(HTMLFontElement);
+enum class Mode {
+ RelativePlus,
+ RelativeMinus,
+ Absolute,
+};
+
+// https://html.spec.whatwg.org/multipage/rendering.html#rules-for-parsing-a-legacy-font-size
+static Optional parse_legacy_font_size(StringView string)
+{
+ // 1. Let input be the attribute's value.
+ // 2. Let position be a pointer into input, initially pointing at the start of the string.
+ GenericLexer lexer { string };
+
+ // 3. Skip ASCII whitespace within input given position.
+ lexer.ignore_while(Web::Infra::is_ascii_whitespace);
+
+ // 4. If position is past the end of input, there is no presentational hint. Return.
+ if (lexer.is_eof())
+ return {};
+
+ // 5. If the character at position is a U+002B PLUS SIGN character (+), then let mode be relative-plus, and advance position to the next character. Otherwise, if the character at position is a U+002D HYPHEN-MINUS character (-), then let mode be relative-minus, and advance position to the next character. Otherwise, let mode be absolute.
+ Mode mode { Mode::Absolute };
+
+ if (lexer.peek() == '+') {
+ mode = Mode::RelativePlus;
+ lexer.consume();
+ } else if (lexer.peek() == '-') {
+ mode = Mode::RelativeMinus;
+ lexer.consume();
+ }
+
+ // 6. Collect a sequence of code points that are ASCII digits from input given position, and let the resulting sequence be digits.
+ size_t start_index = lexer.tell();
+ lexer.consume_while(is_ascii_digit);
+ size_t end_index = lexer.tell();
+ auto digits = lexer.input().substring_view(start_index, end_index - start_index);
+ auto value_or_empty = AK::StringUtils::convert_to_int(digits);
+
+ // 7. If digits is the empty string, there is no presentational hint. Return.
+ if (!value_or_empty.has_value())
+ return {};
+
+ // 8. Interpret digits as a base-ten integer. Let value be the resulting number.
+ auto value = value_or_empty.release_value();
+
+ // 9. If mode is relative-plus, then increment value by 3. If mode is relative-minus, then let value be the result of subtracting value from 3.
+ if (mode == Mode::RelativePlus)
+ value += 3;
+ else if (mode == Mode::RelativeMinus)
+ value = 3 - value;
+
+ // 10. If value is greater than 7, let it be 7.
+ if (value > 7)
+ value = 7;
+
+ // 11. If value is less than 1, let it be 1.
+ if (value < 1)
+ value = 1;
+
+ // 12. Set 'font-size' to the keyword corresponding to the value of value according to the following table:
+ switch (value) {
+ case 1:
+ return CSS::ValueID::XSmall;
+ case 2:
+ return CSS::ValueID::Small;
+ case 3:
+ return CSS::ValueID::Medium;
+ case 4:
+ return CSS::ValueID::Large;
+ case 5:
+ return CSS::ValueID::XLarge;
+ case 6:
+ return CSS::ValueID::XxLarge;
+ case 7:
+ return CSS::ValueID::XxxLarge;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
HTMLFontElement::HTMLFontElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
@@ -35,6 +119,14 @@ void HTMLFontElement::apply_presentational_hints(CSS::StyleProperties& style) co
auto color = parse_legacy_color_value(value);
if (color.has_value())
style.set_property(CSS::PropertyID::Color, CSS::ColorStyleValue::create(color.value()));
+ } else if (name.equals_ignoring_ascii_case("size"sv)) {
+ // When a font element has a size attribute, the user agent is expected to use the following steps, known as the rules for parsing a legacy font size, to treat the attribute as a presentational hint setting the element's 'font-size' property:
+ auto font_size_or_empty = parse_legacy_font_size(value);
+ if (font_size_or_empty.has_value()) {
+ auto font_size = string_from_value_id(font_size_or_empty.release_value());
+ if (auto parsed_value = parse_css_value(CSS::Parser::ParsingContext { document() }, font_size, CSS::PropertyID::FontSize))
+ style.set_property(CSS::PropertyID::FontSize, parsed_value.release_nonnull());
+ }
}
});
}