mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
style: Accept a comma-separated list of language codes in the :lang() pseudo
This is the other extension to the :lang() pseudo-class in Selectors-4. (Also supported in Safari.) Depends on D174999 Differential Revision: https://phabricator.services.mozilla.com/D175000
This commit is contained in:
parent
13e2d10474
commit
a2df8f7ea5
2 changed files with 48 additions and 15 deletions
|
@ -19,7 +19,7 @@ use dom::{DocumentState, ElementState};
|
|||
use selectors::parser::SelectorParseErrorKind;
|
||||
use selectors::SelectorList;
|
||||
use std::fmt;
|
||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_};
|
||||
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError, StyleParseErrorKind, ToCss as ToCss_};
|
||||
|
||||
pub use crate::gecko::pseudo_element::{
|
||||
PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT,
|
||||
|
@ -38,7 +38,13 @@ bitflags! {
|
|||
}
|
||||
|
||||
/// The type used to store the language argument to the `:lang` pseudo-class.
|
||||
pub type Lang = AtomIdent;
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
|
||||
pub enum Lang {
|
||||
/// A single language code.
|
||||
Single(AtomIdent),
|
||||
/// A list of language codes.
|
||||
List(Box<Vec<AtomIdent>>),
|
||||
}
|
||||
|
||||
macro_rules! pseudo_class_name {
|
||||
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => {
|
||||
|
@ -60,6 +66,10 @@ macro_rules! pseudo_class_name {
|
|||
}
|
||||
apply_non_ts_list!(pseudo_class_name);
|
||||
|
||||
impl OneOrMoreSeparated for AtomIdent {
|
||||
type S = Comma;
|
||||
}
|
||||
|
||||
impl ToCss for NonTSPseudoClass {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where
|
||||
|
@ -71,7 +81,10 @@ impl ToCss for NonTSPseudoClass {
|
|||
$(NonTSPseudoClass::$name => concat!(":", $css),)*
|
||||
NonTSPseudoClass::Lang(ref s) => {
|
||||
dest.write_str(":lang(")?;
|
||||
cssparser::ToCss::to_css(s, dest)?;
|
||||
match &s {
|
||||
Lang::Single(lang) => cssparser::ToCss::to_css(lang, dest)?,
|
||||
Lang::List(list) => list.to_css(&mut CssWriter::new(dest))?,
|
||||
}
|
||||
return dest.write_char(')');
|
||||
},
|
||||
NonTSPseudoClass::MozLocaleDir(ref dir) => {
|
||||
|
@ -375,8 +388,17 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
|||
) -> Result<NonTSPseudoClass, ParseError<'i>> {
|
||||
let pseudo_class = match_ignore_ascii_case! { &name,
|
||||
"lang" => {
|
||||
let name = parser.expect_ident_or_string()?;
|
||||
NonTSPseudoClass::Lang(Lang::from(name.as_ref()))
|
||||
let result = parser.parse_comma_separated(|input| {
|
||||
Ok(AtomIdent::from(input.expect_ident_or_string()?.as_ref()))
|
||||
})?;
|
||||
if result.is_empty() {
|
||||
return Err(parser.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
if result.len() == 1 {
|
||||
NonTSPseudoClass::Lang(Lang::Single(result[0].clone()))
|
||||
} else {
|
||||
NonTSPseudoClass::Lang(Lang::List(Box::new(result)))
|
||||
}
|
||||
},
|
||||
"-moz-locale-dir" => {
|
||||
NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?)
|
||||
|
|
|
@ -1560,20 +1560,31 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
}
|
||||
|
||||
fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool {
|
||||
// Gecko supports :lang() from CSS Selectors 3, which only accepts a
|
||||
// single language tag, and which performs simple dash-prefix matching
|
||||
// on it.
|
||||
// Gecko supports :lang() from CSS Selectors 4, which accepts a list
|
||||
// of language tags, and does BCP47-style range matching.
|
||||
let override_lang_ptr = match override_lang {
|
||||
Some(Some(ref atom)) => atom.as_ptr(),
|
||||
_ => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
Gecko_MatchLang(
|
||||
self.0,
|
||||
override_lang_ptr,
|
||||
override_lang.is_some(),
|
||||
value.as_slice().as_ptr(),
|
||||
)
|
||||
match value {
|
||||
Lang::Single(lang) => unsafe {
|
||||
Gecko_MatchLang(
|
||||
self.0,
|
||||
override_lang_ptr,
|
||||
override_lang.is_some(),
|
||||
lang.as_slice().as_ptr(),
|
||||
)
|
||||
},
|
||||
Lang::List(list) => {
|
||||
list.iter().any(|lang| unsafe {
|
||||
Gecko_MatchLang(
|
||||
self.0,
|
||||
override_lang_ptr,
|
||||
override_lang.is_some(),
|
||||
lang.as_slice().as_ptr(),
|
||||
)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue