diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2015-12-17 16:21:29 -0800 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2015-12-29 12:07:07 -0800 |
commit | a05d7f1dfd8500d299007af99861cc86fada9386 (patch) | |
tree | ea956e5046b37168344bdff3ffc4274007d54ab6 /components/layout/css/matching.rs | |
parent | 47059d2d26f14f71e5b7212fa8bc01608eca11b5 (diff) | |
download | servo-a05d7f1dfd8500d299007af99861cc86fada9386.tar.gz servo-a05d7f1dfd8500d299007af99861cc86fada9386.zip |
Hoist style-related context bits into style/.
We do a few things-here:
* Hoist non-layout-dependent fields in SharedLayoutData and LocalLayoutData into style/.
* Hoist parts of css/matching.rs into style/.
* Hoist parts of layout/animation.rs into style/animation.rs.
* Remove the duplicated-but-slightly-different definition of OpaqueNode.
Diffstat (limited to 'components/layout/css/matching.rs')
-rw-r--r-- | components/layout/css/matching.rs | 351 |
1 files changed, 12 insertions, 339 deletions
diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index a9c07848309..e83899e2893 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -13,347 +13,19 @@ use incremental::{self, RestyleDamage}; use msg::ParseErrorReporter; use script::layout_interface::Animation; use selectors::bloom::BloomFilter; -use selectors::matching::{CommonStyleAffectingAttributeMode, CommonStyleAffectingAttributes}; -use selectors::matching::{common_style_affecting_attributes, rare_style_affecting_attributes}; use selectors::parser::PseudoElement; use selectors::{Element}; -use smallvec::SmallVec; -use std::borrow::ToOwned; -use std::hash::{Hash, Hasher}; use std::mem::transmute; -use std::slice::Iter; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; -use string_cache::{Atom, Namespace}; use style::data::PrivateStyleData; use style::dom::{TElement, TNode}; -use style::properties::{ComputedValues, PropertyDeclaration, cascade}; +use style::matching::{ApplicableDeclarations, ApplicableDeclarationsCache}; +use style::matching::{StyleSharingCandidate, StyleSharingCandidateCache}; +use style::properties::{ComputedValues, cascade}; use style::selector_matching::{DeclarationBlock, Stylist}; use util::arc_ptr_eq; -use util::cache::{LRUCache, SimpleHashCache}; use util::opts; -use util::vec::ForgetfulSink; - -pub struct ApplicableDeclarations { - pub normal: SmallVec<[DeclarationBlock; 16]>, - pub before: Vec<DeclarationBlock>, - pub after: Vec<DeclarationBlock>, - - /// Whether the `normal` declarations are shareable with other nodes. - pub normal_shareable: bool, -} - -impl ApplicableDeclarations { - pub fn new() -> ApplicableDeclarations { - ApplicableDeclarations { - normal: SmallVec::new(), - before: Vec::new(), - after: Vec::new(), - normal_shareable: false, - } - } -} - -#[derive(Clone)] -pub struct ApplicableDeclarationsCacheEntry { - pub declarations: Vec<DeclarationBlock>, -} - -impl ApplicableDeclarationsCacheEntry { - fn new(declarations: Vec<DeclarationBlock>) -> ApplicableDeclarationsCacheEntry { - ApplicableDeclarationsCacheEntry { - declarations: declarations, - } - } -} - -impl PartialEq for ApplicableDeclarationsCacheEntry { - fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool { - let this_as_query = ApplicableDeclarationsCacheQuery::new(&*self.declarations); - this_as_query.eq(other) - } -} -impl Eq for ApplicableDeclarationsCacheEntry {} - -impl Hash for ApplicableDeclarationsCacheEntry { - fn hash<H: Hasher>(&self, state: &mut H) { - let tmp = ApplicableDeclarationsCacheQuery::new(&*self.declarations); - tmp.hash(state); - } -} - -struct ApplicableDeclarationsCacheQuery<'a> { - declarations: &'a [DeclarationBlock], -} - -impl<'a> ApplicableDeclarationsCacheQuery<'a> { - fn new(declarations: &'a [DeclarationBlock]) -> ApplicableDeclarationsCacheQuery<'a> { - ApplicableDeclarationsCacheQuery { - declarations: declarations, - } - } -} - -impl<'a> PartialEq for ApplicableDeclarationsCacheQuery<'a> { - fn eq(&self, other: &ApplicableDeclarationsCacheQuery<'a>) -> bool { - if self.declarations.len() != other.declarations.len() { - return false - } - for (this, other) in self.declarations.iter().zip(other.declarations) { - if !arc_ptr_eq(&this.declarations, &other.declarations) { - return false - } - } - true - } -} -impl<'a> Eq for ApplicableDeclarationsCacheQuery<'a> {} - -impl<'a> PartialEq<ApplicableDeclarationsCacheEntry> for ApplicableDeclarationsCacheQuery<'a> { - fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool { - let other_as_query = ApplicableDeclarationsCacheQuery::new(&other.declarations); - self.eq(&other_as_query) - } -} - -impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> { - fn hash<H: Hasher>(&self, state: &mut H) { - for declaration in self.declarations { - // Each declaration contians an Arc, which is a stable - // pointer; we use that for hashing and equality. - let ptr = &*declaration.declarations as *const Vec<PropertyDeclaration>; - ptr.hash(state); - } - } -} - -static APPLICABLE_DECLARATIONS_CACHE_SIZE: usize = 32; - -pub struct ApplicableDeclarationsCache { - cache: SimpleHashCache<ApplicableDeclarationsCacheEntry, Arc<ComputedValues>>, -} - -impl ApplicableDeclarationsCache { - pub fn new() -> ApplicableDeclarationsCache { - ApplicableDeclarationsCache { - cache: SimpleHashCache::new(APPLICABLE_DECLARATIONS_CACHE_SIZE), - } - } - - fn find(&self, declarations: &[DeclarationBlock]) -> Option<Arc<ComputedValues>> { - match self.cache.find(&ApplicableDeclarationsCacheQuery::new(declarations)) { - None => None, - Some(ref values) => Some((*values).clone()), - } - } - - fn insert(&mut self, declarations: Vec<DeclarationBlock>, style: Arc<ComputedValues>) { - self.cache.insert(ApplicableDeclarationsCacheEntry::new(declarations), style) - } - - pub fn evict_all(&mut self) { - self.cache.evict_all(); - } -} - -/// An LRU cache of the last few nodes seen, so that we can aggressively try to reuse their styles. -pub struct StyleSharingCandidateCache { - cache: LRUCache<StyleSharingCandidate, ()>, -} - -fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>(element: &E) - -> CommonStyleAffectingAttributes { - let mut flags = CommonStyleAffectingAttributes::empty(); - for attribute_info in &common_style_affecting_attributes() { - match attribute_info.mode { - CommonStyleAffectingAttributeMode::IsPresent(flag) => { - if element.get_attr(&ns!(), &attribute_info.atom).is_some() { - flags.insert(flag) - } - } - CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => { - match element.get_attr(&ns!(), &attribute_info.atom) { - Some(element_value) if element_value == target_value => { - flags.insert(flag) - } - _ => {} - } - } - } - } - flags -} - -#[derive(Clone)] -pub struct StyleSharingCandidate { - pub style: Arc<ComputedValues>, - pub parent_style: Arc<ComputedValues>, - pub local_name: Atom, - // FIXME(pcwalton): Should be a list of atoms instead. - pub class: Option<String>, - pub namespace: Namespace, - pub common_style_affecting_attributes: CommonStyleAffectingAttributes, - pub link: bool, -} - -impl PartialEq for StyleSharingCandidate { - fn eq(&self, other: &StyleSharingCandidate) -> bool { - arc_ptr_eq(&self.style, &other.style) && - arc_ptr_eq(&self.parent_style, &other.parent_style) && - self.local_name == other.local_name && - self.class == other.class && - self.link == other.link && - self.namespace == other.namespace && - self.common_style_affecting_attributes == other.common_style_affecting_attributes - } -} - -impl StyleSharingCandidate { - /// Attempts to create a style sharing candidate from this node. Returns - /// the style sharing candidate or `None` if this node is ineligible for - /// style sharing. - fn new<'le, E: TElement<'le>>(element: &E) -> Option<StyleSharingCandidate> { - let parent_element = match element.parent_element() { - None => return None, - Some(parent_element) => parent_element, - }; - - let style = unsafe { - match element.as_node().borrow_data_unchecked() { - None => return None, - Some(data_ref) => { - match (*data_ref).style { - None => return None, - Some(ref data) => (*data).clone(), - } - } - } - }; - let parent_style = unsafe { - match parent_element.as_node().borrow_data_unchecked() { - None => return None, - Some(parent_data_ref) => { - match (*parent_data_ref).style { - None => return None, - Some(ref data) => (*data).clone(), - } - } - } - }; - - if element.style_attribute().is_some() { - return None - } - - Some(StyleSharingCandidate { - style: style, - parent_style: parent_style, - local_name: element.get_local_name().clone(), - class: element.get_attr(&ns!(), &atom!("class")) - .map(|string| string.to_owned()), - link: element.is_link(), - namespace: (*element.get_namespace()).clone(), - common_style_affecting_attributes: - create_common_style_affecting_attributes_from_element::<'le, E>(&element) - }) - } - - fn can_share_style_with<'a, E: TElement<'a>>(&self, element: &E) -> bool { - if *element.get_local_name() != self.local_name { - return false - } - - // FIXME(pcwalton): Use `each_class` here instead of slow string comparison. - match (&self.class, element.get_attr(&ns!(), &atom!("class"))) { - (&None, Some(_)) | (&Some(_), None) => return false, - (&Some(ref this_class), Some(element_class)) if - element_class != &**this_class => { - return false - } - (&Some(_), Some(_)) | (&None, None) => {} - } - - if *element.get_namespace() != self.namespace { - return false - } - - let mut matching_rules = ForgetfulSink::new(); - element.synthesize_presentational_hints_for_legacy_attributes(&mut matching_rules); - if !matching_rules.is_empty() { - return false; - } - - // FIXME(pcwalton): It's probably faster to iterate over all the element's attributes and - // use the {common, rare}-style-affecting-attributes tables as lookup tables. - - for attribute_info in &common_style_affecting_attributes() { - match attribute_info.mode { - CommonStyleAffectingAttributeMode::IsPresent(flag) => { - if self.common_style_affecting_attributes.contains(flag) != - element.get_attr(&ns!(), &attribute_info.atom).is_some() { - return false - } - } - CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => { - match element.get_attr(&ns!(), &attribute_info.atom) { - Some(ref element_value) if self.common_style_affecting_attributes - .contains(flag) && - *element_value != target_value => { - return false - } - Some(_) if !self.common_style_affecting_attributes.contains(flag) => { - return false - } - None if self.common_style_affecting_attributes.contains(flag) => { - return false - } - _ => {} - } - } - } - } - - for attribute_name in &rare_style_affecting_attributes() { - if element.get_attr(&ns!(), attribute_name).is_some() { - return false - } - } - - if element.is_link() != self.link { - return false - } - - // TODO(pcwalton): We don't support visited links yet, but when we do there will need to - // be some logic here. - - true - } -} - -static STYLE_SHARING_CANDIDATE_CACHE_SIZE: usize = 40; - -impl StyleSharingCandidateCache { - pub fn new() -> StyleSharingCandidateCache { - StyleSharingCandidateCache { - cache: LRUCache::new(STYLE_SHARING_CANDIDATE_CACHE_SIZE), - } - } - - pub fn iter(&self) -> Iter<(StyleSharingCandidate, ())> { - self.cache.iter() - } - - pub fn insert_if_possible<'le, E: TElement<'le>>(&mut self, element: &E) { - match StyleSharingCandidate::new(element) { - None => {} - Some(candidate) => self.cache.insert(candidate, ()) - } - } - - pub fn touch(&mut self, index: usize) { - self.cache.touch(index) - } -} /// The results of attempting to share a style. pub enum StyleSharingResult { @@ -454,22 +126,22 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode None => None, Some(ref style) => Some(&**style), }; - let (the_style, is_cacheable) = cascade(layout_context.viewport_size, + let (the_style, is_cacheable) = cascade(layout_context.style_context.viewport_size, applicable_declarations, shareable, Some(&***parent_style), cached_computed_values, - layout_context.error_reporter.clone()); + layout_context.style_context.error_reporter.clone()); cacheable = cacheable && is_cacheable; this_style = the_style } None => { - let (the_style, is_cacheable) = cascade(layout_context.viewport_size, + let (the_style, is_cacheable) = cascade(layout_context.style_context.viewport_size, applicable_declarations, shareable, None, None, - layout_context.error_reporter.clone()); + layout_context.style_context.error_reporter.clone()); cacheable = cacheable && is_cacheable; this_style = the_style } @@ -516,7 +188,7 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode let this_opaque = self.opaque(); let had_animations_to_expire; { - let all_expired_animations = layout_context.expired_animations.read().unwrap(); + let all_expired_animations = layout_context.style_context.expired_animations.read().unwrap(); let animations_to_expire = all_expired_animations.get(&this_opaque); had_animations_to_expire = animations_to_expire.is_some(); if let Some(ref animations) = animations_to_expire { @@ -527,17 +199,18 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode } if had_animations_to_expire { - layout_context.expired_animations.write().unwrap().remove(&this_opaque); + layout_context.style_context.expired_animations.write().unwrap().remove(&this_opaque); } // Merge any running transitions into the current style, and cancel them. - let had_running_animations = layout_context.running_animations + let had_running_animations = layout_context.style_context + .running_animations .read() .unwrap() .get(&this_opaque) .is_some(); if had_running_animations { - let mut all_running_animations = layout_context.running_animations.write().unwrap(); + let mut all_running_animations = layout_context.style_context.running_animations.write().unwrap(); for running_animation in all_running_animations.get(&this_opaque).unwrap() { animation::update_style_for_animation(running_animation, style, None); } |