aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/gecko/selector_parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/style/gecko/selector_parser.rs')
-rw-r--r--components/style/gecko/selector_parser.rs127
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();