use crate::context::QuirksMode;
use crate::derives::*;
use crate::selector_map::{
MaybeCaseInsensitiveHashMap, PrecomputedHashMap, SelectorMap, SelectorMapEntry,
};
use crate::selector_parser::{NonTSPseudoClass, SelectorImpl};
use crate::values::AtomIdent;
use crate::AllocErr;
use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded};
use dom::{DocumentState, ElementState};
use selectors::attr::NamespaceConstraint;
use selectors::parser::{
Combinator, Component, RelativeSelector, RelativeSelectorCombinatorCount,
RelativeSelectorMatchHint,
};
use selectors::parser::{Selector, SelectorIter};
use selectors::visitor::{SelectorListKind, SelectorVisitor};
use servo_arc::ThinArc;
use smallvec::SmallVec;
#[derive(Clone, Debug, MallocSizeOf)]
pub struct Dependency {
#[ignore_malloc_size_of = "CssRules have primary refs, we measure there"]
pub selector: Selector<SelectorImpl>,
pub selector_offset: usize,
#[ignore_malloc_size_of = "Arc"]
pub next: Option<ThinArc<(), Dependency>>,
kind: DependencyInvalidationKind,
}
impl SelectorMapEntry for Dependency {
fn selector(&self) -> SelectorIter<'_, SelectorImpl> {
self.selector.iter_from(self.selector_offset)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, MallocSizeOf)]
pub enum NormalDependencyInvalidationKind {
Element,
ElementAndDescendants,
Descendants,
Siblings,
SlottedElements,
Parts,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, MallocSizeOf)]
pub enum RelativeDependencyInvalidationKind {
Ancestors,
Parent,
PrevSibling,
AncestorPrevSibling,
EarlierSibling,
AncestorEarlierSibling,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, MallocSizeOf)]
pub enum ScopeDependencyInvalidationKind {
ExplicitScope,
ImplicitScope,
ScopeEnd,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, MallocSizeOf)]
pub enum DependencyInvalidationKind {
FullSelector,
Normal(NormalDependencyInvalidationKind),
Relative(RelativeDependencyInvalidationKind),
Scope(ScopeDependencyInvalidationKind),
}
#[derive(Clone, Copy, Debug, MallocSizeOf)]
pub enum GeneratedInvalidation<'a> {
Normal,
Scope(Option<&'a ThinArc<(), Dependency>>),
}
#[inline(always)]
fn get_non_relative_invalidation_kind(
selector: &Selector<SelectorImpl>,
selector_offset: usize,
scope_kind: Option<ScopeDependencyInvalidationKind>,
) -> DependencyInvalidationKind {
if let Some(kind) = scope_kind {
return DependencyInvalidationKind::Scope(kind);
}
if selector_offset == 0 {
return DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element);
}
let combinator = selector.combinator_at_match_order(selector_offset - 1);
DependencyInvalidationKind::Normal(match combinator {
Combinator::Child | Combinator::Descendant => NormalDependencyInvalidationKind::Descendants,
Combinator::LaterSibling | Combinator::NextSibling => {
NormalDependencyInvalidationKind::Siblings
},
Combinator::PseudoElement => NormalDependencyInvalidationKind::ElementAndDescendants,
Combinator::SlotAssignment => NormalDependencyInvalidationKind::SlottedElements,
Combinator::Part => NormalDependencyInvalidationKind::Parts,
})
}
impl Dependency {
pub fn new(
selector: Selector<SelectorImpl>,
selector_offset: usize,
next: Option<ThinArc<(), Dependency>>,
kind: DependencyInvalidationKind,
) -> Self {
Self {
selector,
selector_offset,
next,
kind,
}
}
pub fn for_full_selector_invalidation(selector: Selector<SelectorImpl>) -> Self {
Self {
selector_offset: selector.len() + 1,
selector,
next: None,
kind: DependencyInvalidationKind::FullSelector,
}
}
pub fn normal_invalidation_kind(&self) -> NormalDependencyInvalidationKind {
if let DependencyInvalidationKind::Normal(kind) = self.kind {
return kind;
}
unreachable!("Querying normal invalidation kind on non-normal dependency.");
}
#[inline(always)]
pub fn relative_invalidation_kind(&self) -> RelativeDependencyInvalidationKind {
if let DependencyInvalidationKind::Relative(kind) = self.kind {
return kind;
}
unreachable!("Querying relative invalidation kind on non-relative dependency.");
}
pub fn invalidation_kind(&self) -> DependencyInvalidationKind {
self.kind
}
pub fn right_combinator_is_next_sibling(&self) -> bool {
if self.selector_offset == 0 {
return false;
}
matches!(
self.selector
.combinator_at_match_order(self.selector_offset - 1),
Combinator::NextSibling
)
}
pub fn dependency_is_relative_with_single_next_sibling(&self) -> bool {
match self.invalidation_kind() {
DependencyInvalidationKind::Relative(kind) => {
kind == RelativeDependencyInvalidationKind::PrevSibling
},
_ => false,
}
}
}
#[derive(Clone, Debug, MallocSizeOf)]
pub struct StateDependency {
pub dep: Dependency,
pub state: ElementState,
}
impl SelectorMapEntry for StateDependency {
fn selector(&self) -> SelectorIter<'_, SelectorImpl> {
self.dep.selector()
}
}
#[derive(Clone, Debug, MallocSizeOf)]
pub struct DocumentStateDependency {
#[cfg_attr(
feature = "gecko",
ignore_malloc_size_of = "CssRules have primary refs, we measure there"
)]
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
pub dependency: Dependency,
pub state: DocumentState,
}
pub type IdOrClassDependencyMap = MaybeCaseInsensitiveHashMap<Atom, SmallVec<[Dependency; 1]>>;
pub type StateDependencyMap = SelectorMap<StateDependency>;
pub type LocalNameDependencyMap = PrecomputedHashMap<LocalName, SmallVec<[Dependency; 1]>>;
pub type CustomStateDependencyMap = PrecomputedHashMap<AtomIdent, SmallVec<[Dependency; 1]>>;
#[derive(Clone, Debug, MallocSizeOf)]
pub struct InvalidationMap {
pub class_to_selector: IdOrClassDependencyMap,
pub id_to_selector: IdOrClassDependencyMap,
pub state_affecting_selectors: StateDependencyMap,
pub document_state_selectors: Vec<DocumentStateDependency>,
pub other_attribute_affecting_selectors: LocalNameDependencyMap,
pub custom_state_affecting_selectors: CustomStateDependencyMap,
}
#[derive(Clone, Copy, Debug, MallocSizeOf)]
pub struct TSStateForInvalidation(u8);
bitflags! {
impl TSStateForInvalidation : u8 {
const EMPTY = 1 << 0;
const NTH = 1 << 1;
const NTH_EDGE_FIRST = 1 << 2;
const NTH_EDGE_LAST = 1 << 3;
}
}
impl TSStateForInvalidation {
pub fn may_be_optimized(&self) -> bool {
(Self::EMPTY | Self::NTH_EDGE_FIRST | Self::NTH_EDGE_LAST).contains(*self)
}
}
#[derive(Clone, Debug, MallocSizeOf)]
pub struct TSStateDependency {
pub dep: Dependency,
pub state: TSStateForInvalidation,
}
impl SelectorMapEntry for TSStateDependency {
fn selector(&self) -> SelectorIter<'_, SelectorImpl> {
self.dep.selector()
}
}
pub type TSStateDependencyMap = SelectorMap<TSStateDependency>;
pub type AnyDependencyMap = SmallVec<[Dependency; 1]>;
#[derive(Clone, Debug, MallocSizeOf)]
pub struct AdditionalRelativeSelectorInvalidationMap {
pub ts_state_to_selector: TSStateDependencyMap,
pub type_to_selector: LocalNameDependencyMap,
pub any_to_selector: AnyDependencyMap,
pub used: bool,
pub needs_ancestors_traversal: bool,
}
impl AdditionalRelativeSelectorInvalidationMap {
pub fn new() -> Self {
Self {
ts_state_to_selector: TSStateDependencyMap::default(),
type_to_selector: LocalNameDependencyMap::default(),
any_to_selector: SmallVec::default(),
used: false,
needs_ancestors_traversal: false,
}
}
pub fn clear(&mut self) {
self.ts_state_to_selector.clear();
self.type_to_selector.clear();
self.any_to_selector.clear();
}
pub fn shrink_if_needed(&mut self) {
self.ts_state_to_selector.shrink_if_needed();
self.type_to_selector.shrink_if_needed();
}
}
impl InvalidationMap {
pub fn new() -> Self {
Self {
class_to_selector: IdOrClassDependencyMap::new(),
id_to_selector: IdOrClassDependencyMap::new(),
state_affecting_selectors: StateDependencyMap::new(),
document_state_selectors: Vec::new(),
other_attribute_affecting_selectors: LocalNameDependencyMap::default(),
custom_state_affecting_selectors: CustomStateDependencyMap::default(),
}
}
pub fn len(&self) -> usize {
self.state_affecting_selectors.len()
+ self.document_state_selectors.len()
+ self
.other_attribute_affecting_selectors
.iter()
.fold(0, |accum, (_, ref v)| accum + v.len())
+ self
.id_to_selector
.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())
}
pub fn clear(&mut self) {
self.class_to_selector.clear();
self.id_to_selector.clear();
self.state_affecting_selectors.clear();
self.document_state_selectors.clear();
self.other_attribute_affecting_selectors.clear();
self.custom_state_affecting_selectors.clear();
}
pub fn shrink_if_needed(&mut self) {
self.class_to_selector.shrink_if_needed();
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();
}
}
pub fn note_selector_for_invalidation(
selector: &Selector<SelectorImpl>,
quirks_mode: QuirksMode,
map: &mut InvalidationMap,
relative_selector_invalidation_map: &mut InvalidationMap,
additional_relative_selector_invalidation_map: &mut AdditionalRelativeSelectorInvalidationMap,
inner_scope_dependencies: Option<&ThinArc<(), Dependency>>,
scope_kind: Option<ScopeDependencyInvalidationKind>,
) -> Result<Option<Vec<Dependency>>, AllocErr> {
let next_dependency = Dependency::for_full_selector_invalidation(selector.clone());
let mut document_state = DocumentState::empty();
let mut scope_dependencies = ScopeSelectorCollectorState {
inner_dependencies: &inner_scope_dependencies.cloned(),
this_dependencies: None,
scope_kind,
};
{
let mut next_stack = NextSelectors::new();
let mut alloc_error = None;
let mut collector = SelectorDependencyCollector {
map,
relative_selector_invalidation_map,
additional_relative_selector_invalidation_map,
document_state: &mut document_state,
selector,
next_selectors: &mut next_stack,
quirks_mode,
compound_state: PerCompoundState::new(0),
relative_inner_collector: None,
scope_dependencies: &mut scope_dependencies,
alloc_error: &mut alloc_error,
};
let visit_result = collector.visit_whole_selector();
debug_assert_eq!(!visit_result, alloc_error.is_some());
if let Some(alloc_error) = alloc_error {
return Err(alloc_error);
}
}
if !document_state.is_empty() {
let dep = DocumentStateDependency {
state: document_state,
dependency: next_dependency,
};
map.document_state_selectors.try_reserve(1)?;
map.document_state_selectors.push(dep);
}
Ok(scope_dependencies.this_dependencies)
}
struct PerCompoundState {
offset: usize,
element_state: ElementState,
}
impl PerCompoundState {
fn new(offset: usize) -> Self {
Self {
offset,
element_state: ElementState::empty(),
}
}
}
struct NextDependencyEntry {
selector: Selector<SelectorImpl>,
offset: usize,
cached_dependency: Option<ThinArc<(), Dependency>>,
}
struct RelativeSelectorInnerCollectorState<'a> {
next_dependency: &'a ThinArc<(), Dependency>,
relative_compound_state: RelativeSelectorCompoundStateAttributes,
}
struct ScopeSelectorCollectorState<'a> {
inner_dependencies: &'a Option<ThinArc<(), Dependency>>,
this_dependencies: Option<Vec<Dependency>>,
scope_kind: Option<ScopeDependencyInvalidationKind>,
}
trait Collector {
fn dependency(&mut self) -> Dependency;
fn id_map(&mut self) -> &mut IdOrClassDependencyMap;
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 CustomStateDependencyMap;
fn inner_scope_dependencies(&self) -> Option<ThinArc<(), Dependency>>;
fn this_scope_dependencies(&mut self) -> &mut Option<Vec<Dependency>>;
fn update_states(&mut self, element_state: ElementState, document_state: DocumentState);
fn type_map(&mut self) -> &mut LocalNameDependencyMap {
unreachable!();
}
fn ts_state_map(&mut self) -> &mut TSStateDependencyMap {
unreachable!();
}
fn any_vec(&mut self) -> &mut AnyDependencyMap {
unreachable!();
}
}
fn on_attribute<C: Collector>(
local_name: &LocalName,
local_name_lower: &LocalName,
collector: &mut C,
) -> Result<(), AllocErr> {
add_attr_dependency(local_name.clone(), collector)?;
if local_name != local_name_lower {
add_attr_dependency(local_name_lower.clone(), collector)?;
}
Ok(())
}
fn on_id_or_class<C: Collector>(
s: &Component<SelectorImpl>,
quirks_mode: QuirksMode,
collector: &mut C,
) -> Result<(), AllocErr> {
let dependency = collector.dependency();
let (atom, map) = match *s {
Component::ID(ref atom) => (atom, collector.id_map()),
Component::Class(ref atom) => (atom, collector.class_map()),
_ => unreachable!(),
};
let entry = map.try_entry(atom.0.clone(), quirks_mode)?;
let vec = entry.or_insert_with(SmallVec::new);
vec.try_reserve(1)?;
vec.push(dependency);
Ok(())
}
fn on_scope<C: Collector>(collector: &mut C) -> Result<(), AllocErr> {
let new_dependency = collector.dependency();
let this_scope_dependencies = collector.this_scope_dependencies();
this_scope_dependencies
.get_or_insert(Vec::new())
.push(new_dependency);
Ok(())
}
fn add_attr_dependency<C: Collector>(name: LocalName, collector: &mut C) -> Result<(), AllocErr> {
let dependency = collector.dependency();
let map = collector.attribute_map();
add_local_name(name, dependency, map)
}
fn add_custom_state_dependency<C: Collector>(
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,
map: &mut LocalNameDependencyMap,
) -> Result<(), AllocErr> {
map.try_reserve(1)?;
let vec = map.entry(name).or_default();
vec.try_reserve(1)?;
vec.push(dependency);
Ok(())
}
fn on_pseudo_class<C: Collector>(pc: &NonTSPseudoClass, collector: &mut C) -> Result<(), AllocErr> {
collector.update_states(pc.state_flag(), pc.document_state_flag());
let attr_name = match *pc {
#[cfg(feature = "gecko")]
NonTSPseudoClass::MozTableBorderNonzero => local_name!("border"),
#[cfg(feature = "gecko")]
NonTSPseudoClass::MozSelectListBox => {
add_attr_dependency(local_name!("multiple"), collector)?;
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(()),
};
add_attr_dependency(attr_name, collector)
}
fn add_pseudo_class_dependency<C: Collector>(
element_state: ElementState,
quirks_mode: QuirksMode,
collector: &mut C,
) -> Result<(), AllocErr> {
if element_state.is_empty() {
return Ok(());
}
let dependency = collector.dependency();
collector.state_map().insert(
StateDependency {
dep: dependency,
state: element_state,
},
quirks_mode,
)
}
fn visit_all_in_iter_compound<T: SelectorVisitor<Impl = SelectorImpl>>(
visitor: &mut T,
iter: &mut SelectorIter<'_, SelectorImpl>,
) -> (bool, usize) {
let mut index = 0;
for ss in iter {
if !ss.visit(visitor) {
return (false, index);
}
index += 1;
}
(true, index)
}
type NextSelectors = SmallVec<[NextDependencyEntry; 5]>;
struct SelectorDependencyCollector<'a, 'b, 'c> {
map: &'a mut InvalidationMap,
relative_selector_invalidation_map: &'a mut InvalidationMap,
additional_relative_selector_invalidation_map:
&'a mut AdditionalRelativeSelectorInvalidationMap,
document_state: &'a mut DocumentState,
selector: &'a Selector<SelectorImpl>,
next_selectors: &'a mut NextSelectors,
quirks_mode: QuirksMode,
compound_state: PerCompoundState,
relative_inner_collector: Option<RelativeSelectorInnerCollectorState<'b>>,
scope_dependencies: &'a mut ScopeSelectorCollectorState<'c>,
alloc_error: &'a mut Option<AllocErr>,
}
fn next_dependency(
next_selector: &mut NextSelectors,
next_outer_dependency: Option<&ThinArc<(), Dependency>>,
next_scope_dependencies: Option<&ThinArc<(), Dependency>>,
scope_kind: Option<ScopeDependencyInvalidationKind>,
) -> Option<ThinArc<(), Dependency>> {
if next_selector.is_empty() {
return match next_outer_dependency {
Some(..) => next_outer_dependency.cloned(),
None => next_scope_dependencies.cloned(),
};
}
fn dependencies_from(
entries: &mut [NextDependencyEntry],
next_outer_dependency: &Option<&ThinArc<(), Dependency>>,
next_scope_dependencies: &Option<&ThinArc<(), Dependency>>,
scope_kind: Option<ScopeDependencyInvalidationKind>,
) -> Option<ThinArc<(), Dependency>> {
if entries.is_empty() {
return next_scope_dependencies.cloned();
}
let last_index = entries.len() - 1;
let (previous, last) = entries.split_at_mut(last_index);
let last = &mut last[0];
let selector = &last.selector;
let selector_offset = last.offset;
let dependency = Dependency {
selector: selector.clone(),
selector_offset,
next: dependencies_from(
previous,
next_outer_dependency,
next_scope_dependencies,
scope_kind,
),
kind: get_non_relative_invalidation_kind(
selector,
selector_offset,
next_scope_dependencies
.is_some()
.then(|| scope_kind)
.flatten(),
),
};
Some(
last.cached_dependency
.get_or_insert_with(|| ThinArc::from_header_and_iter((), [dependency].into_iter()))
.clone(),
)
}
dependencies_from(
next_selector,
&next_outer_dependency,
&next_scope_dependencies,
scope_kind,
)
}
impl<'a, 'b, 'c> Collector for SelectorDependencyCollector<'a, 'b, 'c> {
fn dependency(&mut self) -> Dependency {
let optional_dependency = self
.relative_inner_collector
.as_ref()
.map(|collector| collector.next_dependency);
let offset = self.compound_state.offset;
let scope_dependencies = self.inner_scope_dependencies();
let next = next_dependency(
self.next_selectors,
optional_dependency,
scope_dependencies.as_ref(),
self.scope_dependencies.scope_kind,
);
Dependency {
selector: self.selector.clone(),
selector_offset: offset,
next: next,
kind: get_non_relative_invalidation_kind(
self.selector,
offset,
scope_dependencies
.is_some()
.then(|| self.scope_dependencies.scope_kind)
.flatten(),
),
}
}
fn id_map(&mut self) -> &mut IdOrClassDependencyMap {
if self.relative_inner_collector.is_none() {
&mut self.map.id_to_selector
} else {
&mut self.relative_selector_invalidation_map.id_to_selector
}
}
fn class_map(&mut self) -> &mut IdOrClassDependencyMap {
if self.relative_inner_collector.is_none() {
&mut self.map.class_to_selector
} else {
&mut self.relative_selector_invalidation_map.class_to_selector
}
}
fn state_map(&mut self) -> &mut StateDependencyMap {
if self.relative_inner_collector.is_none() {
&mut self.map.state_affecting_selectors
} else {
&mut self
.relative_selector_invalidation_map
.state_affecting_selectors
}
}
fn attribute_map(&mut self) -> &mut LocalNameDependencyMap {
if self.relative_inner_collector.is_none() {
&mut self.map.other_attribute_affecting_selectors
} else {
&mut self
.relative_selector_invalidation_map
.other_attribute_affecting_selectors
}
}
fn inner_scope_dependencies(&self) -> Option<ThinArc<(), Dependency>> {
self.scope_dependencies.inner_dependencies.clone()
}
fn this_scope_dependencies(&mut self) -> &mut Option<Vec<Dependency>> {
&mut self.scope_dependencies.this_dependencies
}
fn update_states(&mut self, element_state: ElementState, document_state: DocumentState) {
self.compound_state.element_state |= element_state;
*self.document_state |= document_state;
}
fn custom_state_map(&mut self) -> &mut CustomStateDependencyMap {
if self.relative_inner_collector.is_none() {
&mut self.map.custom_state_affecting_selectors
} else {
&mut self
.relative_selector_invalidation_map
.custom_state_affecting_selectors
}
}
fn type_map(&mut self) -> &mut LocalNameDependencyMap {
debug_assert!(
self.relative_inner_collector.is_some(),
"Asking for relative selector invalidation outside of relative selector"
);
&mut self
.additional_relative_selector_invalidation_map
.type_to_selector
}
fn ts_state_map(&mut self) -> &mut TSStateDependencyMap {
debug_assert!(
self.relative_inner_collector.is_some(),
"Asking for relative selector invalidation outside of relative selector"
);
&mut self
.additional_relative_selector_invalidation_map
.ts_state_to_selector
}
fn any_vec(&mut self) -> &mut AnyDependencyMap {
debug_assert!(
self.relative_inner_collector.is_some(),
"Asking for relative selector invalidation outside of relative selector"
);
&mut self
.additional_relative_selector_invalidation_map
.any_to_selector
}
}
impl<'a, 'b, 'c> SelectorDependencyCollector<'a, 'b, 'c> {
fn visit_whole_selector(&mut self) -> bool {
let iter = self.selector.iter();
self.visit_whole_selector_from(iter, 0)
}
fn visit_whole_selector_from(
&mut self,
mut iter: SelectorIter<SelectorImpl>,
mut index: usize,
) -> bool {
loop {
self.compound_state = PerCompoundState::new(index);
if let Some(state) = self.relative_inner_collector.as_mut() {
state.relative_compound_state = RelativeSelectorCompoundStateAttributes::new();
}
let (keep_traversing, index_offset) = visit_all_in_iter_compound(self, &mut iter);
if !keep_traversing {
return false;
}
index += index_offset;
if let Err(err) = add_pseudo_class_dependency(
self.compound_state.element_state,
self.quirks_mode,
self,
) {
*self.alloc_error = Some(err);
return false;
}
if let Some(state) = self
.relative_inner_collector
.as_ref()
.map(|state| state.relative_compound_state)
{
if let Err(err) =
add_ts_pseudo_class_dependency(state.ts_state, self.quirks_mode, self)
{
*self.alloc_error = Some(err);
return false;
}
if !state.added_entry {
if let Err(err) =
add_non_unique_info(&self.selector, self.compound_state.offset, self)
{
*self.alloc_error = Some(err);
return false;
}
}
}
let combinator = iter.next_sequence();
if combinator.is_none() {
return true;
}
index += 1; }
}
}
impl<'a, 'b, 'c> SelectorVisitor for SelectorDependencyCollector<'a, 'b, 'c> {
type Impl = SelectorImpl;
fn visit_selector_list(
&mut self,
_list_kind: SelectorListKind,
list: &[Selector<SelectorImpl>],
) -> bool {
let next_relative_dependency = self
.relative_inner_collector
.is_some()
.then(|| ThinArc::from_header_and_iter((), std::iter::once(self.dependency())));
for selector in list {
let mut iter = selector.iter();
let saved_added_entry = self
.relative_inner_collector
.as_ref()
.map(|state| state.relative_compound_state.added_entry);
let (keep_traversing, mut index) = visit_all_in_iter_compound(self, &mut iter);
if !keep_traversing {
return false;
}
if let Some(state) = self.relative_inner_collector.as_mut() {
state.relative_compound_state.added_entry = saved_added_entry.unwrap_or_default();
}
let combinator = iter.next_sequence();
if combinator.is_none() {
continue;
}
index += 1;
let offset = self.compound_state.offset;
if self.relative_inner_collector.is_none() {
self.next_selectors.push(NextDependencyEntry {
selector: self.selector.clone(),
offset: offset,
cached_dependency: None,
});
}
debug_assert!(
next_relative_dependency.is_some() == self.relative_inner_collector.is_some(),
"Next relative dependency and relative inner collector must be Some/None at the same time!"
);
let mut nested = SelectorDependencyCollector {
map: &mut *self.map,
relative_selector_invalidation_map: &mut *self.relative_selector_invalidation_map,
additional_relative_selector_invalidation_map: &mut *self
.additional_relative_selector_invalidation_map,
document_state: &mut *self.document_state,
selector,
next_selectors: &mut *self.next_selectors,
quirks_mode: self.quirks_mode,
compound_state: PerCompoundState::new(index),
relative_inner_collector: next_relative_dependency.as_ref().map(
|next_dependency| RelativeSelectorInnerCollectorState {
next_dependency,
relative_compound_state: RelativeSelectorCompoundStateAttributes::new(),
},
),
scope_dependencies: &mut self.scope_dependencies,
alloc_error: &mut *self.alloc_error,
};
if !nested.visit_whole_selector_from(iter, index) {
return false;
}
self.next_selectors.pop();
}
true
}
fn visit_relative_selector_list(
&mut self,
list: &[selectors::parser::RelativeSelector<Self::Impl>],
) -> bool {
if self.relative_inner_collector.is_some() {
return true;
}
self.additional_relative_selector_invalidation_map.used = true;
for relative_selector in list {
self.next_selectors.push(NextDependencyEntry {
selector: self.selector.clone(),
offset: self.compound_state.offset,
cached_dependency: None,
});
let mut nested = RelativeSelectorDependencyCollector {
map: &mut *self.map,
relative_selector_invalidation_map: &mut *self.relative_selector_invalidation_map,
additional_relative_selector_invalidation_map: &mut *self
.additional_relative_selector_invalidation_map,
document_state: &mut *self.document_state,
selector: &relative_selector,
combinator_count: RelativeSelectorCombinatorCount::new(relative_selector),
next_selectors: &mut *self.next_selectors,
quirks_mode: self.quirks_mode,
compound_state: PerCompoundState::new(0),
compound_state_attributes: RelativeSelectorCompoundStateAttributes::new(),
scope_dependencies: &mut self.scope_dependencies,
alloc_error: &mut *self.alloc_error,
};
if !nested.visit_whole_selector() {
return false;
}
self.next_selectors.pop();
}
true
}
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
match on_simple_selector(s, self.quirks_mode, self) {
Ok(result) => {
if let ComponentVisitResult::Handled(state) = result {
if let Some(inner_collector_state) = self.relative_inner_collector.as_mut() {
inner_collector_state.relative_compound_state.added_entry = true;
inner_collector_state
.relative_compound_state
.ts_state
.insert(state);
}
}
true
},
Err(err) => {
*self.alloc_error = Some(err.into());
false
},
}
}
fn visit_attribute_selector(
&mut self,
_: &NamespaceConstraint<&Namespace>,
local_name: &LocalName,
local_name_lower: &LocalName,
) -> bool {
if let Some(state) = self.relative_inner_collector.as_mut() {
state.relative_compound_state.added_entry = true;
}
if let Err(err) = on_attribute(local_name, local_name_lower, self) {
*self.alloc_error = Some(err);
return false;
}
true
}
}
#[derive(Clone, Copy)]
struct RelativeSelectorCompoundStateAttributes {
ts_state: TSStateForInvalidation,
added_entry: bool,
}
impl RelativeSelectorCompoundStateAttributes {
fn new() -> Self {
Self {
ts_state: TSStateForInvalidation::empty(),
added_entry: false,
}
}
}
struct RelativeSelectorDependencyCollector<'a, 'b> {
map: &'a mut InvalidationMap,
relative_selector_invalidation_map: &'a mut InvalidationMap,
additional_relative_selector_invalidation_map:
&'a mut AdditionalRelativeSelectorInvalidationMap,
document_state: &'a mut DocumentState,
selector: &'a RelativeSelector<SelectorImpl>,
combinator_count: RelativeSelectorCombinatorCount,
next_selectors: &'a mut NextSelectors,
quirks_mode: QuirksMode,
compound_state: PerCompoundState,
compound_state_attributes: RelativeSelectorCompoundStateAttributes,
scope_dependencies: &'a mut ScopeSelectorCollectorState<'b>,
alloc_error: &'a mut Option<AllocErr>,
}
fn add_non_unique_info<C: Collector>(
selector: &Selector<SelectorImpl>,
offset: usize,
collector: &mut C,
) -> Result<(), AllocErr> {
for ss in selector.iter_from(offset) {
match ss {
Component::LocalName(ref name) => {
let dependency = collector.dependency();
add_local_name(name.name.clone(), dependency, &mut collector.type_map())?;
if name.name != name.lower_name {
let dependency = collector.dependency();
add_local_name(
name.lower_name.clone(),
dependency,
&mut collector.type_map(),
)?;
}
return Ok(());
},
_ => (),
};
}
collector.any_vec().try_reserve(1)?;
let dependency = collector.dependency();
collector.any_vec().push(dependency);
Ok(())
}
fn add_ts_pseudo_class_dependency<C: Collector>(
state: TSStateForInvalidation,
quirks_mode: QuirksMode,
collector: &mut C,
) -> Result<(), AllocErr> {
if state.is_empty() {
return Ok(());
}
let dependency = collector.dependency();
collector.ts_state_map().insert(
TSStateDependency {
dep: dependency,
state,
},
quirks_mode,
)
}
impl<'a, 'b> RelativeSelectorDependencyCollector<'a, 'b> {
fn visit_whole_selector(&mut self) -> bool {
let mut iter = self.selector.selector.iter_skip_relative_selector_anchor();
let mut index = 0;
self.additional_relative_selector_invalidation_map
.needs_ancestors_traversal |= match self.selector.match_hint {
RelativeSelectorMatchHint::InNextSiblingSubtree
| RelativeSelectorMatchHint::InSiblingSubtree
| RelativeSelectorMatchHint::InSubtree => true,
_ => false,
};
loop {
self.compound_state = PerCompoundState::new(index);
let (keep_traversing, index_offset) = visit_all_in_iter_compound(self, &mut iter);
if !keep_traversing {
return false;
}
index += index_offset;
if let Err(err) = add_pseudo_class_dependency(
self.compound_state.element_state,
self.quirks_mode,
self,
) {
*self.alloc_error = Some(err);
return false;
}
if let Err(err) = add_ts_pseudo_class_dependency(
self.compound_state_attributes.ts_state,
self.quirks_mode,
self,
) {
*self.alloc_error = Some(err);
return false;
}
if !self.compound_state_attributes.added_entry {
if let Err(err) =
add_non_unique_info(&self.selector.selector, self.compound_state.offset, self)
{
*self.alloc_error = Some(err);
return false;
}
}
let combinator = iter.next_sequence();
if let Some(c) = combinator {
match c {
Combinator::Child | Combinator::Descendant => {
self.combinator_count.child_or_descendants -= 1
},
Combinator::NextSibling | Combinator::LaterSibling => {
self.combinator_count.adjacent_or_next_siblings -= 1
},
Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => (),
}
} else {
return true;
}
index += 1; }
}
}
impl<'a, 'b> Collector for RelativeSelectorDependencyCollector<'a, 'b> {
fn dependency(&mut self) -> Dependency {
let scope_dependencies = self.inner_scope_dependencies();
let scope_kind = self.scope_dependencies.scope_kind;
let next = next_dependency(
self.next_selectors,
None,
scope_dependencies.as_ref(),
scope_kind,
);
debug_assert!(
next.as_ref().is_some_and(|d| !matches!(
d.slice()[0].kind,
DependencyInvalidationKind::Relative(_)
)),
"Duplicate relative dependency?"
);
debug_assert!(
next.as_ref().is_some_and(|d| !d.slice().is_empty()),
"Empty dependency?"
);
Dependency {
selector: self.selector.selector.clone(),
selector_offset: self.compound_state.offset,
kind: DependencyInvalidationKind::Relative(
match self.combinator_count.get_match_hint() {
RelativeSelectorMatchHint::InChild => {
RelativeDependencyInvalidationKind::Parent
},
RelativeSelectorMatchHint::InSubtree => {
RelativeDependencyInvalidationKind::Ancestors
},
RelativeSelectorMatchHint::InNextSibling => {
RelativeDependencyInvalidationKind::PrevSibling
},
RelativeSelectorMatchHint::InSibling => {
RelativeDependencyInvalidationKind::EarlierSibling
},
RelativeSelectorMatchHint::InNextSiblingSubtree => {
RelativeDependencyInvalidationKind::AncestorPrevSibling
},
RelativeSelectorMatchHint::InSiblingSubtree => {
RelativeDependencyInvalidationKind::AncestorEarlierSibling
},
},
),
next: next,
}
}
fn id_map(&mut self) -> &mut IdOrClassDependencyMap {
&mut self.relative_selector_invalidation_map.id_to_selector
}
fn class_map(&mut self) -> &mut IdOrClassDependencyMap {
&mut self.relative_selector_invalidation_map.class_to_selector
}
fn state_map(&mut self) -> &mut StateDependencyMap {
&mut self
.relative_selector_invalidation_map
.state_affecting_selectors
}
fn attribute_map(&mut self) -> &mut LocalNameDependencyMap {
&mut self
.relative_selector_invalidation_map
.other_attribute_affecting_selectors
}
fn custom_state_map(&mut self) -> &mut CustomStateDependencyMap {
&mut self
.relative_selector_invalidation_map
.custom_state_affecting_selectors
}
fn inner_scope_dependencies(&self) -> Option<ThinArc<(), Dependency>> {
self.scope_dependencies.inner_dependencies.clone()
}
fn this_scope_dependencies(&mut self) -> &mut Option<Vec<Dependency>> {
&mut self.scope_dependencies.this_dependencies
}
fn update_states(&mut self, element_state: ElementState, document_state: DocumentState) {
self.compound_state.element_state |= element_state;
*self.document_state |= document_state;
}
fn type_map(&mut self) -> &mut LocalNameDependencyMap {
&mut self
.additional_relative_selector_invalidation_map
.type_to_selector
}
fn ts_state_map(&mut self) -> &mut TSStateDependencyMap {
&mut self
.additional_relative_selector_invalidation_map
.ts_state_to_selector
}
fn any_vec(&mut self) -> &mut AnyDependencyMap {
&mut self
.additional_relative_selector_invalidation_map
.any_to_selector
}
}
enum ComponentVisitResult {
IsIrrelevant,
Handled(TSStateForInvalidation),
}
#[inline(always)]
fn on_simple_selector<C: Collector>(
s: &Component<SelectorImpl>,
quirks_mode: QuirksMode,
collector: &mut C,
) -> Result<ComponentVisitResult, AllocErr> {
match *s {
Component::ID(..) | Component::Class(..) => {
on_id_or_class(s, quirks_mode, collector)?;
Ok(ComponentVisitResult::Handled(
TSStateForInvalidation::empty(),
))
},
Component::ImplicitScope | Component::Scope => {
on_scope(collector)?;
Ok(ComponentVisitResult::Handled(
TSStateForInvalidation::empty(),
))
},
Component::NonTSPseudoClass(ref pc) => {
on_pseudo_class(pc, collector)?;
Ok(ComponentVisitResult::Handled(
TSStateForInvalidation::empty(),
))
},
Component::Empty => Ok(ComponentVisitResult::Handled(TSStateForInvalidation::EMPTY)),
Component::Nth(data) => {
let kind = if data.is_simple_edge() {
if data.ty.is_from_end() {
TSStateForInvalidation::NTH_EDGE_LAST
} else {
TSStateForInvalidation::NTH_EDGE_FIRST
}
} else {
TSStateForInvalidation::NTH
};
Ok(ComponentVisitResult::Handled(kind))
},
Component::RelativeSelectorAnchor => unreachable!("Should not visit this far"),
_ => Ok(ComponentVisitResult::IsIrrelevant),
}
}
impl<'a, 'b> SelectorVisitor for RelativeSelectorDependencyCollector<'a, 'b> {
type Impl = SelectorImpl;
fn visit_selector_list(
&mut self,
_list_kind: SelectorListKind,
list: &[Selector<SelectorImpl>],
) -> bool {
let mut next_stack = NextSelectors::new();
let next_dependency = ThinArc::from_header_and_iter((), [self.dependency()].into_iter());
for selector in list {
let mut iter = selector.iter();
let saved_added_entry = self.compound_state_attributes.added_entry;
let (keep_traversing, mut index) = visit_all_in_iter_compound(self, &mut iter);
if !keep_traversing {
return false;
}
let combinator = iter.next_sequence();
self.compound_state_attributes.added_entry = saved_added_entry;
if combinator.is_none() {
continue;
}
index += 1;
let mut nested = SelectorDependencyCollector {
map: &mut *self.map,
relative_selector_invalidation_map: &mut *self.relative_selector_invalidation_map,
additional_relative_selector_invalidation_map: self
.additional_relative_selector_invalidation_map,
document_state: &mut *self.document_state,
selector,
next_selectors: &mut next_stack,
quirks_mode: self.quirks_mode,
compound_state: PerCompoundState::new(index),
relative_inner_collector: Some(RelativeSelectorInnerCollectorState {
next_dependency: &next_dependency,
relative_compound_state: RelativeSelectorCompoundStateAttributes::new(),
}),
scope_dependencies: &mut self.scope_dependencies,
alloc_error: &mut *self.alloc_error,
};
if !nested.visit_whole_selector_from(iter, index) {
return false;
}
}
true
}
fn visit_relative_selector_list(
&mut self,
_list: &[selectors::parser::RelativeSelector<Self::Impl>],
) -> bool {
true
}
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
match on_simple_selector(s, self.quirks_mode, self) {
Ok(result) => {
if let ComponentVisitResult::Handled(state) = result {
self.compound_state_attributes.added_entry = true;
self.compound_state_attributes.ts_state.insert(state);
}
true
},
Err(err) => {
*self.alloc_error = Some(err.into());
false
},
}
}
fn visit_attribute_selector(
&mut self,
_: &NamespaceConstraint<&Namespace>,
local_name: &LocalName,
local_name_lower: &LocalName,
) -> bool {
self.compound_state_attributes.added_entry = true;
if let Err(err) = on_attribute(local_name, local_name_lower, self) {
*self.alloc_error = Some(err);
return false;
}
true
}
}