ListItemMarkerBox.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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::None:
  37. break;
  38. default:
  39. VERIFY_NOT_REACHED();
  40. }
  41. if (m_text.is_null()) {
  42. set_width(4);
  43. return;
  44. }
  45. auto text_width = font().width(m_text);
  46. set_width(text_width);
  47. }
  48. ListItemMarkerBox::~ListItemMarkerBox()
  49. {
  50. }
  51. void ListItemMarkerBox::paint(PaintContext& context, PaintPhase phase)
  52. {
  53. if (phase != PaintPhase::Foreground)
  54. return;
  55. // FIXME: It would be nicer to not have to go via the parent here to get our inherited style.
  56. auto color = parent()->computed_values().color();
  57. auto enclosing = enclosing_int_rect(absolute_rect());
  58. int marker_width = (int)enclosing.height() / 2;
  59. Gfx::IntRect marker_rect { 0, 0, marker_width, marker_width };
  60. marker_rect.center_within(enclosing);
  61. switch (m_list_style_type) {
  62. case CSS::ListStyleType::Square:
  63. context.painter().fill_rect(marker_rect, color);
  64. break;
  65. case CSS::ListStyleType::Circle:
  66. // For some reason for draw_ellipse() the ellipse is outside of the rect while for fill_ellipse() the ellipse is inside.
  67. // Scale the marker_rect with sqrt(2) to get an ellipse arc (circle) that appears as if it was inside of the marker_rect.
  68. marker_rect.set_height(marker_rect.height() / 1.41);
  69. marker_rect.set_width(marker_rect.width() / 1.41);
  70. marker_rect.center_within(enclosing);
  71. context.painter().draw_ellipse_intersecting(marker_rect, color);
  72. break;
  73. case CSS::ListStyleType::Disc:
  74. context.painter().fill_ellipse(marker_rect, color);
  75. break;
  76. case CSS::ListStyleType::Decimal:
  77. case CSS::ListStyleType::DecimalLeadingZero:
  78. case CSS::ListStyleType::LowerAlpha:
  79. case CSS::ListStyleType::LowerLatin:
  80. case CSS::ListStyleType::UpperAlpha:
  81. case CSS::ListStyleType::UpperLatin:
  82. if (m_text.is_null())
  83. break;
  84. context.painter().draw_text(enclosing, m_text, Gfx::TextAlignment::Center);
  85. break;
  86. case CSS::ListStyleType::None:
  87. return;
  88. default:
  89. VERIFY_NOT_REACHED();
  90. }
  91. }
  92. }