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