ListItemMarkerBox.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
  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, NonnullRefPtr<CSS::StyleProperties> style)
  12. : Box(document, nullptr, move(style))
  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. }
  48. ListItemMarkerBox::~ListItemMarkerBox()
  49. {
  50. }
  51. void ListItemMarkerBox::paint(PaintContext& context, PaintPhase phase)
  52. {
  53. if (phase != PaintPhase::Foreground)
  54. return;
  55. auto enclosing = enclosing_int_rect(absolute_rect());
  56. if (auto const* list_style_image = list_style_image_bitmap()) {
  57. context.painter().blit(enclosing.location(), *list_style_image, list_style_image->rect());
  58. return;
  59. }
  60. auto color = computed_values().color();
  61. int marker_width = (int)enclosing.height() / 2;
  62. Gfx::IntRect marker_rect { 0, 0, marker_width, marker_width };
  63. marker_rect.center_within(enclosing);
  64. switch (m_list_style_type) {
  65. case CSS::ListStyleType::Square:
  66. context.painter().fill_rect(marker_rect, color);
  67. break;
  68. case CSS::ListStyleType::Circle:
  69. // For some reason for draw_ellipse() the ellipse is outside of the rect while for fill_ellipse() the ellipse is inside.
  70. // Scale the marker_rect with sqrt(2) to get an ellipse arc (circle) that appears as if it was inside of the marker_rect.
  71. marker_rect.set_height(marker_rect.height() / 1.41);
  72. marker_rect.set_width(marker_rect.width() / 1.41);
  73. marker_rect.center_within(enclosing);
  74. context.painter().draw_ellipse_intersecting(marker_rect, color);
  75. break;
  76. case CSS::ListStyleType::Disc:
  77. context.painter().fill_ellipse(marker_rect, color);
  78. break;
  79. case CSS::ListStyleType::Decimal:
  80. case CSS::ListStyleType::DecimalLeadingZero:
  81. case CSS::ListStyleType::LowerAlpha:
  82. case CSS::ListStyleType::LowerLatin:
  83. case CSS::ListStyleType::LowerRoman:
  84. case CSS::ListStyleType::UpperAlpha:
  85. case CSS::ListStyleType::UpperLatin:
  86. case CSS::ListStyleType::UpperRoman:
  87. if (m_text.is_null())
  88. break;
  89. context.painter().draw_text(enclosing, m_text, Gfx::TextAlignment::Center);
  90. break;
  91. case CSS::ListStyleType::None:
  92. return;
  93. default:
  94. VERIFY_NOT_REACHED();
  95. }
  96. }
  97. Gfx::Bitmap const* ListItemMarkerBox::list_style_image_bitmap() const
  98. {
  99. return list_style_image() ? list_style_image()->bitmap() : nullptr;
  100. }
  101. }