style: Move nth-related logic to the NthSelectorData type for reuse

Drive-by, but selector_list_specificity() was also renamed to
max_selector_list_specificity().

Differential Revision: https://phabricator.services.mozilla.com/D166263
This commit is contained in:
Zach Hoffman 2023-01-09 06:06:27 +00:00 committed by Martin Robinson
parent 1c8408e97e
commit 39b056cf70
2 changed files with 50 additions and 42 deletions

View file

@ -331,7 +331,7 @@ where
// 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());
*specificity += max_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:
@ -339,7 +339,7 @@ where
// 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.
*specificity += selector_list_specificity(list);
*specificity += max_selector_list_specificity(list);
},
Component::Where(..) |
Component::ExplicitUniversalType |
@ -353,7 +353,7 @@ where
}
/// Finds the maximum specificity of elements in the list and returns it.
fn selector_list_specificity<Impl: SelectorImpl>(list: &[Selector<Impl>]) -> Specificity {
fn max_selector_list_specificity<Impl: SelectorImpl>(list: &[Selector<Impl>]) -> Specificity {
let max = list
.iter()
.map(|selector| selector.specificity())

View file

@ -1124,6 +1124,41 @@ impl NthSelectorData {
b: 1,
}
}
/// Writes the beginning of the selector.
#[inline]
fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
dest.write_str(match self.ty {
NthType::Child if self.is_function => ":nth-child(",
NthType::Child => ":first-child",
NthType::LastChild if self.is_function => ":nth-last-child(",
NthType::LastChild => ":last-child",
NthType::OfType if self.is_function => ":nth-of-type(",
NthType::OfType => ":first-of-type",
NthType::LastOfType if self.is_function => ":nth-last-of-type(",
NthType::LastOfType => ":last-of-type",
NthType::OnlyChild => ":only-child",
NthType::OnlyOfType => ":only-of-type",
})
}
/// Serialize <an+b> (part of the CSS Syntax spec, but currently only used here).
/// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value>
#[inline]
fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
match (self.a, self.b) {
(0, 0) => dest.write_char('0'),
(1, 0) => dest.write_char('n'),
(-1, 0) => dest.write_str("-n"),
(_, 0) => write!(dest, "{}n", self.a),
(0, _) => write!(dest, "{}", self.b),
(1, _) => write!(dest, "n{:+}", self.b),
(-1, _) => write!(dest, "-n{:+}", self.b),
(_, _) => write!(dest, "{}n{:+}", self.a, self.b),
}
}
}
/// The properties that comprise an :nth- pseudoclass as of Selectors 4 (e.g.,
@ -1613,26 +1648,6 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
{
use self::Component::*;
/// Serialize <an+b> values (part of the CSS Syntax spec, but currently only used here).
/// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value>
fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result
where
W: fmt::Write,
{
match (a, b) {
(0, 0) => dest.write_char('0'),
(1, 0) => dest.write_char('n'),
(-1, 0) => dest.write_str("-n"),
(_, 0) => write!(dest, "{}n", a),
(0, _) => write!(dest, "{}", b),
(1, _) => write!(dest, "n{:+}", b),
(-1, _) => write!(dest, "-n{:+}", b),
(_, _) => write!(dest, "{}n{:+}", a, b),
}
}
match *self {
Combinator(ref c) => c.to_css(dest),
Slotted(ref selector) => {
@ -1712,32 +1727,25 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
Ok(())
},
Nth(ref nth_data) => {
dest.write_str(match nth_data.ty {
NthType::Child if nth_data.is_function => ":nth-child(",
NthType::Child => ":first-child",
NthType::LastChild if nth_data.is_function => ":nth-last-child(",
NthType::LastChild => ":last-child",
NthType::OfType if nth_data.is_function => ":nth-of-type(",
NthType::OfType => ":first-of-type",
NthType::LastOfType if nth_data.is_function => ":nth-last-of-type(",
NthType::LastOfType => ":last-of-type",
NthType::OnlyChild => ":only-child",
NthType::OnlyOfType => ":only-of-type",
})?;
nth_data.write_start(dest)?;
if nth_data.is_function {
write_affine(dest, nth_data.a, nth_data.b)?;
nth_data.write_affine(dest)?;
dest.write_char(')')?;
}
Ok(())
},
NthOf(ref nth_of_data) => {
let nth_data = nth_of_data.nth_data();
dest.write_str(match nth_data.ty {
NthType::Child => ":nth-child(",
NthType::LastChild => ":nth-last-child(",
_ => unreachable!(),
})?;
write_affine(dest, nth_data.a, nth_data.b)?;
nth_data.write_start(dest)?;
debug_assert!(
nth_data.is_function,
"A selector must be a function to hold An+B notation"
);
nth_data.write_affine(dest)?;
debug_assert!(
matches!(nth_data.ty, NthType::Child | NthType::LastChild),
"Only :nth-child or :nth-last-child can be of a selector list"
);
debug_assert!(
!nth_of_data.selectors().is_empty(),
"The selector list should not be empty"