Position.cpp 3.8 KB

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