mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: Correct style sharing handling for any element that considered :has()
in selector matching
For any element that anchors a `:has()` selector (i.e. Matches a selector that contains a `:has()` on its rightmost side), we prevent style sharing altogether, as evaluation of the `:has()` selector is required in the first place to determine style sharing. On the other hand, any element matching a rule containing `:has()` without anchoring it can do style sharing for siblings, but not cousins. Differential Revision: https://phabricator.services.mozilla.com/D176836
This commit is contained in:
parent
5c0897c8eb
commit
ff8100d396
9 changed files with 91 additions and 6 deletions
|
@ -146,6 +146,7 @@ where
|
|||
|
||||
/// The current element we're anchoring on for evaluating the relative selector.
|
||||
current_relative_selector_anchor: Option<OpaqueElement>,
|
||||
pub considered_relative_selector: bool,
|
||||
|
||||
quirks_mode: QuirksMode,
|
||||
needs_selector_flags: NeedsSelectorFlags,
|
||||
|
@ -199,6 +200,7 @@ where
|
|||
pseudo_element_matching_fn: None,
|
||||
extra_data: Default::default(),
|
||||
current_relative_selector_anchor: None,
|
||||
considered_relative_selector: false,
|
||||
_impl: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -332,6 +334,7 @@ where
|
|||
self.current_relative_selector_anchor = Some(anchor);
|
||||
let result = self.nest(f);
|
||||
self.current_relative_selector_anchor = original_relative_selector_anchor;
|
||||
self.considered_relative_selector = true;
|
||||
result
|
||||
}
|
||||
|
||||
|
|
|
@ -60,13 +60,18 @@ bitflags! {
|
|||
/// The element has an empty selector, so when a child is appended we
|
||||
/// might need to restyle the parent completely.
|
||||
const HAS_EMPTY_SELECTOR = 1 << 4;
|
||||
|
||||
/// This element has a relative selector that anchors to it, or may do so
|
||||
/// if its descendants or its later siblings change.
|
||||
const ANCHORS_RELATIVE_SELECTOR = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementSelectorFlags {
|
||||
/// Returns the subset of flags that apply to the element.
|
||||
pub fn for_self(self) -> ElementSelectorFlags {
|
||||
self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR)
|
||||
self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR |
|
||||
ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR)
|
||||
}
|
||||
|
||||
/// Returns the subset of flags that apply to the parent.
|
||||
|
@ -365,6 +370,12 @@ fn matches_relative_selectors<E: Element>(
|
|||
element: &E,
|
||||
context: &mut MatchingContext<E::Impl>,
|
||||
) -> bool {
|
||||
if context.needs_selector_flags() {
|
||||
// If we've considered anchoring `:has()` selector while trying to match this element,
|
||||
// mark it as such, as it has implications on style sharing (See style sharing
|
||||
// code for further information).
|
||||
element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
|
||||
}
|
||||
for RelativeSelector {
|
||||
match_hint,
|
||||
selector,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue