diff --git a/components/style/dom.rs b/components/style/dom.rs index 04d6a79b384..0a743c60207 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -346,6 +346,14 @@ pub trait TShadowRoot: Sized + Copy + Clone + PartialEq { where Self: 'a; + /// Get the list of shadow parts for this shadow root. + fn parts<'a>(&self) -> &[::ConcreteElement] + where + Self: 'a + { + &[] + } + /// Get a list of elements with a given ID in this shadow root, sorted by /// tree position. /// diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 3ce9e6fe6ab..aa59df56bde 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -185,6 +185,21 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> { bindings::Gecko_ShadowRoot_GetElementsWithId(self.0, id.as_ptr()) })) } + + #[inline] + fn parts<'a>(&self) -> &[::ConcreteElement] + where + Self: 'a + { + let slice: &[*const RawGeckoElement] = &*self.0.mParts; + + #[allow(dead_code)] + unsafe fn static_assert() { + mem::transmute::<*const RawGeckoElement, GeckoElement<'static>>(0xbadc0de as *const _); + } + + unsafe { mem::transmute(slice) } + } } /// A simple wrapper over a non-null Gecko node (`nsINode`) pointer. diff --git a/components/style/invalidation/element/invalidation_map.rs b/components/style/invalidation/element/invalidation_map.rs index 63d6eb6acc4..e0b9cf8d747 100644 --- a/components/style/invalidation/element/invalidation_map.rs +++ b/components/style/invalidation/element/invalidation_map.rs @@ -66,6 +66,8 @@ pub enum DependencyInvalidationKind { Siblings, /// This dependency may affect slotted elements of the element that changed. SlottedElements, + /// This dependency may affect parts of the element that changed. + Parts, } impl Dependency { @@ -98,7 +100,7 @@ impl Dependency { // an eager pseudo, and return only Descendants here if not. Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants, Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements, - Some(Combinator::Part) => unimplemented!("Need to add invalidation for shadow parts"), + Some(Combinator::Part) => DependencyInvalidationKind::Parts, } } } diff --git a/components/style/invalidation/element/invalidator.rs b/components/style/invalidation/element/invalidator.rs index ec1548f4aa3..f00aa57fcff 100644 --- a/components/style/invalidation/element/invalidator.rs +++ b/components/style/invalidation/element/invalidator.rs @@ -72,11 +72,14 @@ pub struct DescendantInvalidationLists<'a> { pub dom_descendants: InvalidationVector<'a>, /// Invalidations for slotted children of an element. pub slotted_descendants: InvalidationVector<'a>, + /// Invalidations for ::part()s of an element. + pub parts: InvalidationVector<'a>, } impl<'a> DescendantInvalidationLists<'a> { fn is_empty(&self) -> bool { - self.dom_descendants.is_empty() && self.slotted_descendants.is_empty() + self.dom_descendants.is_empty() && self.slotted_descendants.is_empty() && + self.parts.is_empty() } } @@ -104,6 +107,8 @@ enum DescendantInvalidationKind { Dom, /// A ::slotted() descendant invalidation. Slotted, + /// A ::part() descendant invalidation. + Part, } /// The kind of invalidation we're processing. @@ -175,7 +180,7 @@ impl<'a> Invalidation<'a> { InvalidationKind::Descendant(DescendantInvalidationKind::Dom) }, Combinator::Part => { - unimplemented!("Need to add invalidation for shadow parts"); + InvalidationKind::Descendant(DescendantInvalidationKind::Part) }, Combinator::SlotAssignment => { InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) @@ -472,6 +477,36 @@ where any_descendant } + fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool { + if invalidations.is_empty() { + return false; + } + + let shadow = match self.element.shadow_root() { + Some(s) => s, + None => return false, + }; + + let mut any = false; + let mut sibling_invalidations = InvalidationVector::new(); + for element in shadow.parts() { + any |= self.invalidate_child( + *element, + invalidations, + &mut sibling_invalidations, + DescendantInvalidationKind::Part, + ); + debug_assert!( + sibling_invalidations.is_empty(), + "::part() shouldn't have sibling combinators to the right, \ + this makes no sense! {:?}", + sibling_invalidations + ); + } + any + } + + fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool { if invalidations.is_empty() { return false; @@ -598,6 +633,7 @@ where any_descendant |= self.invalidate_non_slotted_descendants(&invalidations.dom_descendants); any_descendant |= self.invalidate_slotted_elements(&invalidations.slotted_descendants); + any_descendant |= self.invalidate_parts(&invalidations.parts); any_descendant } @@ -672,7 +708,7 @@ where debug_assert_eq!( descendant_invalidation_kind, DescendantInvalidationKind::Dom, - "Slotted invalidations don't propagate." + "Slotted or part invalidations don't propagate." ); descendant_invalidations.dom_descendants.push(invalidation); } @@ -860,6 +896,9 @@ where .dom_descendants .push(next_invalidation); }, + InvalidationKind::Descendant(DescendantInvalidationKind::Part) => { + descendant_invalidations.parts.push(next_invalidation); + }, InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => { descendant_invalidations .slotted_descendants diff --git a/components/style/invalidation/element/state_and_attributes.rs b/components/style/invalidation/element/state_and_attributes.rs index a49bb6306c5..eccc5f60bbf 100644 --- a/components/style/invalidation/element/state_and_attributes.rs +++ b/components/style/invalidation/element/state_and_attributes.rs @@ -472,6 +472,9 @@ where DependencyInvalidationKind::Siblings => { self.sibling_invalidations.push(invalidation); }, + DependencyInvalidationKind::Parts => { + self.descendant_invalidations.parts.push(invalidation); + }, DependencyInvalidationKind::SlottedElements => { self.descendant_invalidations .slotted_descendants @@ -486,6 +489,7 @@ where match dependency.invalidation_kind() { DependencyInvalidationKind::Element => !self.invalidates_self, DependencyInvalidationKind::SlottedElements => self.element.is_html_slot_element(), + DependencyInvalidationKind::Parts => self.element.shadow_root().is_some(), DependencyInvalidationKind::ElementAndDescendants | DependencyInvalidationKind::Siblings | DependencyInvalidationKind::Descendants => true,