MediaQuery.h 7.6 KB

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