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