MediaQuery.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/NonnullRefPtr.h>
  8. #include <AK/Optional.h>
  9. #include <AK/OwnPtr.h>
  10. #include <AK/RefCounted.h>
  11. #include <LibWeb/CSS/GeneralEnclosed.h>
  12. #include <LibWeb/CSS/MediaFeatureID.h>
  13. #include <LibWeb/CSS/Ratio.h>
  14. #include <LibWeb/CSS/StyleValue.h>
  15. namespace Web::CSS {
  16. // https://www.w3.org/TR/mediaqueries-4/#typedef-mf-value
  17. class MediaFeatureValue {
  18. public:
  19. explicit MediaFeatureValue(ValueID ident)
  20. : m_value(move(ident))
  21. {
  22. }
  23. explicit MediaFeatureValue(Length length)
  24. : m_value(move(length))
  25. {
  26. }
  27. explicit MediaFeatureValue(Ratio ratio)
  28. : m_value(move(ratio))
  29. {
  30. }
  31. explicit MediaFeatureValue(Resolution resolution)
  32. : m_value(move(resolution))
  33. {
  34. }
  35. explicit MediaFeatureValue(float number)
  36. : m_value(number)
  37. {
  38. }
  39. ErrorOr<String> to_string() const;
  40. bool is_ident() const { return m_value.has<ValueID>(); }
  41. bool is_length() const { return m_value.has<Length>(); }
  42. bool is_number() const { return m_value.has<float>(); }
  43. bool is_ratio() const { return m_value.has<Ratio>(); }
  44. bool is_resolution() const { return m_value.has<Resolution>(); }
  45. bool is_same_type(MediaFeatureValue const& other) const;
  46. ValueID const& ident() const
  47. {
  48. VERIFY(is_ident());
  49. return m_value.get<ValueID>();
  50. }
  51. Length const& length() const
  52. {
  53. VERIFY(is_length());
  54. return m_value.get<Length>();
  55. }
  56. Ratio const& ratio() const
  57. {
  58. VERIFY(is_ratio());
  59. return m_value.get<Ratio>();
  60. }
  61. Resolution const& resolution() const
  62. {
  63. VERIFY(is_resolution());
  64. return m_value.get<Resolution>();
  65. }
  66. float number() const
  67. {
  68. VERIFY(is_number());
  69. return m_value.get<float>();
  70. }
  71. private:
  72. Variant<ValueID, Length, Ratio, Resolution, float> m_value;
  73. };
  74. // https://www.w3.org/TR/mediaqueries-4/#mq-features
  75. class MediaFeature {
  76. public:
  77. enum class Comparison {
  78. Equal,
  79. LessThan,
  80. LessThanOrEqual,
  81. GreaterThan,
  82. GreaterThanOrEqual,
  83. };
  84. // Corresponds to `<mf-boolean>` grammar
  85. static MediaFeature boolean(MediaFeatureID id)
  86. {
  87. return MediaFeature(Type::IsTrue, id);
  88. }
  89. // Corresponds to `<mf-plain>` grammar
  90. static MediaFeature plain(MediaFeatureID id, MediaFeatureValue value)
  91. {
  92. return MediaFeature(Type::ExactValue, move(id), move(value));
  93. }
  94. static MediaFeature min(MediaFeatureID id, MediaFeatureValue value)
  95. {
  96. return MediaFeature(Type::MinValue, id, move(value));
  97. }
  98. static MediaFeature max(MediaFeatureID id, MediaFeatureValue value)
  99. {
  100. return MediaFeature(Type::MaxValue, id, move(value));
  101. }
  102. // Corresponds to `<mf-range>` grammar, with a single comparison
  103. static MediaFeature half_range(MediaFeatureValue value, Comparison comparison, MediaFeatureID id)
  104. {
  105. MediaFeature feature { Type::Range, id };
  106. feature.m_range = Range {
  107. .left_value = value,
  108. .left_comparison = comparison,
  109. };
  110. return feature;
  111. }
  112. // Corresponds to `<mf-range>` grammar, with two comparisons
  113. static MediaFeature range(MediaFeatureValue left_value, Comparison left_comparison, MediaFeatureID id, Comparison right_comparison, MediaFeatureValue right_value)
  114. {
  115. MediaFeature feature { Type::Range, id };
  116. feature.m_range = Range {
  117. .left_value = left_value,
  118. .left_comparison = left_comparison,
  119. .right_comparison = right_comparison,
  120. .right_value = right_value,
  121. };
  122. return feature;
  123. }
  124. bool evaluate(HTML::Window const&) const;
  125. ErrorOr<String> to_string() const;
  126. private:
  127. enum class Type {
  128. IsTrue,
  129. ExactValue,
  130. MinValue,
  131. MaxValue,
  132. Range,
  133. };
  134. MediaFeature(Type type, MediaFeatureID id, Optional<MediaFeatureValue> value = {})
  135. : m_type(type)
  136. , m_id(move(id))
  137. , m_value(move(value))
  138. {
  139. }
  140. static bool compare(HTML::Window const& window, MediaFeatureValue left, Comparison comparison, MediaFeatureValue right);
  141. struct Range {
  142. MediaFeatureValue left_value;
  143. Comparison left_comparison;
  144. Optional<Comparison> right_comparison {};
  145. Optional<MediaFeatureValue> right_value {};
  146. };
  147. Type m_type;
  148. MediaFeatureID m_id;
  149. Optional<MediaFeatureValue> m_value {};
  150. Optional<Range> m_range {};
  151. };
  152. // https://www.w3.org/TR/mediaqueries-4/#media-conditions
  153. struct MediaCondition {
  154. enum class Type {
  155. Single,
  156. And,
  157. Or,
  158. Not,
  159. GeneralEnclosed,
  160. };
  161. // Only used in parsing
  162. enum class AllowOr {
  163. No = 0,
  164. Yes = 1,
  165. };
  166. static NonnullOwnPtr<MediaCondition> from_general_enclosed(GeneralEnclosed&&);
  167. static NonnullOwnPtr<MediaCondition> from_feature(MediaFeature&&);
  168. static NonnullOwnPtr<MediaCondition> from_not(NonnullOwnPtr<MediaCondition>&&);
  169. static NonnullOwnPtr<MediaCondition> from_and_list(Vector<NonnullOwnPtr<MediaCondition>>&&);
  170. static NonnullOwnPtr<MediaCondition> from_or_list(Vector<NonnullOwnPtr<MediaCondition>>&&);
  171. MatchResult evaluate(HTML::Window const&) const;
  172. ErrorOr<String> to_string() const;
  173. private:
  174. MediaCondition() = default;
  175. Type type;
  176. Optional<MediaFeature> feature;
  177. Vector<NonnullOwnPtr<MediaCondition>> conditions;
  178. Optional<GeneralEnclosed> general_enclosed;
  179. };
  180. class MediaQuery : public RefCounted<MediaQuery> {
  181. friend class Parser::Parser;
  182. public:
  183. ~MediaQuery() = default;
  184. // https://www.w3.org/TR/mediaqueries-4/#media-types
  185. enum class MediaType {
  186. All,
  187. Print,
  188. Screen,
  189. Unknown,
  190. // Deprecated, must never match:
  191. TTY,
  192. TV,
  193. Projection,
  194. Handheld,
  195. Braille,
  196. Embossed,
  197. Aural,
  198. Speech,
  199. };
  200. static NonnullRefPtr<MediaQuery> create_not_all();
  201. static NonnullRefPtr<MediaQuery> create() { return adopt_ref(*new MediaQuery); }
  202. bool matches() const { return m_matches; }
  203. bool evaluate(HTML::Window const&);
  204. ErrorOr<String> to_string() const;
  205. private:
  206. MediaQuery() = default;
  207. // https://www.w3.org/TR/mediaqueries-4/#mq-not
  208. bool m_negated { false };
  209. MediaType m_media_type { MediaType::All };
  210. OwnPtr<MediaCondition> m_media_condition { nullptr };
  211. // Cached value, updated by evaluate()
  212. bool m_matches { false };
  213. };
  214. ErrorOr<String> serialize_a_media_query_list(Vector<NonnullRefPtr<MediaQuery>> const&);
  215. bool is_media_feature_name(StringView name);
  216. MediaQuery::MediaType media_type_from_string(StringView);
  217. StringView to_string(MediaQuery::MediaType);
  218. }
  219. namespace AK {
  220. template<>
  221. struct Formatter<Web::CSS::MediaFeature> : Formatter<StringView> {
  222. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaFeature const& media_feature)
  223. {
  224. return Formatter<StringView>::format(builder, TRY(media_feature.to_string()));
  225. }
  226. };
  227. template<>
  228. struct Formatter<Web::CSS::MediaCondition> : Formatter<StringView> {
  229. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaCondition const& media_condition)
  230. {
  231. return Formatter<StringView>::format(builder, TRY(media_condition.to_string()));
  232. }
  233. };
  234. template<>
  235. struct Formatter<Web::CSS::MediaQuery> : Formatter<StringView> {
  236. ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaQuery const& media_query)
  237. {
  238. return Formatter<StringView>::format(builder, TRY(media_query.to_string()));
  239. }
  240. };
  241. }