diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index b6e99b2083f..ea0ae646d20 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -133,6 +133,22 @@ impl Visit for NonTSPseudoClass { impl NonTSPseudoClass { + /// Parses the name and returns a non-ts-pseudo-class if succeeds. + /// None otherwise. It doesn't check whether the pseudo-class is enabled + /// in a particular state. + pub fn parse_non_functional(name: &str) -> Option { + macro_rules! pseudo_class_parse { + (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + match_ignore_ascii_case! { &name, + $($css => Some(NonTSPseudoClass::$name),)* + _ => None, + } + } + } + apply_non_ts_list!(pseudo_class_parse) + } + /// Returns true if this pseudo-class has any of the given flags set. fn has_any_flag(&self, flags: NonTSPseudoClassFlag) -> bool { macro_rules! check_flag { @@ -373,23 +389,12 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { location: SourceLocation, name: CowRcStr<'i>, ) -> Result> { - macro_rules! pseudo_class_parse { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { - match_ignore_ascii_case! { &name, - $($css => NonTSPseudoClass::$name,)* - _ => return Err(location.new_custom_error( - SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) - )) - } + if let Some(pseudo_class) = NonTSPseudoClass::parse_non_functional(&name) { + if self.is_pseudo_class_enabled(&pseudo_class) { + return Ok(pseudo_class); } } - let pseudo_class = apply_non_ts_list!(pseudo_class_parse); - if self.is_pseudo_class_enabled(&pseudo_class) { - Ok(pseudo_class) - } else { - Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name))) - } + Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name))) } fn parse_non_ts_functional_pseudo_class<'t>( diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 3381da47e0b..4d5cbc87fdd 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -31,7 +31,7 @@ use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product} use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl}; use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL}; use style::gecko::restyle_damage::GeckoRestyleDamage; -use style::gecko::selector_parser::PseudoElement; +use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement}; use style::gecko::traversal::RecalcStyleOnly; use style::gecko::wrapper::{GeckoElement, GeckoNode}; use style::gecko_bindings::bindings; @@ -5115,3 +5115,14 @@ pub extern "C" fn Servo_ParseCounterStyleDescriptor( result, ).is_ok() } + +#[no_mangle] +pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: *const nsACString) -> u64 { + let name = name.as_ref().unwrap().as_str_unchecked(); + match NonTSPseudoClass::parse_non_functional(name) { + None => 0, + // Ignore :any-link since it contains both visited and unvisited state. + Some(NonTSPseudoClass::AnyLink) => 0, + Some(pseudo_class) => pseudo_class.state_flag().bits(), + } +}