Transformation.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "Transformation.h"
  8. #include <LibWeb/Layout/Node.h>
  9. #include <LibWeb/Painting/PaintableBox.h>
  10. namespace Web::CSS {
  11. Transformation::Transformation(TransformFunction function, Vector<TransformValue>&& values)
  12. : m_function(function)
  13. , m_values(move(values))
  14. {
  15. }
  16. Gfx::FloatMatrix4x4 Transformation::to_matrix(Painting::PaintableBox const& paintable_box) const
  17. {
  18. auto count = m_values.size();
  19. auto value = [&](size_t index, CSS::Length const& reference_length = CSS::Length::make_px(0)) -> float {
  20. return m_values[index].visit(
  21. [&](CSS::LengthPercentage const& value) -> double {
  22. return value.resolved(paintable_box.layout_node(), reference_length).to_px(paintable_box.layout_node()).to_float();
  23. },
  24. [&](CSS::AngleOrCalculated const& value) {
  25. return AK::to_radians(value.resolved(paintable_box.layout_node()).to_degrees());
  26. },
  27. [](double value) {
  28. return value;
  29. });
  30. };
  31. auto reference_box = paintable_box.absolute_rect();
  32. auto width = CSS::Length::make_px(reference_box.width());
  33. auto height = CSS::Length::make_px(reference_box.height());
  34. switch (m_function) {
  35. case CSS::TransformFunction::Matrix:
  36. if (count == 6)
  37. return Gfx::FloatMatrix4x4(value(0), value(2), 0, value(4),
  38. value(1), value(3), 0, value(5),
  39. 0, 0, 1, 0,
  40. 0, 0, 0, 1);
  41. break;
  42. case CSS::TransformFunction::Matrix3d:
  43. if (count == 16)
  44. return Gfx::FloatMatrix4x4(value(0), value(4), value(8), value(12),
  45. value(1), value(5), value(9), value(13),
  46. value(2), value(6), value(10), value(14),
  47. value(3), value(7), value(11), value(15));
  48. break;
  49. case CSS::TransformFunction::Translate:
  50. if (count == 1)
  51. return Gfx::FloatMatrix4x4(1, 0, 0, value(0, width),
  52. 0, 1, 0, 0,
  53. 0, 0, 1, 0,
  54. 0, 0, 0, 1);
  55. if (count == 2)
  56. return Gfx::FloatMatrix4x4(1, 0, 0, value(0, width),
  57. 0, 1, 0, value(1, height),
  58. 0, 0, 1, 0,
  59. 0, 0, 0, 1);
  60. break;
  61. case CSS::TransformFunction::Translate3d:
  62. return Gfx::FloatMatrix4x4(1, 0, 0, value(0, width),
  63. 0, 1, 0, value(1, height),
  64. 0, 0, 1, value(2),
  65. 0, 0, 0, 1);
  66. break;
  67. case CSS::TransformFunction::TranslateX:
  68. if (count == 1)
  69. return Gfx::FloatMatrix4x4(1, 0, 0, value(0, width),
  70. 0, 1, 0, 0,
  71. 0, 0, 1, 0,
  72. 0, 0, 0, 1);
  73. break;
  74. case CSS::TransformFunction::TranslateY:
  75. if (count == 1)
  76. return Gfx::FloatMatrix4x4(1, 0, 0, 0,
  77. 0, 1, 0, value(0, height),
  78. 0, 0, 1, 0,
  79. 0, 0, 0, 1);
  80. break;
  81. case CSS::TransformFunction::TranslateZ:
  82. if (count == 1)
  83. return Gfx::FloatMatrix4x4(1, 0, 0, 0,
  84. 0, 1, 0, 0,
  85. 0, 0, 1, value(0),
  86. 0, 0, 0, 1);
  87. break;
  88. case CSS::TransformFunction::Scale:
  89. if (count == 1)
  90. return Gfx::FloatMatrix4x4(value(0), 0, 0, 0,
  91. 0, value(0), 0, 0,
  92. 0, 0, 1, 0,
  93. 0, 0, 0, 1);
  94. if (count == 2)
  95. return Gfx::FloatMatrix4x4(value(0), 0, 0, 0,
  96. 0, value(1), 0, 0,
  97. 0, 0, 1, 0,
  98. 0, 0, 0, 1);
  99. break;
  100. case CSS::TransformFunction::ScaleX:
  101. if (count == 1)
  102. return Gfx::FloatMatrix4x4(value(0), 0, 0, 0,
  103. 0, 1, 0, 0,
  104. 0, 0, 1, 0,
  105. 0, 0, 0, 1);
  106. break;
  107. case CSS::TransformFunction::ScaleY:
  108. if (count == 1)
  109. return Gfx::FloatMatrix4x4(1, 0, 0, 0,
  110. 0, value(0), 0, 0,
  111. 0, 0, 1, 0,
  112. 0, 0, 0, 1);
  113. break;
  114. case CSS::TransformFunction::RotateX:
  115. if (count == 1)
  116. return Gfx::rotation_matrix({ 1.0f, 0.0f, 0.0f }, value(0));
  117. break;
  118. case CSS::TransformFunction::RotateY:
  119. if (count == 1)
  120. return Gfx::rotation_matrix({ 0.0f, 1.0f, 0.0f }, value(0));
  121. break;
  122. case CSS::TransformFunction::Rotate:
  123. case CSS::TransformFunction::RotateZ:
  124. if (count == 1)
  125. return Gfx::rotation_matrix({ 0.0f, 0.0f, 1.0f }, value(0));
  126. break;
  127. case CSS::TransformFunction::Skew:
  128. if (count == 1)
  129. return Gfx::FloatMatrix4x4(1, tanf(value(0)), 0, 0,
  130. 0, 1, 0, 0,
  131. 0, 0, 1, 0,
  132. 0, 0, 0, 1);
  133. if (count == 2)
  134. return Gfx::FloatMatrix4x4(1, tanf(value(0)), 0, 0,
  135. tanf(value(1)), 1, 0, 0,
  136. 0, 0, 1, 0,
  137. 0, 0, 0, 1);
  138. break;
  139. case CSS::TransformFunction::SkewX:
  140. if (count == 1)
  141. return Gfx::FloatMatrix4x4(1, tanf(value(0)), 0, 0,
  142. 0, 1, 0, 0,
  143. 0, 0, 1, 0,
  144. 0, 0, 0, 1);
  145. break;
  146. case CSS::TransformFunction::SkewY:
  147. if (count == 1)
  148. return Gfx::FloatMatrix4x4(1, 0, 0, 0,
  149. tanf(value(0)), 1, 0, 0,
  150. 0, 0, 1, 0,
  151. 0, 0, 0, 1);
  152. break;
  153. }
  154. dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Unhandled transformation function {} with {} arguments", to_string(m_function), m_values.size());
  155. return Gfx::FloatMatrix4x4::identity();
  156. }
  157. }