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::values::computed;
14use cssparser::{Delimiter, Parser};
15use cssparser::{ParserInput, Token};
16use selectors::kleene_value::KleeneValue;
17
18#[derive(Clone, MallocSizeOf, ToCss, ToShmem)]
20#[css(comma, derive_debug)]
21pub struct MediaList {
22 #[css(iterable)]
24 pub media_queries: Vec<MediaQuery>,
25}
26
27impl MediaList {
28 pub fn parse(context: &ParserContext, input: &mut Parser) -> Self {
36 if input.is_exhausted() {
37 return Self::empty();
38 }
39
40 let mut media_queries = vec![];
41 loop {
42 let start_position = input.position();
43 match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) {
44 Ok(mq) => {
45 media_queries.push(mq);
46 },
47 Err(err) => {
48 media_queries.push(MediaQuery::never_matching());
49 let location = err.location;
50 let error = ContextualParseError::InvalidMediaRule(
51 input.slice_from(start_position),
52 err,
53 );
54 context.log_css_error(location, error);
55 },
56 }
57
58 match input.next() {
59 Ok(&Token::Comma) => {},
60 Ok(_) => unreachable!(),
61 Err(_) => break,
62 }
63 }
64
65 MediaList { media_queries }
66 }
67
68 pub fn empty() -> Self {
70 MediaList {
71 media_queries: vec![],
72 }
73 }
74
75 pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
77 if self.media_queries.is_empty() {
80 return true;
81 }
82
83 computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
84 self.media_queries.iter().any(|mq| {
85 let mut query_match = if mq.media_type.matches(device.media_type()) {
86 mq.condition
87 .as_ref()
88 .map_or(KleeneValue::True, |c| c.matches(context))
89 } else {
90 KleeneValue::False
91 };
92
93 if matches!(mq.qualifier, Some(Qualifier::Not)) {
95 query_match = !query_match;
96 }
97 query_match.to_bool(false)
98 })
99 })
100 }
101
102 pub fn is_empty(&self) -> bool {
104 self.media_queries.is_empty()
105 }
106
107 pub fn is_viewport_dependent(&self) -> bool {
109 self.media_queries.iter().any(|q| q.is_viewport_dependent())
110 }
111
112 pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool {
117 let mut input = ParserInput::new(new_medium);
118 let mut parser = Parser::new(&mut input);
119 let new_query = match MediaQuery::parse(&context, &mut parser) {
120 Ok(query) => query,
121 Err(_) => {
122 return false;
123 },
124 };
125 self.media_queries.retain(|query| query != &new_query);
129 self.media_queries.push(new_query);
130 true
131 }
132
133 pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool {
138 let mut input = ParserInput::new(old_medium);
139 let mut parser = Parser::new(&mut input);
140 let old_query = match MediaQuery::parse(context, &mut parser) {
141 Ok(query) => query,
142 Err(_) => {
143 return false;
144 },
145 };
146 let old_len = self.media_queries.len();
147 self.media_queries.retain(|query| query != &old_query);
148 old_len != self.media_queries.len()
149 }
150}