style: Track document state dependencies in the invalidation maps.

This commit is contained in:
Emilio Cobos Álvarez 2018-01-11 15:40:37 +01:00
parent 14661e470f
commit 2c1d72ad1a
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -6,7 +6,7 @@
use {Atom, LocalName, Namespace}; use {Atom, LocalName, Namespace};
use context::QuirksMode; use context::QuirksMode;
use element_state::ElementState; use element_state::{DocumentState, ElementState};
use fallible::FallibleVec; use fallible::FallibleVec;
use hashglobe::FailedAllocationError; use hashglobe::FailedAllocationError;
use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry}; use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry};
@ -133,6 +133,19 @@ impl SelectorMapEntry for StateDependency {
} }
} }
/// The same, but for document state selectors.
#[derive(Clone, Debug, MallocSizeOf)]
pub struct DocumentStateDependency {
/// The selector that is affected. We don't need to track an offset, since
/// when it changes it changes for the whole document anyway.
#[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 selector: Selector<SelectorImpl>,
/// The state this dependency is affected by.
pub state: DocumentState,
}
/// A map where we store invalidations. /// A map where we store invalidations.
/// ///
/// This is slightly different to a SelectorMap, in the sense of that the same /// This is slightly different to a SelectorMap, in the sense of that the same
@ -151,6 +164,8 @@ pub struct InvalidationMap {
pub id_to_selector: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[Dependency; 1]>>, pub id_to_selector: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[Dependency; 1]>>,
/// A map of all the state dependencies. /// A map of all the state dependencies.
pub state_affecting_selectors: SelectorMap<StateDependency>, pub state_affecting_selectors: SelectorMap<StateDependency>,
/// A list of document state dependencies in the rules we represent.
pub document_state_selectors: Vec<DocumentStateDependency>,
/// A map of other attribute affecting selectors. /// A map of other attribute affecting selectors.
pub other_attribute_affecting_selectors: SelectorMap<Dependency>, pub other_attribute_affecting_selectors: SelectorMap<Dependency>,
/// Whether there are attribute rules of the form `[class~="foo"]` that may /// Whether there are attribute rules of the form `[class~="foo"]` that may
@ -172,6 +187,7 @@ impl InvalidationMap {
class_to_selector: MaybeCaseInsensitiveHashMap::new(), class_to_selector: MaybeCaseInsensitiveHashMap::new(),
id_to_selector: MaybeCaseInsensitiveHashMap::new(), id_to_selector: MaybeCaseInsensitiveHashMap::new(),
state_affecting_selectors: SelectorMap::new(), state_affecting_selectors: SelectorMap::new(),
document_state_selectors: Vec::new(),
other_attribute_affecting_selectors: SelectorMap::new(), other_attribute_affecting_selectors: SelectorMap::new(),
has_class_attribute_selectors: false, has_class_attribute_selectors: false,
has_id_attribute_selectors: false, has_id_attribute_selectors: false,
@ -181,6 +197,7 @@ impl InvalidationMap {
/// Returns the number of dependencies stored in the invalidation map. /// Returns the number of dependencies stored in the invalidation map.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.state_affecting_selectors.len() + self.state_affecting_selectors.len() +
self.document_state_selectors.len() +
self.other_attribute_affecting_selectors.len() + self.other_attribute_affecting_selectors.len() +
self.id_to_selector.iter().fold(0, |accum, (_, ref v)| { self.id_to_selector.iter().fold(0, |accum, (_, ref v)| {
accum + v.len() accum + v.len()
@ -195,7 +212,7 @@ impl InvalidationMap {
pub fn note_selector( pub fn note_selector(
&mut self, &mut self,
selector: &Selector<SelectorImpl>, selector: &Selector<SelectorImpl>,
quirks_mode: QuirksMode quirks_mode: QuirksMode,
) -> Result<(), FailedAllocationError> { ) -> Result<(), FailedAllocationError> {
self.collect_invalidations_for(selector, quirks_mode) self.collect_invalidations_for(selector, quirks_mode)
} }
@ -205,6 +222,7 @@ impl InvalidationMap {
self.class_to_selector.clear(); self.class_to_selector.clear();
self.id_to_selector.clear(); self.id_to_selector.clear();
self.state_affecting_selectors.clear(); self.state_affecting_selectors.clear();
self.document_state_selectors.clear();
self.other_attribute_affecting_selectors.clear(); self.other_attribute_affecting_selectors.clear();
self.has_id_attribute_selectors = false; self.has_id_attribute_selectors = false;
self.has_class_attribute_selectors = false; self.has_class_attribute_selectors = false;
@ -222,6 +240,8 @@ impl InvalidationMap {
let mut combinator; let mut combinator;
let mut index = 0; let mut index = 0;
let mut document_state = DocumentState::empty();
loop { loop {
let sequence_start = index; let sequence_start = index;
@ -229,6 +249,7 @@ impl InvalidationMap {
classes: SmallVec::new(), classes: SmallVec::new(),
ids: SmallVec::new(), ids: SmallVec::new(),
state: ElementState::empty(), state: ElementState::empty(),
document_state: &mut document_state,
other_attributes: false, other_attributes: false,
has_id_attribute_selectors: false, has_id_attribute_selectors: false,
has_class_attribute_selectors: false, has_class_attribute_selectors: false,
@ -297,15 +318,28 @@ impl InvalidationMap {
index += 1; // Account for the combinator. index += 1; // Account for the combinator.
} }
if !document_state.is_empty() {
self.document_state_selectors.try_push(DocumentStateDependency {
state: document_state,
selector: selector.clone(),
})?;
}
Ok(()) Ok(())
} }
} }
/// A struct that collects invalidations for a given compound selector. /// A struct that collects invalidations for a given compound selector.
struct CompoundSelectorDependencyCollector { struct CompoundSelectorDependencyCollector<'a> {
/// The state this compound selector is affected by. /// The state this compound selector is affected by.
state: ElementState, state: ElementState,
/// The document this _complex_ selector is affected by.
///
/// We don't need to track state per compound selector, since it's global
/// state and it changes for everything.
document_state: &'a mut DocumentState,
/// The classes this compound selector is affected by. /// The classes this compound selector is affected by.
/// ///
/// NB: This will be often a single class, but could be multiple in /// NB: This will be often a single class, but could be multiple in
@ -330,7 +364,7 @@ struct CompoundSelectorDependencyCollector {
has_class_attribute_selectors: bool, has_class_attribute_selectors: bool,
} }
impl SelectorVisitor for CompoundSelectorDependencyCollector { impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
type Impl = SelectorImpl; type Impl = SelectorImpl;
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool { fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
@ -353,6 +387,7 @@ impl SelectorVisitor for CompoundSelectorDependencyCollector {
} }
_ => pc.state_flag(), _ => pc.state_flag(),
}; };
*self.document_state |= pc.document_state_flag();
} }
_ => {} _ => {}
} }