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