Length.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (c) 2020, 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/NonnullOwnPtr.h>
  8. #include <AK/Variant.h>
  9. #include <LibGfx/Font.h>
  10. #include <LibGfx/Rect.h>
  11. #include <LibWeb/CSS/Length.h>
  12. #include <LibWeb/CSS/Percentage.h>
  13. #include <LibWeb/DOM/Document.h>
  14. #include <LibWeb/HTML/BrowsingContext.h>
  15. #include <LibWeb/HTML/HTMLHtmlElement.h>
  16. namespace Web::CSS {
  17. Length::Length() = default;
  18. Length::Length(int value, Type type)
  19. : m_type(type)
  20. , m_value(value)
  21. {
  22. }
  23. Length::Length(float value, Type type)
  24. : m_type(type)
  25. , m_value(value)
  26. {
  27. }
  28. Length Length::make_auto()
  29. {
  30. return Length(0, Type::Auto);
  31. }
  32. Length Length::make_px(float value)
  33. {
  34. return Length(value, Type::Px);
  35. }
  36. Length Length::percentage_of(Percentage const& percentage) const
  37. {
  38. if (is_undefined_or_auto()) {
  39. dbgln("Attempting to get percentage of an undefined or auto length, this seems wrong? But for now we just return the original length.");
  40. return *this;
  41. }
  42. return Length { percentage.as_fraction() * raw_value(), m_type };
  43. }
  44. Length Length::resolved(const Length& fallback_for_undefined, const Layout::Node& layout_node, float reference_for_percent) const
  45. {
  46. if (is_undefined())
  47. return fallback_for_undefined;
  48. if (is_calculated())
  49. return Length(resolve_calculated_value(layout_node, reference_for_percent), Type::Px);
  50. if (is_percentage())
  51. return make_px(raw_value() / 100.0f * reference_for_percent);
  52. if (is_relative())
  53. return make_px(to_px(layout_node));
  54. return *this;
  55. }
  56. Length Length::resolved_or_auto(const Layout::Node& layout_node, float reference_for_percent) const
  57. {
  58. return resolved(make_auto(), layout_node, reference_for_percent);
  59. }
  60. Length Length::resolved_or_zero(const Layout::Node& layout_node, float reference_for_percent) const
  61. {
  62. return resolved(make_px(0), layout_node, reference_for_percent);
  63. }
  64. void Length::set_calculated_style(CalculatedStyleValue* value)
  65. {
  66. m_calculated_style = value;
  67. }
  68. float Length::relative_length_to_px(Gfx::IntRect const& viewport_rect, Gfx::FontMetrics const& font_metrics, float root_font_size) const
  69. {
  70. switch (m_type) {
  71. case Type::Ex:
  72. return m_value * font_metrics.x_height;
  73. case Type::Em:
  74. return m_value * font_metrics.size;
  75. case Type::Ch:
  76. // FIXME: Use layout_node.font().glyph_height() when writing-mode is not horizontal-tb (it has to be implemented first)
  77. return m_value * (font_metrics.glyph_width + font_metrics.glyph_spacing);
  78. case Type::Rem:
  79. return m_value * root_font_size;
  80. case Type::Vw:
  81. return viewport_rect.width() * (m_value / 100);
  82. case Type::Vh:
  83. return viewport_rect.height() * (m_value / 100);
  84. case Type::Vmin:
  85. return min(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
  86. case Type::Vmax:
  87. return max(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
  88. default:
  89. VERIFY_NOT_REACHED();
  90. }
  91. }
  92. float Length::to_px(Layout::Node const& layout_node) const
  93. {
  94. if (!layout_node.document().browsing_context())
  95. return 0;
  96. auto viewport_rect = layout_node.document().browsing_context()->viewport_rect();
  97. auto* root_element = layout_node.document().document_element();
  98. if (!root_element || !root_element->layout_node())
  99. return 0;
  100. return to_px(viewport_rect, layout_node.font().metrics('M'), root_element->layout_node()->font().presentation_size());
  101. }
  102. static float resolve_calc_value(CalculatedStyleValue::CalcValue const&, const Layout::Node& layout_node, float reference_for_percent);
  103. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const&);
  104. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const&, const Layout::Node& layout_node, float reference_for_percent);
  105. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const&, const Layout::Node& layout_node, float reference_for_percent);
  106. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const&);
  107. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const&);
  108. float Length::resolve_calculated_value(const Layout::Node& layout_node, float reference_for_percent) const
  109. {
  110. if (!m_calculated_style)
  111. return 0.0f;
  112. auto& expression = m_calculated_style->expression();
  113. auto length = resolve_calc_sum(expression, layout_node, reference_for_percent);
  114. return length;
  115. };
  116. static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, const Layout::Node& layout_node, float reference_for_percent)
  117. {
  118. return calc_value.visit(
  119. [](float value) { return value; },
  120. [&](Length const& length) {
  121. return length.resolved_or_zero(layout_node, reference_for_percent).to_px(layout_node);
  122. },
  123. [&](NonnullOwnPtr<CalculatedStyleValue::CalcSum> const& calc_sum) {
  124. return resolve_calc_sum(calc_sum, layout_node, reference_for_percent);
  125. },
  126. [](auto&) {
  127. VERIFY_NOT_REACHED();
  128. return 0.0f;
  129. });
  130. }
  131. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const& calc_number_product)
  132. {
  133. auto value = resolve_calc_number_value(calc_number_product->first_calc_number_value);
  134. for (auto& additional_number_value : calc_number_product->zero_or_more_additional_calc_number_values) {
  135. auto additional_value = resolve_calc_number_value(additional_number_value.value);
  136. if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Multiply)
  137. value *= additional_value;
  138. else if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Divide)
  139. value /= additional_value;
  140. else
  141. VERIFY_NOT_REACHED();
  142. }
  143. return value;
  144. }
  145. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const& calc_number_sum)
  146. {
  147. auto value = resolve_calc_number_product(calc_number_sum->first_calc_number_product);
  148. for (auto& additional_product : calc_number_sum->zero_or_more_additional_calc_number_products) {
  149. auto additional_value = resolve_calc_number_product(additional_product.calc_number_product);
  150. if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Add)
  151. value += additional_value;
  152. else if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Subtract)
  153. value -= additional_value;
  154. else
  155. VERIFY_NOT_REACHED();
  156. }
  157. return value;
  158. }
  159. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const& number_value)
  160. {
  161. return number_value.visit(
  162. [](float number) { return number; },
  163. [](NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const& calc_number_sum) {
  164. return resolve_calc_number_sum(calc_number_sum);
  165. });
  166. }
  167. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const& calc_product, const Layout::Node& layout_node, float reference_for_percent)
  168. {
  169. auto value = resolve_calc_value(calc_product->first_calc_value, layout_node, reference_for_percent);
  170. for (auto& additional_value : calc_product->zero_or_more_additional_calc_values) {
  171. additional_value.value.visit(
  172. [&](CalculatedStyleValue::CalcValue const& calc_value) {
  173. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Multiply)
  174. VERIFY_NOT_REACHED();
  175. auto resolved_value = resolve_calc_value(calc_value, layout_node, reference_for_percent);
  176. value *= resolved_value;
  177. },
  178. [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) {
  179. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Divide)
  180. VERIFY_NOT_REACHED();
  181. auto resolved_calc_number_value = resolve_calc_number_value(calc_number_value);
  182. value /= resolved_calc_number_value;
  183. });
  184. }
  185. return value;
  186. }
  187. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const& calc_sum, const Layout::Node& layout_node, float reference_for_percent)
  188. {
  189. auto value = resolve_calc_product(calc_sum->first_calc_product, layout_node, reference_for_percent);
  190. for (auto& additional_product : calc_sum->zero_or_more_additional_calc_products) {
  191. auto additional_value = resolve_calc_product(additional_product.calc_product, layout_node, reference_for_percent);
  192. if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Add)
  193. value += additional_value;
  194. else if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Subtract)
  195. value -= additional_value;
  196. else
  197. VERIFY_NOT_REACHED();
  198. }
  199. return value;
  200. }
  201. const char* Length::unit_name() const
  202. {
  203. switch (m_type) {
  204. case Type::Cm:
  205. return "cm";
  206. case Type::In:
  207. return "in";
  208. case Type::Px:
  209. return "px";
  210. case Type::Pt:
  211. return "pt";
  212. case Type::Mm:
  213. return "mm";
  214. case Type::Q:
  215. return "Q";
  216. case Type::Pc:
  217. return "pc";
  218. case Type::Ex:
  219. return "ex";
  220. case Type::Em:
  221. return "em";
  222. case Type::Ch:
  223. return "ch";
  224. case Type::Rem:
  225. return "rem";
  226. case Type::Auto:
  227. return "auto";
  228. case Type::Percentage:
  229. return "%";
  230. case Type::Undefined:
  231. return "undefined";
  232. case Type::Vh:
  233. return "vh";
  234. case Type::Vw:
  235. return "vw";
  236. case Type::Vmax:
  237. return "vmax";
  238. case Type::Vmin:
  239. return "vmin";
  240. case Type::Calculated:
  241. return "calculated";
  242. }
  243. VERIFY_NOT_REACHED();
  244. }
  245. }