mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
style: Handle nested slots correctly in slotted matching and invalidation.
The patch and test should be pretty much self-descriptive. Differential Revision: https://phabricator.services.mozilla.com/D14063
This commit is contained in:
parent
a519d9ecc3
commit
7f5a9e0f45
3 changed files with 45 additions and 17 deletions
|
@ -410,6 +410,7 @@ fn next_element_for_combinator<E>(
|
||||||
element: &E,
|
element: &E,
|
||||||
combinator: Combinator,
|
combinator: Combinator,
|
||||||
selector: &SelectorIter<E::Impl>,
|
selector: &SelectorIter<E::Impl>,
|
||||||
|
context: &MatchingContext<E::Impl>,
|
||||||
) -> Option<E>
|
) -> Option<E>
|
||||||
where
|
where
|
||||||
E: Element,
|
E: Element,
|
||||||
|
@ -449,12 +450,21 @@ where
|
||||||
element.containing_shadow_host()
|
element.containing_shadow_host()
|
||||||
},
|
},
|
||||||
Combinator::SlotAssignment => {
|
Combinator::SlotAssignment => {
|
||||||
|
debug_assert!(
|
||||||
|
context.current_host.is_some(),
|
||||||
|
"Should not be trying to match slotted rules in a non-shadow-tree context"
|
||||||
|
);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
element
|
element
|
||||||
.assigned_slot()
|
.assigned_slot()
|
||||||
.map_or(true, |s| s.is_html_slot_element())
|
.map_or(true, |s| s.is_html_slot_element())
|
||||||
);
|
);
|
||||||
element.assigned_slot()
|
let scope = context.current_host?;
|
||||||
|
let mut current_slot = element.assigned_slot()?;
|
||||||
|
while current_slot.containing_shadow_host().unwrap().opaque() != scope {
|
||||||
|
current_slot = current_slot.assigned_slot()?;
|
||||||
|
}
|
||||||
|
Some(current_slot)
|
||||||
},
|
},
|
||||||
Combinator::PseudoElement => element.pseudo_element_originating_element(),
|
Combinator::PseudoElement => element.pseudo_element_originating_element(),
|
||||||
}
|
}
|
||||||
|
@ -511,7 +521,12 @@ where
|
||||||
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
|
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut next_element = next_element_for_combinator(element, combinator, &selector_iter);
|
let mut next_element = next_element_for_combinator(
|
||||||
|
element,
|
||||||
|
combinator,
|
||||||
|
&selector_iter,
|
||||||
|
&context,
|
||||||
|
);
|
||||||
|
|
||||||
// Stop matching :visited as soon as we find a link, or a combinator for
|
// Stop matching :visited as soon as we find a link, or a combinator for
|
||||||
// something that isn't an ancestor.
|
// something that isn't an ancestor.
|
||||||
|
@ -575,7 +590,12 @@ where
|
||||||
visited_handling = VisitedHandlingMode::AllLinksUnvisited;
|
visited_handling = VisitedHandlingMode::AllLinksUnvisited;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_element = next_element_for_combinator(&element, combinator, &selector_iter);
|
next_element = next_element_for_combinator(
|
||||||
|
&element,
|
||||||
|
combinator,
|
||||||
|
&selector_iter,
|
||||||
|
&context,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,8 @@ use crate::parser::SelectorImpl;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
/// Opaque representation of an Element, for identity comparisons. We use
|
/// Opaque representation of an Element, for identity comparisons.
|
||||||
/// NonZeroPtrMut to get the NonZero optimization.
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
||||||
pub struct OpaqueElement(NonNull<()>);
|
pub struct OpaqueElement(NonNull<()>);
|
||||||
|
|
||||||
unsafe impl Send for OpaqueElement {}
|
unsafe impl Send for OpaqueElement {}
|
||||||
|
|
|
@ -471,25 +471,34 @@ where
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let slot = self.element;
|
||||||
|
self.invalidate_slotted_elements_in_slot(slot, invalidations)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalidate_slotted_elements_in_slot(
|
||||||
|
&mut self,
|
||||||
|
slot: E,
|
||||||
|
invalidations: &[Invalidation<'b>],
|
||||||
|
) -> bool {
|
||||||
let mut any = false;
|
let mut any = false;
|
||||||
|
|
||||||
let mut sibling_invalidations = InvalidationVector::new();
|
let mut sibling_invalidations = InvalidationVector::new();
|
||||||
let element = self.element;
|
for node in slot.slotted_nodes() {
|
||||||
for node in element.slotted_nodes() {
|
|
||||||
let element = match node.as_element() {
|
let element = match node.as_element() {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
any |= self.invalidate_child(
|
if element.is_html_slot_element() {
|
||||||
element,
|
any |= self.invalidate_slotted_elements_in_slot(element, invalidations);
|
||||||
invalidations,
|
} else {
|
||||||
&mut sibling_invalidations,
|
any |= self.invalidate_child(
|
||||||
DescendantInvalidationKind::Slotted,
|
element,
|
||||||
);
|
invalidations,
|
||||||
|
&mut sibling_invalidations,
|
||||||
// FIXME(emilio): Need to handle nested slotted nodes if `element`
|
DescendantInvalidationKind::Slotted,
|
||||||
// is itself a <slot>.
|
);
|
||||||
|
}
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
sibling_invalidations.is_empty(),
|
sibling_invalidations.is_empty(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue