mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
style: Keep track of nested dependencies for :where() and :is().
The tricky part of :is() and :where() is that they can have combinators inside, so something like this is valid: foo:is(#bar > .baz) ~ taz The current invalidation logic is based on the assumption that you can represent a combinator as a (selector, offset) tuple, which are stored in the Dependency struct. This assumption breaks with :is() and :where(), so we need to make them be able to represent a combinator in an "inner" selector. For this purpose, we add a `parent` dependency. With it, when invalidating inside the `:is()` we can represent combinators inside as a stack. The basic idea is that, for the example above, when an id of "bar" is added or removed, we'd find a dependency like: Dependency { selector: #bar > .baz, offset: 1, // pointing to the `>` combinator parent: Some(Dependency { selector: foo:is(#bar > .baz) > taz, offset: 1, // Pointing to the `~` combinator. parent: None, }) } That way, we'd start matching at the element that changed, towards the right, and if we find an element that matches .baz, instead of invalidating that element, we'd look at the parent dependency, then double-check that the whole left-hand-side of the selector (foo:is(#bar > .baz)) actually changed, and then keep invalidating to the right using the parent dependency as usual. This patch only builds the data structure and keeps the code compiling, the actual invalidation work will come in a following patch. Differential Revision: https://phabricator.services.mozilla.com/D71421
This commit is contained in:
parent
cd63d7b272
commit
c1bc588c93
2 changed files with 249 additions and 150 deletions
|
@ -79,6 +79,39 @@ impl<'a, 'b: 'a, E: TElement + 'b> StateAndAttrInvalidationProcessor<'a, 'b, E>
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks a dependency against a given element and wrapper, to see if something
|
||||
/// changed.
|
||||
pub fn check_dependency<E, W>(
|
||||
dependency: &Dependency,
|
||||
element: &E,
|
||||
wrapper: &W,
|
||||
context: &mut MatchingContext<'_, SelectorImpl>,
|
||||
)
|
||||
where
|
||||
E: TElement,
|
||||
W: selectors::Element<Impl = E::Impl>,
|
||||
{
|
||||
let matches_now = matches_selector(
|
||||
&dependency.selector,
|
||||
dependency.selector_offset,
|
||||
None,
|
||||
element,
|
||||
&mut context,
|
||||
&mut |_, _| {},
|
||||
);
|
||||
|
||||
let matched_then = matches_selector(
|
||||
&dependency.selector,
|
||||
dependency.selector_offset,
|
||||
None,
|
||||
wrapper,
|
||||
&mut context,
|
||||
&mut |_, _| {},
|
||||
);
|
||||
|
||||
matched_then != matches_now
|
||||
}
|
||||
|
||||
/// Whether we should process the descendants of a given element for style
|
||||
/// invalidation.
|
||||
pub fn should_process_descendants(data: &ElementData) -> bool {
|
||||
|
@ -412,28 +445,9 @@ where
|
|||
}
|
||||
|
||||
/// Check whether a dependency should be taken into account.
|
||||
#[inline]
|
||||
fn check_dependency(&mut self, dependency: &Dependency) -> bool {
|
||||
let element = &self.element;
|
||||
let wrapper = &self.wrapper;
|
||||
let matches_now = matches_selector(
|
||||
&dependency.selector,
|
||||
dependency.selector_offset,
|
||||
None,
|
||||
element,
|
||||
&mut self.matching_context,
|
||||
&mut |_, _| {},
|
||||
);
|
||||
|
||||
let matched_then = matches_selector(
|
||||
&dependency.selector,
|
||||
dependency.selector_offset,
|
||||
None,
|
||||
wrapper,
|
||||
&mut self.matching_context,
|
||||
&mut |_, _| {},
|
||||
);
|
||||
|
||||
matched_then != matches_now
|
||||
check_dependency(&self.element, &self.wrapper, &mut self.matching_context)
|
||||
}
|
||||
|
||||
fn scan_dependency(&mut self, dependency: &'selectors Dependency) {
|
||||
|
@ -456,7 +470,13 @@ where
|
|||
|
||||
let invalidation_kind = dependency.invalidation_kind();
|
||||
if matches!(invalidation_kind, DependencyInvalidationKind::Element) {
|
||||
self.invalidates_self = true;
|
||||
if let Some(ref parent) = dependency.parent {
|
||||
// We know something changed in the inner selector, go outwards
|
||||
// now.
|
||||
self.scan_dependency(parent);
|
||||
} else {
|
||||
self.invalidates_self = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue