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