From 7f5a9e0f4589e49369ca1abaac562fdcc69faa36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 13 Dec 2018 02:17:53 +0000 Subject: [PATCH] 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 --- components/selectors/matching.rs | 26 ++++++++++++++-- components/selectors/tree.rs | 5 ++- .../style/invalidation/element/invalidator.rs | 31 ++++++++++++------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index d8d083d7b28..8a9a2790f52 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -410,6 +410,7 @@ fn next_element_for_combinator( element: &E, combinator: Combinator, selector: &SelectorIter, + context: &MatchingContext, ) -> Option where E: Element, @@ -449,12 +450,21 @@ where element.containing_shadow_host() }, 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!( element .assigned_slot() .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(), } @@ -511,7 +521,12 @@ where 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 // something that isn't an ancestor. @@ -575,7 +590,12 @@ where 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, + ); } } diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index 9e606ab9124..6d8c5fcd25f 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -11,9 +11,8 @@ use crate::parser::SelectorImpl; use std::fmt::Debug; use std::ptr::NonNull; -/// Opaque representation of an Element, for identity comparisons. We use -/// NonZeroPtrMut to get the NonZero optimization. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] +/// Opaque representation of an Element, for identity comparisons. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub struct OpaqueElement(NonNull<()>); unsafe impl Send for OpaqueElement {} diff --git a/components/style/invalidation/element/invalidator.rs b/components/style/invalidation/element/invalidator.rs index fdcdff1b69f..4640c7c0442 100644 --- a/components/style/invalidation/element/invalidator.rs +++ b/components/style/invalidation/element/invalidator.rs @@ -471,25 +471,34 @@ where 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 sibling_invalidations = InvalidationVector::new(); - let element = self.element; - for node in element.slotted_nodes() { + for node in slot.slotted_nodes() { let element = match node.as_element() { Some(e) => e, None => continue, }; - any |= self.invalidate_child( - element, - invalidations, - &mut sibling_invalidations, - DescendantInvalidationKind::Slotted, - ); - - // FIXME(emilio): Need to handle nested slotted nodes if `element` - // is itself a . + if element.is_html_slot_element() { + any |= self.invalidate_slotted_elements_in_slot(element, invalidations); + } else { + any |= self.invalidate_child( + element, + invalidations, + &mut sibling_invalidations, + DescendantInvalidationKind::Slotted, + ); + } debug_assert!( sibling_invalidations.is_empty(),