mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Use an Atom to represent Direction values in pseudo-classes.
Differential Revision: https://phabricator.services.mozilla.com/D4730
This commit is contained in:
parent
1e6aa62c6f
commit
4ee3b56d54
5 changed files with 54 additions and 58 deletions
|
@ -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(
|
||||||
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
///
|
||||||
|
/// "ltr" and "rtl" values are normalized to lowercase.
|
||||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||||
pub enum Direction {
|
pub struct Direction(pub Atom);
|
||||||
/// left-to-right semantic directionality
|
|
||||||
|
/// Horizontal values for the :dir() pseudo class
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum HorizontalDirection {
|
||||||
|
/// :dir(ltr)
|
||||||
Ltr,
|
Ltr,
|
||||||
/// right-to-left semantic directionality
|
/// :dir(rtl)
|
||||||
Rtl,
|
Rtl,
|
||||||
/// Some other provided directionality value
|
|
||||||
///
|
|
||||||
/// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass.
|
|
||||||
Other(Box<str>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue