mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
style: Add simple parsing and matching support for :has
Parsing is behind a config value `layout.css.has-selectors.enabled`. This change does not support p:has(> a) combinators, but will handle them gracefully, just not matching on them. Differential Revision: https://phabricator.services.mozilla.com/D149515
This commit is contained in:
parent
dcdf9f33d5
commit
3d0cf4dbf9
8 changed files with 85 additions and 10 deletions
|
@ -261,6 +261,11 @@ pub trait Parser<'i> {
|
|||
false
|
||||
}
|
||||
|
||||
/// Whether to parse the :has pseudo-class.
|
||||
fn parse_has(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Whether the given function name is an alias for the `:is()` function.
|
||||
fn is_is_alias(&self, _name: &str) -> bool {
|
||||
false
|
||||
|
@ -1116,6 +1121,12 @@ pub enum Component<Impl: SelectorImpl> {
|
|||
///
|
||||
/// Same comment as above re. the argument.
|
||||
Is(Box<[Selector<Impl>]>),
|
||||
/// The `:has` pseudo-class.
|
||||
///
|
||||
/// https://drafts.csswg.org/selectors/#has-pseudo
|
||||
///
|
||||
/// Same comment as above re. the argument.
|
||||
Has(Box<[Selector<Impl>]>),
|
||||
/// An implementation-dependent pseudo-element selector.
|
||||
PseudoElement(#[cfg_attr(feature = "shmem", shmem(field_bound))] Impl::PseudoElement),
|
||||
|
||||
|
@ -1589,11 +1600,12 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
|
|||
write_affine(dest, a, b)?;
|
||||
dest.write_char(')')
|
||||
},
|
||||
Is(ref list) | Where(ref list) | Negation(ref list) => {
|
||||
Is(ref list) | Where(ref list) | Negation(ref list) | Has(ref list) => {
|
||||
match *self {
|
||||
Where(..) => dest.write_str(":where(")?,
|
||||
Is(..) => dest.write_str(":is(")?,
|
||||
Negation(..) => dest.write_str(":not(")?,
|
||||
Has(..) => dest.write_str(":has(")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
serialize_selector_list(list.iter(), dest)?;
|
||||
|
@ -2253,7 +2265,7 @@ where
|
|||
Ok(empty)
|
||||
}
|
||||
|
||||
fn parse_is_or_where<'i, 't, P, Impl>(
|
||||
fn parse_is_where_has<'i, 't, P, Impl>(
|
||||
parser: &P,
|
||||
input: &mut CssParser<'i, 't>,
|
||||
state: SelectorParsingState,
|
||||
|
@ -2295,8 +2307,9 @@ where
|
|||
"nth-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthOfType),
|
||||
"nth-last-child" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastChild),
|
||||
"nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastOfType),
|
||||
"is" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Is),
|
||||
"where" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Where),
|
||||
"is" if parser.parse_is_and_where() => return parse_is_where_has(parser, input, state, Component::Is),
|
||||
"where" if parser.parse_is_and_where() => return parse_is_where_has(parser, input, state, Component::Where),
|
||||
"has" if parser.parse_has() => return parse_is_where_has(parser, input, state, Component::Has),
|
||||
"host" => {
|
||||
if !state.allows_tree_structural_pseudo_classes() {
|
||||
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
||||
|
@ -2310,7 +2323,7 @@ where
|
|||
}
|
||||
|
||||
if parser.parse_is_and_where() && parser.is_is_alias(&name) {
|
||||
return parse_is_or_where(parser, input, state, Component::Is);
|
||||
return parse_is_where_has(parser, input, state, Component::Is);
|
||||
}
|
||||
|
||||
if !state.allows_custom_functional_pseudo_classes() {
|
||||
|
@ -2684,6 +2697,10 @@ pub mod tests {
|
|||
true
|
||||
}
|
||||
|
||||
fn parse_has(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_part(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue