ListItemMarkerBox.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Tobias Christiansen <tobi@tobyase.de>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/StringBuilder.h>
  8. #include <LibGfx/Painter.h>
  9. #include <LibWeb/Layout/ListItemMarkerBox.h>
  10. namespace Web::Layout {
  11. ListItemMarkerBox::ListItemMarkerBox(DOM::Document& document, CSS::ListStyleType style_type, size_t index)
  12. : Box(document, nullptr, CSS::StyleProperties::create())
  13. , m_list_style_type(style_type)
  14. , m_index(index)
  15. {
  16. switch (m_list_style_type) {
  17. case CSS::ListStyleType::Square:
  18. case CSS::ListStyleType::Circle:
  19. case CSS::ListStyleType::Disc:
  20. break;
  21. case CSS::ListStyleType::Decimal:
  22. m_text = String::formatted("{}.", m_index);
  23. break;
  24. case CSS::ListStyleType::DecimalLeadingZero:
  25. // This is weird, but in accordance to spec.
  26. m_text = m_index < 10 ? String::formatted("0{}.", m_index) : String::formatted("{}.", m_index);
  27. break;
  28. case CSS::ListStyleType::LowerAlpha:
  29. case CSS::ListStyleType::LowerLatin:
  30. m_text = String::bijective_base_from(m_index - 1).to_lowercase();
  31. break;
  32. case CSS::ListStyleType::UpperAlpha:
  33. case CSS::ListStyleType::UpperLatin:
  34. m_text = String::bijective_base_from(m_index - 1);
  35. break;
  36. case CSS::ListStyleType::LowerRoman:
  37. m_text = String::roman_number_from(m_index).to_lowercase();
  38. break;
  39. case CSS::ListStyleType::UpperRoman:
  40. m_text = String::roman_number_from(m_index);
  41. break;
  42. case CSS::ListStyleType::None:
  43. break;
  44. default:
  45. VERIFY_NOT_REACHED();
  46. }
  47. if (m_text.is_null()) {
  48. set_width(4);
  49. return;
  50. }
  51. auto text_width = font().width(m_text);
  52. set_width(text_width);
  53. }
  54. ListItemMarkerBox::~ListItemMarkerBox()
  55. {
  56. }
  57. void ListItemMarkerBox::paint(PaintContext& context, PaintPhase phase)
  58. {
  59. if (phase != PaintPhase::Foreground)
  60. return;
  61. // FIXME: It would be nicer to not have to go via the parent here to get our inherited style.
  62. auto color = parent()->computed_values().color();
  63. auto enclosing = enclosing_int_rect(absolute_rect());
  64. int marker_width = (int)enclosing.height() / 2;
  65. Gfx::IntRect marker_rect { 0, 0, marker_width, marker_width };
  66. marker_rect.center_within(enclosing);
  67. switch (m_list_style_type) {
  68. case CSS::ListStyleType::Square:
  69. context.painter().fill_rect(marker_rect, color);
  70. break;
  71. case CSS::ListStyleType::Circle:
  72. // For some reason for draw_ellipse() the ellipse is outside of the rect while for fill_ellipse() the ellipse is inside.
  73. // Scale the marker_rect with sqrt(2) to get an ellipse arc (circle) that appears as if it was inside of the marker_rect.
  74. marker_rect.set_height(marker_rect.height() / 1.41);
  75. marker_rect.set_width(marker_rect.width() / 1.41);
  76. marker_rect.center_within(enclosing);
  77. context.painter().draw_ellipse_intersecting(marker_rect, color);
  78. break;
  79. case CSS::ListStyleType::Disc:
  80. context.painter().fill_ellipse(marker_rect, color);
  81. break;
  82. case CSS::ListStyleType::Decimal:
  83. case CSS::ListStyleType::DecimalLeadingZero:
  84. case CSS::ListStyleType::LowerAlpha:
  85. case CSS::ListStyleType::LowerLatin:
  86. case CSS::ListStyleType::LowerRoman:
  87. case CSS::ListStyleType::UpperAlpha:
  88. case CSS::ListStyleType::UpperLatin:
  89. case CSS::ListStyleType::UpperRoman:
  90. if (m_text.is_null())
  91. break;
  92. context.painter().draw_text(enclosing, m_text, Gfx::TextAlignment::Center);
  93. break;
  94. case CSS::ListStyleType::None:
  95. return;
  96. default:
  97. VERIFY_NOT_REACHED();
  98. }
  99. }
  100. }