1use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
8use crate::dom::{TElement, TNode, TShadowRoot};
9use crate::properties::{AnimationDeclarations, PropertyDeclarationBlock};
10use crate::rule_tree::{CascadeLevel, CascadeOrigin, ShadowCascadeOrder};
11use crate::selector_map::SelectorMap;
12use crate::selector_parser::PseudoElement;
13use crate::shared_lock::Locked;
14use crate::stylesheets::{layer_rule::LayerOrder, Origin};
15use crate::stylist::{AuthorStylesEnabled, CascadeData, Rule, RuleInclusion, Stylist};
16use selectors::matching::MatchingContext;
17use servo_arc::ArcBorrow;
18use smallvec::SmallVec;
19
20#[inline]
38pub fn containing_shadow_ignoring_svg_use<E: TElement>(
39 element: E,
40) -> Option<<E::ConcreteNode as TNode>::ConcreteShadowRoot> {
41 let mut shadow = element.containing_shadow()?;
42 loop {
43 let host = shadow.host();
44 let host_is_svg_use_element =
45 host.is_svg_element() && host.local_name() == &**local_name!("use");
46 if !host_is_svg_use_element {
47 return Some(shadow);
48 }
49 debug_assert!(
50 shadow.style_data().is_none(),
51 "We allow no stylesheets in <svg:use> subtrees"
52 );
53 shadow = host.containing_shadow()?;
54 }
55}
56
57pub struct RuleCollector<'a, 'b: 'a, E>
63where
64 E: TElement,
65{
66 element: E,
67 rule_hash_target: E,
68 stylist: &'a Stylist,
69 pseudo_elements: &'a [PseudoElement],
73 style_attribute: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
74 smil_override: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
75 animation_declarations: AnimationDeclarations,
76 rule_inclusion: RuleInclusion,
77 rules: &'a mut ApplicableDeclarationList,
78 context: &'a mut MatchingContext<'b, E::Impl>,
79 matches_user_and_content_rules: bool,
80 matches_document_author_rules: bool,
81 in_sort_scope: bool,
82}
83
84impl<'a, 'b: 'a, E> RuleCollector<'a, 'b, E>
85where
86 E: TElement,
87{
88 pub fn new(
90 stylist: &'a Stylist,
91 element: E,
92 rule_hash_target: E,
93 pseudo_elements: &'a [PseudoElement],
94 style_attribute: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
95 smil_override: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
96 animation_declarations: AnimationDeclarations,
97 rule_inclusion: RuleInclusion,
98 rules: &'a mut ApplicableDeclarationList,
99 context: &'a mut MatchingContext<'b, E::Impl>,
100 ) -> Self {
101 debug_assert_eq!(rule_hash_target, element.ultimate_originating_element());
102 debug_assert!(pseudo_elements.iter().all(|p| !p.is_precomputed()));
103
104 let matches_user_and_content_rules = rule_hash_target.matches_user_and_content_rules();
105 Self {
106 element,
107 rule_hash_target,
108 stylist,
109 pseudo_elements,
110 style_attribute,
111 smil_override,
112 animation_declarations,
113 rule_inclusion,
114 context,
115 rules,
116 matches_user_and_content_rules,
117 matches_document_author_rules: matches_user_and_content_rules,
118 in_sort_scope: false,
119 }
120 }
121
122 #[inline]
128 fn in_tree(&mut self, host: Option<E>, f: impl FnOnce(&mut Self)) {
129 debug_assert!(!self.in_sort_scope, "Nested sorting makes no sense");
130 let start = self.rules.len();
131 self.in_sort_scope = true;
132 let old_host = self.context.current_host.take();
133 self.context.current_host = host.map(|e| e.opaque());
134 f(self);
135 if start != self.rules.len() {
136 self.rules[start..].sort_unstable_by_key(|block| block.sort_key());
137 }
138 self.context.current_host = old_host;
139 self.in_sort_scope = false;
140 }
141
142 #[inline]
143 fn in_shadow_tree(&mut self, host: E, f: impl FnOnce(&mut Self)) {
144 self.in_tree(Some(host), f);
145 }
146
147 fn collect_stylist_rules(&mut self, origin: Origin) {
148 let cascade_level = match origin {
149 Origin::UserAgent => CascadeLevel::new(CascadeOrigin::UA),
150 Origin::User => CascadeLevel::new(CascadeOrigin::User),
151 Origin::Author => CascadeLevel::same_tree_author_normal(),
152 };
153
154 self.in_tree(None, |collector| {
155 let cascade_data = collector.stylist.cascade_data().borrow_for_origin(origin);
156 if origin == Origin::UserAgent && collector.is_element_backed_pseudo_element() {
159 if let Some(map) = cascade_data.normal_rules(&[]) {
160 collector.collect_rules_in_map_with_target(
161 map,
162 cascade_level,
163 cascade_data,
164 collector.element,
165 );
166 }
167 }
168 if let Some(map) = cascade_data.normal_rules(collector.pseudo_elements) {
169 collector.collect_rules_in_map(map, cascade_level, cascade_data);
170 }
171 });
172 }
173
174 fn collect_user_agent_rules(&mut self) {
175 self.collect_stylist_rules(Origin::UserAgent);
176 #[cfg(feature = "gecko")]
177 self.collect_view_transition_dynamic_rules();
178 }
179
180 #[cfg(feature = "gecko")]
181 fn collect_view_transition_dynamic_rules(&mut self) {
182 if !self
183 .pseudo_elements
184 .first()
185 .is_some_and(|p| p.is_named_view_transition())
186 {
187 return;
188 }
189 let len_before_vt_rules = self.rules.len();
190 self.element
191 .synthesize_view_transition_dynamic_rules(self.rules);
192 if cfg!(debug_assertions) && self.rules.len() != len_before_vt_rules {
193 for declaration in &self.rules[len_before_vt_rules..] {
194 assert_eq!(declaration.level(), CascadeLevel::new(CascadeOrigin::UA));
195 }
196 }
197 }
198
199 fn collect_user_rules(&mut self) {
200 if !self.matches_user_and_content_rules {
201 return;
202 }
203
204 self.collect_stylist_rules(Origin::User);
205 }
206
207 fn collect_presentational_hints(&mut self) {
212 if !self.pseudo_elements.is_empty() {
213 return;
214 }
215
216 let length_before_preshints = self.rules.len();
217 self.element
218 .synthesize_presentational_hints_for_legacy_attributes(
219 self.context.visited_handling(),
220 self.rules,
221 );
222 if cfg!(debug_assertions) && self.rules.len() != length_before_preshints {
223 for declaration in &self.rules[length_before_preshints..] {
224 assert_eq!(
225 declaration.level(),
226 CascadeLevel::new(CascadeOrigin::PresHints)
227 );
228 }
229 }
230 }
231
232 #[inline]
233 fn collect_rules_in_list(
234 &mut self,
235 part_rules: &[Rule],
236 cascade_level: CascadeLevel,
237 cascade_data: &CascadeData,
238 ) {
239 debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
240 SelectorMap::get_matching_rules(
241 self.element,
242 part_rules,
243 self.rules,
244 self.context,
245 cascade_level,
246 cascade_data,
247 self.stylist,
248 );
249 }
250
251 #[inline]
252 fn collect_rules_in_map(
253 &mut self,
254 map: &SelectorMap<Rule>,
255 cascade_level: CascadeLevel,
256 cascade_data: &CascadeData,
257 ) {
258 self.collect_rules_in_map_with_target(
259 map,
260 cascade_level,
261 cascade_data,
262 self.rule_hash_target,
263 );
264 }
265
266 #[inline]
267 fn collect_rules_in_map_with_target(
268 &mut self,
269 map: &SelectorMap<Rule>,
270 cascade_level: CascadeLevel,
271 cascade_data: &CascadeData,
272 rule_hash_target: E,
273 ) {
274 debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
275 map.get_all_matching_rules(
276 self.element,
277 rule_hash_target,
278 self.rules,
279 self.context,
280 cascade_level,
281 cascade_data,
282 self.stylist,
283 );
284 }
285
286 #[inline]
291 fn is_element_backed_pseudo_element(&self) -> bool {
292 self.rule_hash_target != self.element
293 && self.pseudo_elements.len() == 1
294 && self.pseudo_elements[0].is_element_backed()
295 }
296
297 fn collect_host_and_slotted_rules(&mut self) {
299 let mut slots = SmallVec::<[_; 3]>::new();
300 let mut current = self.rule_hash_target.assigned_slot();
301 let mut shadow_cascade_order = ShadowCascadeOrder::for_outermost_shadow_tree();
302
303 while let Some(slot) = current {
304 debug_assert!(
305 self.matches_user_and_content_rules,
306 "We should not slot NAC anywhere"
307 );
308 slots.push(slot);
309 current = slot.assigned_slot();
310 shadow_cascade_order.dec();
311 }
312
313 self.collect_host_rules(shadow_cascade_order);
314
315 for slot in slots.iter().rev() {
318 shadow_cascade_order.inc();
319
320 let shadow = slot.containing_shadow().unwrap();
321 let data = match shadow.style_data() {
322 Some(d) => d,
323 None => continue,
324 };
325
326 let slotted_rules = match data.slotted_rules(self.pseudo_elements) {
327 Some(r) => r,
328 None => continue,
329 };
330
331 self.in_shadow_tree(shadow.host(), |collector| {
332 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
333 collector.collect_rules_in_map(slotted_rules, cascade_level, data);
334 });
335 }
336 }
337
338 fn collect_rules_from_containing_shadow_tree(&mut self) {
339 if !self.matches_user_and_content_rules {
340 return;
341 }
342
343 let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target);
344 let containing_shadow = match containing_shadow {
345 Some(s) => s,
346 None => return,
347 };
348
349 self.matches_document_author_rules = false;
350
351 let cascade_data = match containing_shadow.style_data() {
352 Some(c) => c,
353 None => return,
354 };
355
356 let cascade_level = CascadeLevel::same_tree_author_normal();
357 self.in_shadow_tree(containing_shadow.host(), |collector| {
358 if let Some(map) = cascade_data.normal_rules(collector.pseudo_elements) {
359 collector.collect_rules_in_map(map, cascade_level, cascade_data);
360 }
361
362 let hash_target = collector.rule_hash_target;
364 if !hash_target.has_part_attr() {
365 return;
366 }
367
368 let part_rules = match cascade_data.part_rules(collector.pseudo_elements) {
369 Some(p) => p,
370 None => return,
371 };
372
373 hash_target.each_part(|part| {
374 if let Some(part_rules) = part_rules.get(&part.0) {
375 collector.collect_rules_in_list(part_rules, cascade_level, cascade_data);
376 }
377 });
378 });
379 }
380
381 fn collect_host_rules(&mut self, shadow_cascade_order: ShadowCascadeOrder) {
383 let Some(shadow) = self.rule_hash_target.shadow_root() else {
384 return;
385 };
386 let Some(cascade_data) = shadow.style_data() else {
387 return;
388 };
389 let rule_hash_target = self.rule_hash_target;
390 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
391 self.in_shadow_tree(rule_hash_target, |collector| {
392 if let Some(host_rules) = cascade_data.featureless_host_rules(collector.pseudo_elements)
393 {
394 debug_assert!(!collector.context.featureless(), "How?");
395 collector.context.featureless = true;
396 collector.collect_rules_in_map(host_rules, cascade_level, cascade_data);
397 collector.context.featureless = false;
398 }
399 if collector.is_element_backed_pseudo_element() {
402 if let Some(map) = cascade_data.normal_rules(&[]) {
403 collector.collect_rules_in_map_with_target(
404 map,
405 cascade_level,
406 cascade_data,
407 collector.element,
408 );
409 }
410 }
411 });
412 }
413
414 fn collect_document_author_rules(&mut self) {
415 if !self.matches_document_author_rules {
416 return;
417 }
418
419 self.collect_stylist_rules(Origin::Author);
420 }
421
422 fn collect_part_rules_from_outer_trees(&mut self) {
423 if !self.rule_hash_target.has_part_attr() {
424 return;
425 }
426
427 let mut inner_shadow = match self.rule_hash_target.containing_shadow() {
428 Some(s) => s,
429 None => return,
430 };
431
432 let mut shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree();
433
434 let mut parts = SmallVec::<[_; 3]>::new();
435 self.rule_hash_target.each_part(|p| parts.push(p.clone()));
436
437 loop {
438 if parts.is_empty() {
439 return;
440 }
441
442 let inner_shadow_host = inner_shadow.host();
443 let outer_shadow = inner_shadow_host.containing_shadow();
444 let cascade_data = match outer_shadow {
445 Some(shadow) => shadow.style_data(),
446 None => Some(
447 self.stylist
448 .cascade_data()
449 .borrow_for_origin(Origin::Author),
450 ),
451 };
452
453 if let Some(cascade_data) = cascade_data {
454 if let Some(part_rules) = cascade_data.part_rules(self.pseudo_elements) {
455 let containing_host = outer_shadow.map(|s| s.host());
456 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
457 self.in_tree(containing_host, |collector| {
458 for p in &parts {
459 if let Some(part_rules) = part_rules.get(&p.0) {
460 collector.collect_rules_in_list(
461 part_rules,
462 cascade_level,
463 cascade_data,
464 );
465 }
466 }
467 });
468 shadow_cascade_order.inc();
469 }
470 }
471
472 inner_shadow = match outer_shadow {
473 Some(s) => s,
474 None => break, };
476
477 let mut new_parts = SmallVec::new();
478 for part in &parts {
479 inner_shadow_host.each_exported_part(part, |exported_part| {
480 new_parts.push(exported_part.clone());
481 });
482 }
483 parts = new_parts;
484 }
485 }
486
487 fn collect_style_attribute(&mut self) {
488 if let Some(sa) = self.style_attribute {
489 self.rules
490 .push(ApplicableDeclarationBlock::from_declarations(
491 sa.clone_arc(),
492 CascadeLevel::same_tree_author_normal(),
493 LayerOrder::style_attribute(),
494 ));
495 }
496 }
497
498 fn collect_animation_rules(&mut self) {
499 if let Some(so) = self.smil_override {
500 self.rules
501 .push(ApplicableDeclarationBlock::from_declarations(
502 so.clone_arc(),
503 CascadeLevel::new(CascadeOrigin::SMILOverride),
504 LayerOrder::root(),
505 ));
506 }
507
508 if let Some(anim) = self.animation_declarations.animations.take() {
512 self.rules
513 .push(ApplicableDeclarationBlock::from_declarations(
514 anim,
515 CascadeLevel::new(CascadeOrigin::Animations),
516 LayerOrder::root(),
517 ));
518 }
519
520 if let Some(anim) = self.animation_declarations.transitions.take() {
523 self.rules
524 .push(ApplicableDeclarationBlock::from_declarations(
525 anim,
526 CascadeLevel::new(CascadeOrigin::Transitions),
527 LayerOrder::root(),
528 ));
529 }
530 }
531
532 pub fn collect_all(mut self) {
536 self.collect_user_agent_rules();
537 self.collect_user_rules();
538 if self.rule_inclusion == RuleInclusion::DefaultOnly {
539 return;
540 }
541 self.collect_presentational_hints();
542 if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
545 return;
546 }
547 self.collect_host_and_slotted_rules();
548 self.collect_rules_from_containing_shadow_tree();
549 self.collect_document_author_rules();
550 self.collect_style_attribute();
551 self.collect_part_rules_from_outer_trees();
552 self.collect_animation_rules();
553 }
554}