mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
style: Record names that appear in attribute selectors.
This commit is contained in:
parent
48fdda3f07
commit
5cf915118e
2 changed files with 74 additions and 1 deletions
|
@ -27,7 +27,7 @@ use selectors::Element;
|
||||||
use selectors::bloom::BloomFilter;
|
use selectors::bloom::BloomFilter;
|
||||||
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
||||||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
|
||||||
use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorIter};
|
use selectors::parser::{AttrSelector, Combinator, Component, Selector, SelectorInner, SelectorIter};
|
||||||
use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
|
use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
|
@ -118,6 +118,23 @@ pub struct Stylist {
|
||||||
/// Selector dependencies used to compute restyle hints.
|
/// Selector dependencies used to compute restyle hints.
|
||||||
dependencies: DependencySet,
|
dependencies: DependencySet,
|
||||||
|
|
||||||
|
/// The attribute local names that appear in attribute selectors. Used
|
||||||
|
/// to avoid taking element snapshots when an irrelevant attribute changes.
|
||||||
|
/// (We don't bother storing the namespace, since namespaced attributes
|
||||||
|
/// are rare.)
|
||||||
|
///
|
||||||
|
/// FIXME(heycam): This doesn't really need to be a counting Bloom filter.
|
||||||
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "just an array")]
|
||||||
|
attribute_dependencies: BloomFilter,
|
||||||
|
|
||||||
|
/// Whether `"style"` appears in an attribute selector. This is not common,
|
||||||
|
/// and by tracking this explicitly, we can avoid taking an element snapshot
|
||||||
|
/// in the common case of style=""` changing due to modifying
|
||||||
|
/// `element.style`. (We could track this in `attribute_dependencies`, like
|
||||||
|
/// all other attributes, but we should probably not risk incorrectly
|
||||||
|
/// returning `true` for `"style"` just due to a hash collision.)
|
||||||
|
style_attribute_dependency: bool,
|
||||||
|
|
||||||
/// Selectors that require explicit cache revalidation (i.e. which depend
|
/// Selectors that require explicit cache revalidation (i.e. which depend
|
||||||
/// on state that is not otherwise visible to the cache, like attributes or
|
/// on state that is not otherwise visible to the cache, like attributes or
|
||||||
/// tree-structural state like child index and pseudos).
|
/// tree-structural state like child index and pseudos).
|
||||||
|
@ -184,6 +201,8 @@ impl Stylist {
|
||||||
rules_source_order: 0,
|
rules_source_order: 0,
|
||||||
rule_tree: RuleTree::new(),
|
rule_tree: RuleTree::new(),
|
||||||
dependencies: DependencySet::new(),
|
dependencies: DependencySet::new(),
|
||||||
|
attribute_dependencies: BloomFilter::new(),
|
||||||
|
style_attribute_dependency: false,
|
||||||
selectors_for_cache_revalidation: SelectorMap::new(),
|
selectors_for_cache_revalidation: SelectorMap::new(),
|
||||||
num_selectors: 0,
|
num_selectors: 0,
|
||||||
num_declarations: 0,
|
num_declarations: 0,
|
||||||
|
@ -254,6 +273,8 @@ impl Stylist {
|
||||||
self.rules_source_order = 0;
|
self.rules_source_order = 0;
|
||||||
// We want to keep rule_tree around across stylist rebuilds.
|
// We want to keep rule_tree around across stylist rebuilds.
|
||||||
self.dependencies.clear();
|
self.dependencies.clear();
|
||||||
|
self.attribute_dependencies.clear();
|
||||||
|
self.style_attribute_dependency = false;
|
||||||
self.selectors_for_cache_revalidation = SelectorMap::new();
|
self.selectors_for_cache_revalidation = SelectorMap::new();
|
||||||
self.num_selectors = 0;
|
self.num_selectors = 0;
|
||||||
self.num_declarations = 0;
|
self.num_declarations = 0;
|
||||||
|
@ -375,6 +396,7 @@ impl Stylist {
|
||||||
self.add_rule_to_map(selector, locked, stylesheet);
|
self.add_rule_to_map(selector, locked, stylesheet);
|
||||||
self.dependencies.note_selector(selector);
|
self.dependencies.note_selector(selector);
|
||||||
self.note_for_revalidation(selector);
|
self.note_for_revalidation(selector);
|
||||||
|
self.note_attribute_dependencies(selector);
|
||||||
}
|
}
|
||||||
self.rules_source_order += 1;
|
self.rules_source_order += 1;
|
||||||
}
|
}
|
||||||
|
@ -434,6 +456,28 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given attribute might appear in an attribute
|
||||||
|
/// selector of some rule in the stylist.
|
||||||
|
pub fn might_have_attribute_dependency(&self,
|
||||||
|
local_name: &<SelectorImpl as ::selectors::SelectorImpl>::LocalName)
|
||||||
|
-> bool {
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
let style_lower_name = local_name!("style");
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
let style_lower_name = atom!("style");
|
||||||
|
|
||||||
|
if *local_name == style_lower_name {
|
||||||
|
self.style_attribute_dependency
|
||||||
|
} else {
|
||||||
|
self.attribute_dependencies.might_contain(local_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn note_attribute_dependencies(&mut self, selector: &Selector<SelectorImpl>) {
|
||||||
|
selector.visit(&mut AttributeDependencyVisitor(self));
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
||||||
/// universal rules and applying them.
|
/// universal rules and applying them.
|
||||||
///
|
///
|
||||||
|
@ -962,6 +1006,28 @@ impl Drop for Stylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Visitor to collect names that appear in attribute selectors.
|
||||||
|
struct AttributeDependencyVisitor<'a>(&'a mut Stylist);
|
||||||
|
|
||||||
|
impl<'a> SelectorVisitor for AttributeDependencyVisitor<'a> {
|
||||||
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
fn visit_attribute_selector(&mut self, selector: &AttrSelector<Self::Impl>) -> bool {
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
let style_lower_name = local_name!("style");
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
let style_lower_name = atom!("style");
|
||||||
|
|
||||||
|
if selector.lower_name == style_lower_name {
|
||||||
|
self.0.style_attribute_dependency = true;
|
||||||
|
} else {
|
||||||
|
self.0.attribute_dependencies.insert(&selector.name);
|
||||||
|
self.0.attribute_dependencies.insert(&selector.lower_name);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Visitor determine whether a selector requires cache revalidation.
|
/// Visitor determine whether a selector requires cache revalidation.
|
||||||
///
|
///
|
||||||
/// Note that we just check simple selectors and eagerly return when the first
|
/// Note that we just check simple selectors and eagerly return when the first
|
||||||
|
|
|
@ -2331,3 +2331,10 @@ pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(raw_data: RawServoStyleS
|
||||||
parent_style,
|
parent_style,
|
||||||
declarations.clone()).into_strong()
|
declarations.clone()).into_strong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(raw_data: RawServoStyleSetBorrowed,
|
||||||
|
local_name: *mut nsIAtom) -> bool {
|
||||||
|
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
||||||
|
unsafe { Atom::with(local_name, &mut |atom| data.stylist.might_have_attribute_dependency(atom)) }
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue