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 let cascade_data = self.stylist.cascade_data().borrow_for_origin(origin);
155 let map = match cascade_data.normal_rules(&self.pseudo_elements) {
156 Some(m) => m,
157 None => return,
158 };
159
160 self.in_tree(None, |collector| {
161 collector.collect_rules_in_map(map, cascade_level, cascade_data);
162 });
163 }
164
165 fn collect_user_agent_rules(&mut self) {
166 self.collect_stylist_rules(Origin::UserAgent);
167 #[cfg(feature = "gecko")]
168 self.collect_view_transition_dynamic_rules();
169 }
170
171 #[cfg(feature = "gecko")]
172 fn collect_view_transition_dynamic_rules(&mut self) {
173 if !self
174 .pseudo_elements
175 .first()
176 .is_some_and(|p| p.is_named_view_transition())
177 {
178 return;
179 }
180 let len_before_vt_rules = self.rules.len();
181 self.element
182 .synthesize_view_transition_dynamic_rules(self.rules);
183 if cfg!(debug_assertions) && self.rules.len() != len_before_vt_rules {
184 for declaration in &self.rules[len_before_vt_rules..] {
185 assert_eq!(declaration.level(), CascadeLevel::new(CascadeOrigin::UA));
186 }
187 }
188 }
189
190 fn collect_user_rules(&mut self) {
191 if !self.matches_user_and_content_rules {
192 return;
193 }
194
195 self.collect_stylist_rules(Origin::User);
196 }
197
198 fn collect_presentational_hints(&mut self) {
203 if !self.pseudo_elements.is_empty() {
204 return;
205 }
206
207 let length_before_preshints = self.rules.len();
208 self.element
209 .synthesize_presentational_hints_for_legacy_attributes(
210 self.context.visited_handling(),
211 self.rules,
212 );
213 if cfg!(debug_assertions) && self.rules.len() != length_before_preshints {
214 for declaration in &self.rules[length_before_preshints..] {
215 assert_eq!(
216 declaration.level(),
217 CascadeLevel::new(CascadeOrigin::PresHints)
218 );
219 }
220 }
221 }
222
223 #[inline]
224 fn collect_rules_in_list(
225 &mut self,
226 part_rules: &[Rule],
227 cascade_level: CascadeLevel,
228 cascade_data: &CascadeData,
229 ) {
230 debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
231 SelectorMap::get_matching_rules(
232 self.element,
233 part_rules,
234 &mut self.rules,
235 &mut self.context,
236 cascade_level,
237 cascade_data,
238 &self.stylist,
239 );
240 }
241
242 #[inline]
243 fn collect_rules_in_map(
244 &mut self,
245 map: &SelectorMap<Rule>,
246 cascade_level: CascadeLevel,
247 cascade_data: &CascadeData,
248 ) {
249 self.collect_rules_in_map_with_target(
250 map,
251 cascade_level,
252 cascade_data,
253 self.rule_hash_target,
254 );
255 }
256
257 #[inline]
258 fn collect_rules_in_map_with_target(
259 &mut self,
260 map: &SelectorMap<Rule>,
261 cascade_level: CascadeLevel,
262 cascade_data: &CascadeData,
263 rule_hash_target: E,
264 ) {
265 debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
266 map.get_all_matching_rules(
267 self.element,
268 rule_hash_target,
269 &mut self.rules,
270 &mut self.context,
271 cascade_level,
272 cascade_data,
273 &self.stylist,
274 );
275 }
276
277 #[inline]
282 fn is_element_backed_pseudo_element(&self) -> bool {
283 self.rule_hash_target != self.element
284 && self.pseudo_elements.len() == 1
285 && self.pseudo_elements[0].is_element_backed()
286 }
287
288 fn collect_host_and_slotted_rules(&mut self) {
290 let mut slots = SmallVec::<[_; 3]>::new();
291 let mut current = self.rule_hash_target.assigned_slot();
292 let mut shadow_cascade_order = ShadowCascadeOrder::for_outermost_shadow_tree();
293
294 while let Some(slot) = current {
295 debug_assert!(
296 self.matches_user_and_content_rules,
297 "We should not slot NAC anywhere"
298 );
299 slots.push(slot);
300 current = slot.assigned_slot();
301 shadow_cascade_order.dec();
302 }
303
304 self.collect_host_rules(shadow_cascade_order);
305
306 for slot in slots.iter().rev() {
309 shadow_cascade_order.inc();
310
311 let shadow = slot.containing_shadow().unwrap();
312 let data = match shadow.style_data() {
313 Some(d) => d,
314 None => continue,
315 };
316 let slotted_rules = match data.slotted_rules(&self.pseudo_elements) {
317 Some(r) => r,
318 None => continue,
319 };
320
321 self.in_shadow_tree(shadow.host(), |collector| {
322 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
323 collector.collect_rules_in_map(slotted_rules, cascade_level, data);
324 });
325 }
326 }
327
328 fn collect_rules_from_containing_shadow_tree(&mut self) {
329 if !self.matches_user_and_content_rules {
330 return;
331 }
332
333 let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target);
334 let containing_shadow = match containing_shadow {
335 Some(s) => s,
336 None => return,
337 };
338
339 self.matches_document_author_rules = false;
340
341 let cascade_data = match containing_shadow.style_data() {
342 Some(c) => c,
343 None => return,
344 };
345
346 let cascade_level = CascadeLevel::same_tree_author_normal();
347 self.in_shadow_tree(containing_shadow.host(), |collector| {
348 if let Some(map) = cascade_data.normal_rules(&collector.pseudo_elements) {
349 collector.collect_rules_in_map(map, cascade_level, cascade_data);
350 }
351
352 let hash_target = collector.rule_hash_target;
354 if !hash_target.has_part_attr() {
355 return;
356 }
357
358 let part_rules = match cascade_data.part_rules(&collector.pseudo_elements) {
359 Some(p) => p,
360 None => return,
361 };
362
363 hash_target.each_part(|part| {
364 if let Some(part_rules) = part_rules.get(&part.0) {
365 collector.collect_rules_in_list(part_rules, cascade_level, cascade_data);
366 }
367 });
368 });
369 }
370
371 fn collect_host_rules(&mut self, shadow_cascade_order: ShadowCascadeOrder) {
373 let Some(shadow) = self.rule_hash_target.shadow_root() else {
374 return;
375 };
376 let Some(cascade_data) = shadow.style_data() else {
377 return;
378 };
379 let rule_hash_target = self.rule_hash_target;
380 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
381 self.in_shadow_tree(rule_hash_target, |collector| {
382 if let Some(host_rules) =
383 cascade_data.featureless_host_rules(&collector.pseudo_elements)
384 {
385 debug_assert!(!collector.context.featureless(), "How?");
386 collector.context.featureless = true;
387 collector.collect_rules_in_map(host_rules, cascade_level, cascade_data);
388 collector.context.featureless = false;
389 }
390 if collector.is_element_backed_pseudo_element() {
393 if let Some(map) = cascade_data.normal_rules(&[]) {
394 collector.collect_rules_in_map_with_target(
395 map,
396 cascade_level,
397 cascade_data,
398 collector.element,
399 );
400 }
401 }
402 });
403 }
404
405 fn collect_document_author_rules(&mut self) {
406 if !self.matches_document_author_rules {
407 return;
408 }
409
410 self.collect_stylist_rules(Origin::Author);
411 }
412
413 fn collect_part_rules_from_outer_trees(&mut self) {
414 if !self.rule_hash_target.has_part_attr() {
415 return;
416 }
417
418 let mut inner_shadow = match self.rule_hash_target.containing_shadow() {
419 Some(s) => s,
420 None => return,
421 };
422
423 let mut shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree();
424
425 let mut parts = SmallVec::<[_; 3]>::new();
426 self.rule_hash_target.each_part(|p| parts.push(p.clone()));
427
428 loop {
429 if parts.is_empty() {
430 return;
431 }
432
433 let inner_shadow_host = inner_shadow.host();
434 let outer_shadow = inner_shadow_host.containing_shadow();
435 let cascade_data = match outer_shadow {
436 Some(shadow) => shadow.style_data(),
437 None => Some(
438 self.stylist
439 .cascade_data()
440 .borrow_for_origin(Origin::Author),
441 ),
442 };
443
444 if let Some(cascade_data) = cascade_data {
445 if let Some(part_rules) = cascade_data.part_rules(&self.pseudo_elements) {
446 let containing_host = outer_shadow.map(|s| s.host());
447 let cascade_level = CascadeLevel::author_normal(shadow_cascade_order);
448 self.in_tree(containing_host, |collector| {
449 for p in &parts {
450 if let Some(part_rules) = part_rules.get(&p.0) {
451 collector.collect_rules_in_list(
452 part_rules,
453 cascade_level,
454 cascade_data,
455 );
456 }
457 }
458 });
459 shadow_cascade_order.inc();
460 }
461 }
462
463 inner_shadow = match outer_shadow {
464 Some(s) => s,
465 None => break, };
467
468 let mut new_parts = SmallVec::new();
469 for part in &parts {
470 inner_shadow_host.each_exported_part(part, |exported_part| {
471 new_parts.push(exported_part.clone());
472 });
473 }
474 parts = new_parts;
475 }
476 }
477
478 fn collect_style_attribute(&mut self) {
479 if let Some(sa) = self.style_attribute {
480 self.rules
481 .push(ApplicableDeclarationBlock::from_declarations(
482 sa.clone_arc(),
483 CascadeLevel::same_tree_author_normal(),
484 LayerOrder::style_attribute(),
485 ));
486 }
487 }
488
489 fn collect_animation_rules(&mut self) {
490 if let Some(so) = self.smil_override {
491 self.rules
492 .push(ApplicableDeclarationBlock::from_declarations(
493 so.clone_arc(),
494 CascadeLevel::new(CascadeOrigin::SMILOverride),
495 LayerOrder::root(),
496 ));
497 }
498
499 if let Some(anim) = self.animation_declarations.animations.take() {
503 self.rules
504 .push(ApplicableDeclarationBlock::from_declarations(
505 anim,
506 CascadeLevel::new(CascadeOrigin::Animations),
507 LayerOrder::root(),
508 ));
509 }
510
511 if let Some(anim) = self.animation_declarations.transitions.take() {
514 self.rules
515 .push(ApplicableDeclarationBlock::from_declarations(
516 anim,
517 CascadeLevel::new(CascadeOrigin::Transitions),
518 LayerOrder::root(),
519 ));
520 }
521 }
522
523 pub fn collect_all(mut self) {
527 self.collect_user_agent_rules();
528 self.collect_user_rules();
529 if self.rule_inclusion == RuleInclusion::DefaultOnly {
530 return;
531 }
532 self.collect_presentational_hints();
533 if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
536 return;
537 }
538 self.collect_host_and_slotted_rules();
539 self.collect_rules_from_containing_shadow_tree();
540 self.collect_document_author_rules();
541 self.collect_style_attribute();
542 self.collect_part_rules_from_outer_trees();
543 self.collect_animation_rules();
544 }
545}