Position.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Position.h"
  7. #include <LibGfx/Point.h>
  8. #include <LibGfx/Rect.h>
  9. #include <LibWeb/CSS/StyleValue.h>
  10. namespace Web::CSS {
  11. CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect const& rect) const
  12. {
  13. // Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense)
  14. CSSPixels x = horizontal_position.visit(
  15. [&](HorizontalPreset preset) -> CSSPixels {
  16. return rect.width() * [&] {
  17. switch (preset) {
  18. case HorizontalPreset::Left:
  19. return 0.0f;
  20. case HorizontalPreset::Center:
  21. return 0.5f;
  22. case HorizontalPreset::Right:
  23. return 1.0f;
  24. default:
  25. VERIFY_NOT_REACHED();
  26. }
  27. }();
  28. },
  29. [&](LengthPercentage length_percentage) -> CSSPixels {
  30. return length_percentage.resolved(node, Length::make_px(rect.width())).to_px(node);
  31. });
  32. CSSPixels y = vertical_position.visit(
  33. [&](VerticalPreset preset) -> CSSPixels {
  34. return rect.height() * [&] {
  35. switch (preset) {
  36. case VerticalPreset::Top:
  37. return 0.0f;
  38. case VerticalPreset::Center:
  39. return 0.5f;
  40. case VerticalPreset::Bottom:
  41. return 1.0f;
  42. default:
  43. VERIFY_NOT_REACHED();
  44. }
  45. }();
  46. },
  47. [&](LengthPercentage length_percentage) -> CSSPixels {
  48. return length_percentage.resolved(node, Length::make_px(rect.height())).to_px(node);
  49. });
  50. if (x_relative_to == HorizontalEdge::Right)
  51. x = rect.width() - x;
  52. if (y_relative_to == VerticalEdge::Bottom)
  53. y = rect.height() - y;
  54. return CSSPixelPoint { rect.x() + x, rect.y() + y };
  55. }
  56. ErrorOr<void> PositionValue::serialize(StringBuilder& builder) const
  57. {
  58. // Note: This means our serialization with simplify any with explicit edges that are just `top left`.
  59. bool has_relative_edges = x_relative_to == HorizontalEdge::Right || y_relative_to == VerticalEdge::Bottom;
  60. if (has_relative_edges)
  61. TRY(builder.try_append(x_relative_to == HorizontalEdge::Left ? "left "sv : "right "sv));
  62. TRY(horizontal_position.visit(
  63. [&](HorizontalPreset preset) -> ErrorOr<void> {
  64. return builder.try_append([&] {
  65. switch (preset) {
  66. case HorizontalPreset::Left:
  67. return "left"sv;
  68. case HorizontalPreset::Center:
  69. return "center"sv;
  70. case HorizontalPreset::Right:
  71. return "right"sv;
  72. default:
  73. VERIFY_NOT_REACHED();
  74. }
  75. }());
  76. },
  77. [&](LengthPercentage length_percentage) -> ErrorOr<void> {
  78. return builder.try_appendff(TRY(length_percentage.to_string()));
  79. }));
  80. TRY(builder.try_append(' '));
  81. if (has_relative_edges)
  82. TRY(builder.try_append(y_relative_to == VerticalEdge::Top ? "top "sv : "bottom "sv));
  83. TRY(vertical_position.visit(
  84. [&](VerticalPreset preset) -> ErrorOr<void> {
  85. return builder.try_append([&] {
  86. switch (preset) {
  87. case VerticalPreset::Top:
  88. return "top"sv;
  89. case VerticalPreset::Center:
  90. return "center"sv;
  91. case VerticalPreset::Bottom:
  92. return "bottom"sv;
  93. default:
  94. VERIFY_NOT_REACHED();
  95. }
  96. }());
  97. },
  98. [&](LengthPercentage length_percentage) -> ErrorOr<void> {
  99. return builder.try_append(TRY(length_percentage.to_string()));
  100. }));
  101. return {};
  102. }
  103. }