mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
style: Represent FirstChild, FirstOfType, LastChild, LastOfType, OnlyChild, and OnlyOfType as functionless Nth variants
Like bug 1808226, this doesn't change any behavior, it just simplifies matching. I also added a WPT JavaScript test for :only-of-type, since dedicated WPT JavScript tests already exist for the other pseudo-classes this patch touches. Differential Revision: https://phabricator.services.mozilla.com/D165859
This commit is contained in:
parent
dc225e0b2f
commit
211761ad88
5 changed files with 76 additions and 74 deletions
|
@ -711,16 +711,10 @@ where
|
||||||
Component::Class(..) |
|
Component::Class(..) |
|
||||||
Component::AttributeInNoNamespaceExists { .. } |
|
Component::AttributeInNoNamespaceExists { .. } |
|
||||||
Component::AttributeInNoNamespace { .. } |
|
Component::AttributeInNoNamespace { .. } |
|
||||||
Component::FirstChild |
|
|
||||||
Component::LastChild |
|
|
||||||
Component::OnlyChild |
|
|
||||||
Component::Root |
|
Component::Root |
|
||||||
Component::Empty |
|
Component::Empty |
|
||||||
Component::Scope |
|
Component::Scope |
|
||||||
Component::Nth(..) |
|
Component::Nth(..) |
|
||||||
Component::FirstOfType |
|
|
||||||
Component::LastOfType |
|
|
||||||
Component::OnlyOfType |
|
|
||||||
Component::Host(None) => 0,
|
Component::Host(None) => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,16 +316,10 @@ where
|
||||||
Component::AttributeInNoNamespace { .. } |
|
Component::AttributeInNoNamespace { .. } |
|
||||||
Component::AttributeInNoNamespaceExists { .. } |
|
Component::AttributeInNoNamespaceExists { .. } |
|
||||||
Component::AttributeOther(..) |
|
Component::AttributeOther(..) |
|
||||||
Component::FirstChild |
|
|
||||||
Component::LastChild |
|
|
||||||
Component::OnlyChild |
|
|
||||||
Component::Root |
|
Component::Root |
|
||||||
Component::Empty |
|
Component::Empty |
|
||||||
Component::Scope |
|
Component::Scope |
|
||||||
Component::Nth(..) |
|
Component::Nth(..) |
|
||||||
Component::FirstOfType |
|
|
||||||
Component::LastOfType |
|
|
||||||
Component::OnlyOfType |
|
|
||||||
Component::NonTSPseudoClass(..) => {
|
Component::NonTSPseudoClass(..) => {
|
||||||
specificity.class_like_selectors += 1;
|
specificity.class_like_selectors += 1;
|
||||||
},
|
},
|
||||||
|
|
|
@ -387,14 +387,8 @@ fn hover_and_active_quirk_applies<Impl: SelectorImpl>(
|
||||||
Component::Class(_) |
|
Component::Class(_) |
|
||||||
Component::PseudoElement(_) |
|
Component::PseudoElement(_) |
|
||||||
Component::Negation(_) |
|
Component::Negation(_) |
|
||||||
Component::FirstChild |
|
|
||||||
Component::LastChild |
|
|
||||||
Component::OnlyChild |
|
|
||||||
Component::Empty |
|
Component::Empty |
|
||||||
Component::Nth(_) |
|
Component::Nth(_) => false,
|
||||||
Component::FirstOfType |
|
|
||||||
Component::LastOfType |
|
|
||||||
Component::OnlyOfType => false,
|
|
||||||
Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
|
Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
|
||||||
_ => true,
|
_ => true,
|
||||||
})
|
})
|
||||||
|
@ -784,12 +778,6 @@ where
|
||||||
}
|
}
|
||||||
element.match_non_ts_pseudo_class(pc, &mut context.shared)
|
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::Root => element.is_root(),
|
||||||
Component::Empty => {
|
Component::Empty => {
|
||||||
if context.shared.needs_selector_flags() {
|
if context.shared.needs_selector_flags() {
|
||||||
|
@ -812,23 +800,46 @@ where
|
||||||
Some(ref scope_element) => element.opaque() == *scope_element,
|
Some(ref scope_element) => element.opaque() == *scope_element,
|
||||||
None => element.is_root(),
|
None => element.is_root(),
|
||||||
},
|
},
|
||||||
Component::Nth(nth_data) => matches_generic_nth_child(
|
Component::Nth(nth_data) => {
|
||||||
element,
|
if nth_data.is_function ||
|
||||||
context.shared,
|
(match nth_data.ty {
|
||||||
nth_data.a,
|
NthType::Child => return matches_first_child(element, context.shared),
|
||||||
nth_data.b,
|
NthType::LastChild => return matches_last_child(element, context.shared),
|
||||||
nth_data.ty == NthType::OfType || nth_data.ty == NthType::LastOfType,
|
NthType::OnlyChild => {
|
||||||
nth_data.ty == NthType::LastChild || nth_data.ty == NthType::LastOfType,
|
return matches_first_child(element, context.shared) &&
|
||||||
),
|
matches_last_child(element, context.shared)
|
||||||
Component::FirstOfType => {
|
},
|
||||||
matches_generic_nth_child(element, context.shared, 0, 1, true, false)
|
NthType::OnlyOfType => {
|
||||||
},
|
return matches_generic_nth_child(
|
||||||
Component::LastOfType => {
|
element,
|
||||||
matches_generic_nth_child(element, context.shared, 0, 1, true, true)
|
context.shared,
|
||||||
},
|
nth_data.a,
|
||||||
Component::OnlyOfType => {
|
nth_data.b,
|
||||||
matches_generic_nth_child(element, context.shared, 0, 1, true, false) &&
|
true,
|
||||||
matches_generic_nth_child(element, context.shared, 0, 1, true, 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| {
|
Component::Is(ref list) | Component::Where(ref list) => context.shared.nest(|context| {
|
||||||
for selector in &**list {
|
for selector in &**list {
|
||||||
|
|
|
@ -1042,8 +1042,10 @@ impl Combinator {
|
||||||
pub enum NthType {
|
pub enum NthType {
|
||||||
Child,
|
Child,
|
||||||
LastChild,
|
LastChild,
|
||||||
|
OnlyChild,
|
||||||
OfType,
|
OfType,
|
||||||
LastOfType,
|
LastOfType,
|
||||||
|
OnlyOfType,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g.,
|
/// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g.,
|
||||||
|
@ -1053,6 +1055,7 @@ pub enum NthType {
|
||||||
#[shmem(no_bounds)]
|
#[shmem(no_bounds)]
|
||||||
pub struct NthSelectorData {
|
pub struct NthSelectorData {
|
||||||
pub ty: NthType,
|
pub ty: NthType,
|
||||||
|
pub is_function: bool,
|
||||||
pub a: i32,
|
pub a: i32,
|
||||||
pub b: i32,
|
pub b: i32,
|
||||||
}
|
}
|
||||||
|
@ -1099,16 +1102,10 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
|
|
||||||
/// Pseudo-classes
|
/// Pseudo-classes
|
||||||
Negation(Box<[Selector<Impl>]>),
|
Negation(Box<[Selector<Impl>]>),
|
||||||
FirstChild,
|
|
||||||
LastChild,
|
|
||||||
OnlyChild,
|
|
||||||
Root,
|
Root,
|
||||||
Empty,
|
Empty,
|
||||||
Scope,
|
Scope,
|
||||||
Nth(NthSelectorData),
|
Nth(NthSelectorData),
|
||||||
FirstOfType,
|
|
||||||
LastOfType,
|
|
||||||
OnlyOfType,
|
|
||||||
NonTSPseudoClass(#[cfg_attr(feature = "shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
|
NonTSPseudoClass(#[cfg_attr(feature = "shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
|
||||||
/// The ::slotted() pseudo-element:
|
/// The ::slotted() pseudo-element:
|
||||||
///
|
///
|
||||||
|
@ -1598,9 +1595,6 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
|
||||||
AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
|
AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
|
||||||
|
|
||||||
// Pseudo-classes
|
// 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"),
|
Root => dest.write_str(":root"),
|
||||||
Empty => dest.write_str(":empty"),
|
Empty => dest.write_str(":empty"),
|
||||||
Scope => dest.write_str(":scope"),
|
Scope => dest.write_str(":scope"),
|
||||||
|
@ -1613,17 +1607,27 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
|
||||||
}
|
}
|
||||||
Ok(())
|
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) => {
|
Nth(nth_data) => {
|
||||||
match nth_data.ty {
|
if nth_data.is_function {
|
||||||
NthType::Child => dest.write_str(":nth-child(")?,
|
match nth_data.ty {
|
||||||
NthType::LastChild => dest.write_str(":nth-last-child(")?,
|
NthType::Child => dest.write_str(":nth-child("),
|
||||||
NthType::OfType => dest.write_str(":nth-of-type(")?,
|
NthType::LastChild => dest.write_str(":nth-last-child("),
|
||||||
NthType::LastOfType => dest.write_str(":nth-last-of-type(")?,
|
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(')')
|
dest.write_char(')')
|
||||||
},
|
},
|
||||||
Is(ref list) | Where(ref list) | Negation(ref list) | Has(ref list) => {
|
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));
|
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
||||||
}
|
}
|
||||||
let (a, b) = parse_nth(input)?;
|
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
|
/// Returns whether the name corresponds to a CSS2 pseudo-element that
|
||||||
|
@ -2534,16 +2543,16 @@ where
|
||||||
|
|
||||||
if state.allows_tree_structural_pseudo_classes() {
|
if state.allows_tree_structural_pseudo_classes() {
|
||||||
match_ignore_ascii_case! { &name,
|
match_ignore_ascii_case! { &name,
|
||||||
"first-child" => return Ok(Component::FirstChild),
|
"first-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: Child, is_function: false, a: 0, b: 1})),
|
||||||
"last-child" => return Ok(Component::LastChild),
|
"last-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: LastChild, is_function: false, a: 0, b: 1})),
|
||||||
"only-child" => return Ok(Component::OnlyChild),
|
"only-child" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OnlyChild, is_function: false, a: 0, b: 1})),
|
||||||
"root" => return Ok(Component::Root),
|
"root" => return Ok(Component::Root),
|
||||||
"empty" => return Ok(Component::Empty),
|
"empty" => return Ok(Component::Empty),
|
||||||
"scope" => return Ok(Component::Scope),
|
"scope" => return Ok(Component::Scope),
|
||||||
"host" if P::parse_host(parser) => return Ok(Component::Host(None)),
|
"host" if P::parse_host(parser) => return Ok(Component::Host(None)),
|
||||||
"first-of-type" => return Ok(Component::FirstOfType),
|
"first-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OfType, is_function: false, a: 0, b: 1})),
|
||||||
"last-of-type" => return Ok(Component::LastOfType),
|
"last-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: LastOfType, is_function: false, a: 0, b: 1})),
|
||||||
"only-of-type" => return Ok(Component::OnlyOfType),
|
"only-of-type" => return Ok(Component::Nth(NthSelectorData{ ty: NthType:: OnlyOfType, is_function: false, a: 0, b: 1})),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1918,13 +1918,7 @@ fn component_needs_revalidation(
|
||||||
Component::AttributeInNoNamespace { .. } |
|
Component::AttributeInNoNamespace { .. } |
|
||||||
Component::AttributeOther(_) |
|
Component::AttributeOther(_) |
|
||||||
Component::Empty |
|
Component::Empty |
|
||||||
Component::FirstChild |
|
Component::Nth(..) => true,
|
||||||
Component::LastChild |
|
|
||||||
Component::OnlyChild |
|
|
||||||
Component::Nth(..) |
|
|
||||||
Component::FirstOfType |
|
|
||||||
Component::LastOfType |
|
|
||||||
Component::OnlyOfType => true,
|
|
||||||
Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(),
|
Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue