diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index 41b83b0c40e..352557735b3 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -17,7 +17,7 @@ //! is non-trivial. This module encapsulates those details and presents an //! easy-to-use API for the parser. -use crate::parser::{Combinator, Component, SelectorImpl}; +use crate::parser::{Combinator, Component, NonTSPseudoClass, SelectorImpl}; use crate::sink::Push; use servo_arc::{Arc, HeaderWithLength, ThinArc}; use smallvec::{self, SmallVec}; @@ -322,9 +322,13 @@ where Component::NthLastOfType(..) | Component::FirstOfType | Component::LastOfType | - Component::OnlyOfType | - Component::NonTSPseudoClass(..) => { + Component::OnlyOfType => { specificity.class_like_selectors += 1; + } + Component::NonTSPseudoClass(ref pseudo) => { + if !pseudo.has_zero_specificity() { + specificity.class_like_selectors += 1; + } }, Component::ExplicitUniversalType | Component::ExplicitAnyNamespace | diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 507121bbf97..92a5b039b90 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -52,6 +52,9 @@ pub trait NonTSPseudoClass: Sized + ToCss { /// /// https://drafts.csswg.org/selectors-4/#useraction-pseudos fn is_user_action_state(&self) -> bool; + + /// Whether this pseudo-class has zero specificity. + fn has_zero_specificity(&self) -> bool; } /// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a @@ -2336,6 +2339,11 @@ pub mod tests { fn is_user_action_state(&self) -> bool { self.is_active_or_hover() } + + #[inline] + fn has_zero_specificity(&self) -> bool { + false + } } impl ToCss for PseudoClass { diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index f38757189d0..eca60fdc586 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -94,6 +94,7 @@ macro_rules! apply_non_ts_list { ("-moz-last-node", MozLastNode, lastNode, _, _), ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, mozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), ("-moz-is-html", MozIsHTML, mozIsHTML, _, _), ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 2aad41adc9c..fec3c9247c3 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -233,6 +233,9 @@ impl NonTSPseudoClass { // across all the elements involved and the latter is already // checked for by our caching precondtions. NonTSPseudoClass::MozIsHTML | + // We prevent style sharing for NAC. + NonTSPseudoClass::MozNativeAnonymous | + NonTSPseudoClass::MozNativeAnonymousNoSpecificity | // :-moz-placeholder is parsed but never matches. NonTSPseudoClass::MozPlaceholder | // :-moz-locale-dir and :-moz-window-inactive depend only on @@ -275,6 +278,11 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass { NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus ) } + + #[inline] + fn has_zero_specificity(&self) -> bool { + matches!(*self, NonTSPseudoClass::MozNativeAnonymousNoSpecificity) + } } /// The dummy struct we use to implement our selector parsing. diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index bf4da090646..e0079921072 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -2130,7 +2130,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } true }, - NonTSPseudoClass::MozNativeAnonymous => self.is_in_native_anonymous_subtree(), + NonTSPseudoClass::MozNativeAnonymous | + NonTSPseudoClass::MozNativeAnonymousNoSpecificity => self.is_in_native_anonymous_subtree(), NonTSPseudoClass::MozUseShadowTreeRoot => self.is_root_of_use_element_shadow_tree(), NonTSPseudoClass::MozTableBorderNonzero => unsafe { bindings::Gecko_IsTableBorderNonzero(self.0) diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 977a6c59a85..942dcdba1bb 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -309,6 +309,11 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass { NonTSPseudoClass::Active | NonTSPseudoClass::Hover | NonTSPseudoClass::Focus ) } + + #[inline] + fn has_zero_specificity(&self) -> bool { + false + } } impl ToCss for NonTSPseudoClass {