diff options
Diffstat (limited to 'components/style/gecko/selector_parser.rs')
-rw-r--r-- | components/style/gecko/selector_parser.rs | 127 |
1 files changed, 49 insertions, 78 deletions
diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index fa514835e8c..2365356f2f8 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -17,9 +17,11 @@ use selectors::parser::{SelectorParseErrorKind, Visit}; use selectors::parser::{self as selector_parser, Selector}; use selectors::visitor::SelectorVisitor; use std::fmt; +use str::starts_with_ignore_ascii_case; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; use thin_slice::ThinBoxedSlice; +use values::serialize_atom_identifier; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT}; pub use gecko::snapshot::SnapshotMap; @@ -35,12 +37,11 @@ bitflags! { } } -/// The type used for storing pseudo-class string arguments. -pub type PseudoClassStringArg = ThinBoxedSlice<u16>; +/// The type used to store the language argument to the `:lang` pseudo-class. +pub type Lang = Atom; 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),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub enum NonTSPseudoClass { @@ -48,19 +49,17 @@ macro_rules! pseudo_class_name { #[doc = $css] $name, )* - $( - #[doc = $s_css] - $s_name(PseudoClassStringArg), - )* + /// The `:lang` pseudo-class. + Lang(Lang), /// The `:dir` pseudo-class. - Dir(Box<Direction>), + Dir(Direction), /// The non-standard `:-moz-any` pseudo-class. /// /// TODO(emilio): We disallow combinators and pseudos here, so we /// should use SimpleSelector instead MozAny(ThinBoxedSlice<Selector<SelectorImpl>>), /// The non-standard `:-moz-locale-dir` pseudo-class. - MozLocaleDir(Box<Direction>), + MozLocaleDir(Direction), } } } @@ -71,25 +70,15 @@ impl ToCss for NonTSPseudoClass { where W: fmt::Write, { - use cssparser::CssStringWriter; - use std::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),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* - $(NonTSPseudoClass::$s_name(ref s) => { - dest.write_str(concat!(":", $s_css, "("))?; - { - // FIXME(emilio): Avoid the extra allocation! - let mut css = CssStringWriter::new(dest); - - // Discount the null char in the end from the - // string. - css.write_str(&String::from_utf16(&s[..s.len() - 1]).unwrap())?; - } - return dest.write_str(")") - }, )* + NonTSPseudoClass::Lang(ref s) => { + dest.write_str(":lang(")?; + serialize_atom_identifier(s, dest)?; + return dest.write_char(')'); + }, NonTSPseudoClass::MozLocaleDir(ref dir) => { dest.write_str(":-moz-locale-dir(")?; dir.to_css(&mut CssWriter::new(dest))?; @@ -109,7 +98,7 @@ impl ToCss for NonTSPseudoClass { dest.write_str(", ")?; selector.to_css(dest)?; } - return dest.write_str(")") + return dest.write_char(')') } } } @@ -144,8 +133,7 @@ impl NonTSPseudoClass { /// in a particular state. pub fn parse_non_functional(name: &str) -> Option<Self> { 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),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => Some(NonTSPseudoClass::$name),)* _ => None, @@ -166,12 +154,11 @@ 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),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => check_flag!($flags),)* - $(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)* NonTSPseudoClass::MozLocaleDir(_) | + NonTSPseudoClass::Lang(_) | NonTSPseudoClass::Dir(_) | NonTSPseudoClass::MozAny(_) => false, } @@ -194,9 +181,8 @@ impl NonTSPseudoClass { }, // Otherwise, a pseudo-class is enabled in content when it // doesn't have any enabled flag. - _ => !self.has_any_flag( - NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, - ), + _ => !self + .has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), } } @@ -221,13 +207,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),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => flag!($state),)* - $(NonTSPseudoClass::$s_name(..) => flag!($s_state),)* NonTSPseudoClass::Dir(..) | NonTSPseudoClass::MozLocaleDir(..) | + NonTSPseudoClass::Lang(..) | NonTSPseudoClass::MozAny(..) => ElementState::empty(), } } @@ -247,8 +232,7 @@ impl NonTSPseudoClass { /// Returns true if the given pseudoclass should trigger style sharing cache /// revalidation. pub fn needs_cache_revalidation(&self) -> bool { - self.state_flag().is_empty() && - !matches!(*self, + self.state_flag().is_empty() && !matches!(*self, // :-moz-any is handled by the revalidation visitor walking // the things inside it; it does not need to cause // revalidation on its own. @@ -282,7 +266,8 @@ impl NonTSPseudoClass { pub fn is_attr_based(&self) -> bool { matches!( *self, - NonTSPseudoClass::MozTableBorderNonzero | NonTSPseudoClass::MozBrowserFrame | + NonTSPseudoClass::MozTableBorderNonzero | + NonTSPseudoClass::MozBrowserFrame | NonTSPseudoClass::Lang(..) ) } @@ -398,42 +383,29 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { name: CowRcStr<'i>, parser: &mut Parser<'i, 't>, ) -> Result<NonTSPseudoClass, ParseError<'i>> { - 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),)*]) => { - match_ignore_ascii_case! { &name, - $($s_css => { - let name = parser.expect_ident_or_string()?; - // convert to null terminated utf16 string - // since that's what Gecko deals with - let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect(); - NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into()) - }, )* - "-moz-locale-dir" => { - NonTSPseudoClass::MozLocaleDir( - Box::new(Direction::parse(parser)?) - ) - }, - "dir" => { - NonTSPseudoClass::Dir( - Box::new(Direction::parse(parser)?) - ) - }, - "-moz-any" => { - NonTSPseudoClass::MozAny( - selector_parser::parse_compound_selector_list( - self, - parser, - )?.into() - ) - } - _ => return Err(parser.new_custom_error( - SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) - )) - } + let pseudo_class = match_ignore_ascii_case! { &name, + "lang" => { + let name = parser.expect_ident_or_string()?; + NonTSPseudoClass::Lang(Atom::from(name.as_ref())) + }, + "-moz-locale-dir" => { + NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?) + }, + "dir" => { + NonTSPseudoClass::Dir(Direction::parse(parser)?) + }, + "-moz-any" => { + NonTSPseudoClass::MozAny( + selector_parser::parse_compound_selector_list( + self, + parser, + )?.into() + ) } - } - let pseudo_class = apply_non_ts_list!(pseudo_class_string_parse); + _ => return Err(parser.new_custom_error( + SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) + )) + }; if self.is_pseudo_class_enabled(&pseudo_class) { Ok(pseudo_class) } else { @@ -468,8 +440,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { name: CowRcStr<'i>, parser: &mut Parser<'i, 't>, ) -> Result<PseudoElement, ParseError<'i>> { - // FIXME: -moz-tree check should probably be ascii-case-insensitive. - if name.starts_with("-moz-tree-") { + if starts_with_ignore_ascii_case(&name, "-moz-tree-") { // Tree pseudo-elements can have zero or more arguments, separated // by either comma or space. let mut args = Vec::new(); |