1use crate::context::QuirksMode;
8use crate::media_queries::Device;
9use crate::shared_lock::SharedRwLockReadGuard;
10use crate::stylesheets::{
11 CssRule, CssRuleRef, CustomMediaEvaluator, CustomMediaMap, DocumentRule, ImportRule, MediaRule,
12 SupportsRule,
13};
14use smallvec::SmallVec;
15use std::ops::Deref;
16use std::slice;
17
18pub struct RulesIterator<'a, 'b, C, CMM>
20where
21 'b: 'a,
22 C: NestedRuleIterationCondition + 'static,
23 CMM: Deref<Target = CustomMediaMap>,
24{
25 device: &'a Device,
26 quirks_mode: QuirksMode,
27 custom_media: CMM,
28 guard: &'a SharedRwLockReadGuard<'b>,
29 stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
30 _phantom: ::std::marker::PhantomData<C>,
31}
32
33impl<'a, 'b, C, CMM> RulesIterator<'a, 'b, C, CMM>
34where
35 'b: 'a,
36 C: NestedRuleIterationCondition + 'static,
37 CMM: Deref<Target = CustomMediaMap>,
38{
39 pub fn custom_media(&mut self) -> &mut CMM {
41 &mut self.custom_media
42 }
43
44 pub fn new(
46 device: &'a Device,
47 quirks_mode: QuirksMode,
48 custom_media: CMM,
49 guard: &'a SharedRwLockReadGuard<'b>,
50 rules: slice::Iter<'a, CssRule>,
51 ) -> Self {
52 let mut stack = SmallVec::new();
53 stack.push(rules);
54 Self {
55 device,
56 quirks_mode,
57 custom_media,
58 guard,
59 stack,
60 _phantom: ::std::marker::PhantomData,
61 }
62 }
63
64 pub fn skip_children(&mut self) {
66 self.stack.pop();
67 }
68
69 pub fn children(
71 rule: &'a CssRule,
72 device: &'a Device,
73 quirks_mode: QuirksMode,
74 custom_media_map: &CustomMediaMap,
75 guard: &'a SharedRwLockReadGuard<'_>,
76 effective: &mut bool,
77 ) -> Option<slice::Iter<'a, CssRule>> {
78 *effective = true;
79 match *rule {
80 CssRule::Namespace(_)
81 | CssRule::FontFace(_)
82 | CssRule::CounterStyle(_)
83 | CssRule::CustomMedia(_)
84 | CssRule::Keyframes(_)
85 | CssRule::Margin(_)
86 | CssRule::Property(_)
87 | CssRule::LayerStatement(_)
88 | CssRule::FontFeatureValues(_)
89 | CssRule::FontPaletteValues(_)
90 | CssRule::NestedDeclarations(_)
91 | CssRule::PositionTry(_) => None,
92 CssRule::Page(ref page_rule) => {
93 let page_rule = page_rule.read_with(guard);
94 let rules = page_rule.rules.read_with(guard);
95 Some(rules.0.iter())
96 },
97 CssRule::Style(ref style_rule) => {
98 let style_rule = style_rule.read_with(guard);
99 style_rule
100 .rules
101 .as_ref()
102 .map(|r| r.read_with(guard).0.iter())
103 },
104 CssRule::Import(ref import_rule) => {
105 let import_rule = import_rule.read_with(guard);
106 if !C::process_import(guard, device, quirks_mode, custom_media_map, import_rule) {
107 *effective = false;
108 return None;
109 }
110 Some(import_rule.stylesheet.rules(guard).iter())
111 },
112 CssRule::Document(ref doc_rule) => {
113 if !C::process_document(guard, device, quirks_mode, doc_rule) {
114 *effective = false;
115 return None;
116 }
117 Some(doc_rule.rules.read_with(guard).0.iter())
118 },
119 CssRule::Container(ref container_rule) => {
120 Some(container_rule.rules.read_with(guard).0.iter())
121 },
122 CssRule::Media(ref media_rule) => {
123 if !C::process_media(guard, device, quirks_mode, custom_media_map, media_rule) {
124 *effective = false;
125 return None;
126 }
127 Some(media_rule.rules.read_with(guard).0.iter())
128 },
129 CssRule::Supports(ref supports_rule) => {
130 if !C::process_supports(guard, device, quirks_mode, supports_rule) {
131 *effective = false;
132 return None;
133 }
134 Some(supports_rule.rules.read_with(guard).0.iter())
135 },
136 CssRule::LayerBlock(ref layer_rule) => Some(layer_rule.rules.read_with(guard).0.iter()),
137 CssRule::Scope(ref rule) => Some(rule.rules.read_with(guard).0.iter()),
138 CssRule::StartingStyle(ref rule) => Some(rule.rules.read_with(guard).0.iter()),
139 }
140 }
141}
142
143impl<'a, 'b, C, CMM> Iterator for RulesIterator<'a, 'b, C, CMM>
144where
145 'b: 'a,
146 C: NestedRuleIterationCondition + 'static,
147 CMM: Deref<Target = CustomMediaMap>,
148{
149 type Item = &'a CssRule;
150
151 fn next(&mut self) -> Option<Self::Item> {
152 while !self.stack.is_empty() {
153 let rule = {
154 let nested_iter = self.stack.last_mut().unwrap();
155 match nested_iter.next() {
156 Some(r) => r,
157 None => {
158 self.stack.pop();
159 continue;
160 },
161 }
162 };
163
164 let mut effective = true;
165 let children = Self::children(
166 rule,
167 self.device,
168 self.quirks_mode,
169 &self.custom_media,
170 self.guard,
171 &mut effective,
172 );
173 if !effective {
174 continue;
175 }
176
177 if let Some(children) = children {
178 self.stack.push(children);
181 }
182
183 return Some(rule);
184 }
185
186 None
187 }
188}
189
190pub trait NestedRuleIterationCondition {
192 fn process_import(
194 guard: &SharedRwLockReadGuard,
195 device: &Device,
196 quirks_mode: QuirksMode,
197 custom_media_map: &CustomMediaMap,
198 rule: &ImportRule,
199 ) -> bool;
200
201 fn process_media(
203 guard: &SharedRwLockReadGuard,
204 device: &Device,
205 quirks_mode: QuirksMode,
206 custom_media_map: &CustomMediaMap,
207 rule: &MediaRule,
208 ) -> bool;
209
210 fn process_document(
213 guard: &SharedRwLockReadGuard,
214 device: &Device,
215 quirks_mode: QuirksMode,
216 rule: &DocumentRule,
217 ) -> bool;
218
219 fn process_supports(
221 guard: &SharedRwLockReadGuard,
222 device: &Device,
223 quirks_mode: QuirksMode,
224 rule: &SupportsRule,
225 ) -> bool;
226}
227
228pub struct EffectiveRules;
230
231impl EffectiveRules {
232 pub fn is_effective(
234 guard: &SharedRwLockReadGuard,
235 device: &Device,
236 quirks_mode: QuirksMode,
237 custom_media_map: &CustomMediaMap,
238 rule: &CssRuleRef,
239 ) -> bool {
240 match *rule {
241 CssRuleRef::Import(import_rule) => {
242 let import_rule = import_rule.read_with(guard);
243 Self::process_import(guard, device, quirks_mode, custom_media_map, import_rule)
244 },
245 CssRuleRef::Document(doc_rule) => {
246 Self::process_document(guard, device, quirks_mode, doc_rule)
247 },
248 CssRuleRef::Media(media_rule) => {
249 Self::process_media(guard, device, quirks_mode, custom_media_map, media_rule)
250 },
251 CssRuleRef::Supports(supports_rule) => {
252 Self::process_supports(guard, device, quirks_mode, supports_rule)
253 },
254 _ => true,
255 }
256 }
257}
258
259impl NestedRuleIterationCondition for EffectiveRules {
260 fn process_import(
261 guard: &SharedRwLockReadGuard,
262 device: &Device,
263 quirks_mode: QuirksMode,
264 custom_media_map: &CustomMediaMap,
265 rule: &ImportRule,
266 ) -> bool {
267 match rule.stylesheet.media(guard) {
268 Some(m) => m.evaluate(
269 device,
270 quirks_mode,
271 &mut CustomMediaEvaluator::new(custom_media_map, guard),
272 ),
273 None => true,
274 }
275 }
276
277 fn process_media(
278 guard: &SharedRwLockReadGuard,
279 device: &Device,
280 quirks_mode: QuirksMode,
281 custom_media_map: &CustomMediaMap,
282 rule: &MediaRule,
283 ) -> bool {
284 rule.media_queries.read_with(guard).evaluate(
285 device,
286 quirks_mode,
287 &mut CustomMediaEvaluator::new(custom_media_map, guard),
288 )
289 }
290
291 fn process_document(
292 _: &SharedRwLockReadGuard,
293 device: &Device,
294 _: QuirksMode,
295 rule: &DocumentRule,
296 ) -> bool {
297 rule.condition.evaluate(device)
298 }
299
300 fn process_supports(
301 _: &SharedRwLockReadGuard,
302 _: &Device,
303 _: QuirksMode,
304 rule: &SupportsRule,
305 ) -> bool {
306 rule.enabled
307 }
308}
309
310pub struct AllRules;
312
313impl NestedRuleIterationCondition for AllRules {
314 fn process_import(
315 _: &SharedRwLockReadGuard,
316 _: &Device,
317 _: QuirksMode,
318 _: &CustomMediaMap,
319 _: &ImportRule,
320 ) -> bool {
321 true
322 }
323
324 fn process_media(
325 _: &SharedRwLockReadGuard,
326 _: &Device,
327 _: QuirksMode,
328 _: &CustomMediaMap,
329 _: &MediaRule,
330 ) -> bool {
331 true
332 }
333
334 fn process_document(
335 _: &SharedRwLockReadGuard,
336 _: &Device,
337 _: QuirksMode,
338 _: &DocumentRule,
339 ) -> bool {
340 true
341 }
342
343 fn process_supports(
344 _: &SharedRwLockReadGuard,
345 _: &Device,
346 _: QuirksMode,
347 _: &SupportsRule,
348 ) -> bool {
349 true
350 }
351}
352
353pub type EffectiveRulesIterator<'a, 'b, CMM> = RulesIterator<'a, 'b, EffectiveRules, CMM>;
357
358impl<'a, 'b, CMM> EffectiveRulesIterator<'a, 'b, CMM>
359where
360 CMM: Deref<Target = CustomMediaMap>,
361{
362 pub fn effective_children(
365 device: &'a Device,
366 quirks_mode: QuirksMode,
367 custom_media_map: CMM,
368 guard: &'a SharedRwLockReadGuard<'b>,
369 rule: &'a CssRule,
370 ) -> Self {
371 let children = RulesIterator::<AllRules, CMM>::children(
372 rule,
373 device,
374 quirks_mode,
375 &custom_media_map,
376 guard,
377 &mut false,
378 );
379 EffectiveRulesIterator::new(
380 device,
381 quirks_mode,
382 custom_media_map,
383 guard,
384 children.unwrap_or([].iter()),
385 )
386 }
387}