style/media_queries/
media_list.rs1use super::{Device, MediaQuery, Qualifier};
10use crate::context::QuirksMode;
11use crate::error_reporting::ContextualParseError;
12use crate::parser::ParserContext;
13use crate::stylesheets::CustomMediaEvaluator;
14use crate::values::computed;
15use cssparser::{Delimiter, Parser};
16use cssparser::{ParserInput, Token};
17use selectors::kleene_value::KleeneValue;
18
19#[derive(Clone, MallocSizeOf, ToCss, ToShmem)]
21#[css(comma, derive_debug)]
22pub struct MediaList {
23 #[css(iterable)]
25 pub media_queries: Vec<MediaQuery>,
26}
27
28impl MediaList {
29 pub fn parse(context: &ParserContext, input: &mut Parser) -> Self {
37 if input.is_exhausted() {
38 return Self::empty();
39 }
40
41 let mut media_queries = vec![];
42 loop {
43 let start_position = input.position();
44 match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) {
45 Ok(mq) => {
46 media_queries.push(mq);
47 },
48 Err(err) => {
49 media_queries.push(MediaQuery::never_matching());
50 let location = err.location;
51 let error = ContextualParseError::InvalidMediaRule(
52 input.slice_from(start_position),
53 err,
54 );
55 context.log_css_error(location, error);
56 },
57 }
58
59 match input.next() {
60 Ok(&Token::Comma) => {},
61 Ok(_) => unreachable!(),
62 Err(_) => break,
63 }
64 }
65
66 MediaList { media_queries }
67 }
68
69 pub fn empty() -> Self {
71 MediaList {
72 media_queries: vec![],
73 }
74 }
75
76 pub fn evaluate(
78 &self,
79 device: &Device,
80 quirks_mode: QuirksMode,
81 custom: &mut CustomMediaEvaluator,
82 ) -> bool {
83 computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
84 self.matches(context, custom).to_bool(false)
85 })
86 }
87
88 pub fn matches(
90 &self,
91 context: &computed::Context,
92 custom: &mut CustomMediaEvaluator,
93 ) -> KleeneValue {
94 if self.media_queries.is_empty() {
97 return KleeneValue::True;
98 }
99 KleeneValue::any(self.media_queries.iter(), |mq| {
100 let mut query_match = if mq.media_type.matches(context.device().media_type()) {
101 mq.condition
102 .as_ref()
103 .map_or(KleeneValue::True, |c| c.matches(context, custom))
104 } else {
105 KleeneValue::False
106 };
107 if matches!(mq.qualifier, Some(Qualifier::Not)) {
109 query_match = !query_match;
110 }
111 query_match
112 })
113 }
114
115 pub fn is_empty(&self) -> bool {
117 self.media_queries.is_empty()
118 }
119
120 pub fn is_viewport_dependent(&self) -> bool {
122 self.media_queries.iter().any(|q| q.is_viewport_dependent())
123 }
124
125 pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool {
130 let mut input = ParserInput::new(new_medium);
131 let mut parser = Parser::new(&mut input);
132 let new_query = match MediaQuery::parse(&context, &mut parser) {
133 Ok(query) => query,
134 Err(_) => {
135 return false;
136 },
137 };
138 self.media_queries.retain(|query| query != &new_query);
142 self.media_queries.push(new_query);
143 true
144 }
145
146 pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool {
151 let mut input = ParserInput::new(old_medium);
152 let mut parser = Parser::new(&mut input);
153 let old_query = match MediaQuery::parse(context, &mut parser) {
154 Ok(query) => query,
155 Err(_) => {
156 return false;
157 },
158 };
159 let old_len = self.media_queries.len();
160 self.media_queries.retain(|query| query != &old_query);
161 old_len != self.media_queries.len()
162 }
163}