diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index 6db52526441..4702f15e2d8 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -711,16 +711,10 @@ where Component::Class(..) | Component::AttributeInNoNamespaceExists { .. } | Component::AttributeInNoNamespace { .. } | - Component::FirstChild | - Component::LastChild | - Component::OnlyChild | Component::Root | Component::Empty | Component::Scope | Component::Nth(..) | - Component::FirstOfType | - Component::LastOfType | - Component::OnlyOfType | Component::Host(None) => 0, } } diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index 3bda08c8ff8..0a21fd3f37f 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -316,16 +316,10 @@ where Component::AttributeInNoNamespace { .. } | Component::AttributeInNoNamespaceExists { .. } | Component::AttributeOther(..) | - Component::FirstChild | - Component::LastChild | - Component::OnlyChild | Component::Root | Component::Empty | Component::Scope | Component::Nth(..) | - Component::FirstOfType | - Component::LastOfType | - Component::OnlyOfType | Component::NonTSPseudoClass(..) => { specificity.class_like_selectors += 1; }, diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 3afe67cbb33..334eb113658 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -387,14 +387,8 @@ fn hover_and_active_quirk_applies( Component::Class(_) | Component::PseudoElement(_) | Component::Negation(_) | - Component::FirstChild | - Component::LastChild | - Component::OnlyChild | Component::Empty | - Component::Nth(_) | - Component::FirstOfType | - Component::LastOfType | - Component::OnlyOfType => false, + Component::Nth(_) => false, Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(), _ => true, }) @@ -784,12 +778,6 @@ where } element.match_non_ts_pseudo_class(pc, &mut context.shared) }, - Component::FirstChild => matches_first_child(element, context.shared), - Component::LastChild => matches_last_child(element, context.shared), - Component::OnlyChild => { - matches_first_child(element, context.shared) && - matches_last_child(element, context.shared) - }, Component::Root => element.is_root(), Component::Empty => { if context.shared.needs_selector_flags() { @@ -812,23 +800,46 @@ where Some(ref scope_element) => element.opaque() == *scope_element, None => element.is_root(), }, - Component::Nth(nth_data) => matches_generic_nth_child( - element, - context.shared, - nth_data.a, - nth_data.b, - nth_data.ty == NthType::OfType || nth_data.ty == NthType::LastOfType, - nth_data.ty == NthType::LastChild || nth_data.ty == NthType::LastOfType, - ), - Component::FirstOfType => { - matches_generic_nth_child(element, context.shared, 0, 1, true, false) - }, - Component::LastOfType => { - matches_generic_nth_child(element, context.shared, 0, 1, true, true) - }, - Component::OnlyOfType => { - matches_generic_nth_child(element, context.shared, 0, 1, true, false) && - matches_generic_nth_child(element, context.shared, 0, 1, true, true) + Component::Nth(nth_data) => { + if nth_data.is_function || + (match nth_data.ty { + NthType::Child => return matches_first_child(element, context.shared), + NthType::LastChild => return matches_last_child(element, context.shared), + NthType::OnlyChild => { + return matches_first_child(element, context.shared) && + matches_last_child(element, context.shared) + }, + NthType::OnlyOfType => { + return matches_generic_nth_child( + element, + context.shared, + nth_data.a, + nth_data.b, + true, + false, + ) && matches_generic_nth_child( + element, + context.shared, + nth_data.a, + nth_data.b, + true, + true, + ) + }, + _ => true, + }) + { + matches_generic_nth_child( + element, + context.shared, + nth_data.a, + nth_data.b, + nth_data.ty == NthType::OfType || nth_data.ty == NthType::LastOfType, + nth_data.ty == NthType::LastChild || nth_data.ty == NthType::LastOfType, + ) + } else { + unreachable!() + } }, Component::Is(ref list) | Component::Where(ref list) => context.shared.nest(|context| { for selector in &**list { diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index de89b14d3c2..8607005895d 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -1042,8 +1042,10 @@ impl Combinator { pub enum NthType { Child, LastChild, + OnlyChild, OfType, LastOfType, + OnlyOfType, } /// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g., @@ -1053,6 +1055,7 @@ pub enum NthType { #[shmem(no_bounds)] pub struct NthSelectorData { pub ty: NthType, + pub is_function: bool, pub a: i32, pub b: i32, } @@ -1099,16 +1102,10 @@ pub enum Component { /// Pseudo-classes Negation(Box<[Selector]>), - FirstChild, - LastChild, - OnlyChild, Root, Empty, Scope, Nth(NthSelectorData), - FirstOfType, - LastOfType, - OnlyOfType, NonTSPseudoClass(#[cfg_attr(feature = "shmem", shmem(field_bound))] Impl::NonTSPseudoClass), /// The ::slotted() pseudo-element: /// @@ -1598,9 +1595,6 @@ impl ToCss for Component { AttributeOther(ref attr_selector) => attr_selector.to_css(dest), // Pseudo-classes - FirstChild => dest.write_str(":first-child"), - LastChild => dest.write_str(":last-child"), - OnlyChild => dest.write_str(":only-child"), Root => dest.write_str(":root"), Empty => dest.write_str(":empty"), Scope => dest.write_str(":scope"), @@ -1613,17 +1607,27 @@ impl ToCss for Component { } Ok(()) }, - FirstOfType => dest.write_str(":first-of-type"), - LastOfType => dest.write_str(":last-of-type"), - OnlyOfType => dest.write_str(":only-of-type"), Nth(nth_data) => { - match nth_data.ty { - NthType::Child => dest.write_str(":nth-child(")?, - NthType::LastChild => dest.write_str(":nth-last-child(")?, - NthType::OfType => dest.write_str(":nth-of-type(")?, - NthType::LastOfType => dest.write_str(":nth-last-of-type(")?, + if nth_data.is_function { + match nth_data.ty { + NthType::Child => dest.write_str(":nth-child("), + NthType::LastChild => dest.write_str(":nth-last-child("), + NthType::OfType => dest.write_str(":nth-of-type("), + NthType::LastOfType => dest.write_str(":nth-last-of-type("), + _ => unreachable!(), + }?; + write_affine(dest, nth_data.a, nth_data.b)?; + } else { + match nth_data.ty { + NthType::Child => dest.write_str(":first-child"), + + NthType::LastChild => dest.write_str(":last-child"), + NthType::OnlyChild => dest.write_str(":only-child"), + NthType::OfType => dest.write_str(":first-of-type"), + NthType::LastOfType => dest.write_str(":last-of-type"), + NthType::OnlyOfType => dest.write_str(":only-of-type"), + }?; } - write_affine(dest, nth_data.a, nth_data.b)?; dest.write_char(')') }, Is(ref list) | Where(ref list) | Negation(ref list) | Has(ref list) => { @@ -2373,7 +2377,12 @@ where return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); } let (a, b) = parse_nth(input)?; - Ok(Component::Nth(NthSelectorData { ty, a, b })) + Ok(Component::Nth(NthSelectorData { + ty, + is_function: true, + a, + b, + })) } /// Returns whether the name corresponds to a CSS2 pseudo-element that @@ -2534,16 +2543,16 @@ where if state.allows_tree_structural_pseudo_classes() { match_ignore_ascii_case! { &name, - "first-child" => return Ok(Component::FirstChild), - "last-child" => return Ok(Component::LastChild), - "only-child" => return Ok(Component::OnlyChild), + "first-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: Child, is_function: false, a: 0, b: 1})), + "last-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: LastChild, is_function: false, a: 0, b: 1})), + "only-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OnlyChild, is_function: false, a: 0, b: 1})), "root" => return Ok(Component::Root), "empty" => return Ok(Component::Empty), "scope" => return Ok(Component::Scope), "host" if P::parse_host(parser) => return Ok(Component::Host(None)), - "first-of-type" => return Ok(Component::FirstOfType), - "last-of-type" => return Ok(Component::LastOfType), - "only-of-type" => return Ok(Component::OnlyOfType), + "first-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OfType, is_function: false, a: 0, b: 1})), + "last-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: LastOfType, is_function: false, a: 0, b: 1})), + "only-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OnlyOfType, is_function: false, a: 0, b: 1})), _ => {}, } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 0d91d8d741c..ffcbd2da49e 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1918,13 +1918,7 @@ fn component_needs_revalidation( Component::AttributeInNoNamespace { .. } | Component::AttributeOther(_) | Component::Empty | - Component::FirstChild | - Component::LastChild | - Component::OnlyChild | - Component::Nth(..) | - Component::FirstOfType | - Component::LastOfType | - Component::OnlyOfType => true, + Component::Nth(..) => true, Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(), _ => false, }