Bug 1792501: Part 3 - Let :has contribute to dependencies. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D185676
This commit is contained in:
David Shin 2023-09-14 22:21:25 +00:00
Родитель 0dfd1143fd
Коммит aa280d1e29
3 изменённых файлов: 68 добавлений и 20 удалений

Просмотреть файл

@ -1927,6 +1927,11 @@ impl<Impl: SelectorImpl> Component<Impl> {
return false;
}
},
Has(ref list) => {
if !visitor.visit_relative_selector_list(list) {
return false;
}
},
_ => {},
}

Просмотреть файл

@ -7,7 +7,7 @@
#![deny(missing_docs)]
use crate::attr::NamespaceConstraint;
use crate::parser::{Combinator, Component, Selector, SelectorImpl};
use crate::parser::{Combinator, Component, RelativeSelector, Selector, SelectorImpl};
/// A trait to visit selector properties.
///
@ -34,6 +34,14 @@ pub trait SelectorVisitor: Sized {
true
}
/// Visit a nested relative selector list. The caller is responsible to call visit
/// into the internal selectors if / as needed.
///
/// The default implementation skips it altogether.
fn visit_relative_selector_list(&mut self, _list: &[RelativeSelector<Self::Impl>]) -> bool {
true
}
/// Visit a nested selector list. The caller is responsible to call visit
/// into the internal selectors if / as needed.
///
@ -73,6 +81,8 @@ bitflags! {
/// The visitor is inside :nth-child(.. of <selector list>) or
/// :nth-last-child(.. of <selector list>)
const NTH_OF = 1 << 3;
/// The visitor is inside :has(..)
const HAS = 1 << 4;
}
}
@ -108,4 +118,19 @@ impl SelectorListKind {
pub fn in_nth_of(&self) -> bool {
self.intersects(SelectorListKind::NTH_OF)
}
/// Whether the visitor is inside :has(..)
pub fn in_has(&self) -> bool {
self.intersects(SelectorListKind::HAS)
}
/// Whether this nested selector is relevant for nth-of dependencies.
pub fn relevant_to_nth_of_dependencies(&self) -> bool {
// Order of nesting for `:has` and `:nth-child(.. of ..)` doesn't matter, because:
// * `:has(:nth-child(.. of ..))`: The location of the anchoring element is
// independent from where `:nth-child(.. of ..)` is applied.
// * `:nth-child(.. of :has(..))`: Invalidations inside `:has` must first use the
// `:has` machinary to find the anchor, then carry out the remaining invalidation.
self.in_nth_of() && !self.in_has()
}
}

Просмотреть файл

@ -2003,6 +2003,25 @@ fn component_needs_revalidation(
}
}
impl<'a> StylistSelectorVisitor<'a> {
fn visit_nested_selector(
&mut self,
in_selector_list_of: SelectorListKind,
selector: &Selector<SelectorImpl>
) {
let old_passed_rightmost_selector = self.passed_rightmost_selector;
let old_in_selector_list_of = self.in_selector_list_of;
self.passed_rightmost_selector = false;
self.in_selector_list_of = in_selector_list_of;
let _ret = selector.visit(self);
debug_assert!(_ret, "We never return false");
self.passed_rightmost_selector = old_passed_rightmost_selector;
self.in_selector_list_of = old_in_selector_list_of;
}
}
impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
type Impl = SelectorImpl;
@ -2026,21 +2045,18 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
) -> bool {
let in_selector_list_of = self.in_selector_list_of | list_kind;
for selector in list {
let mut nested = StylistSelectorVisitor {
passed_rightmost_selector: false,
needs_revalidation: &mut *self.needs_revalidation,
in_selector_list_of,
mapped_ids: &mut *self.mapped_ids,
nth_of_mapped_ids: &mut *self.nth_of_mapped_ids,
attribute_dependencies: &mut *self.attribute_dependencies,
nth_of_class_dependencies: &mut *self.nth_of_class_dependencies,
nth_of_attribute_dependencies: &mut *self.nth_of_attribute_dependencies,
state_dependencies: &mut *self.state_dependencies,
nth_of_state_dependencies: &mut *self.nth_of_state_dependencies,
document_state_dependencies: &mut *self.document_state_dependencies,
};
let _ret = selector.visit(&mut nested);
debug_assert!(_ret, "We never return false");
self.visit_nested_selector(in_selector_list_of, selector);
}
true
}
fn visit_relative_selector_list(
&mut self,
list: &[selectors::parser::RelativeSelector<Self::Impl>],
) -> bool {
let in_selector_list_of = self.in_selector_list_of | SelectorListKind::HAS;
for selector in list {
self.visit_nested_selector(in_selector_list_of, &selector.selector);
}
true
}
@ -2051,7 +2067,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
name: &LocalName,
lower_name: &LocalName,
) -> bool {
if self.in_selector_list_of.in_nth_of() {
if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
self.nth_of_attribute_dependencies.insert(name.clone());
if name != lower_name {
self.nth_of_attribute_dependencies
@ -2077,7 +2093,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
self.document_state_dependencies
.insert(p.document_state_flag());
if self.in_selector_list_of.in_nth_of() {
if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
self.nth_of_state_dependencies.insert(p.state_flag());
}
},
@ -2097,11 +2113,13 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
self.mapped_ids.insert(id.0.clone());
}
if self.in_selector_list_of.in_nth_of() {
if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
self.nth_of_mapped_ids.insert(id.0.clone());
}
},
Component::Class(ref class) if self.in_selector_list_of.in_nth_of() => {
Component::Class(ref class)
if self.in_selector_list_of.relevant_to_nth_of_dependencies() =>
{
self.nth_of_class_dependencies.insert(class.0.clone());
},
_ => {},