From abcc9b301c37ada8bde4e333b7a07c2ee6324704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 29 May 2017 21:56:21 +0200 Subject: [PATCH] style: Add a CachedStyleSharingData to hold the candidate class list and revalidation results. --- components/style/sharing/checks.rs | 17 +----- components/style/sharing/mod.rs | 85 ++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 24 deletions(-) diff --git a/components/style/sharing/checks.rs b/components/style/sharing/checks.rs index 4ac537e0009..84ec5c5f0a5 100644 --- a/components/style/sharing/checks.rs +++ b/components/style/sharing/checks.rs @@ -72,13 +72,7 @@ pub fn have_same_class(element: E, let mut element_class_attributes = vec![]; element.each_class(|c| element_class_attributes.push(c.clone())); - if candidate.class_attributes.is_none() { - let mut attrs = vec![]; - candidate.element.each_class(|c| attrs.push(c.clone())); - candidate.class_attributes = Some(attrs) - } - - element_class_attributes == *candidate.class_attributes.as_ref().unwrap() + element_class_attributes == candidate.class_list() } /// Compare element and candidate state, but ignore visitedness. Styles don't @@ -137,15 +131,8 @@ pub fn revalidate(element: E, &mut set_selector_flags)); } - if candidate.revalidation_match_results.is_none() { - let results = - stylist.match_revalidation_selectors(&*candidate.element, bloom, - &mut |_, _| {}); - candidate.revalidation_match_results = Some(results); - } - let for_element = info.revalidation_match_results.as_ref().unwrap(); - let for_candidate = candidate.revalidation_match_results.as_ref().unwrap(); + let for_candidate = candidate.revalidation_match_results(stylist, bloom); // This assert "ensures", to some extent, that the two candidates have // matched the same rulehash buckets, and as such, that the bits we're diff --git a/components/style/sharing/mod.rs b/components/style/sharing/mod.rs index 67fde2e047b..145ede1a23b 100644 --- a/components/style/sharing/mod.rs +++ b/components/style/sharing/mod.rs @@ -14,8 +14,10 @@ use dom::{TElement, SendElement}; use matching::{ChildCascadeRequirement, MatchMethods}; use properties::ComputedValues; use selectors::bloom::BloomFilter; -use selectors::matching::StyleRelations; +use selectors::matching::{ElementSelectorFlags, StyleRelations}; use sink::ForgetfulSink; +use smallvec::SmallVec; +use stylist::Stylist; mod checks; @@ -32,23 +34,86 @@ pub enum StyleSharingBehavior { Disallow, } +/// Some data we want to avoid recomputing all the time while trying to share +/// style. +#[derive(Debug)] +pub struct CachedStyleSharingData { + /// The class list of this element. + /// + /// TODO(emilio): See if it's worth to sort them, or doing something else in + /// a similar fashion as what Boris is doing for the ID attribute. + class_list: Option>, + + /// The cached result of matching this entry against the revalidation + /// selectors. + revalidation_match_results: Option, +} + +impl CachedStyleSharingData { + /// Get or compute the class-list associated with this element. + pub fn class_list(&mut self, element: E) -> &[Atom] + where E: TElement, + { + if self.class_list.is_none() { + let mut class_list = SmallVec::new(); + element.each_class(|c| class_list.push(c.clone())); + self.class_list = Some(class_list); + } + &*self.class_list.as_ref().unwrap() + } + + /// Computes the revalidation results if needed, and returns it. + fn revalidation_match_results( + &mut self, + element: E, + stylist: &Stylist, + bloom: &BloomFilter, + flags_setter: &mut F + ) -> &BitVec + where E: TElement, + F: FnMut(&E, ElementSelectorFlags), + { + if self.revalidation_match_results.is_none() { + self.revalidation_match_results = + Some(stylist.match_revalidation_selectors(&element, bloom, + flags_setter)); + } + + self.revalidation_match_results.as_ref().unwrap() + } +} + /// Information regarding a style sharing candidate, that is, an entry in the /// style sharing cache. /// /// Note that this information is stored in TLS and cleared after the traversal, /// and once here, the style information of the element is immutable, so it's /// safe to access. -/// -/// TODO: We can stick a lot more info here. #[derive(Debug)] pub struct StyleSharingCandidate { /// The element. We use SendElement here so that the cache may live in /// ScopedTLS. element: SendElement, - /// The cached class names. - class_attributes: Option>, - /// The cached result of matching this entry against the revalidation selectors. - revalidation_match_results: Option, + cache: CachedStyleSharingData, +} + +impl StyleSharingCandidate { + /// Get the classlist of this candidate. + fn class_list(&mut self) -> &[Atom] { + self.cache.class_list(*self.element) + } + + /// Get the classlist of this candidate. + fn revalidation_match_results( + &mut self, + stylist: &Stylist, + bloom: &BloomFilter, + ) -> &BitVec { + self.cache.revalidation_match_results(*self.element, + stylist, + bloom, + &mut |_, _| {}) + } } impl PartialEq> for StyleSharingCandidate { @@ -177,8 +242,10 @@ impl StyleSharingCandidateCache { self.cache.insert(StyleSharingCandidate { element: unsafe { SendElement::new(*element) }, - class_attributes: None, - revalidation_match_results: revalidation_match_results, + cache: CachedStyleSharingData { + class_list: None, + revalidation_match_results: revalidation_match_results, + } }); }