PercentageOr.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/String.h>
  8. #include <AK/Variant.h>
  9. #include <LibWeb/CSS/Angle.h>
  10. #include <LibWeb/CSS/Frequency.h>
  11. #include <LibWeb/CSS/Length.h>
  12. #include <LibWeb/CSS/Number.h>
  13. #include <LibWeb/CSS/Percentage.h>
  14. #include <LibWeb/CSS/StyleValues/CSSMathValue.h>
  15. #include <LibWeb/CSS/Time.h>
  16. namespace Web::CSS {
  17. template<typename T>
  18. class PercentageOr {
  19. public:
  20. PercentageOr(T t)
  21. : m_value(move(t))
  22. {
  23. }
  24. PercentageOr(Percentage percentage)
  25. : m_value(move(percentage))
  26. {
  27. }
  28. PercentageOr(NonnullRefPtr<CSSMathValue> calculated)
  29. : m_value(move(calculated))
  30. {
  31. }
  32. ~PercentageOr() = default;
  33. PercentageOr<T>& operator=(T t)
  34. {
  35. m_value = move(t);
  36. return *this;
  37. }
  38. PercentageOr<T>& operator=(Percentage percentage)
  39. {
  40. m_value = move(percentage);
  41. return *this;
  42. }
  43. bool is_percentage() const { return m_value.template has<Percentage>(); }
  44. bool is_calculated() const { return m_value.template has<NonnullRefPtr<CSSMathValue>>(); }
  45. bool contains_percentage() const
  46. {
  47. return m_value.visit(
  48. [&](T const&) {
  49. return false;
  50. },
  51. [&](Percentage const&) {
  52. return true;
  53. },
  54. [&](NonnullRefPtr<CSSMathValue> const& calculated) {
  55. return calculated->contains_percentage();
  56. });
  57. }
  58. Percentage const& percentage() const
  59. {
  60. VERIFY(is_percentage());
  61. return m_value.template get<Percentage>();
  62. }
  63. NonnullRefPtr<CSSMathValue> const& calculated() const
  64. {
  65. VERIFY(is_calculated());
  66. return m_value.template get<NonnullRefPtr<CSSMathValue>>();
  67. }
  68. CSSPixels to_px(Layout::Node const& layout_node, CSSPixels reference_value) const
  69. {
  70. if constexpr (IsSame<T, Length>) {
  71. if (auto const* length = m_value.template get_pointer<Length>()) {
  72. if (length->is_absolute())
  73. return length->absolute_length_to_px();
  74. }
  75. }
  76. return resolved(layout_node, reference_value).to_px(layout_node);
  77. }
  78. T resolved(Layout::Node const& layout_node, T reference_value) const
  79. requires(!IsSame<T, Length>)
  80. {
  81. return m_value.visit(
  82. [&](T const& t) {
  83. return t;
  84. },
  85. [&](Percentage const& percentage) {
  86. return reference_value.percentage_of(percentage);
  87. },
  88. [&](NonnullRefPtr<CSSMathValue> const& calculated) {
  89. return T::resolve_calculated(calculated, layout_node, reference_value);
  90. });
  91. }
  92. T resolved(Layout::Node const& layout_node, CSSPixels reference_value) const
  93. {
  94. return m_value.visit(
  95. [&](T const& t) {
  96. return t;
  97. },
  98. [&](Percentage const& percentage) {
  99. return Length::make_px(CSSPixels(percentage.value() * reference_value) / 100);
  100. },
  101. [&](NonnullRefPtr<CSSMathValue> const& calculated) {
  102. return T::resolve_calculated(calculated, layout_node, reference_value);
  103. });
  104. }
  105. String to_string() const
  106. {
  107. if (is_calculated())
  108. return m_value.template get<NonnullRefPtr<CSSMathValue>>()->to_string();
  109. if (is_percentage())
  110. return m_value.template get<Percentage>().to_string();
  111. return m_value.template get<T>().to_string();
  112. }
  113. bool operator==(PercentageOr<T> const& other) const
  114. {
  115. if (is_calculated() != other.is_calculated())
  116. return false;
  117. if (is_percentage() != other.is_percentage())
  118. return false;
  119. if (is_calculated())
  120. return (*m_value.template get<NonnullRefPtr<CSSMathValue>>() == *other.m_value.template get<NonnullRefPtr<CSSMathValue>>());
  121. if (is_percentage())
  122. return (m_value.template get<Percentage>() == other.m_value.template get<Percentage>());
  123. return (m_value.template get<T>() == other.m_value.template get<T>());
  124. }
  125. protected:
  126. bool is_t() const { return m_value.template has<T>(); }
  127. T const& get_t() const { return m_value.template get<T>(); }
  128. private:
  129. Variant<T, Percentage, NonnullRefPtr<CSSMathValue>> m_value;
  130. };
  131. template<typename T>
  132. bool operator==(PercentageOr<T> const& percentage_or, T const& t)
  133. {
  134. return percentage_or == PercentageOr<T> { t };
  135. }
  136. template<typename T>
  137. bool operator==(T const& t, PercentageOr<T> const& percentage_or)
  138. {
  139. return t == percentage_or;
  140. }
  141. template<typename T>
  142. bool operator==(PercentageOr<T> const& percentage_or, Percentage const& percentage)
  143. {
  144. return percentage_or == PercentageOr<T> { percentage };
  145. }
  146. template<typename T>
  147. bool operator==(Percentage const& percentage, PercentageOr<T> const& percentage_or)
  148. {
  149. return percentage == percentage_or;
  150. }
  151. class AnglePercentage : public PercentageOr<Angle> {
  152. public:
  153. using PercentageOr<Angle>::PercentageOr;
  154. bool is_angle() const { return is_t(); }
  155. Angle const& angle() const { return get_t(); }
  156. };
  157. class FrequencyPercentage : public PercentageOr<Frequency> {
  158. public:
  159. using PercentageOr<Frequency>::PercentageOr;
  160. bool is_frequency() const { return is_t(); }
  161. Frequency const& frequency() const { return get_t(); }
  162. };
  163. class LengthPercentage : public PercentageOr<Length> {
  164. public:
  165. using PercentageOr<Length>::PercentageOr;
  166. bool is_auto() const { return is_length() && length().is_auto(); }
  167. bool is_length() const { return is_t(); }
  168. Length const& length() const { return get_t(); }
  169. };
  170. class TimePercentage : public PercentageOr<Time> {
  171. public:
  172. using PercentageOr<Time>::PercentageOr;
  173. bool is_time() const { return is_t(); }
  174. Time const& time() const { return get_t(); }
  175. };
  176. struct NumberPercentage : public PercentageOr<Number> {
  177. public:
  178. using PercentageOr<Number>::PercentageOr;
  179. bool is_number() const { return is_t(); }
  180. Number const& number() const { return get_t(); }
  181. };
  182. }
  183. template<>
  184. struct AK::Formatter<Web::CSS::Percentage> : Formatter<StringView> {
  185. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::Percentage const& percentage)
  186. {
  187. return Formatter<StringView>::format(builder, percentage.to_string());
  188. }
  189. };
  190. template<>
  191. struct AK::Formatter<Web::CSS::AnglePercentage> : Formatter<StringView> {
  192. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::AnglePercentage const& angle_percentage)
  193. {
  194. return Formatter<StringView>::format(builder, angle_percentage.to_string());
  195. }
  196. };
  197. template<>
  198. struct AK::Formatter<Web::CSS::FrequencyPercentage> : Formatter<StringView> {
  199. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::FrequencyPercentage const& frequency_percentage)
  200. {
  201. return Formatter<StringView>::format(builder, frequency_percentage.to_string());
  202. }
  203. };
  204. template<>
  205. struct AK::Formatter<Web::CSS::LengthPercentage> : Formatter<StringView> {
  206. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::LengthPercentage const& length_percentage)
  207. {
  208. return Formatter<StringView>::format(builder, length_percentage.to_string());
  209. }
  210. };
  211. template<>
  212. struct AK::Formatter<Web::CSS::TimePercentage> : Formatter<StringView> {
  213. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::TimePercentage const& time_percentage)
  214. {
  215. return Formatter<StringView>::format(builder, time_percentage.to_string());
  216. }
  217. };