From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../style/invalidation/element/element_wrapper.rs | 24 ++++++++ .../style/invalidation/element/invalidation_map.rs | 37 ++++++++++++ .../invalidation/element/relative_selector.rs | 25 +++++--- .../invalidation/element/state_and_attributes.rs | 66 ++++++++++++++++------ 4 files changed, 126 insertions(+), 26 deletions(-) (limited to 'servo/components/style/invalidation/element') diff --git a/servo/components/style/invalidation/element/element_wrapper.rs b/servo/components/style/invalidation/element/element_wrapper.rs index e17afd7774..9a39b7d5a0 100644 --- a/servo/components/style/invalidation/element/element_wrapper.rs +++ b/servo/components/style/invalidation/element/element_wrapper.rs @@ -73,6 +73,18 @@ pub trait ElementSnapshot: Sized { where F: FnMut(&AtomIdent); + + /// If this snapshot contains CustomStateSet information. + fn has_custom_states(&self) -> bool; + + /// A callback that should be called for each CustomState of the snapshot. + fn has_custom_state(&self, state: &AtomIdent) -> bool; + + /// A callback that should be called for each CustomState of the snapshot. + fn each_custom_state(&self, callback: F) + where + F: FnMut(&AtomIdent); + /// The `xml:lang=""` or `lang=""` attribute value per this snapshot. fn lang_attr(&self) -> Option; } @@ -213,6 +225,11 @@ where .match_element_lang(Some(self.get_lang()), lang_arg); }, + // CustomStateSet should match against the snapshot before element + NonTSPseudoClass::CustomState(ref state) => { + return self.has_custom_state(&state.0) + }, + _ => {}, } @@ -357,6 +374,13 @@ where } } + fn has_custom_state(&self, state: &AtomIdent) -> bool { + match self.snapshot() { + Some(snapshot) if snapshot.has_custom_states() => snapshot.has_custom_state(state), + _ => self.element.has_custom_state(state), + } + } + fn is_empty(&self) -> bool { self.element.is_empty() } diff --git a/servo/components/style/invalidation/element/invalidation_map.rs b/servo/components/style/invalidation/element/invalidation_map.rs index cb03862740..f42f542dd2 100644 --- a/servo/components/style/invalidation/element/invalidation_map.rs +++ b/servo/components/style/invalidation/element/invalidation_map.rs @@ -10,6 +10,7 @@ use crate::selector_map::{ }; use crate::selector_parser::{NonTSPseudoClass, SelectorImpl}; use crate::AllocErr; +use crate::values::AtomIdent; use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded}; use dom::{DocumentState, ElementState}; use selectors::attr::NamespaceConstraint; @@ -259,6 +260,8 @@ pub type IdOrClassDependencyMap = MaybeCaseInsensitiveHashMap; /// Dependency mapping for local names. pub type LocalNameDependencyMap = PrecomputedHashMap>; +/// Dependency mapping for customstates +pub type CustomStateDependencyMap = PrecomputedHashMap>; /// A map where we store invalidations. /// @@ -282,6 +285,8 @@ pub struct InvalidationMap { pub document_state_selectors: Vec, /// A map of other attribute affecting selectors. pub other_attribute_affecting_selectors: LocalNameDependencyMap, + /// A map of CSS custom states + pub custom_state_affecting_selectors: CustomStateDependencyMap, } /// Tree-structural pseudoclasses that we care about for (Relative selector) invalidation. @@ -383,6 +388,7 @@ impl InvalidationMap { state_affecting_selectors: StateDependencyMap::new(), document_state_selectors: Vec::new(), other_attribute_affecting_selectors: LocalNameDependencyMap::default(), + custom_state_affecting_selectors: CustomStateDependencyMap::default(), } } @@ -397,6 +403,9 @@ impl InvalidationMap { .iter() .fold(0, |accum, (_, ref v)| accum + v.len()) + self.class_to_selector + .iter() + .fold(0, |accum, (_, ref v)| accum + v.len()) + + self.custom_state_affecting_selectors .iter() .fold(0, |accum, (_, ref v)| accum + v.len()) } @@ -408,6 +417,7 @@ impl InvalidationMap { self.state_affecting_selectors.clear(); self.document_state_selectors.clear(); self.other_attribute_affecting_selectors.clear(); + self.custom_state_affecting_selectors.clear(); } /// Shrink the capacity of hash maps if needed. @@ -416,6 +426,7 @@ impl InvalidationMap { self.id_to_selector.shrink_if_needed(); self.state_affecting_selectors.shrink_if_needed(); self.other_attribute_affecting_selectors.shrink_if_needed(); + self.custom_state_affecting_selectors.shrink_if_needed(); } } @@ -489,6 +500,7 @@ trait Collector { fn class_map(&mut self) -> &mut IdOrClassDependencyMap; fn state_map(&mut self) -> &mut StateDependencyMap; fn attribute_map(&mut self) -> &mut LocalNameDependencyMap; + fn custom_state_map(&mut self) -> &mut LocalNameDependencyMap; fn update_states(&mut self, element_state: ElementState, document_state: DocumentState); // In normal invalidations, type-based dependencies don't need to be explicitly tracked; @@ -551,6 +563,16 @@ fn add_attr_dependency(name: LocalName, collector: &mut C) -> Resu add_local_name(name, dependency, map) } +fn add_custom_state_dependency(name: AtomIdent, collector: &mut C) -> Result<(), AllocErr> { + let dependency = collector.dependency(); + let map = collector.custom_state_map(); + map.try_reserve(1)?; + let vec = map.entry(name).or_default(); + vec.try_reserve(1)?; + vec.push(dependency); + Ok(()) +} + fn add_local_name( name: LocalName, dependency: Dependency, @@ -576,6 +598,9 @@ fn on_pseudo_class(pc: &NonTSPseudoClass, collector: &mut C) -> Re return add_attr_dependency(local_name!("size"), collector); }, NonTSPseudoClass::Lang(..) => local_name!("lang"), + NonTSPseudoClass::CustomState(ref name) => { + return add_custom_state_dependency(name.0.clone(), collector); + }, _ => return Ok(()), }; @@ -702,6 +727,10 @@ impl<'a> Collector for SelectorDependencyCollector<'a> { self.compound_state.element_state |= element_state; *self.document_state |= document_state; } + + fn custom_state_map(&mut self) -> &mut CustomStateDependencyMap { + &mut self.map.custom_state_affecting_selectors + } } impl<'a> SelectorDependencyCollector<'a> { @@ -1074,6 +1103,10 @@ impl<'a> Collector for RelativeSelectorDependencyCollector<'a> { &mut self.map.map.other_attribute_affecting_selectors } + fn custom_state_map(&mut self) -> &mut CustomStateDependencyMap { + &mut self.map.map.custom_state_affecting_selectors + } + fn update_states(&mut self, element_state: ElementState, document_state: DocumentState) { self.compound_state.state.element_state |= element_state; *self.document_state |= document_state; @@ -1255,6 +1288,10 @@ impl<'a, 'b> Collector for RelativeSelectorInnerDependencyCollector<'a, 'b> { &mut self.map.map.other_attribute_affecting_selectors } + fn custom_state_map(&mut self) -> &mut CustomStateDependencyMap { + &mut self.map.map.custom_state_affecting_selectors + } + fn update_states(&mut self, element_state: ElementState, document_state: DocumentState) { self.compound_state.state.element_state |= element_state; *self.document_state |= document_state; diff --git a/servo/components/style/invalidation/element/relative_selector.rs b/servo/components/style/invalidation/element/relative_selector.rs index ccb48e349f..41222304be 100644 --- a/servo/components/style/invalidation/element/relative_selector.rs +++ b/servo/components/style/invalidation/element/relative_selector.rs @@ -53,12 +53,12 @@ impl DomMutationOperation { fn accept(&self, d: &Dependency, e: E) -> bool { match self { Self::Insert | Self::Append | Self::Remove => { - e.relative_selector_search_direction().is_some() + !e.relative_selector_search_direction().is_empty() }, // `:has(+ .a + .b)` with `.anchor + .a + .remove + .b` - `.a` would be present // in the search path. Self::SideEffectPrevSibling => { - e.relative_selector_search_direction().is_some() && + !e.relative_selector_search_direction().is_empty() && d.right_combinator_is_next_sibling() }, // If an element is being removed and would cause next-sibling match to happen, @@ -499,6 +499,19 @@ where }, None => (), }); + element.each_custom_state(|v| { + match map.map.custom_state_affecting_selectors.get(v) { + Some(v) => { + for dependency in v { + if !operation.accept(dependency, element) { + continue; + } + self.add_dependency(dependency, element, scope); + } + }, + None => (), + } + }); element.each_attr_name( |v| match map.map.other_attribute_affecting_selectors.get(v) { Some(v) => { @@ -782,11 +795,7 @@ where /// Is this element in the direction of the given relative selector search path? fn in_search_direction(element: &E, desired: ElementSelectorFlags) -> bool { - if let Some(direction) = element.relative_selector_search_direction() { - direction.intersects(desired) - } else { - false - } + element.relative_selector_search_direction().intersects(desired) } /// Handle a potential relative selector anchor. @@ -1145,7 +1154,7 @@ where dep: &'a Dependency, ) { debug_assert!(dep.parent.is_some(), "Orphaned inners selector?"); - if element.relative_selector_search_direction().is_none() { + if element.relative_selector_search_direction().is_empty() { return; } self.invalidations.push(( diff --git a/servo/components/style/invalidation/element/state_and_attributes.rs b/servo/components/style/invalidation/element/state_and_attributes.rs index 1c58cddf1e..d5f0723d66 100644 --- a/servo/components/style/invalidation/element/state_and_attributes.rs +++ b/servo/components/style/invalidation/element/state_and_attributes.rs @@ -19,11 +19,12 @@ use crate::selector_map::SelectorMap; use crate::selector_parser::Snapshot; use crate::stylesheets::origin::OriginSet; use crate::{Atom, WeakAtom}; +use crate::values::AtomIdent; use dom::ElementState; use selectors::attr::CaseSensitivity; +use selectors::kleene_value::KleeneValue; use selectors::matching::{ - matches_selector, MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags, - SelectorCaches, VisitedHandlingMode, + matches_selector_kleene, MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags, SelectorCaches, VisitedHandlingMode }; use smallvec::SmallVec; @@ -41,6 +42,8 @@ where added_id: Option<&'a WeakAtom>, classes_removed: &'a SmallVec<[Atom; 8]>, classes_added: &'a SmallVec<[Atom; 8]>, + custom_states_removed: &'a SmallVec<[AtomIdent; 8]>, + custom_states_added: &'a SmallVec<[AtomIdent; 8]>, state_changes: ElementState, descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>, sibling_invalidations: &'a mut InvalidationVector<'selectors>, @@ -97,23 +100,25 @@ where E: TElement, W: selectors::Element, { - let matches_now = matches_selector( - &dependency.selector, - dependency.selector_offset, - None, - element, - context, - ); + context.for_invalidation_comparison(|context| { + let matches_now = matches_selector_kleene( + &dependency.selector, + dependency.selector_offset, + None, + element, + context, + ); - let matched_then = matches_selector( - &dependency.selector, - dependency.selector_offset, - None, - wrapper, - context, - ); + let matched_then = matches_selector_kleene( + &dependency.selector, + dependency.selector_offset, + None, + wrapper, + context, + ); - matched_then != matches_now + matched_then != matches_now || matches_now == KleeneValue::Unknown + }) } /// Whether we should process the descendants of a given element for style @@ -243,7 +248,7 @@ where return false; }; - if !snapshot.has_attrs() && state_changes.is_empty() { + if !snapshot.has_attrs() && !snapshot.has_custom_states() && state_changes.is_empty() { return false; } @@ -264,6 +269,21 @@ where }) } + let mut custom_states_removed = SmallVec::<[AtomIdent; 8]>::new(); + let mut custom_states_added = SmallVec::<[AtomIdent; 8]>::new(); + if snapshot.has_custom_states() { + snapshot.each_custom_state(|s| { + if !element.has_custom_state(s) { + custom_states_removed.push(s.clone()) + } + }); + element.each_custom_state(|s| { + if !snapshot.has_custom_state(s) { + custom_states_added.push(s.clone()) + } + }) + } + let mut id_removed = None; let mut id_added = None; if snapshot.id_changed() { @@ -326,6 +346,8 @@ where added_id: id_added, classes_removed: &classes_removed, classes_added: &classes_added, + custom_states_removed: &custom_states_removed, + custom_states_added: &custom_states_added, descendant_invalidations, sibling_invalidations, invalidates_self: false, @@ -443,6 +465,14 @@ where } } + for state in self.custom_states_added.iter().chain(self.custom_states_removed.iter()) { + if let Some(deps) = map.custom_state_affecting_selectors.get(state) { + for dep in deps { + self.scan_dependency(dep); + } + } + } + self.snapshot.each_attr_changed(|attribute| { if let Some(deps) = map.other_attribute_affecting_selectors.get(attribute) { for dep in deps { -- cgit v1.2.3