Length.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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/DOM/Document.h>
  13. #include <LibWeb/HTML/HTMLHtmlElement.h>
  14. #include <LibWeb/Page/BrowsingContext.h>
  15. namespace Web::CSS {
  16. float Length::relative_length_to_px(Gfx::IntRect const& viewport_rect, Gfx::FontMetrics const& font_metrics, float root_font_size) const
  17. {
  18. switch (m_type) {
  19. case Type::Ex:
  20. return m_value * font_metrics.x_height;
  21. case Type::Em:
  22. return m_value * font_metrics.size;
  23. case Type::Ch:
  24. // FIXME: Use layout_node.font().glyph_height() when writing-mode is not horizontal-tb (it has to be implemented first)
  25. return m_value * (font_metrics.glyph_width + font_metrics.glyph_spacing);
  26. case Type::Rem:
  27. return m_value * root_font_size;
  28. case Type::Vw:
  29. return viewport_rect.width() * (m_value / 100);
  30. case Type::Vh:
  31. return viewport_rect.height() * (m_value / 100);
  32. case Type::Vmin:
  33. return min(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
  34. case Type::Vmax:
  35. return max(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
  36. default:
  37. VERIFY_NOT_REACHED();
  38. }
  39. }
  40. float Length::to_px(Layout::Node const& layout_node) const
  41. {
  42. if (!layout_node.document().browsing_context())
  43. return 0;
  44. auto viewport_rect = layout_node.document().browsing_context()->viewport_rect();
  45. auto* root_element = layout_node.document().document_element();
  46. if (!root_element || !root_element->layout_node())
  47. return 0;
  48. return to_px(viewport_rect, layout_node.font().metrics('M'), root_element->layout_node()->font().presentation_size());
  49. }
  50. float Length::relative_length_to_px(Layout::Node const& layout_node) const
  51. {
  52. auto viewport_rect = layout_node.document().browsing_context()->viewport_rect();
  53. auto root_element = layout_node.document().document_element();
  54. return relative_length_to_px(viewport_rect, layout_node.font().metrics('M'), root_element->layout_node()->font().presentation_size());
  55. }
  56. static float resolve_calc_value(CalculatedStyleValue::CalcValue const&, const Layout::Node& layout_node, float reference_for_percent);
  57. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const&);
  58. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const&, const Layout::Node& layout_node, float reference_for_percent);
  59. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const&, const Layout::Node& layout_node, float reference_for_percent);
  60. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const&);
  61. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const&);
  62. float Length::resolve_calculated_value(const Layout::Node& layout_node, float reference_for_percent) const
  63. {
  64. if (!m_calculated_style)
  65. return 0.0f;
  66. auto& expression = m_calculated_style->expression();
  67. auto length = resolve_calc_sum(expression, layout_node, reference_for_percent);
  68. return length;
  69. };
  70. static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, const Layout::Node& layout_node, float reference_for_percent)
  71. {
  72. return calc_value.visit(
  73. [](float value) { return value; },
  74. [&](Length length) {
  75. return length.resolved_or_zero(layout_node, reference_for_percent).to_px(layout_node);
  76. },
  77. [&](NonnullOwnPtr<CalculatedStyleValue::CalcSum>& calc_sum) {
  78. return resolve_calc_sum(calc_sum, layout_node, reference_for_percent);
  79. },
  80. [](auto&) {
  81. VERIFY_NOT_REACHED();
  82. return 0.0f;
  83. });
  84. }
  85. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const& calc_number_product)
  86. {
  87. auto value = resolve_calc_number_value(calc_number_product->first_calc_number_value);
  88. for (auto& additional_number_value : calc_number_product->zero_or_more_additional_calc_number_values) {
  89. auto additional_value = resolve_calc_number_value(additional_number_value.value);
  90. if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Multiply)
  91. value *= additional_value;
  92. else if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Divide)
  93. value /= additional_value;
  94. else
  95. VERIFY_NOT_REACHED();
  96. }
  97. return value;
  98. }
  99. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const& calc_number_sum)
  100. {
  101. auto value = resolve_calc_number_product(calc_number_sum->first_calc_number_product);
  102. for (auto& additional_product : calc_number_sum->zero_or_more_additional_calc_number_products) {
  103. auto additional_value = resolve_calc_number_product(additional_product.calc_number_product);
  104. if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Add)
  105. value += additional_value;
  106. else if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Subtract)
  107. value -= additional_value;
  108. else
  109. VERIFY_NOT_REACHED();
  110. }
  111. return value;
  112. }
  113. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const& number_value)
  114. {
  115. return number_value.visit(
  116. [](float number) { return number; },
  117. [](NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum>& calc_number_sum) {
  118. return resolve_calc_number_sum(calc_number_sum);
  119. });
  120. }
  121. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const& calc_product, const Layout::Node& layout_node, float reference_for_percent)
  122. {
  123. auto value = resolve_calc_value(calc_product->first_calc_value, layout_node, reference_for_percent);
  124. for (auto& additional_value : calc_product->zero_or_more_additional_calc_values) {
  125. additional_value.value.visit(
  126. [&](CalculatedStyleValue::CalcValue const& calc_value) {
  127. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Multiply)
  128. VERIFY_NOT_REACHED();
  129. auto resolved_value = resolve_calc_value(calc_value, layout_node, reference_for_percent);
  130. value *= resolved_value;
  131. },
  132. [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) {
  133. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Divide)
  134. VERIFY_NOT_REACHED();
  135. auto resolved_calc_number_value = resolve_calc_number_value(calc_number_value);
  136. value /= resolved_calc_number_value;
  137. });
  138. }
  139. return value;
  140. }
  141. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const& calc_sum, const Layout::Node& layout_node, float reference_for_percent)
  142. {
  143. auto value = resolve_calc_product(calc_sum->first_calc_product, layout_node, reference_for_percent);
  144. for (auto& additional_product : calc_sum->zero_or_more_additional_calc_products) {
  145. auto additional_value = resolve_calc_product(additional_product.calc_product, layout_node, reference_for_percent);
  146. if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Add)
  147. value += additional_value;
  148. else if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Subtract)
  149. value -= additional_value;
  150. else
  151. VERIFY_NOT_REACHED();
  152. }
  153. return value;
  154. }
  155. const char* Length::unit_name() const
  156. {
  157. switch (m_type) {
  158. case Type::Cm:
  159. return "cm";
  160. case Type::In:
  161. return "in";
  162. case Type::Px:
  163. return "px";
  164. case Type::Pt:
  165. return "pt";
  166. case Type::Mm:
  167. return "mm";
  168. case Type::Q:
  169. return "Q";
  170. case Type::Pc:
  171. return "pc";
  172. case Type::Ex:
  173. return "ex";
  174. case Type::Em:
  175. return "em";
  176. case Type::Ch:
  177. return "ch";
  178. case Type::Rem:
  179. return "rem";
  180. case Type::Auto:
  181. return "auto";
  182. case Type::Percentage:
  183. return "%";
  184. case Type::Undefined:
  185. return "undefined";
  186. case Type::Vh:
  187. return "vh";
  188. case Type::Vw:
  189. return "vw";
  190. case Type::Vmax:
  191. return "vmax";
  192. case Type::Vmin:
  193. return "vmin";
  194. case Type::Calculated:
  195. return "calculated";
  196. }
  197. VERIFY_NOT_REACHED();
  198. }
  199. }