MediaQuery.h 7.4 KB

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