HTMLFontElement.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/GenericLexer.h>
  7. #include <LibWeb/Bindings/HTMLFontElementPrototype.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/CSS/Parser/Parser.h>
  10. #include <LibWeb/CSS/Parser/ParsingContext.h>
  11. #include <LibWeb/CSS/StyleProperties.h>
  12. #include <LibWeb/CSS/StyleValues/CSSColorValue.h>
  13. #include <LibWeb/HTML/HTMLFontElement.h>
  14. #include <LibWeb/HTML/Parser/HTMLParser.h>
  15. #include <LibWeb/Infra/CharacterTypes.h>
  16. namespace Web::HTML {
  17. GC_DEFINE_ALLOCATOR(HTMLFontElement);
  18. enum class Mode {
  19. RelativePlus,
  20. RelativeMinus,
  21. Absolute,
  22. };
  23. // https://html.spec.whatwg.org/multipage/rendering.html#rules-for-parsing-a-legacy-font-size
  24. static Optional<CSS::Keyword> parse_legacy_font_size(StringView string)
  25. {
  26. // 1. Let input be the attribute's value.
  27. // 2. Let position be a pointer into input, initially pointing at the start of the string.
  28. GenericLexer lexer { string };
  29. // 3. Skip ASCII whitespace within input given position.
  30. lexer.ignore_while(Web::Infra::is_ascii_whitespace);
  31. // 4. If position is past the end of input, there is no presentational hint. Return.
  32. if (lexer.is_eof())
  33. return {};
  34. // 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.
  35. Mode mode { Mode::Absolute };
  36. if (lexer.peek() == '+') {
  37. mode = Mode::RelativePlus;
  38. lexer.consume();
  39. } else if (lexer.peek() == '-') {
  40. mode = Mode::RelativeMinus;
  41. lexer.consume();
  42. }
  43. // 6. Collect a sequence of code points that are ASCII digits from input given position, and let the resulting sequence be digits.
  44. size_t start_index = lexer.tell();
  45. lexer.consume_while(is_ascii_digit);
  46. size_t end_index = lexer.tell();
  47. auto digits = lexer.input().substring_view(start_index, end_index - start_index);
  48. auto value_or_empty = AK::StringUtils::convert_to_int<i32>(digits);
  49. // 7. If digits is the empty string, there is no presentational hint. Return.
  50. if (!value_or_empty.has_value())
  51. return {};
  52. // 8. Interpret digits as a base-ten integer. Let value be the resulting number.
  53. auto value = value_or_empty.release_value();
  54. // 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.
  55. if (mode == Mode::RelativePlus)
  56. value += 3;
  57. else if (mode == Mode::RelativeMinus)
  58. value = 3 - value;
  59. // 10. If value is greater than 7, let it be 7.
  60. if (value > 7)
  61. value = 7;
  62. // 11. If value is less than 1, let it be 1.
  63. if (value < 1)
  64. value = 1;
  65. // 12. Set 'font-size' to the keyword corresponding to the value of value according to the following table:
  66. switch (value) {
  67. case 1:
  68. return CSS::Keyword::XSmall;
  69. case 2:
  70. return CSS::Keyword::Small;
  71. case 3:
  72. return CSS::Keyword::Medium;
  73. case 4:
  74. return CSS::Keyword::Large;
  75. case 5:
  76. return CSS::Keyword::XLarge;
  77. case 6:
  78. return CSS::Keyword::XxLarge;
  79. case 7:
  80. return CSS::Keyword::XxxLarge;
  81. default:
  82. VERIFY_NOT_REACHED();
  83. }
  84. }
  85. HTMLFontElement::HTMLFontElement(DOM::Document& document, DOM::QualifiedName qualified_name)
  86. : HTMLElement(document, move(qualified_name))
  87. {
  88. }
  89. HTMLFontElement::~HTMLFontElement() = default;
  90. void HTMLFontElement::initialize(JS::Realm& realm)
  91. {
  92. Base::initialize(realm);
  93. WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLFontElement);
  94. }
  95. void HTMLFontElement::apply_presentational_hints(CSS::StyleProperties& style) const
  96. {
  97. for_each_attribute([&](auto& name, auto& value) {
  98. if (name.equals_ignoring_ascii_case("color"sv)) {
  99. // https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3:rules-for-parsing-a-legacy-colour-value
  100. auto color = parse_legacy_color_value(value);
  101. if (color.has_value())
  102. style.set_property(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(color.value()));
  103. } else if (name.equals_ignoring_ascii_case("size"sv)) {
  104. // 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:
  105. auto font_size_or_empty = parse_legacy_font_size(value);
  106. if (font_size_or_empty.has_value()) {
  107. auto font_size = string_from_keyword(font_size_or_empty.release_value());
  108. if (auto parsed_value = parse_css_value(CSS::Parser::ParsingContext { document() }, font_size, CSS::PropertyID::FontSize))
  109. style.set_property(CSS::PropertyID::FontSize, parsed_value.release_nonnull());
  110. }
  111. }
  112. });
  113. }
  114. }