diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-04-03 18:04:34 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-03 18:04:34 -0500 |
commit | eee25e23132b0f5d4cb50e5af4691b6e4bf75978 (patch) | |
tree | 21aba7882fbbb3baf700abdaf80459b48695218e /components | |
parent | 806584da9ac923feaac1d4c22ca030d75c26c31d (diff) | |
parent | 3f0d022ba2658ae25b4ef47f0c2939de79b90d7e (diff) | |
download | servo-eee25e23132b0f5d4cb50e5af4691b6e4bf75978.tar.gz servo-eee25e23132b0f5d4cb50e5af4691b6e4bf75978.zip |
Auto merge of #16250 - bholley:pseudo_repr, r=emilio
Don't use a HashMap for pseudo-element styles
Reviewed in https://bugzilla.mozilla.org/show_bug.cgi?id=1335708
@bors-servo try
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16250)
<!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 34 | ||||
-rw-r--r-- | components/style/data.rs | 113 | ||||
-rw-r--r-- | components/style/gecko/selector_parser.rs | 84 | ||||
-rw-r--r-- | components/style/matching.rs | 46 | ||||
-rw-r--r-- | components/style/selector_parser.rs | 38 | ||||
-rw-r--r-- | components/style/servo/selector_parser.rs | 72 | ||||
-rw-r--r-- | components/style/stylist.rs | 8 |
7 files changed, 256 insertions, 139 deletions
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 08de74f0e21..a1c59d83114 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -339,7 +339,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + .unwrap() .borrow() .styles().pseudos - .contains_key(&PseudoElement::Before) { + .has(&PseudoElement::Before) { Some(self.with_pseudo(PseudoElementType::Before(None))) } else { None @@ -352,7 +352,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + .unwrap() .borrow() .styles().pseudos - .contains_key(&PseudoElement::After) { + .has(&PseudoElement::After) { Some(self.with_pseudo(PseudoElementType::After(None))) } else { None @@ -397,31 +397,29 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + // Precompute non-eagerly-cascaded pseudo-element styles if not // cached before. let style_pseudo = other.style_pseudo_element(); + let mut data = self.get_style_data().unwrap().borrow_mut(); match style_pseudo.cascade_type() { // Already computed during the cascade. - PseudoElementCascadeType::Eager => {}, + PseudoElementCascadeType::Eager => { + data.styles().pseudos.get(&style_pseudo) + .unwrap().values().clone() + }, PseudoElementCascadeType::Precomputed => { - if !self.get_style_data() - .unwrap() - .borrow() - .styles().pseudos.contains_key(&style_pseudo) { - let mut data = self.get_style_data().unwrap().borrow_mut(); + if !data.styles().cached_pseudos.contains_key(&style_pseudo) { let new_style = context.stylist.precomputed_values_for_pseudo( &context.guards, &style_pseudo, Some(data.styles().primary.values()), CascadeFlags::empty()); - data.styles_mut().pseudos + data.styles_mut().cached_pseudos .insert(style_pseudo.clone(), new_style); } + data.styles().cached_pseudos.get(&style_pseudo) + .unwrap().values().clone() } PseudoElementCascadeType::Lazy => { - if !self.get_style_data() - .unwrap() - .borrow() - .styles().pseudos.contains_key(&style_pseudo) { - let mut data = self.get_style_data().unwrap().borrow_mut(); + if !data.styles().cached_pseudos.contains_key(&style_pseudo) { let new_style = context.stylist .lazily_compute_pseudo_element_style( @@ -429,15 +427,13 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + unsafe { &self.unsafe_get() }, &style_pseudo, data.styles().primary.values()); - data.styles_mut().pseudos + data.styles_mut().cached_pseudos .insert(style_pseudo.clone(), new_style.unwrap()); } + data.styles().cached_pseudos.get(&style_pseudo) + .unwrap().values().clone() } } - - self.get_style_data().unwrap().borrow() - .styles().pseudos.get(&style_pseudo) - .unwrap().values().clone() } } } diff --git a/components/style/data.rs b/components/style/data.rs index a5a1e1712cb..9eb831e07a1 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -11,11 +11,11 @@ use properties::ComputedValues; use properties::longhands::display::computed_value as display; use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; use rule_tree::StrongRuleNode; -use selector_parser::{PseudoElement, RestyleDamage, Snapshot}; -use std::collections::HashMap; +use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage, Snapshot}; +#[cfg(feature = "servo")] use std::collections::HashMap; use std::fmt; -use std::hash::BuildHasherDefault; -use std::ops::{Deref, DerefMut}; +#[cfg(feature = "servo")] use std::hash::BuildHasherDefault; +use std::ops::Deref; use std::sync::Arc; use stylist::Stylist; use thread_state; @@ -73,42 +73,98 @@ impl fmt::Debug for ComputedStyle { } } -type PseudoStylesInner = HashMap<PseudoElement, ComputedStyle, - BuildHasherDefault<::fnv::FnvHasher>>; - -/// A set of styles for a given element's pseudo-elements. -/// -/// This is a map from pseudo-element to `ComputedStyle`. -/// -/// TODO(emilio): This should probably be a small array by default instead of a -/// full-blown `HashMap`. +/// A list of styles for eagerly-cascaded pseudo-elements. Lazily-allocated. #[derive(Clone, Debug)] -pub struct PseudoStyles(PseudoStylesInner); +pub struct EagerPseudoStyles(Option<Box<[Option<ComputedStyle>]>>); -impl PseudoStyles { - /// Construct an empty set of `PseudoStyles`. - pub fn empty() -> Self { - PseudoStyles(HashMap::with_hasher(Default::default())) +impl EagerPseudoStyles { + /// Returns whether there are any pseudo styles. + pub fn is_empty(&self) -> bool { + self.0.is_some() } -} -impl Deref for PseudoStyles { - type Target = PseudoStylesInner; - fn deref(&self) -> &Self::Target { &self.0 } -} + /// Returns a reference to the style for a given eager pseudo, if it exists. + pub fn get(&self, pseudo: &PseudoElement) -> Option<&ComputedStyle> { + debug_assert!(pseudo.is_eager()); + self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref()) + } + + /// Returns a mutable reference to the style for a given eager pseudo, if it exists. + pub fn get_mut(&mut self, pseudo: &PseudoElement) -> Option<&mut ComputedStyle> { + debug_assert!(pseudo.is_eager()); + self.0.as_mut().and_then(|p| p[pseudo.eager_index()].as_mut()) + } -impl DerefMut for PseudoStyles { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + /// Returns true if the EagerPseudoStyles has a ComputedStyle for |pseudo|. + pub fn has(&self, pseudo: &PseudoElement) -> bool { + self.get(pseudo).is_some() + } + + /// Inserts a pseudo-element. The pseudo-element must not already exist. + pub fn insert(&mut self, pseudo: &PseudoElement, style: ComputedStyle) { + debug_assert!(!self.has(pseudo)); + if self.0.is_none() { + self.0 = Some(vec![None; EAGER_PSEUDO_COUNT].into_boxed_slice()); + } + self.0.as_mut().unwrap()[pseudo.eager_index()] = Some(style); + } + + /// Removes a pseudo-element style if it exists, and returns it. + pub fn take(&mut self, pseudo: &PseudoElement) -> Option<ComputedStyle> { + let result = match self.0.as_mut() { + None => return None, + Some(arr) => arr[pseudo.eager_index()].take(), + }; + let empty = self.0.as_ref().unwrap().iter().all(|x| x.is_none()); + if empty { + self.0 = None; + } + result + } + + /// Returns a list of the pseudo-elements. + pub fn keys(&self) -> Vec<PseudoElement> { + let mut v = Vec::new(); + if let Some(ref arr) = self.0 { + for i in 0..EAGER_PSEUDO_COUNT { + if arr[i].is_some() { + v.push(PseudoElement::from_eager_index(i)); + } + } + } + v + } + + /// Sets the rule node for a given pseudo-element, which must already have an entry. + /// + /// Returns true if the rule node changed. + pub fn set_rules(&mut self, pseudo: &PseudoElement, rules: StrongRuleNode) -> bool { + debug_assert!(self.has(pseudo)); + let mut style = self.get_mut(pseudo).unwrap(); + let changed = style.rules != rules; + style.rules = rules; + changed + } } +/// A cache of precomputed and lazy pseudo-elements, used by servo. This isn't +/// a very efficient design, but is the result of servo having previously used +/// the eager pseudo map (when it was a map) for this cache. +#[cfg(feature = "servo")] +type PseudoElementCache = HashMap<PseudoElement, ComputedStyle, BuildHasherDefault<::fnv::FnvHasher>>; +#[cfg(feature = "gecko")] +type PseudoElementCache = (); + /// The styles associated with a node, including the styles for any /// pseudo-elements. #[derive(Clone, Debug)] pub struct ElementStyles { /// The element's style. pub primary: ComputedStyle, - /// The map of styles for the element's pseudos. - pub pseudos: PseudoStyles, + /// A list of the styles for the element's eagerly-cascaded pseudo-elements. + pub pseudos: EagerPseudoStyles, + /// NB: This is an empty field for gecko. + pub cached_pseudos: PseudoElementCache, } impl ElementStyles { @@ -116,7 +172,8 @@ impl ElementStyles { pub fn new(primary: ComputedStyle) -> Self { ElementStyles { primary: primary, - pseudos: PseudoStyles::empty(), + pseudos: EagerPseudoStyles(None), + cached_pseudos: PseudoElementCache::default(), } } diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 232087df9ee..c6e4a524142 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -42,7 +42,39 @@ use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PseudoElement(Atom, bool); +/// List of eager pseudos. Keep this in sync with the count below. +macro_rules! each_eager_pseudo { + ($macro_name:ident, $atom_macro:ident) => { + $macro_name!($atom_macro!(":after"), 0); + $macro_name!($atom_macro!(":before"), 1); + } +} + +/// The number of eager pseudo-elements (just ::before and ::after). +pub const EAGER_PSEUDO_COUNT: usize = 2; + + impl PseudoElement { + /// Gets the canonical index of this eagerly-cascaded pseudo-element. + #[inline] + pub fn eager_index(&self) -> usize { + macro_rules! case { + ($atom:expr, $idx:expr) => { if *self.as_atom() == $atom { return $idx; } } + } + each_eager_pseudo!(case, atom); + panic!("Not eager") + } + + /// Creates a pseudo-element from an eager index. + #[inline] + pub fn from_eager_index(i: usize) -> Self { + macro_rules! case { + ($atom:expr, $idx:expr) => { if i == $idx { return PseudoElement($atom, false); } } + } + each_eager_pseudo!(case, atom); + panic!("Not eager") + } + /// Get the pseudo-element as an atom. #[inline] pub fn as_atom(&self) -> &Atom { @@ -55,6 +87,35 @@ impl PseudoElement { self.1 } + /// Whether this pseudo-element is ::before or ::after. + #[inline] + pub fn is_before_or_after(&self) -> bool { + *self.as_atom() == atom!(":before") || + *self.as_atom() == atom!(":after") + } + + /// Whether this pseudo-element is eagerly-cascaded. + #[inline] + pub fn is_eager(&self) -> bool { + macro_rules! case { + ($atom:expr, $idx:expr) => { if *self.as_atom() == $atom { return true; } } + } + each_eager_pseudo!(case, atom); + return false; + } + + /// Whether this pseudo-element is lazily-cascaded. + #[inline] + pub fn is_lazy(&self) -> bool { + !self.is_eager() && !self.is_precomputed() + } + + /// Whether this pseudo-element is precomputed. + #[inline] + pub fn is_precomputed(&self) -> bool { + self.is_anon_box() + } + /// Construct a pseudo-element from an `Atom`, receiving whether it is also /// an anonymous box, and don't check it on release builds. /// @@ -398,7 +459,8 @@ impl SelectorImpl { /// /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`. pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType { - if Self::pseudo_is_before_or_after(pseudo) { + if pseudo.is_eager() { + debug_assert!(!pseudo.is_anon_box()); return PseudoElementCascadeType::Eager } @@ -409,6 +471,19 @@ impl SelectorImpl { PseudoElementCascadeType::Lazy } + /// A helper to traverse each eagerly cascaded pseudo-element, executing + /// `fun` on it. + #[inline] + pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F) + where F: FnMut(PseudoElement), + { + macro_rules! case { + ($atom:expr, $idx:expr) => { fun(PseudoElement($atom, false)); } + } + each_eager_pseudo!(case, atom); + } + + #[inline] /// Executes a function for each pseudo-element. pub fn each_pseudo_element<F>(mut fun: F) @@ -424,13 +499,6 @@ impl SelectorImpl { } #[inline] - /// Returns whether the given pseudo-element is `::before` or `::after`. - pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool { - *pseudo.as_atom() == atom!(":before") || - *pseudo.as_atom() == atom!(":after") - } - - #[inline] /// Returns the relevant state flag for a given non-tree-structural /// pseudo-class. pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { diff --git a/components/style/matching.rs b/components/style/matching.rs index 323561abca9..29865b69e0a 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -20,13 +20,11 @@ use properties::longhands::display::computed_value as display; use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode}; use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl}; -use selectors::MatchAttr; use selectors::bloom::BloomFilter; use selectors::matching::{ElementSelectorFlags, StyleRelations}; use selectors::matching::AFFECTED_BY_PSEUDO_ELEMENTS; use servo_config::opts; use sink::ForgetfulSink; -use std::collections::hash_map::Entry; use std::sync::Arc; use stylist::ApplicableDeclarationBlock; @@ -903,9 +901,9 @@ pub trait MatchMethods : TElement { // Compute rule nodes for eagerly-cascaded pseudo-elements. let mut matches_different_pseudos = false; SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| { - let mut per_pseudo = &mut data.styles_mut().pseudos; + let mut pseudos = &mut data.styles_mut().pseudos; debug_assert!(applicable_declarations.is_empty()); - let pseudo_animation_rules = if <Self as MatchAttr>::Impl::pseudo_is_before_or_after(&pseudo) { + let pseudo_animation_rules = if pseudo.is_before_or_after() { self.get_animation_rules(Some(&pseudo)) } else { AnimationRules(None, None) @@ -921,19 +919,13 @@ pub trait MatchMethods : TElement { if !applicable_declarations.is_empty() { let new_rules = compute_rule_node::<Self>(rule_tree, &mut applicable_declarations); - match per_pseudo.entry(pseudo) { - Entry::Occupied(mut e) => { - if e.get().rules != new_rules { - e.get_mut().rules = new_rules; - rule_nodes_changed = true; - } - }, - Entry::Vacant(e) => { - e.insert(ComputedStyle::new_partial(new_rules)); - matches_different_pseudos = true; - } + if pseudos.has(&pseudo) { + rule_nodes_changed = pseudos.set_rules(&pseudo, new_rules); + } else { + pseudos.insert(&pseudo, ComputedStyle::new_partial(new_rules)); + matches_different_pseudos = true; } - } else if per_pseudo.remove(&pseudo).is_some() { + } else if pseudos.take(&pseudo).is_some() { matches_different_pseudos = true; } }); @@ -948,7 +940,7 @@ pub trait MatchMethods : TElement { } // If we have any pseudo elements, indicate so in the primary StyleRelations. - if !data.styles().pseudos.is_empty() { + if data.styles().pseudos.is_empty() { primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS; } @@ -995,11 +987,10 @@ pub trait MatchMethods : TElement { animation_rule.as_ref(), primary_rules); - let iter = element_styles.pseudos.iter_mut().filter(|&(p, _)| - <Self as MatchAttr>::Impl::pseudo_is_before_or_after(p)); - for (pseudo, ref mut computed) in iter { - let animation_rule = self.get_animation_rule(Some(pseudo)); - let pseudo_rules = &mut computed.rules; + let pseudos = &mut element_styles.pseudos; + for pseudo in pseudos.keys().iter().filter(|p| p.is_before_or_after()) { + let animation_rule = self.get_animation_rule(Some(&pseudo)); + let pseudo_rules = &mut pseudos.get_mut(&pseudo).unwrap().rules; replace_rule_node(CascadeLevel::Animations, animation_rule.as_ref(), pseudo_rules); @@ -1198,11 +1189,10 @@ pub trait MatchMethods : TElement { // // Note that we've already set up the map of matching pseudo-elements // in match_element (and handled the damage implications of changing - // which pseudos match), so now we can just iterate the map. This does - // mean collecting the keys, so that the borrow checker will let us pass - // the mutable |data| to the inner cascade function. - let matched_pseudos: Vec<PseudoElement> = - data.styles().pseudos.keys().cloned().collect(); + // which pseudos match), so now we can just iterate what we have. This + // does mean collecting owned pseudos, so that the borrow checker will + // let us pass the mutable |data| to the inner cascade function. + let matched_pseudos = data.styles().pseudos.keys(); for pseudo in matched_pseudos { // If the new primary style is display:none, we don't need pseudo // styles, but we still need to clear any stale values. @@ -1212,7 +1202,7 @@ pub trait MatchMethods : TElement { } // Only ::before and ::after are animatable. - let animate = <Self as MatchAttr>::Impl::pseudo_is_before_or_after(&pseudo); + let animate = pseudo.is_before_or_after(); self.cascade_primary_or_pseudo(context, data, Some(&pseudo), &mut possibly_expired_animations, CascadeBooleans { diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index e8ed76bd01f..52f0a6b6d51 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -102,26 +102,6 @@ pub enum PseudoElementCascadeType { Precomputed, } -impl PseudoElementCascadeType { - /// Simple accessor to check whether the cascade type is eager. - #[inline] - pub fn is_eager(&self) -> bool { - *self == PseudoElementCascadeType::Eager - } - - /// Simple accessor to check whether the cascade type is lazy. - #[inline] - pub fn is_lazy(&self) -> bool { - *self == PseudoElementCascadeType::Lazy - } - - /// Simple accessor to check whether the cascade type is precomputed. - #[inline] - pub fn is_precomputed(&self) -> bool { - *self == PseudoElementCascadeType::Precomputed - } -} - /// An extension to rust-selector's `Element` trait. pub trait ElementExt: Element<Impl=SelectorImpl> + Debug { /// Whether this element is a `link`. @@ -134,22 +114,6 @@ pub trait ElementExt: Element<Impl=SelectorImpl> + Debug { } impl SelectorImpl { - /// A helper to traverse each eagerly cascaded pseudo-element, executing - /// `fun` on it. - /// - /// TODO(emilio): We can optimize this for Gecko using the pseudo-element - /// macro, and we should consider doing that for Servo too. - #[inline] - pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F) - where F: FnMut(PseudoElement), - { - Self::each_pseudo_element(|pseudo| { - if Self::pseudo_element_cascade_type(&pseudo).is_eager() { - fun(pseudo) - } - }) - } - /// A helper to traverse each precomputed pseudo-element, executing `fun` on /// it. /// @@ -160,7 +124,7 @@ impl SelectorImpl { where F: FnMut(PseudoElement), { Self::each_pseudo_element(|pseudo| { - if Self::pseudo_element_cascade_type(&pseudo).is_precomputed() { + if pseudo.is_precomputed() { fun(pseudo) } }) diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index e45e82358dd..a2be7c46415 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -19,6 +19,7 @@ use selectors::parser::{AttrSelector, SelectorMethods}; use std::borrow::Cow; use std::fmt; use std::fmt::Debug; +use std::mem; /// A pseudo-element, both public and private. /// @@ -26,10 +27,13 @@ use std::fmt::Debug; #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] +#[repr(usize)] pub enum PseudoElement { + // Eager pseudos. Keep these first so that eager_index() works. + After = 0, Before, - After, Selection, + // Non-eager pseudos. DetailsSummary, DetailsContent, ServoText, @@ -48,8 +52,8 @@ impl ToCss for PseudoElement { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { use self::PseudoElement::*; dest.write_str(match *self { - Before => "::before", After => "::after", + Before => "::before", Selection => "::selection", DetailsSummary => "::-servo-details-summary", DetailsContent => "::-servo-details-content", @@ -67,25 +71,60 @@ impl ToCss for PseudoElement { } } +/// The number of eager pseudo-elements. Keep this in sync with cascade_type. +pub const EAGER_PSEUDO_COUNT: usize = 3; + impl PseudoElement { + /// Gets the canonical index of this eagerly-cascaded pseudo-element. + #[inline] + pub fn eager_index(&self) -> usize { + debug_assert!(self.is_eager()); + self.clone() as usize + } + + /// Creates a pseudo-element from an eager index. + #[inline] + pub fn from_eager_index(i: usize) -> Self { + assert!(i < EAGER_PSEUDO_COUNT); + let result: PseudoElement = unsafe { mem::transmute(i) }; + debug_assert!(result.is_eager()); + result + } + /// Whether the current pseudo element is :before or :after. #[inline] pub fn is_before_or_after(&self) -> bool { - match *self { - PseudoElement::Before | - PseudoElement::After => true, - _ => false, - } + matches!(*self, PseudoElement::After | PseudoElement::Before) + } + + /// Whether this pseudo-element is eagerly-cascaded. + #[inline] + pub fn is_eager(&self) -> bool { + self.cascade_type() == PseudoElementCascadeType::Eager + } + + /// Whether this pseudo-element is lazily-cascaded. + #[inline] + pub fn is_lazy(&self) -> bool { + self.cascade_type() == PseudoElementCascadeType::Lazy + } + + /// Whether this pseudo-element is precomputed. + #[inline] + pub fn is_precomputed(&self) -> bool { + self.cascade_type() == PseudoElementCascadeType::Precomputed } /// Returns which kind of cascade type has this pseudo. /// /// For more info on cascade types, see docs/components/style.md + /// + /// Note: Keep this in sync with EAGER_PSEUDO_COUNT. #[inline] pub fn cascade_type(&self) -> PseudoElementCascadeType { match *self { - PseudoElement::Before | PseudoElement::After | + PseudoElement::Before | PseudoElement::Selection => PseudoElementCascadeType::Eager, PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, PseudoElement::DetailsContent | @@ -369,6 +408,17 @@ impl SelectorImpl { pseudo.cascade_type() } + /// A helper to traverse each eagerly cascaded pseudo-element, executing + /// `fun` on it. + #[inline] + pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F) + where F: FnMut(PseudoElement), + { + for i in 0..EAGER_PSEUDO_COUNT { + fun(PseudoElement::from_eager_index(i)); + } + } + /// Executes `fun` for each pseudo-element. #[inline] pub fn each_pseudo_element<F>(mut fun: F) @@ -396,12 +446,6 @@ impl SelectorImpl { pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { pc.state_flag() } - - /// Returns whether this pseudo is either :before or :after. - #[inline] - pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool { - pseudo.is_before_or_after() - } } /// Servo's version of an element snapshot. diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 8b1f83dae26..afd78e1b4d2 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -345,7 +345,7 @@ impl Stylist { parent: Option<&Arc<ComputedValues>>, cascade_flags: CascadeFlags) -> ComputedStyle { - debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed()); + debug_assert!(pseudo.is_precomputed()); let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) { Some(declarations) => { @@ -435,7 +435,7 @@ impl Stylist { fmt::Debug + PresentationalHintsSynthetizer { - debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy()); + debug_assert!(pseudo.is_lazy()); if self.pseudos_map.get(pseudo).is_none() { return None; } @@ -603,9 +603,7 @@ impl Stylist { debug_assert!(!self.is_device_dirty); debug_assert!(style_attribute.is_none() || pseudo_element.is_none(), "Style attributes do not apply to pseudo-elements"); - debug_assert!(pseudo_element.is_none() || - !SelectorImpl::pseudo_element_cascade_type(pseudo_element.as_ref().unwrap()) - .is_precomputed()); + debug_assert!(pseudo_element.as_ref().map_or(true, |p| !p.is_precomputed())); let map = match pseudo_element { Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(), |