diff options
author | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-04-29 22:29:59 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-05-03 19:01:54 +0200 |
commit | 9caaa6004e294cbcc10891eac379454fc323c859 (patch) | |
tree | bac4db243a1435295a055258b445a28775131ffd /components/style/selector_matching.rs | |
parent | 3f2ceeff5dd1966dafe34381e20ec405ab72ccee (diff) | |
download | servo-9caaa6004e294cbcc10891eac379454fc323c859.tar.gz servo-9caaa6004e294cbcc10891eac379454fc323c859.zip |
style: Support lazy pseudo-elements
These can't be supported in Servo as of right now, because I'm not
totally sure the accesses that should be done in layout would be
thread-safe.
It can be revisited later though.
Diffstat (limited to 'components/style/selector_matching.rs')
-rw-r--r-- | components/style/selector_matching.rs | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 72fdec38e43..e59955f3a0e 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -8,7 +8,6 @@ use dom::TElement; use element_state::*; use error_reporting::{ParseErrorReporter, StdoutErrorReporter}; -use euclid::Size2D; use media_queries::{Device, MediaType}; use properties::{self, ComputedValues, PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet}; @@ -127,9 +126,9 @@ pub struct Stylist<Impl: SelectorImplExt> { /// Applicable declarations for a given non-eagerly cascaded pseudo-element. /// These are eagerly computed once, and then used to resolve the new /// computed values on the fly on layout. - non_eagerly_cascaded_pseudo_element_decls: HashMap<Impl::PseudoElement, - Vec<DeclarationBlock>, - BuildHasherDefault<::fnv::FnvHasher>>, + precomputed_pseudo_element_decls: HashMap<Impl::PseudoElement, + Vec<DeclarationBlock>, + BuildHasherDefault<::fnv::FnvHasher>>, rules_source_order: usize, @@ -148,7 +147,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { element_map: PerPseudoElementSelectorMap::new(), pseudos_map: HashMap::with_hasher(Default::default()), - non_eagerly_cascaded_pseudo_element_decls: HashMap::with_hasher(Default::default()), + precomputed_pseudo_element_decls: HashMap::with_hasher(Default::default()), rules_source_order: 0, state_deps: DependencySet::new(), }; @@ -175,7 +174,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new()); }); - self.non_eagerly_cascaded_pseudo_element_decls = HashMap::with_hasher(Default::default()); + self.precomputed_pseudo_element_decls = HashMap::with_hasher(Default::default()); self.rules_source_order = 0; self.state_deps.clear(); @@ -242,39 +241,70 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { self.rules_source_order = rules_source_order; - Impl::each_non_eagerly_cascaded_pseudo_element(|pseudo| { - // TODO: Don't precompute this, compute it on demand instead and - // cache it. - // - // This is actually kind of hard, because the stylist is shared - // between threads. + Impl::each_precomputed_pseudo_element(|pseudo| { + // TODO: Consider not doing this and just getting the rules on the + // fly. It should be a bit slower, but we'd take rid of the + // extra field, and avoid this precomputation entirely. if let Some(map) = self.pseudos_map.remove(&pseudo) { let mut declarations = vec![]; map.user_agent.normal.get_universal_rules(&mut declarations); map.user_agent.important.get_universal_rules(&mut declarations); - self.non_eagerly_cascaded_pseudo_element_decls.insert(pseudo, declarations); + self.precomputed_pseudo_element_decls.insert(pseudo, declarations); } }) } - pub fn computed_values_for_pseudo(&self, - pseudo: &Impl::PseudoElement, - parent: Option<&Arc<Impl::ComputedValues>>) -> Option<Arc<Impl::ComputedValues>> { - debug_assert!(!Impl::is_eagerly_cascaded_pseudo_element(pseudo)); - if let Some(declarations) = self.non_eagerly_cascaded_pseudo_element_decls.get(pseudo) { + /// Computes the style for a given "precomputed" pseudo-element, taking the + /// universal rules and applying them. + pub fn precomputed_values_for_pseudo(&self, + pseudo: &Impl::PseudoElement, + parent: Option<&Arc<Impl::ComputedValues>>) + -> Option<Arc<Impl::ComputedValues>> { + debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_precomputed()); + if let Some(declarations) = self.precomputed_pseudo_element_decls.get(pseudo) { + let (computed, _) = - properties::cascade::<Impl::ComputedValues>(Size2D::zero(), - &declarations, false, - parent.map(|p| &**p), None, - box StdoutErrorReporter); + properties::cascade(self.device.au_viewport_size(), + &declarations, false, + parent.map(|p| &**p), None, + box StdoutErrorReporter); Some(Arc::new(computed)) } else { parent.map(|p| p.clone()) } } + pub fn lazily_compute_pseudo_element_style<E>(&self, + element: &E, + pseudo: &Impl::PseudoElement, + parent: &Arc<Impl::ComputedValues>) + -> Option<Arc<Impl::ComputedValues>> + where E: Element<Impl=Impl> + TElement { + debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_lazy()); + if self.pseudos_map.get(pseudo).is_none() { + return None; + } + + let mut declarations = vec![]; + + // NB: This being cached could be worth it, maybe allow an optional + // ApplicableDeclarationsCache?. + self.push_applicable_declarations(element, + None, + None, + Some(pseudo), + &mut declarations); + + let (computed, _) = + properties::cascade(self.device.au_viewport_size(), + &declarations, false, + Some(&**parent), None, + box StdoutErrorReporter); + Some(Arc::new(computed)) + } + pub fn compute_restyle_hint<E>(&self, element: &E, snapshot: &ElementSnapshot, // NB: We need to pass current_state as an argument because @@ -325,7 +355,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { element: &E, parent_bf: Option<&BloomFilter>, style_attribute: Option<&PropertyDeclarationBlock>, - pseudo_element: Option<Impl::PseudoElement>, + pseudo_element: Option<&Impl::PseudoElement>, applicable_declarations: &mut V) -> bool where E: Element<Impl=Impl> + TElement, @@ -334,7 +364,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { assert!(style_attribute.is_none() || pseudo_element.is_none(), "Style attributes do not apply to pseudo-elements"); debug_assert!(pseudo_element.is_none() || - Impl::is_eagerly_cascaded_pseudo_element(pseudo_element.as_ref().unwrap())); + !Impl::pseudo_element_cascade_type(pseudo_element.as_ref().unwrap()).is_precomputed()); let map = match pseudo_element { Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(), |