diff options
author | Tiaan Louw <tlouw@mozilla.com> | 2022-06-20 08:53:02 +0000 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-10-02 14:37:19 +0000 |
commit | 3d0cf4dbf9cb40bc120be3173ce1b3afcbc9c956 (patch) | |
tree | 9ead13ff59495c7782284d91de5e467c1d61f281 /components/selectors/parser.rs | |
parent | dcdf9f33d552a17cd37459a2da28a361e215c14f (diff) | |
download | servo-3d0cf4dbf9cb40bc120be3173ce1b3afcbc9c956.tar.gz servo-3d0cf4dbf9cb40bc120be3173ce1b3afcbc9c956.zip |
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
Diffstat (limited to 'components/selectors/parser.rs')
-rw-r--r-- | components/selectors/parser.rs | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 2720d723568..2fc5ad02d39 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -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 } |