HTMLFontElement.cpp 5.0 KB

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