Length.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Tobias Christiansen <tobi@tobyase.de>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/NonnullOwnPtr.h>
  8. #include <AK/Variant.h>
  9. #include <LibWeb/CSS/Length.h>
  10. #include <LibWeb/DOM/Document.h>
  11. #include <LibWeb/HTML/HTMLHtmlElement.h>
  12. #include <LibWeb/Page/BrowsingContext.h>
  13. namespace Web::CSS {
  14. float Length::relative_length_to_px(const Layout::Node& layout_node) const
  15. {
  16. switch (m_type) {
  17. case Type::Ex:
  18. return m_value * layout_node.font().x_height();
  19. case Type::Em:
  20. return m_value * layout_node.font_size();
  21. case Type::Rem:
  22. return m_value * layout_node.document().document_element()->layout_node()->font_size();
  23. case Type::Vw:
  24. return layout_node.document().browsing_context()->viewport_rect().width() * (m_value / 100);
  25. case Type::Vh:
  26. return layout_node.document().browsing_context()->viewport_rect().height() * (m_value / 100);
  27. case Type::Vmin: {
  28. auto viewport = layout_node.document().browsing_context()->viewport_rect();
  29. return min(viewport.width(), viewport.height()) * (m_value / 100);
  30. }
  31. case Type::Vmax: {
  32. auto viewport = layout_node.document().browsing_context()->viewport_rect();
  33. return max(viewport.width(), viewport.height()) * (m_value / 100);
  34. }
  35. default:
  36. VERIFY_NOT_REACHED();
  37. }
  38. }
  39. static float resolve_calc_value(CalculatedStyleValue::CalcValue const&, const Layout::Node& layout_node, float reference_for_percent);
  40. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const&);
  41. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const&, const Layout::Node& layout_node, float reference_for_percent);
  42. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const&, const Layout::Node& layout_node, float reference_for_percent);
  43. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const&);
  44. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const&);
  45. float Length::resolve_calculated_value(const Layout::Node& layout_node, float reference_for_percent) const
  46. {
  47. if (!m_calculated_style)
  48. return 0.0f;
  49. auto& expression = m_calculated_style->expression();
  50. auto length = resolve_calc_sum(expression, layout_node, reference_for_percent);
  51. return length;
  52. };
  53. static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, const Layout::Node& layout_node, float reference_for_percent)
  54. {
  55. return calc_value.visit(
  56. [](float value) { return value; },
  57. [&](Length length) {
  58. return length.resolved_or_zero(layout_node, reference_for_percent).to_px(layout_node);
  59. },
  60. [&](NonnullOwnPtr<CalculatedStyleValue::CalcSum>& calc_sum) {
  61. return resolve_calc_sum(calc_sum, layout_node, reference_for_percent);
  62. },
  63. [](auto&) {
  64. VERIFY_NOT_REACHED();
  65. return 0.0f;
  66. });
  67. }
  68. static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const& calc_number_product)
  69. {
  70. auto value = resolve_calc_number_value(calc_number_product->first_calc_number_value);
  71. for (auto& additional_number_value : calc_number_product->zero_or_more_additional_calc_number_values) {
  72. auto additional_value = resolve_calc_number_value(additional_number_value.value);
  73. if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Multiply)
  74. value *= additional_value;
  75. else if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Divide)
  76. value /= additional_value;
  77. else
  78. VERIFY_NOT_REACHED();
  79. }
  80. return value;
  81. }
  82. static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const& calc_number_sum)
  83. {
  84. auto value = resolve_calc_number_product(calc_number_sum->first_calc_number_product);
  85. for (auto& additional_product : calc_number_sum->zero_or_more_additional_calc_number_products) {
  86. auto additional_value = resolve_calc_number_product(additional_product.calc_number_product);
  87. if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Add)
  88. value += additional_value;
  89. else if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Subtract)
  90. value -= additional_value;
  91. else
  92. VERIFY_NOT_REACHED();
  93. }
  94. return value;
  95. }
  96. static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const& number_value)
  97. {
  98. return number_value.visit(
  99. [](float number) { return number; },
  100. [](NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum>& calc_number_sum) {
  101. return resolve_calc_number_sum(calc_number_sum);
  102. });
  103. }
  104. static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const& calc_product, const Layout::Node& layout_node, float reference_for_percent)
  105. {
  106. auto value = resolve_calc_value(calc_product->first_calc_value, layout_node, reference_for_percent);
  107. for (auto& additional_value : calc_product->zero_or_more_additional_calc_values) {
  108. additional_value.value.visit(
  109. [&](CalculatedStyleValue::CalcValue const& calc_value) {
  110. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Multiply)
  111. VERIFY_NOT_REACHED();
  112. auto resolved_value = resolve_calc_value(calc_value, layout_node, reference_for_percent);
  113. value *= resolved_value;
  114. },
  115. [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) {
  116. if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::Divide)
  117. VERIFY_NOT_REACHED();
  118. auto resolved_calc_number_value = resolve_calc_number_value(calc_number_value);
  119. value /= resolved_calc_number_value;
  120. });
  121. }
  122. return value;
  123. }
  124. static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const& calc_sum, const Layout::Node& layout_node, float reference_for_percent)
  125. {
  126. auto value = resolve_calc_product(calc_sum->first_calc_product, layout_node, reference_for_percent);
  127. for (auto& additional_product : calc_sum->zero_or_more_additional_calc_products) {
  128. auto additional_value = resolve_calc_product(additional_product.calc_product, layout_node, reference_for_percent);
  129. if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Add)
  130. value += additional_value;
  131. else if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Subtract)
  132. value -= additional_value;
  133. else
  134. VERIFY_NOT_REACHED();
  135. }
  136. return value;
  137. }
  138. const char* Length::unit_name() const
  139. {
  140. switch (m_type) {
  141. case Type::Cm:
  142. return "cm";
  143. case Type::In:
  144. return "in";
  145. case Type::Px:
  146. return "px";
  147. case Type::Pt:
  148. return "pt";
  149. case Type::Mm:
  150. return "mm";
  151. case Type::Q:
  152. return "Q";
  153. case Type::Pc:
  154. return "pc";
  155. case Type::Ex:
  156. return "ex";
  157. case Type::Em:
  158. return "em";
  159. case Type::Rem:
  160. return "rem";
  161. case Type::Auto:
  162. return "auto";
  163. case Type::Percentage:
  164. return "%";
  165. case Type::Undefined:
  166. return "undefined";
  167. case Type::Vh:
  168. return "vh";
  169. case Type::Vw:
  170. return "vw";
  171. case Type::Vmax:
  172. return "vmax";
  173. case Type::Vmin:
  174. return "vmin";
  175. case Type::Calculated:
  176. return "calculated";
  177. }
  178. VERIFY_NOT_REACHED();
  179. }
  180. }