style: Implement parsing and serialization for nth-child(An+B of selector list) and :nth-last-child(An+B of selector list)

:nth-{,last-}child parsing is disabled by default for now by pref
layout.css.nth-child-of.enabled.

Differential Revision: https://phabricator.services.mozilla.com/D165895
This commit is contained in:
Zach Hoffman 2023-01-07 14:32:42 +00:00 committed by Martin Robinson
parent b7d64ee6a4
commit 1c8408e97e
6 changed files with 123 additions and 11 deletions

View file

@ -17,7 +17,7 @@
//! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser.
use crate::parser::{Combinator, Component, SelectorImpl};
use crate::parser::{Combinator, Component, Selector, SelectorImpl};
use crate::sink::Push;
use bitflags::bitflags;
use derive_more::{Add, AddAssign};
@ -323,17 +323,23 @@ where
Component::NonTSPseudoClass(..) => {
specificity.class_like_selectors += 1;
},
Component::NthOf(ref nth_of_data) => {
// https://drafts.csswg.org/selectors/#specificity-rules:
//
// The specificity of the :nth-last-child() pseudo-class,
// like the :nth-child() pseudo-class, combines the
// specificity of a regular pseudo-class with that of its
// selector argument S.
specificity.class_like_selectors += 1;
*specificity += selector_list_specificity(nth_of_data.selectors());
},
Component::Negation(ref list) | Component::Is(ref list) | Component::Has(ref list) => {
// https://drafts.csswg.org/selectors/#specificity-rules:
//
// The specificity of an :is(), :not(), or :has() pseudo-class
// is replaced by the specificity of the most specific complex
// selector in its selector list argument.
let mut max = 0;
for selector in &**list {
max = std::cmp::max(selector.specificity(), max);
}
*specificity += Specificity::from(max);
*specificity += selector_list_specificity(list);
},
Component::Where(..) |
Component::ExplicitUniversalType |
@ -346,6 +352,16 @@ where
}
}
/// Finds the maximum specificity of elements in the list and returns it.
fn selector_list_specificity<Impl: SelectorImpl>(list: &[Selector<Impl>]) -> Specificity {
let max = list
.iter()
.map(|selector| selector.specificity())
.max()
.unwrap_or(0);
Specificity::from(max)
}
let mut specificity = Default::default();
for simple_selector in iter {
simple_selector_specificity(&simple_selector, &mut specificity);