Length.cpp 8.0 KB

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