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