diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index b5c2c4cd5ba..0a5fe00be02 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -116,9 +116,6 @@ macro_rules! apply_non_ts_list { ], string: [ ("lang", Lang, lang, _, _), - ], - keyword: [ - ("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, _), ] } } diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 72da9346a36..b70054fe84a 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -36,9 +36,8 @@ pub type PseudoClassStringArg = Box<[u16]>; macro_rules! pseudo_class_name { (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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { - #[doc = "Our representation of a non tree-structural pseudo-class."] + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, PartialEq)] pub enum NonTSPseudoClass { $( @@ -49,10 +48,6 @@ macro_rules! pseudo_class_name { #[doc = $s_css] $s_name(PseudoClassStringArg), )* - $( - #[doc = $k_css] - $k_name(Box<[u16]>), - )* /// The `:dir` pseudo-class. Dir(Box), /// The non-standard `:-moz-any` pseudo-class. @@ -60,6 +55,8 @@ macro_rules! pseudo_class_name { /// TODO(emilio): We disallow combinators and pseudos here, so we /// should use SimpleSelector instead MozAny(Box<[Selector]>), + /// The non-standard `:-moz-locale-dir` pseudo-class. + MozLocaleDir(Box), } } } @@ -71,8 +68,7 @@ impl ToCss for NonTSPseudoClass { use fmt::Write; macro_rules! pseudo_class_serialize { (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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* $(NonTSPseudoClass::$s_name(ref s) => { @@ -87,16 +83,14 @@ impl ToCss for NonTSPseudoClass { } return dest.write_str(")") }, )* - $(NonTSPseudoClass::$k_name(ref s) => { - // Don't include the terminating nul. - let value = String::from_utf16(&s[..s.len() - 1]).unwrap(); - dest.write_str(concat!(":", $k_css, "("))?; - dest.write_str(&value)?; + NonTSPseudoClass::MozLocaleDir(ref dir) => { + dest.write_str(":-moz-locale-dir(")?; + dir.to_css(dest)?; return dest.write_char(')') - }, )* + }, NonTSPseudoClass::Dir(ref dir) => { dest.write_str(":dir(")?; - (**dir).to_css(dest)?; + dir.to_css(dest)?; return dest.write_char(')') }, NonTSPseudoClass::MozAny(ref selectors) => { @@ -146,13 +140,14 @@ impl NonTSPseudoClass { } macro_rules! pseudo_class_check_is_enabled_in { (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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => check_flag!($flags),)* $(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)* - $(NonTSPseudoClass::$k_name(..) => check_flag!($k_flags),)* - NonTSPseudoClass::Dir(_) => false, + // TODO(emilio): Maybe -moz-locale-dir shouldn't be + // content-exposed. + NonTSPseudoClass::MozLocaleDir(_) | + NonTSPseudoClass::Dir(_) | NonTSPseudoClass::MozAny(_) => false, } } @@ -191,13 +186,12 @@ impl NonTSPseudoClass { } macro_rules! pseudo_class_state { (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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => flag!($state),)* $(NonTSPseudoClass::$s_name(..) => flag!($s_state),)* - $(NonTSPseudoClass::$k_name(..) => flag!($k_state),)* - NonTSPseudoClass::Dir(..) => ElementState::empty(), + NonTSPseudoClass::Dir(..) | + NonTSPseudoClass::MozLocaleDir(..) | NonTSPseudoClass::MozAny(..) => ElementState::empty(), } } @@ -256,12 +250,11 @@ impl NonTSPseudoClass { } macro_rules! pseudo_class_geckotype { (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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => gecko_type!($gecko_type),)* $(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)* - $(NonTSPseudoClass::$k_name(..) => gecko_type!($k_gecko_type),)* + NonTSPseudoClass::MozLocaleDir(_) => gecko_type!(mozLocaleDir), NonTSPseudoClass::Dir(_) => gecko_type!(dir), NonTSPseudoClass::MozAny(_) => gecko_type!(any), } @@ -353,8 +346,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { ) -> 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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_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( @@ -378,8 +370,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { ) -> Result> { macro_rules! pseudo_class_string_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),)*], - keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($s_css => { let name = parser.expect_ident_or_string()?; @@ -388,23 +379,15 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { let utf16: Vec = name.encode_utf16().chain(Some(0u16)).collect(); NonTSPseudoClass::$s_name(utf16.into_boxed_slice()) }, )* - $($k_css => { - let name = parser.expect_ident()?; - // Convert to ASCII-lowercase nul-terminated UTF-16 string. - let utf16: Vec = name.encode_utf16().map(utf16_to_ascii_lowercase) - .chain(Some(0u16)).collect(); - NonTSPseudoClass::$k_name(utf16.into_boxed_slice()) - }, )* + "-moz-locale-dir" => { + NonTSPseudoClass::MozLocaleDir( + Box::new(Direction::parse(parser)?) + ) + }, "dir" => { - let name: &str = parser.expect_ident()?; - let direction = match_ignore_ascii_case! { name, - "rtl" => Direction::Rtl, - "ltr" => Direction::Ltr, - _ => { - Direction::Other(Box::from(name)) - }, - }; - NonTSPseudoClass::Dir(Box::new(direction)) + NonTSPseudoClass::Dir( + Box::new(Direction::parse(parser)?) + ) }, "-moz-any" => { NonTSPseudoClass::MozAny( @@ -496,13 +479,6 @@ impl SelectorImpl { } } -fn utf16_to_ascii_lowercase(unit: u16) -> u16 { - match unit { - 65...90 => unit + 32, // A-Z => a-z - _ => unit - } -} - unsafe impl HasFFI for SelectorList { type FFIType = RawServoSelectorList; } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 687b95fde82..56ad17e6009 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -46,7 +46,6 @@ use gecko_bindings::bindings::Gecko_GetUnvisitedLinkAttrDeclarationBlock; use gecko_bindings::bindings::Gecko_GetVisitedLinkAttrDeclarationBlock; use gecko_bindings::bindings::Gecko_IsSignificantChild; use gecko_bindings::bindings::Gecko_MatchLang; -use gecko_bindings::bindings::Gecko_MatchStringArgPseudo; use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr; use gecko_bindings::bindings::Gecko_UpdateAnimations; use gecko_bindings::structs; @@ -2111,7 +2110,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { self.get_document_theme() == DocumentTheme::Doc_Theme_Dark } NonTSPseudoClass::MozWindowInactive => { - self.document_state().contains(DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE) + self.document_state() + .contains(DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE) } NonTSPseudoClass::MozPlaceholder => false, NonTSPseudoClass::MozAny(ref sels) => { @@ -2125,13 +2125,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::Lang(ref lang_arg) => { self.match_element_lang(None, lang_arg) } - NonTSPseudoClass::MozLocaleDir(ref s) => { - unsafe { - Gecko_MatchStringArgPseudo( - self.0, - pseudo_class.to_gecko_pseudoclasstype().unwrap(), - s.as_ptr(), - ) + NonTSPseudoClass::MozLocaleDir(ref dir) => { + let doc_is_rtl = + self.document_state() + .contains(DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE); + + match **dir { + Direction::Ltr => !doc_is_rtl, + Direction::Rtl => doc_is_rtl, + Direction::Other(..) => false, } } NonTSPseudoClass::Dir(ref dir) => { diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index b4870557cc2..54978d284b7 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -183,9 +183,23 @@ pub enum Direction { /// right-to-left semantic directionality Rtl, /// Some other provided directionality value + /// + /// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass. Other(Box), } +impl Direction { + /// Parse a direction value. + pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result> { + let ident = parser.expect_ident()?; + Ok(match_ignore_ascii_case! { &ident, + "rtl" => Direction::Rtl, + "ltr" => Direction::Ltr, + _ => Direction::Other(Box::from(ident.as_ref())), + }) + } +} + impl ToCss for Direction { fn to_css(&self, dest: &mut W) -> fmt::Result where W: Write { let dir_str = match *self {