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;
21use style_traits::ParsingMode;
22
23#[derive(Clone, MallocSizeOf, ToCss, ToShmem)]
25#[css(comma, derive_debug)]
26pub struct MediaList {
27 #[css(iterable)]
29 pub media_queries: Vec<MediaQuery>,
30}
31
32impl MediaList {
33 pub fn parse(context: &mut ParserContext, input: &mut Parser) -> Self {
41 context.with_parsing_mode(ParsingMode::MEDIA_QUERY_CONDITION, |context| {
42 if input.is_exhausted() {
43 return Self::empty();
44 }
45
46 let mut media_queries = vec![];
47 loop {
48 let start_position = input.position();
49 match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i))
50 {
51 Ok(mq) => {
52 media_queries.push(mq);
53 },
54 Err(err) => {
55 media_queries.push(MediaQuery::never_matching());
56 let location = err.location;
57 let error = ContextualParseError::InvalidMediaRule(
58 input.slice_from(start_position),
59 err,
60 );
61 context.log_css_error(location, error);
62 },
63 }
64
65 match input.next() {
66 Ok(&Token::Comma) => {},
67 Ok(_) => unreachable!(),
68 Err(_) => break,
69 }
70 }
71
72 MediaList { media_queries }
73 })
74 }
75
76 pub fn empty() -> Self {
78 MediaList {
79 media_queries: vec![],
80 }
81 }
82
83 pub fn evaluate(
85 &self,
86 device: &Device,
87 quirks_mode: QuirksMode,
88 custom: &mut CustomMediaEvaluator,
89 ) -> bool {
90 computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
91 self.matches(context, custom).to_bool(false)
92 })
93 }
94
95 pub fn matches(
97 &self,
98 context: &computed::Context,
99 custom: &mut CustomMediaEvaluator,
100 ) -> KleeneValue {
101 if self.media_queries.is_empty() {
104 return KleeneValue::True;
105 }
106 KleeneValue::any(self.media_queries.iter(), |mq| {
107 let mut query_match = if mq.media_type.matches(context.device().media_type()) {
108 mq.condition.as_ref().map_or(KleeneValue::True, |c| {
109 c.matches(context, custom, &mut AttributeTracker::new_dummy())
110 })
111 } else {
112 KleeneValue::False
113 };
114 if matches!(mq.qualifier, Some(Qualifier::Not)) {
116 query_match = !query_match;
117 }
118 query_match
119 })
120 }
121
122 pub fn is_empty(&self) -> bool {
124 self.media_queries.is_empty()
125 }
126
127 pub fn is_viewport_dependent(&self) -> bool {
129 self.media_queries.iter().any(|q| q.is_viewport_dependent())
130 }
131
132 pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool {
137 let mut input = ParserInput::new(new_medium);
138 let mut parser = Parser::new(&mut input);
139 let new_query = match MediaQuery::parse(&context, &mut parser) {
140 Ok(query) => query,
141 Err(_) => {
142 return false;
143 },
144 };
145 self.media_queries.retain(|query| query != &new_query);
149 self.media_queries.push(new_query);
150 true
151 }
152
153 pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool {
158 let mut input = ParserInput::new(old_medium);
159 let mut parser = Parser::new(&mut input);
160 let old_query = match MediaQuery::parse(context, &mut parser) {
161 Ok(query) => query,
162 Err(_) => {
163 return false;
164 },
165 };
166 let old_len = self.media_queries.len();
167 self.media_queries.retain(|query| query != &old_query);
168 old_len != self.media_queries.len()
169 }
170}