mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
parent
e6b05fa204
commit
10f3ef42bb
7 changed files with 73 additions and 27 deletions
|
@ -10,6 +10,7 @@
|
||||||
pub enum PseudoClass {
|
pub enum PseudoClass {
|
||||||
Bare,
|
Bare,
|
||||||
String(Box<[u16]>),
|
String(Box<[u16]>),
|
||||||
|
Dir(Box<()>),
|
||||||
MozAny(Box<[()]>),
|
MozAny(Box<[()]>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, _, _),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue