style: Make invalidation state also be with the ::slotted rules.

MozReview-Commit-ID: GYmsXYvL9vj
This commit is contained in:
Emilio Cobos Álvarez 2017-12-18 11:58:59 +01:00
parent 5115cbd1c0
commit ce1d8cd232
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
6 changed files with 310 additions and 187 deletions

View file

@ -263,7 +263,9 @@ impl ElementData {
let mut xbl_stylists = SmallVec::<[_; 3]>::new(); let mut xbl_stylists = SmallVec::<[_; 3]>::new();
let cut_off_inheritance = let cut_off_inheritance =
element.each_xbl_stylist(|s| xbl_stylists.push(s)); element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
xbl_stylists.push((data, quirks_mode))
});
let mut processor = StateAndAttrInvalidationProcessor::new( let mut processor = StateAndAttrInvalidationProcessor::new(
shared_context, shared_context,

View file

@ -31,7 +31,7 @@ use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::ops::Deref; use std::ops::Deref;
use stylist::Stylist; use stylist::{StyleRuleCascadeData, Stylist};
use traversal_flags::TraversalFlags; use traversal_flags::TraversalFlags;
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed /// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
@ -774,6 +774,41 @@ pub trait TElement
false false
} }
/// Executes the callback for each applicable style rule data which isn't
/// the main document's data (which stores UA / author rules).
///
/// Returns whether normal document author rules should apply.
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
where
Self: 'a,
F: FnMut(AtomicRef<'a, StyleRuleCascadeData>, QuirksMode),
{
let cut_off_inheritance = self.each_xbl_stylist(|stylist| {
let quirks_mode = stylist.quirks_mode();
f(
AtomicRef::map(stylist, |stylist| stylist.normal_author_cascade_data()),
quirks_mode,
)
});
let mut current = self.assigned_slot();
while let Some(slot) = current {
slot.each_xbl_stylist(|stylist| {
let quirks_mode = stylist.quirks_mode();
if stylist.slotted_author_cascade_data().is_some() {
f(
AtomicRef::map(stylist, |stylist| stylist.slotted_author_cascade_data().unwrap()),
quirks_mode,
)
}
});
current = slot.assigned_slot();
}
cut_off_inheritance
}
/// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap. /// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn get_css_transitions_info(&self) fn get_css_transitions_info(&self)

View file

@ -24,7 +24,7 @@ use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::matching::matches_selector; use selectors::matching::matches_selector;
use smallvec::SmallVec; use smallvec::SmallVec;
use stylesheets::origin::{Origin, OriginSet}; use stylesheets::origin::{Origin, OriginSet};
use stylist::Stylist; use stylist::StyleRuleCascadeData;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum VisitedDependent { enum VisitedDependent {
@ -57,7 +57,7 @@ where
/// changes. /// changes.
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> { pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
shared_context: &'a SharedStyleContext<'b>, shared_context: &'a SharedStyleContext<'b>,
xbl_stylists: &'a [AtomicRef<'b, Stylist>], shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
cut_off_inheritance: bool, cut_off_inheritance: bool,
element: E, element: E,
data: &'a mut ElementData, data: &'a mut ElementData,
@ -68,7 +68,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
/// Creates a new StateAndAttrInvalidationProcessor. /// Creates a new StateAndAttrInvalidationProcessor.
pub fn new( pub fn new(
shared_context: &'a SharedStyleContext<'b>, shared_context: &'a SharedStyleContext<'b>,
xbl_stylists: &'a [AtomicRef<'b, Stylist>], shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
cut_off_inheritance: bool, cut_off_inheritance: bool,
element: E, element: E,
data: &'a mut ElementData, data: &'a mut ElementData,
@ -84,7 +84,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
Self { Self {
shared_context, shared_context,
xbl_stylists, shadow_rule_datas,
cut_off_inheritance, cut_off_inheritance,
element, element,
data, data,
@ -211,20 +211,18 @@ where
OriginSet::all() OriginSet::all()
}; };
self.shared_context.stylist.each_invalidation_map(|invalidation_map, origin| { self.shared_context.stylist.each_normal_rule_cascade_data(|cascade_data, origin| {
if document_origins.contains(origin.into()) { if document_origins.contains(origin.into()) {
collector.collect_dependencies_in_invalidation_map(invalidation_map); collector.collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
} }
}); });
for stylist in self.xbl_stylists { for &(ref data, quirks_mode) in self.shadow_rule_datas {
// FIXME(emilio): Replace with assert / remove when we // FIXME(emilio): Replace with assert / remove when we figure
// figure out what to do with the quirks mode mismatches // out what to do with the quirks mode mismatches
// (that is, when bug 1406875 is properly fixed). // (that is, when bug 1406875 is properly fixed).
collector.quirks_mode = stylist.quirks_mode(); collector.quirks_mode = quirks_mode;
stylist.each_invalidation_map(|invalidation_map, _| { collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
collector.collect_dependencies_in_invalidation_map(invalidation_map);
})
} }
collector.invalidates_self collector.invalidates_self

View file

@ -133,6 +133,7 @@ where
} }
/// The type of rebuild that we need to do for a given stylesheet. /// The type of rebuild that we need to do for a given stylesheet.
#[derive(Clone, Copy, Debug)]
pub enum SheetRebuildKind { pub enum SheetRebuildKind {
/// A full rebuild, of both cascade data and invalidation data. /// A full rebuild, of both cascade data and invalidation data.
Full, Full,

View file

@ -132,7 +132,7 @@ impl UserAgentCascadeDataCache {
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
sizes.mOther += self.entries.shallow_size_of(ops); sizes.mOther += self.entries.shallow_size_of(ops);
for arc in self.entries.iter() { for arc in self.entries.iter() {
// These are primary Arc references that can be measured // These are primary Arc references that can be measured
@ -465,27 +465,30 @@ impl Stylist {
/// Returns the number of revalidation_selectors. /// Returns the number of revalidation_selectors.
pub fn num_revalidation_selectors(&self) -> usize { pub fn num_revalidation_selectors(&self) -> usize {
self.cascade_data.iter_origins() self.cascade_data.iter_origins()
.map(|(d, _)| d.selectors_for_cache_revalidation.len()).sum() .map(|(data, _)| {
data.normal_style_rule_data.selectors_for_cache_revalidation.len() +
data.slotted_rule_data.as_ref().map_or(0, |d| {
d.selectors_for_cache_revalidation.len()
})
}).sum()
} }
/// Returns the number of entries in invalidation maps. /// Returns the number of entries in invalidation maps.
pub fn num_invalidations(&self) -> usize { pub fn num_invalidations(&self) -> usize {
self.cascade_data.iter_origins() self.cascade_data.iter_origins()
.map(|(d, _)| d.invalidation_map.len()).sum() .map(|(data, _)| {
data.normal_style_rule_data.invalidation_map.len() +
data.slotted_rule_data.as_ref().map_or(0, |d| d.invalidation_map.len())
}).sum()
} }
/// Invokes `f` with the `InvalidationMap` for each origin. /// Returns whether the given DocumentState bit is relied upon by a selector
/// /// of some rule.
/// NOTE(heycam) This might be better as an `iter_invalidation_maps`, once pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
/// we have `impl trait` and can return that easily without bothering to self.cascade_data.iter_origins()
/// create a whole new iterator type. .any(|(d, _)| {
pub fn each_invalidation_map<'a, F>(&'a self, mut f: F) d.normal_style_rule_data.has_document_state_dependency(state)
where })
F: FnMut(&'a InvalidationMap, Origin)
{
for (data, origin) in self.cascade_data.iter_origins() {
f(&data.invalidation_map, origin)
}
} }
/// Flush the list of stylesheets if they changed, ensuring the stylist is /// Flush the list of stylesheets if they changed, ensuring the stylist is
@ -601,40 +604,39 @@ impl Stylist {
self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard) self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard)
} }
/// Returns whether the given attribute might appear in an attribute /// Executes `f` on each of the normal rule cascade datas in this styleset.
/// selector of some rule in the stylist. pub fn each_normal_rule_cascade_data<'a, F>(&'a self, mut f: F)
pub fn might_have_attribute_dependency( where
&self, F: FnMut(&'a StyleRuleCascadeData, Origin),
local_name: &LocalName, {
) -> bool { for (data, origin) in self.cascade_data.iter_origins() {
if *local_name == local_name!("style") { f(&data.normal_style_rule_data, origin);
self.cascade_data
.iter_origins()
.any(|(d, _)| d.style_attribute_dependency)
} else {
self.cascade_data
.iter_origins()
.any(|(d, _)| {
d.attribute_dependencies
.might_contain_hash(local_name.get_hash())
})
} }
} }
/// Returns whether the given ElementState bit is relied upon by a selector /// Returns whether for any of the applicable style rule data a given
/// of some rule in the stylist. /// condition is true.
pub fn has_state_dependency(&self, state: ElementState) -> bool { pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
self.cascade_data where
.iter_origins() E: TElement,
.any(|(d, _)| d.state_dependencies.intersects(state)) F: FnMut(&StyleRuleCascadeData, QuirksMode) -> bool,
} {
if f(&self.cascade_data.user_agent.cascade_data.normal_style_rule_data, self.quirks_mode()) {
return true;
}
/// Returns whether the given DocumentState bit is relied upon by a selector let mut maybe = false;
/// of some rule in the stylist.
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool { let cut_off = element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
self.cascade_data maybe = maybe || f(&*data, quirks_mode);
.iter_origins() });
.any(|(d, _)| d.document_state_dependencies.intersects(state))
if maybe || cut_off {
return maybe;
}
f(&self.cascade_data.author.normal_style_rule_data, self.quirks_mode()) ||
f(&self.cascade_data.user.normal_style_rule_data, self.quirks_mode())
} }
/// Computes the style for a given "precomputed" pseudo-element, taking the /// Computes the style for a given "precomputed" pseudo-element, taking the
@ -1232,7 +1234,7 @@ impl Stylist {
rule_hash_target.matches_user_and_author_rules(); rule_hash_target.matches_user_and_author_rules();
// Step 1: Normal user-agent rules. // Step 1: Normal user-agent rules.
if let Some(map) = self.cascade_data.user_agent.cascade_data.rules.borrow_for_pseudo(pseudo_element) { if let Some(map) = self.cascade_data.user_agent.cascade_data.normal_rules(pseudo_element) {
map.get_all_matching_rules( map.get_all_matching_rules(
element, element,
&rule_hash_target, &rule_hash_target,
@ -1270,7 +1272,7 @@ impl Stylist {
// Which may be more what you would probably expect. // Which may be more what you would probably expect.
if matches_user_and_author_rules { if matches_user_and_author_rules {
// Step 3a: User normal rules. // Step 3a: User normal rules.
if let Some(map) = self.cascade_data.user.rules.borrow_for_pseudo(pseudo_element) { if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
map.get_all_matching_rules( map.get_all_matching_rules(
element, element,
&rule_hash_target, &rule_hash_target,
@ -1289,7 +1291,7 @@ impl Stylist {
let cut_off_inheritance = element.each_xbl_stylist(|stylist| { let cut_off_inheritance = element.each_xbl_stylist(|stylist| {
// ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets // ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets
// under eAuthorSheetFeatures level. // under eAuthorSheetFeatures level.
if let Some(map) = stylist.cascade_data.author.rules.borrow_for_pseudo(pseudo_element) { if let Some(map) = stylist.cascade_data.author.normal_rules(pseudo_element) {
// NOTE(emilio): This is needed because the XBL stylist may // NOTE(emilio): This is needed because the XBL stylist may
// think it has a different quirks mode than the document. // think it has a different quirks mode than the document.
// //
@ -1320,7 +1322,7 @@ impl Stylist {
!cut_off_inheritance !cut_off_inheritance
{ {
// Step 3c: Author normal rules. // Step 3c: Author normal rules.
if let Some(map) = self.cascade_data.author.rules.borrow_for_pseudo(pseudo_element) { if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
map.get_all_matching_rules( map.get_all_matching_rules(
element, element,
&rule_hash_target, &rule_hash_target,
@ -1338,9 +1340,7 @@ impl Stylist {
// maybe we need to merge the sorting with the above // maybe we need to merge the sorting with the above
// get_all_matching_rules. // get_all_matching_rules.
slot.each_xbl_stylist(|stylist| { slot.each_xbl_stylist(|stylist| {
let slotted_rules = if let Some(map) = stylist.cascade_data.author.slotted_rules(pseudo_element) {
stylist.cascade_data.author.slotted_rules.as_ref();
if let Some(map) = slotted_rules.and_then(|r| r.borrow_for_pseudo(pseudo_element)) {
map.get_all_matching_rules( map.get_all_matching_rules(
element, element,
&rule_hash_target, &rule_hash_target,
@ -1431,23 +1431,26 @@ impl Stylist {
} }
let hash = id.get_hash(); let hash = id.get_hash();
for (data, _) in self.cascade_data.iter_origins() { self.any_applicable_rule_data(element, |data, _| {
if data.mapped_ids.might_contain_hash(hash) { data.mapped_ids.might_contain_hash(hash)
return true; })
} }
}
let mut xbl_rules_may_contain = false; /// Returns the cascade data for the normal rules.
#[inline]
pub fn normal_author_cascade_data(&self) -> &StyleRuleCascadeData {
&self.cascade_data.author.normal_style_rule_data
}
element.each_xbl_stylist(|stylist| { /// Returns the cascade data for the slotted rules in this scope, if any.
xbl_rules_may_contain = xbl_rules_may_contain || #[inline]
stylist.cascade_data.author.mapped_ids.might_contain_hash(hash) pub fn slotted_author_cascade_data(&self) -> Option<&StyleRuleCascadeData> {
}); self.cascade_data.author.slotted_rule_data.as_ref().map(|d| &**d)
xbl_rules_may_contain
} }
/// Returns the registered `@keyframes` animation for the specified name. /// Returns the registered `@keyframes` animation for the specified name.
///
/// FIXME(emilio): This needs to account for the element rules.
#[inline] #[inline]
pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> { pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> {
self.cascade_data self.cascade_data
@ -1485,7 +1488,7 @@ impl Stylist {
// this in the caller by asserting that the bitvecs are same-length. // this in the caller by asserting that the bitvecs are same-length.
let mut results = SmallBitVec::new(); let mut results = SmallBitVec::new();
for (data, _) in self.cascade_data.iter_origins() { for (data, _) in self.cascade_data.iter_origins() {
data.selectors_for_cache_revalidation.lookup( data.normal_style_rule_data.selectors_for_cache_revalidation.lookup(
element, element,
self.quirks_mode, self.quirks_mode,
|selector_and_hashes| { |selector_and_hashes| {
@ -1502,10 +1505,10 @@ impl Stylist {
); );
} }
element.each_xbl_stylist(|stylist| { element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
stylist.cascade_data.author.selectors_for_cache_revalidation.lookup( data.selectors_for_cache_revalidation.lookup(
element, element,
stylist.quirks_mode, quirks_mode,
|selector_and_hashes| { |selector_and_hashes| {
results.push(matches_selector( results.push(matches_selector(
&selector_and_hashes.selector, &selector_and_hashes.selector,
@ -1862,6 +1865,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
/// A set of rules for element and pseudo-elements. /// A set of rules for element and pseudo-elements.
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
struct ElementAndPseudoRules { struct ElementAndPseudoRules {
/// Rules from stylesheets at this `CascadeData`'s origin. /// Rules from stylesheets at this `CascadeData`'s origin.
element_map: SelectorMap<Rule>, element_map: SelectorMap<Rule>,
@ -1924,31 +1928,14 @@ impl ElementAndPseudoRules {
} }
} }
/// Data resulting from performing the CSS cascade that is specific to a given /// Cascade data generated from style rules.
/// origin.
///
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Debug)] #[derive(Debug)]
struct CascadeData { #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
/// The rules at this cascade level. pub struct StyleRuleCascadeData {
/// The actual style rules.
rules: ElementAndPseudoRules, rules: ElementAndPseudoRules,
/// ::slotted() pseudo-element rules. /// The invalidation map for these rules.
///
/// We need to store them separately because an element needs to match scoped
/// pseudo-element rules in different style scopes.
///
/// In particular, you need to go through all the style data in all the
/// containing style scopes starting from the closest assigned slot.
slotted_rules: Option<Box<ElementAndPseudoRules>>,
/// A map with all the animations at this `CascadeData`'s origin, indexed
/// by name.
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
/// The invalidation map for the rules at this origin.
invalidation_map: InvalidationMap, invalidation_map: InvalidationMap,
/// The attribute local names that appear in attribute selectors. Used /// The attribute local names that appear in attribute selectors. Used
@ -1988,6 +1975,146 @@ struct CascadeData {
/// tree-structural state like child index and pseudos). /// tree-structural state like child index and pseudos).
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>, selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
}
impl StyleRuleCascadeData {
#[inline(always)]
fn insert(
&mut self,
rule: Rule,
pseudo_element: Option<&PseudoElement>,
quirks_mode: QuirksMode,
rebuild_kind: SheetRebuildKind,
) -> Result<(), FailedAllocationError> {
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map.note_selector(&rule.selector, quirks_mode)?;
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
};
rule.selector.visit(&mut visitor);
if visitor.needs_revalidation {
self.selectors_for_cache_revalidation.insert(
RevalidationSelectorAndHashes::new(
rule.selector.clone(),
rule.hashes.clone(),
),
quirks_mode
)?;
}
}
self.rules.insert(rule, pseudo_element, quirks_mode)
}
/// Returns the invalidation map.
#[inline]
pub fn invalidation_map(&self) -> &InvalidationMap {
&self.invalidation_map
}
#[cfg(feature = "gecko")]
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.rules.add_size_of(ops, sizes);
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
}
fn clear_cascade_data(&mut self) {
self.rules.clear();
}
fn clear(&mut self) {
self.clear_cascade_data();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
self.selectors_for_cache_revalidation.clear();
}
/// Returns whether the given attribute might appear in an attribute
/// selector of some rule.
#[inline]
pub fn might_have_attribute_dependency(
&self,
local_name: &LocalName,
) -> bool {
if *local_name == local_name!("style") {
return self.style_attribute_dependency
}
self.attribute_dependencies.might_contain_hash(local_name.get_hash())
}
/// Returns whether the given ElementState bit is relied upon by a selector
/// of some rule.
#[inline]
pub fn has_state_dependency(&self, state: ElementState) -> bool {
self.state_dependencies.intersects(state)
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule in the stylist.
#[inline]
fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.document_state_dependencies.intersects(state)
}
}
impl StyleRuleCascadeData {
fn new() -> Self {
Self {
rules: ElementAndPseudoRules::default(),
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
selectors_for_cache_revalidation: SelectorMap::new(),
}
}
#[inline]
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.rules.borrow_for_pseudo(pseudo)
}
}
/// Data resulting from performing the CSS cascade that is specific to a given
/// origin.
///
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Debug)]
struct CascadeData {
/// The data coming from normal style rules that apply to elements at this
/// cascade level.
normal_style_rule_data: StyleRuleCascadeData,
/// The data coming from ::slotted() pseudo-element rules.
///
/// We need to store them separately because an element needs to match
/// ::slotted() pseudo-element rules in different shadow roots.
///
/// In particular, we need to go through all the style data in all the
/// containing style scopes starting from the closest assigned slot.
slotted_rule_data: Option<Box<StyleRuleCascadeData>>,
/// A map with all the animations at this `CascadeData`'s origin, indexed
/// by name.
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
/// Effective media query results cached from the last rebuild. /// Effective media query results cached from the last rebuild.
effective_media_query_results: EffectiveMediaQueryResults, effective_media_query_results: EffectiveMediaQueryResults,
@ -2009,17 +2136,10 @@ struct CascadeData {
impl CascadeData { impl CascadeData {
fn new() -> Self { fn new() -> Self {
Self { Self {
rules: ElementAndPseudoRules::default(), normal_style_rule_data: StyleRuleCascadeData::new(),
slotted_rules: None, slotted_rule_data: None,
animations: Default::default(), animations: Default::default(),
extra_data: ExtraStyleData::default(), extra_data: ExtraStyleData::default(),
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
selectors_for_cache_revalidation: SelectorMap::new(),
effective_media_query_results: EffectiveMediaQueryResults::new(), effective_media_query_results: EffectiveMediaQueryResults::new(),
rules_source_order: 0, rules_source_order: 0,
num_selectors: 0, num_selectors: 0,
@ -2027,6 +2147,16 @@ impl CascadeData {
} }
} }
#[inline]
fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.normal_style_rule_data.rules(pseudo)
}
#[inline]
fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.slotted_rule_data.as_ref().and_then(|d| d.rules(pseudo))
}
/// Collects all the applicable media query results into `results`. /// Collects all the applicable media query results into `results`.
/// ///
/// This duplicates part of the logic in `add_stylesheet`, which is /// This duplicates part of the logic in `add_stylesheet`, which is
@ -2125,43 +2255,26 @@ impl CascadeData {
let rule = Rule::new( let rule = Rule::new(
selector.clone(), selector.clone(),
hashes.clone(), hashes,
locked.clone(), locked.clone(),
self.rules_source_order self.rules_source_order
); );
if selector.is_slotted() { let style_rule_cascade_data = if selector.is_slotted() {
if self.slotted_rules.is_none() { if self.slotted_rule_data.is_none() {
self.slotted_rules = Some(Default::default()); self.slotted_rule_data = Some(Box::new(StyleRuleCascadeData::new()));
} }
let slotted_rules = self.slotted_rules.as_mut().unwrap(); self.slotted_rule_data.as_mut().unwrap()
slotted_rules.insert(rule, pseudo_element, quirks_mode)?;
} else { } else {
self.rules.insert(rule, pseudo_element, quirks_mode)?; &mut self.normal_style_rule_data
} };
if rebuild_kind.should_rebuild_invalidation() { style_rule_cascade_data.insert(
self.invalidation_map rule,
.note_selector(selector, quirks_mode)?; pseudo_element,
let mut visitor = StylistSelectorVisitor { quirks_mode,
needs_revalidation: false, rebuild_kind,
passed_rightmost_selector: false, )?;
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
};
selector.visit(&mut visitor);
if visitor.needs_revalidation {
self.selectors_for_cache_revalidation.insert(
RevalidationSelectorAndHashes::new(selector.clone(), hashes),
quirks_mode
)?;
}
}
} }
self.rules_source_order += 1; self.rules_source_order += 1;
} }
@ -2313,8 +2426,10 @@ impl CascadeData {
/// Clears the cascade data, but not the invalidation data. /// Clears the cascade data, but not the invalidation data.
fn clear_cascade_data(&mut self) { fn clear_cascade_data(&mut self) {
self.rules.clear(); self.normal_style_rule_data.clear_cascade_data();
self.slotted_rules = None; if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear_cascade_data();
}
self.animations.clear(); self.animations.clear();
self.extra_data.clear(); self.extra_data.clear();
self.rules_source_order = 0; self.rules_source_order = 0;
@ -2324,30 +2439,21 @@ impl CascadeData {
fn clear(&mut self) { fn clear(&mut self) {
self.clear_cascade_data(); self.clear_cascade_data();
self.normal_style_rule_data.clear();
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear();
}
self.effective_media_query_results.clear(); self.effective_media_query_results.clear();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
self.selectors_for_cache_revalidation.clear();
} }
/// Measures heap usage. /// Measures heap usage.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.rules.add_size_of(ops, sizes); self.normal_style_rule_data.add_size_of(ops, sizes);
if let Some(ref slotted_rules) = self.slotted_rules { if let Some(ref slotted_rules) = self.slotted_rule_data {
slotted_rules.add_size_of(ops, sizes); slotted_rules.add_size_of(ops, sizes);
} }
sizes.mOther += self.animations.size_of(ops); sizes.mOther += self.animations.size_of(ops);
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
sizes.mOther += self.effective_media_query_results.size_of(ops); sizes.mOther += self.effective_media_query_results.size_of(ops);
sizes.mOther += self.extra_data.size_of(ops); sizes.mOther += self.extra_data.size_of(ops);
} }

View file

@ -4326,25 +4326,14 @@ pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
) -> bool { ) -> bool {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let element = GeckoElement(element); let element = GeckoElement(element);
let mut has_dep = false;
unsafe { unsafe {
Atom::with(local_name, |atom| { Atom::with(local_name, |atom| {
has_dep = data.stylist.might_have_attribute_dependency(atom); data.stylist.any_applicable_rule_data(element, |data, _| {
data.might_have_attribute_dependency(atom)
if !has_dep { })
// TODO(emilio): Consider optimizing this storing attribute
// dependencies from UA sheets separately, so we could optimize
// the above lookup if cut_off_inheritance is true.
element.each_xbl_stylist(|stylist| {
has_dep =
has_dep || stylist.might_have_attribute_dependency(atom);
});
}
}) })
} }
has_dep
} }
#[no_mangle] #[no_mangle]
@ -4358,17 +4347,9 @@ pub extern "C" fn Servo_StyleSet_HasStateDependency(
let state = ElementState::from_bits_truncate(state); let state = ElementState::from_bits_truncate(state);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let mut has_dep = data.stylist.has_state_dependency(state); data.stylist.any_applicable_rule_data(element, |data, _| {
if !has_dep { data.has_state_dependency(state)
// TODO(emilio): Consider optimizing this storing attribute })
// dependencies from UA sheets separately, so we could optimize
// the above lookup if cut_off_inheritance is true.
element.each_xbl_stylist(|stylist| {
has_dep = has_dep || stylist.has_state_dependency(state);
});
}
has_dep
} }
#[no_mangle] #[no_mangle]