1use crate::context::SharedStyleContext;
9use crate::data::ElementData;
10use crate::dom::{TElement, TNode};
11use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
12use crate::invalidation::element::invalidation_map::*;
13use crate::invalidation::element::invalidator::{
14 DescendantInvalidationLists, InvalidationVector, SiblingTraversalMap,
15};
16use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
17use crate::invalidation::element::restyle_hints::RestyleHint;
18use crate::selector_map::SelectorMap;
19use crate::selector_parser::Snapshot;
20use crate::stylesheets::origin::OriginSet;
21use crate::values::AtomIdent;
22use crate::{Atom, WeakAtom};
23use dom::ElementState;
24use selectors::attr::CaseSensitivity;
25use selectors::kleene_value::KleeneValue;
26use selectors::matching::{
27 matches_selector_kleene, IncludeStartingStyle, MatchingContext, MatchingForInvalidation,
28 MatchingMode, NeedsSelectorFlags, SelectorCaches, VisitedHandlingMode,
29};
30use selectors::OpaqueElement;
31use smallvec::SmallVec;
32
33struct Collector<'a, 'b: 'a, 'selectors: 'a, E>
35where
36 E: TElement,
37{
38 element: E,
39 wrapper: ElementWrapper<'b, E>,
40 snapshot: &'a Snapshot,
41 matching_context: &'a mut MatchingContext<'b, E::Impl>,
42 lookup_element: E,
43 removed_id: Option<&'a WeakAtom>,
44 added_id: Option<&'a WeakAtom>,
45 classes_removed: &'a SmallVec<[Atom; 8]>,
46 classes_added: &'a SmallVec<[Atom; 8]>,
47 custom_states_removed: &'a SmallVec<[AtomIdent; 8]>,
48 custom_states_added: &'a SmallVec<[AtomIdent; 8]>,
49 state_changes: ElementState,
50 descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
51 sibling_invalidations: &'a mut InvalidationVector<'selectors>,
52 invalidates_self: bool,
53}
54
55pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
58 shared_context: &'a SharedStyleContext<'b>,
59 element: E,
60 data: &'a mut ElementData,
61 matching_context: MatchingContext<'a, E::Impl>,
62 traversal_map: SiblingTraversalMap<E>,
63}
64
65impl<'a, 'b: 'a, E: TElement + 'b> StateAndAttrInvalidationProcessor<'a, 'b, E> {
66 pub fn new(
68 shared_context: &'a SharedStyleContext<'b>,
69 element: E,
70 data: &'a mut ElementData,
71 selector_caches: &'a mut SelectorCaches,
72 ) -> Self {
73 let matching_context = MatchingContext::new_for_visited(
74 MatchingMode::Normal,
75 None,
76 selector_caches,
77 VisitedHandlingMode::AllLinksVisitedAndUnvisited,
78 IncludeStartingStyle::No,
79 shared_context.quirks_mode(),
80 NeedsSelectorFlags::No,
81 MatchingForInvalidation::Yes,
82 );
83
84 Self {
85 shared_context,
86 element,
87 data,
88 matching_context,
89 traversal_map: SiblingTraversalMap::default(),
90 }
91 }
92}
93
94pub fn check_dependency<E, W>(
97 dependency: &Dependency,
98 element: &E,
99 wrapper: &W,
100 context: &mut MatchingContext<'_, E::Impl>,
101 scope: Option<OpaqueElement>,
102) -> bool
103where
104 E: TElement,
105 W: selectors::Element<Impl = E::Impl>,
106{
107 context.for_invalidation_comparison(|context| {
108 context.nest_for_scope_condition(scope, |context|{
109
110 let matches_now = matches_selector_kleene(
111 &dependency.selector,
112 dependency.selector_offset,
113 None,
114 element,
115 context,
116 );
117
118 if scope.is_some() && matches_now != KleeneValue::False {
123 return true;
124 }
125
126 let matched_then = matches_selector_kleene(
127 &dependency.selector,
128 dependency.selector_offset,
129 None,
130 wrapper,
131 context,
132 );
133
134 matched_then != matches_now || matches_now == KleeneValue::Unknown
135 })
136 })
137}
138
139pub fn should_process_descendants(data: &ElementData) -> bool {
142 !data.styles.is_display_none() && !data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
143}
144
145pub fn propagate_dirty_bit_up_to<E>(ancestor: E, child: E)
147where
148 E: TElement,
149{
150 let mut current = child.traversal_parent();
156 while let Some(parent) = current.take() {
157 unsafe { parent.set_dirty_descendants() };
158 current = parent.traversal_parent();
159
160 if parent == ancestor {
161 return;
162 }
163 }
164 debug_assert!(
165 false,
166 "Should've found {:?} as an ancestor of {:?}",
167 ancestor, child
168 );
169}
170
171pub fn invalidated_descendants<E>(element: E, child: E)
173where
174 E: TElement,
175{
176 if !child.has_data() {
177 return;
178 }
179 propagate_dirty_bit_up_to(element, child)
180}
181
182pub fn invalidated_self<E>(element: E) -> bool
185where
186 E: TElement,
187{
188 let mut data = match element.mutate_data() {
189 Some(data) => data,
190 None => return false,
191 };
192 data.hint.insert(RestyleHint::RESTYLE_SELF);
193 true
194}
195
196pub fn invalidated_sibling<E>(element: E, of: E)
198where
199 E: TElement,
200{
201 debug_assert_eq!(
202 element.as_node().parent_node(),
203 of.as_node().parent_node(),
204 "Should be siblings"
205 );
206 if !invalidated_self(element) {
207 return;
208 }
209 if element.traversal_parent() != of.traversal_parent() {
210 let parent = element.as_node().parent_element_or_host();
211 debug_assert!(
212 parent.is_some(),
213 "How can we have siblings without parent nodes?"
214 );
215 if let Some(e) = parent {
216 propagate_dirty_bit_up_to(e, element)
217 }
218 }
219}
220
221impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, 'a, E>
222 for StateAndAttrInvalidationProcessor<'a, 'b, E>
223where
224 E: TElement,
225{
226 fn invalidates_on_pseudo_element(&self) -> bool {
230 true
231 }
232
233 fn check_outer_dependency(&mut self, dependency: &Dependency, element: E, scope: Option<OpaqueElement>) -> bool {
234 let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
238 check_dependency(dependency, &element, &wrapper, &mut self.matching_context, scope)
239 }
240
241 fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
242 &mut self.matching_context
243 }
244
245 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> {
246 &self.traversal_map
247 }
248
249 fn collect_invalidations(
250 &mut self,
251 element: E,
252 _self_invalidations: &mut InvalidationVector<'a>,
253 descendant_invalidations: &mut DescendantInvalidationLists<'a>,
254 sibling_invalidations: &mut InvalidationVector<'a>,
255 ) -> bool {
256 debug_assert_eq!(element, self.element);
257 debug_assert!(element.has_snapshot(), "Why bothering?");
258
259 let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
260
261 let state_changes = wrapper.state_changes();
262 let Some(snapshot) = wrapper.snapshot() else {
263 return false;
264 };
265
266 if !snapshot.has_attrs() && !snapshot.has_custom_states() && state_changes.is_empty() {
267 return false;
268 }
269
270 let mut classes_removed = SmallVec::<[Atom; 8]>::new();
271 let mut classes_added = SmallVec::<[Atom; 8]>::new();
272 if snapshot.class_changed() {
273 snapshot.each_class(|c| {
275 if !element.has_class(c, CaseSensitivity::CaseSensitive) {
276 classes_removed.push(c.0.clone())
277 }
278 });
279
280 element.each_class(|c| {
281 if !snapshot.has_class(c, CaseSensitivity::CaseSensitive) {
282 classes_added.push(c.0.clone())
283 }
284 })
285 }
286
287 let mut custom_states_removed = SmallVec::<[AtomIdent; 8]>::new();
288 let mut custom_states_added = SmallVec::<[AtomIdent; 8]>::new();
289 if snapshot.has_custom_states() {
290 snapshot.each_custom_state(|s| {
291 if !element.has_custom_state(s) {
292 custom_states_removed.push(s.clone())
293 }
294 });
295 element.each_custom_state(|s| {
296 if !snapshot.has_custom_state(s) {
297 custom_states_added.push(s.clone())
298 }
299 })
300 }
301
302 let mut id_removed = None;
303 let mut id_added = None;
304 if snapshot.id_changed() {
305 let old_id = snapshot.id_attr();
306 let current_id = element.id();
307
308 if old_id != current_id {
309 id_removed = old_id;
310 id_added = current_id;
311 }
312 }
313
314 if log_enabled!(::log::Level::Debug) {
315 debug!("Collecting changes for: {:?}", element);
316 if !state_changes.is_empty() {
317 debug!(" > state: {:?}", state_changes);
318 }
319 if snapshot.id_changed() {
320 debug!(" > id changed: +{:?} -{:?}", id_added, id_removed);
321 }
322 if snapshot.class_changed() {
323 debug!(
324 " > class changed: +{:?} -{:?}",
325 classes_added, classes_removed
326 );
327 }
328 let mut attributes_changed = false;
329 snapshot.each_attr_changed(|_| {
330 attributes_changed = true;
331 });
332 if attributes_changed {
333 debug!(
334 " > attributes changed, old: {}",
335 snapshot.debug_list_attributes()
336 )
337 }
338 }
339
340 let lookup_element = if element.implemented_pseudo_element().is_some() {
341 element.pseudo_element_originating_element().unwrap()
342 } else {
343 element
344 };
345
346 let mut shadow_rule_datas = SmallVec::<[_; 3]>::new();
347 let matches_document_author_rules =
348 element.each_applicable_non_document_style_rule_data(|data, host| {
349 shadow_rule_datas.push((data, host.opaque()))
350 });
351
352 let invalidated_self = {
353 let mut collector = Collector {
354 wrapper,
355 lookup_element,
356 state_changes,
357 element,
358 snapshot: &snapshot,
359 matching_context: &mut self.matching_context,
360 removed_id: id_removed,
361 added_id: id_added,
362 classes_removed: &classes_removed,
363 classes_added: &classes_added,
364 custom_states_removed: &custom_states_removed,
365 custom_states_added: &custom_states_added,
366 descendant_invalidations,
367 sibling_invalidations,
368 invalidates_self: false,
369 };
370
371 let document_origins = if !matches_document_author_rules {
372 OriginSet::ORIGIN_USER_AGENT | OriginSet::ORIGIN_USER
373 } else {
374 OriginSet::all()
375 };
376
377 for (cascade_data, origin) in self.shared_context.stylist.iter_origins() {
378 if document_origins.contains(origin.into()) {
379 collector
380 .collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
381 }
382 }
383
384 for &(ref data, ref host) in &shadow_rule_datas {
385 collector.matching_context.current_host = Some(host.clone());
386 collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
387 }
388
389 collector.invalidates_self
390 };
391
392 if descendant_invalidations.dom_descendants.len() > 150 {
403 self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
404 }
405
406 if invalidated_self {
407 self.data.hint.insert(RestyleHint::RESTYLE_SELF);
408 }
409
410 invalidated_self
411 }
412
413 fn should_process_descendants(&mut self, element: E) -> bool {
414 if element == self.element {
415 return should_process_descendants(&self.data);
416 }
417
418 match element.borrow_data() {
419 Some(d) => should_process_descendants(&d),
420 None => return false,
421 }
422 }
423
424 fn recursion_limit_exceeded(&mut self, element: E) {
425 if element == self.element {
426 self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
427 return;
428 }
429
430 if let Some(mut data) = element.mutate_data() {
431 data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
432 }
433 }
434
435 fn invalidated_descendants(&mut self, element: E, child: E) {
436 invalidated_descendants(element, child)
437 }
438
439 fn invalidated_self(&mut self, element: E) {
440 debug_assert_ne!(element, self.element);
441 invalidated_self(element);
442 }
443
444 fn invalidated_sibling(&mut self, element: E, of: E) {
445 debug_assert_ne!(element, self.element);
446 invalidated_sibling(element, of);
447 }
448}
449
450impl<'a, 'b, 'selectors, E> Collector<'a, 'b, 'selectors, E>
451where
452 E: TElement,
453 'selectors: 'a,
454{
455 fn collect_dependencies_in_invalidation_map(&mut self, map: &'selectors InvalidationMap) {
456 let quirks_mode = self.matching_context.quirks_mode();
457 let removed_id = self.removed_id;
458 if let Some(ref id) = removed_id {
459 if let Some(deps) = map.id_to_selector.get(id, quirks_mode) {
460 for dep in deps {
461 self.scan_dependency(dep);
462 }
463 }
464 }
465
466 let added_id = self.added_id;
467 if let Some(ref id) = added_id {
468 if let Some(deps) = map.id_to_selector.get(id, quirks_mode) {
469 for dep in deps {
470 self.scan_dependency(dep);
471 }
472 }
473 }
474
475 for class in self.classes_added.iter().chain(self.classes_removed.iter()) {
476 if let Some(deps) = map.class_to_selector.get(class, quirks_mode) {
477 for dep in deps {
478 self.scan_dependency(dep);
479 }
480 }
481 }
482
483 for state in self
484 .custom_states_added
485 .iter()
486 .chain(self.custom_states_removed.iter())
487 {
488 if let Some(deps) = map.custom_state_affecting_selectors.get(state) {
489 for dep in deps {
490 self.scan_dependency(dep);
491 }
492 }
493 }
494
495 self.snapshot.each_attr_changed(|attribute| {
496 if let Some(deps) = map.other_attribute_affecting_selectors.get(attribute) {
497 for dep in deps {
498 self.scan_dependency(dep);
499 }
500 }
501 });
502
503 self.collect_state_dependencies(&map.state_affecting_selectors)
504 }
505
506 fn collect_state_dependencies(&mut self, map: &'selectors SelectorMap<StateDependency>) {
507 if self.state_changes.is_empty() {
508 return;
509 }
510 map.lookup_with_additional(
511 self.lookup_element,
512 self.matching_context.quirks_mode(),
513 self.removed_id,
514 self.classes_removed,
515 self.state_changes,
516 |dependency| {
517 if !dependency.state.intersects(self.state_changes) {
518 return true;
519 }
520 self.scan_dependency(&dependency.dep);
521 true
522 },
523 );
524 }
525
526 #[inline]
528 fn check_dependency(&mut self, dependency: &Dependency) -> bool {
529 check_dependency(
530 dependency,
531 &self.element,
532 &self.wrapper,
533 &mut self.matching_context,
534 None,
535 )
536 }
537
538 fn scan_dependency(&mut self, dependency: &'selectors Dependency) {
539 debug_assert!(
540 matches!(
541 dependency.invalidation_kind(),
542 DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_)
543 ),
544 "Found unexpected dependency invalidation kind"
545 );
546 debug!(
547 "TreeStyleInvalidator::scan_dependency({:?}, {:?})",
548 self.element, dependency
549 );
550
551 if !self.dependency_may_be_relevant(dependency) {
552 return;
553 }
554
555 if self.check_dependency(dependency) || matches!(
556 dependency.invalidation_kind(),
557 DependencyInvalidationKind::Scope(_)
558 )
559 {
560 return self.note_dependency(dependency);
561 }
562 }
563
564 fn note_dependency(&mut self, dependency: &'selectors Dependency) {
565 debug_assert!(self.dependency_may_be_relevant(dependency));
566 let invalidation_kind = dependency.invalidation_kind();
567 if matches!(invalidation_kind, DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element)) {
568 if let Some(ref next) = dependency.next {
569 self.scan_dependency(&next.as_ref().slice()[0]);
572 } else {
573 self.invalidates_self = true;
574 }
575 return;
576 }
577
578 if matches!(invalidation_kind, DependencyInvalidationKind::Scope(_)){
579 if dependency.selector_offset == 0 {
580 if let Some(ref next) = dependency.next{
581 for dep in next.as_ref().slice(){
582 self.scan_dependency(dep);
583 }
584 }
585 } else {
586 let invalidation =
587 Invalidation::new(&dependency, self.matching_context.current_host.clone(), Some(self.element.opaque()));
588
589 self.invalidates_self |= push_invalidation(
590 invalidation,
591 invalidation_kind,
592 self.descendant_invalidations,
593 self.sibling_invalidations,
594 );
595 }
596 return;
597 }
598
599 debug_assert_ne!(dependency.selector_offset, 0);
600 debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
601
602 let invalidation =
603 Invalidation::new(&dependency, self.matching_context.current_host.clone(), self.matching_context.scope_element.clone());
604
605 self.invalidates_self |= push_invalidation(
606 invalidation,
607 invalidation_kind,
608 self.descendant_invalidations,
609 self.sibling_invalidations,
610 );
611 }
612
613 fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool {
616 match dependency.invalidation_kind() {
617 DependencyInvalidationKind::FullSelector |
618 DependencyInvalidationKind::Relative(_) => unreachable!(),
619 DependencyInvalidationKind::Scope(_) => true,
620 DependencyInvalidationKind::Normal(kind) => {
621 match kind {
622 NormalDependencyInvalidationKind::Element => !self.invalidates_self,
623 NormalDependencyInvalidationKind::SlottedElements => {
624 self.element.is_html_slot_element()
625 },
626 NormalDependencyInvalidationKind::Parts => self.element.shadow_root().is_some(),
627 NormalDependencyInvalidationKind::ElementAndDescendants |
628 NormalDependencyInvalidationKind::Siblings |
629 NormalDependencyInvalidationKind::Descendants => true,
630 }
631 },
632 }
633 }
634}
635
636pub(crate) fn push_invalidation<'a>(
637 invalidation: Invalidation<'a>,
638 invalidation_kind: DependencyInvalidationKind,
639 descendant_invalidations: &mut DescendantInvalidationLists<'a>,
640 sibling_invalidations: &mut InvalidationVector<'a>,
641) -> bool {
642 match invalidation_kind {
643 DependencyInvalidationKind::FullSelector => unreachable!(),
644 DependencyInvalidationKind::Relative(_) => unreachable!(),
645 DependencyInvalidationKind::Scope(_) => {
646 descendant_invalidations.dom_descendants.push(invalidation);
647 true
648 },
649 DependencyInvalidationKind::Normal(kind) => {
650 match kind {
651 NormalDependencyInvalidationKind::Element => unreachable!(),
652 NormalDependencyInvalidationKind::ElementAndDescendants => {
653 descendant_invalidations.dom_descendants.push(invalidation);
654 true
655 },
656 NormalDependencyInvalidationKind::Descendants => {
657 descendant_invalidations.dom_descendants.push(invalidation);
658 false
659 },
660 NormalDependencyInvalidationKind::Siblings => {
661 sibling_invalidations.push(invalidation);
662 false
663 },
664 NormalDependencyInvalidationKind::Parts => {
665 descendant_invalidations.parts.push(invalidation);
666 false
667 },
668 NormalDependencyInvalidationKind::SlottedElements => {
669 descendant_invalidations
670 .slotted_descendants
671 .push(invalidation);
672 false
673 },
674 }
675 }
676 }
677}
678
679pub(crate) fn dependency_may_be_relevant<E: TElement>(
680 dependency: &Dependency,
681 element: &E,
682 already_invalidated_self: bool,
683) -> bool {
684 match dependency.invalidation_kind() {
685 DependencyInvalidationKind::FullSelector => unreachable!(),
686 DependencyInvalidationKind::Relative(_) => unreachable!(),
687 DependencyInvalidationKind::Scope(_) => true,
688 DependencyInvalidationKind::Normal(kind) => {
689 match kind {
690 NormalDependencyInvalidationKind::Element => !already_invalidated_self,
691 NormalDependencyInvalidationKind::SlottedElements => element.is_html_slot_element(),
692 NormalDependencyInvalidationKind::Parts => element.shadow_root().is_some(),
693 NormalDependencyInvalidationKind::ElementAndDescendants |
694 NormalDependencyInvalidationKind::Siblings |
695 NormalDependencyInvalidationKind::Descendants => true,
696 }
697 },
698 }
699}