From 8821ad72f4a95ea04fe8d73fa6e868410c2349f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 4 Jun 2018 16:27:00 +0200 Subject: [PATCH] style: Make pseudo-elements work with :host. Imported WebKit's test as a WPT. Bug: 1465291 Reviewed-by: xidorn MozReview-Commit-ID: 19ZThuoqKLW --- components/selectors/parser.rs | 22 +++++++++++++++--- components/style/stylist.rs | 41 +++++++++++++--------------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index fc840bfe926..2c9d6505776 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -544,10 +544,26 @@ impl Selector { } /// Whether this selector is a featureless :host selector, with no - /// combinators to the left. + /// combinators to the left, and optionally has a pseudo-element to the + /// right. #[inline] - pub fn is_featureless_host_selector(&self) -> bool { - self.iter().is_featureless_host_selector() + pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool { + let mut iter = self.iter(); + if !self.has_pseudo_element() { + return iter.is_featureless_host_selector(); + } + + // Skip the pseudo-element. + for _ in &mut iter { } + + match iter.next_sequence() { + None => return false, + Some(combinator) => { + debug_assert_eq!(combinator, Combinator::PseudoElement); + } + } + + iter.is_featureless_host_selector() } /// Returns an iterator over this selector in matching order (right-to-left), diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 34f187e483a..e777921e668 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1951,14 +1951,9 @@ pub struct CascadeData { /// cascade level. normal_rules: ElementAndPseudoRules, - /// The `:host` pseudo rules that are the rightmost selector. - /// - /// Note that as of right now these can't affect invalidation in any way, - /// until we support the :host() notation. - /// - /// Also, note that other engines don't accept stuff like :host::before / - /// :host::after, so we don't need to store pseudo rules at all. - host_rules: Option>>, + /// The `:host` pseudo rules that are the rightmost selector (without + /// accounting for pseudo-elements). + host_rules: Option>, /// The data coming from ::slotted() pseudo-element rules. /// @@ -2122,11 +2117,7 @@ impl CascadeData { #[inline] fn host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap> { - if pseudo.is_some() { - return None; - } - - self.host_rules.as_ref().map(|rules| &**rules) + self.host_rules.as_ref().and_then(|d| d.rules(pseudo)) } #[inline] @@ -2258,20 +2249,20 @@ impl CascadeData { } } - if selector.is_featureless_host_selector() { - let host_rules = self.host_rules - .get_or_insert_with(|| Box::new(Default::default())); - host_rules.insert(rule, quirks_mode)?; + // NOTE(emilio): It's fine to look at :host and then at + // ::slotted(..), since :host::slotted(..) could never + // possibly match, as is not a valid shadow host. + let rules = if selector.is_featureless_host_selector_or_pseudo_element() { + self.host_rules + .get_or_insert_with(|| Box::new(Default::default())) + } else if selector.is_slotted() { + self.slotted_rules + .get_or_insert_with(|| Box::new(Default::default())) } else { - let rules = if selector.is_slotted() { - self.slotted_rules - .get_or_insert_with(|| Box::new(Default::default())) - } else { - &mut self.normal_rules - }; + &mut self.normal_rules + }; - rules.insert(rule, pseudo_element, quirks_mode)?; - } + rules.insert(rule, pseudo_element, quirks_mode)?; } self.rules_source_order += 1; },