MediaQuery.h 7.8 KB

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