Length.cpp 7.7 KB

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