style: Use an Atom to represent Direction values in pseudo-classes.

Differential Revision: https://phabricator.services.mozilla.com/D4730
This commit is contained in:
Cameron McCormack 2018-08-31 15:18:59 +10:00 committed by Emilio Cobos Álvarez
parent 1e6aa62c6f
commit 4ee3b56d54
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
5 changed files with 54 additions and 58 deletions

View file

@ -54,14 +54,14 @@ macro_rules! pseudo_class_name {
$s_name(PseudoClassStringArg), $s_name(PseudoClassStringArg),
)* )*
/// The `:dir` pseudo-class. /// The `:dir` pseudo-class.
Dir(Box<Direction>), Dir(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
/// should use SimpleSelector instead /// should use SimpleSelector instead
MozAny(ThinBoxedSlice<Selector<SelectorImpl>>), MozAny(ThinBoxedSlice<Selector<SelectorImpl>>),
/// The non-standard `:-moz-locale-dir` pseudo-class. /// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Box<Direction>), MozLocaleDir(Direction),
} }
} }
} }
@ -411,14 +411,10 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into()) NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into())
}, )* }, )*
"-moz-locale-dir" => { "-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir( NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?)
Box::new(Direction::parse(parser)?)
)
}, },
"dir" => { "dir" => {
NonTSPseudoClass::Dir( NonTSPseudoClass::Dir(Direction::parse(parser)?)
Box::new(Direction::parse(parser)?)
)
}, },
"-moz-any" => { "-moz-any" => {
NonTSPseudoClass::MozAny( NonTSPseudoClass::MozAny(

View file

@ -69,7 +69,7 @@ use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::animated_properties::{AnimationValue, AnimationValueMap}; use properties::animated_properties::{AnimationValue, AnimationValueMap};
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, Direction, PseudoClassStringArg}; use selector_parser::{AttrValue, HorizontalDirection, PseudoClassStringArg};
use selectors::{Element, OpaqueElement}; use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -2237,24 +2237,22 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozLocaleDir(ref dir) => { NonTSPseudoClass::MozLocaleDir(ref dir) => {
let state_bit = DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE; let state_bit = DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE;
if context.extra_data.document_state.intersects(state_bit) { if context.extra_data.document_state.intersects(state_bit) {
// NOTE(emilio): We could still return false for // NOTE(emilio): We could still return false for values
// Direction::Other(..), but we don't bother. // other than "ltr" and "rtl", but we don't bother.
return !context.in_negation(); return !context.in_negation();
} }
let doc_is_rtl = self.document_state().contains(state_bit); let doc_is_rtl = self.document_state().contains(state_bit);
match **dir { match dir.as_horizontal_direction() {
Direction::Ltr => !doc_is_rtl, Some(HorizontalDirection::Ltr) => !doc_is_rtl,
Direction::Rtl => doc_is_rtl, Some(HorizontalDirection::Rtl) => doc_is_rtl,
Direction::Other(..) => false, None => false,
} }
}, },
NonTSPseudoClass::Dir(ref dir) => match **dir { NonTSPseudoClass::Dir(ref dir) => {
Direction::Ltr => self.state().intersects(ElementState::IN_LTR_STATE), self.state().intersects(dir.element_state())
Direction::Rtl => self.state().intersects(ElementState::IN_RTL_STATE), }
Direction::Other(..) => false,
},
} }
} }

View file

@ -188,8 +188,7 @@ where
// 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 dir) => { NonTSPseudoClass::Dir(ref dir) => {
use invalidation::element::invalidation_map::dir_selector_to_state; let selector_flag = dir.element_state();
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,8 +10,6 @@ use element_state::{DocumentState, 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,20 +17,6 @@ use selectors::parser::{Selector, SelectorIter, Visit};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use smallvec::SmallVec; use smallvec::SmallVec;
#[cfg(feature = "gecko")]
/// Gets the element state relevant to the given `:dir` pseudo-class selector.
pub fn dir_selector_to_state(dir: &Direction) -> ElementState {
match *dir {
Direction::Ltr => ElementState::IN_LTR_STATE,
Direction::Rtl => ElementState::IN_RTL_STATE,
Direction::Other(_) => {
// :dir(something-random) is a valid selector, but shouldn't
// match anything.
ElementState::empty()
},
}
}
/// Mapping between (partial) CompoundSelectors (and the combinator to their /// Mapping between (partial) CompoundSelectors (and the combinator to their
/// right) and the states and attributes they depend on. /// right) and the states and attributes they depend on.
/// ///
@ -382,7 +366,7 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
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 dir) => dir_selector_to_state(dir), NonTSPseudoClass::Dir(ref dir) => dir.element_state(),
_ => pc.state_flag(), _ => pc.state_flag(),
}; };
*self.document_state |= pc.document_state_flag(); *self.document_state |= pc.document_state_flag();

View file

@ -7,10 +7,13 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use cssparser::{Parser as CssParser, ParserInput}; use cssparser::{Parser as CssParser, ParserInput};
use element_state::ElementState;
use selectors::parser::SelectorList; use selectors::parser::SelectorList;
use std::fmt::{self, Debug, Write}; use std::fmt::{self, Debug, Write};
use string_cache::Atom;
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, ParseError, ToCss};
use stylesheets::{Namespaces, Origin, UrlExtraData}; use stylesheets::{Namespaces, Origin, UrlExtraData};
use values::serialize_atom_identifier;
/// 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
/// selector parser implementation. /// selector parser implementation.
@ -172,27 +175,49 @@ impl<T> PerPseudoElementMap<T> {
} }
/// Values for the :dir() pseudo class /// Values for the :dir() pseudo class
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub enum Direction {
/// left-to-right semantic directionality
Ltr,
/// right-to-left semantic directionality
Rtl,
/// Some other provided directionality value
/// ///
/// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass. /// "ltr" and "rtl" values are normalized to lowercase.
Other(Box<str>), #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub struct Direction(pub Atom);
/// Horizontal values for the :dir() pseudo class
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum HorizontalDirection {
/// :dir(ltr)
Ltr,
/// :dir(rtl)
Rtl,
} }
impl Direction { impl Direction {
/// Parse a direction value. /// Parse a direction value.
pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> { pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> {
let ident = parser.expect_ident()?; let ident = parser.expect_ident()?;
Ok(match_ignore_ascii_case! { &ident, Ok(Direction(match_ignore_ascii_case! { &ident,
"rtl" => Direction::Rtl, "rtl" => atom!("rtl"),
"ltr" => Direction::Ltr, "ltr" => atom!("ltr"),
_ => Direction::Other(Box::from(ident.as_ref())), _ => Atom::from(ident.as_ref()),
}) }))
}
/// Convert this Direction into a HorizontalDirection, if applicable
pub fn as_horizontal_direction(&self) -> Option<HorizontalDirection> {
if self.0 == atom!("ltr") {
Some(HorizontalDirection::Ltr)
} else if self.0 == atom!("rtl") {
Some(HorizontalDirection::Rtl)
} else {
None
}
}
/// Gets the element state relevant to this :dir() selector.
pub fn element_state(&self) -> ElementState {
match self.as_horizontal_direction() {
Some(HorizontalDirection::Ltr) => ElementState::IN_LTR_STATE,
Some(HorizontalDirection::Rtl) => ElementState::IN_RTL_STATE,
None => ElementState::empty(),
}
} }
} }
@ -201,12 +226,6 @@ impl ToCss for Direction {
where where
W: Write, W: Write,
{ {
let dir_str = match *self { serialize_atom_identifier(&self.0, dest)
Direction::Rtl => "rtl",
Direction::Ltr => "ltr",
// FIXME: This should be escaped as an identifier; see #19231
Direction::Other(ref other) => other,
};
dest.write_str(dir_str)
} }
} }