style: :dir() pseudo class now represented by enum

Fixes #19195
This commit is contained in:
Michael Wilson 2017-11-10 00:00:48 -08:00
parent e6b05fa204
commit 10f3ef42bb
7 changed files with 73 additions and 27 deletions

View file

@ -10,6 +10,7 @@
pub enum PseudoClass { pub enum PseudoClass {
Bare, Bare,
String(Box<[u16]>), String(Box<[u16]>),
Dir(Box<()>),
MozAny(Box<[()]>), MozAny(Box<[()]>),
} }

View file

@ -120,7 +120,6 @@ macro_rules! apply_non_ts_list {
], ],
keyword: [ keyword: [
("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, _), ("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, _),
("dir", Dir, dir, _, _),
] ]
} }
} }

View file

@ -9,13 +9,13 @@ use element_state::{DocumentState, ElementState};
use gecko_bindings::structs::CSSPseudoClassType; use gecko_bindings::structs::CSSPseudoClassType;
use gecko_bindings::structs::RawServoSelectorList; use gecko_bindings::structs::RawServoSelectorList;
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use selector_parser::{SelectorParser, PseudoElementCascadeType}; use selector_parser::{Direction, SelectorParser, PseudoElementCascadeType};
use selectors::SelectorList; use selectors::SelectorList;
use selectors::parser::{Selector, SelectorMethods, SelectorParseErrorKind}; use selectors::parser::{Selector, SelectorMethods, SelectorParseErrorKind};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use std::fmt; use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind, ToCss as ToCss_};
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT}; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT};
pub use gecko::snapshot::SnapshotMap; pub use gecko::snapshot::SnapshotMap;
@ -53,6 +53,8 @@ macro_rules! pseudo_class_name {
#[doc = $k_css] #[doc = $k_css]
$k_name(Box<[u16]>), $k_name(Box<[u16]>),
)* )*
/// The `:dir` pseudo-class.
Dir(Box<Direction>),
/// The non-standard `:-moz-any` pseudo-class. /// The non-standard `:-moz-any` pseudo-class.
/// ///
/// TODO(emilio): We disallow combinators and pseudos here, so we /// TODO(emilio): We disallow combinators and pseudos here, so we
@ -92,6 +94,12 @@ impl ToCss for NonTSPseudoClass {
dest.write_str(&value)?; dest.write_str(&value)?;
return dest.write_char(')') return dest.write_char(')')
}, )* }, )*
NonTSPseudoClass::Dir(ref dir) => {
dest.write_str(":dir(")?;
// FIXME: This should be escaped as an identifier; see #19231
(**dir).to_css(dest)?;
return dest.write_char(')')
},
NonTSPseudoClass::MozAny(ref selectors) => { NonTSPseudoClass::MozAny(ref selectors) => {
dest.write_str(":-moz-any(")?; dest.write_str(":-moz-any(")?;
let mut iter = selectors.iter(); let mut iter = selectors.iter();
@ -145,6 +153,7 @@ impl NonTSPseudoClass {
$(NonTSPseudoClass::$name => check_flag!($flags),)* $(NonTSPseudoClass::$name => check_flag!($flags),)*
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)* $(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
$(NonTSPseudoClass::$k_name(..) => check_flag!($k_flags),)* $(NonTSPseudoClass::$k_name(..) => check_flag!($k_flags),)*
NonTSPseudoClass::Dir(_) => false,
NonTSPseudoClass::MozAny(_) => false, NonTSPseudoClass::MozAny(_) => false,
} }
} }
@ -189,6 +198,7 @@ impl NonTSPseudoClass {
$(NonTSPseudoClass::$name => flag!($state),)* $(NonTSPseudoClass::$name => flag!($state),)*
$(NonTSPseudoClass::$s_name(..) => flag!($s_state),)* $(NonTSPseudoClass::$s_name(..) => flag!($s_state),)*
$(NonTSPseudoClass::$k_name(..) => flag!($k_state),)* $(NonTSPseudoClass::$k_name(..) => flag!($k_state),)*
NonTSPseudoClass::Dir(..) => ElementState::empty(),
NonTSPseudoClass::MozAny(..) => ElementState::empty(), NonTSPseudoClass::MozAny(..) => ElementState::empty(),
} }
} }
@ -253,6 +263,7 @@ impl NonTSPseudoClass {
$(NonTSPseudoClass::$name => gecko_type!($gecko_type),)* $(NonTSPseudoClass::$name => gecko_type!($gecko_type),)*
$(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)* $(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)*
$(NonTSPseudoClass::$k_name(..) => gecko_type!($k_gecko_type),)* $(NonTSPseudoClass::$k_name(..) => gecko_type!($k_gecko_type),)*
NonTSPseudoClass::Dir(_) => gecko_type!(dir),
NonTSPseudoClass::MozAny(_) => gecko_type!(any), NonTSPseudoClass::MozAny(_) => gecko_type!(any),
} }
} }
@ -360,6 +371,17 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
.chain(Some(0u16)).collect(); .chain(Some(0u16)).collect();
NonTSPseudoClass::$k_name(utf16.into_boxed_slice()) NonTSPseudoClass::$k_name(utf16.into_boxed_slice())
}, )* }, )*
"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))
},
"-moz-any" => { "-moz-any" => {
let selectors = parser.parse_comma_separated(|input| { let selectors = parser.parse_comma_separated(|input| {
Selector::parse(self, input) Selector::parse(self, input)

View file

@ -74,7 +74,7 @@ use properties::animated_properties::{AnimationValue, AnimationValueMap};
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
use properties::style_structs::Font; use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel; use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::{AttrValue, PseudoClassStringArg}; use selector_parser::{AttrValue, Direction, PseudoClassStringArg};
use selectors::{Element, OpaqueElement}; use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext}; use selectors::matching::{ElementSelectorFlags, MatchingContext};
@ -2068,8 +2068,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Lang(ref lang_arg) => { NonTSPseudoClass::Lang(ref lang_arg) => {
self.match_element_lang(None, lang_arg) self.match_element_lang(None, lang_arg)
} }
NonTSPseudoClass::MozLocaleDir(ref s) | NonTSPseudoClass::MozLocaleDir(ref s) => {
NonTSPseudoClass::Dir(ref s) => {
unsafe { unsafe {
Gecko_MatchStringArgPseudo( Gecko_MatchStringArgPseudo(
self.0, self.0,
@ -2078,6 +2077,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
) )
} }
} }
NonTSPseudoClass::Dir(ref dir) => {
match **dir {
Direction::Ltr => self.get_state().intersects(ElementState::IN_LTR_STATE),
Direction::Rtl => self.get_state().intersects(ElementState::IN_RTL_STATE),
Direction::Other(..) => false,
}
}
} }
} }

View file

@ -182,9 +182,9 @@ impl<'a, E> Element for ElementWrapper<'a, E>
// FIXME(bz): How can I set this up so once Servo adds :dir() // FIXME(bz): How can I set this up so once Servo adds :dir()
// support we don't forget to update this code? // support we don't forget to update this code?
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
NonTSPseudoClass::Dir(ref s) => { NonTSPseudoClass::Dir(ref dir) => {
use invalidation::element::invalidation_map::dir_selector_to_state; use invalidation::element::invalidation_map::dir_selector_to_state;
let selector_flag = dir_selector_to_state(s); let selector_flag = dir_selector_to_state(dir);
if selector_flag.is_empty() { if selector_flag.is_empty() {
// :dir() with some random argument; does not match. // :dir() with some random argument; does not match.
return false; return false;

View file

@ -10,6 +10,8 @@ use element_state::ElementState;
use fallible::FallibleVec; use fallible::FallibleVec;
use hashglobe::FailedAllocationError; use hashglobe::FailedAllocationError;
use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry}; use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry};
#[cfg(feature = "gecko")]
use selector_parser::Direction;
use selector_parser::SelectorImpl; use selector_parser::SelectorImpl;
use selectors::attr::NamespaceConstraint; use selectors::attr::NamespaceConstraint;
use selectors::parser::{Combinator, Component}; use selectors::parser::{Combinator, Component};
@ -19,21 +21,15 @@ use smallvec::SmallVec;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
/// Gets the element state relevant to the given `:dir` pseudo-class selector. /// Gets the element state relevant to the given `:dir` pseudo-class selector.
pub fn dir_selector_to_state(s: &[u16]) -> ElementState { pub fn dir_selector_to_state(dir: &Direction) -> ElementState {
use element_state::ElementState; match *dir {
Direction::Ltr => ElementState::IN_LTR_STATE,
// Jump through some hoops to deal with our Box<[u16]> thing. Direction::Rtl => ElementState::IN_RTL_STATE,
const LTR: [u16; 4] = [b'l' as u16, b't' as u16, b'r' as u16, 0]; Direction::Other(_) => {
const RTL: [u16; 4] = [b'r' as u16, b't' as u16, b'l' as u16, 0];
if LTR == *s {
ElementState::IN_LTR_STATE
} else if RTL == *s {
ElementState::IN_RTL_STATE
} else {
// :dir(something-random) is a valid selector, but shouldn't // :dir(something-random) is a valid selector, but shouldn't
// match anything. // match anything.
ElementState::empty() ElementState::empty()
},
} }
} }
@ -342,8 +338,8 @@ impl SelectorVisitor for CompoundSelectorDependencyCollector {
self.other_attributes |= pc.is_attr_based(); self.other_attributes |= pc.is_attr_based();
self.state |= match *pc { self.state |= match *pc {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
NonTSPseudoClass::Dir(ref s) => { NonTSPseudoClass::Dir(ref dir) => {
dir_selector_to_state(s) dir_selector_to_state(dir)
} }
_ => pc.state_flag(), _ => pc.state_flag(),
}; };

View file

@ -8,8 +8,8 @@
use cssparser::{Parser as CssParser, ParserInput}; use cssparser::{Parser as CssParser, ParserInput};
use selectors::parser::SelectorList; use selectors::parser::SelectorList;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug, Write};
use style_traits::ParseError; use style_traits::{ParseError, ToCss};
use stylesheets::{Origin, Namespaces, UrlExtraData}; use stylesheets::{Origin, Namespaces, UrlExtraData};
/// A convenient alias for the type that represents an attribute value used for /// A convenient alias for the type that represents an attribute value used for
@ -173,3 +173,25 @@ impl<T> PerPseudoElementMap<T> {
self.entries.iter() self.entries.iter()
} }
} }
/// Values for the :dir() pseudo class
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Direction {
/// left-to-right semantic directionality
Ltr,
/// right-to-left semantic directionality
Rtl,
/// Some other provided directionality value
Other(Box<str>),
}
impl ToCss for Direction {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write {
let dir_str = match *self {
Direction::Rtl => "rtl",
Direction::Ltr => "ltr",
Direction::Other(ref other) => other,
};
dest.write_str(dir_str)
}
}