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()); + } } }); }