MediaQuery.h 7.2 KB

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