diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs index ab999cab6ba..daa1de2f1fe 100644 --- a/components/script/dom/bindings/root.rs +++ b/components/script/dom/bindings/root.rs @@ -291,6 +291,20 @@ impl MutNullableDom { self.set(None); value } + + /// Runs the given callback on the object if it's not null. + pub(crate) fn if_is_some(&self, cb: F) -> Option<&R> + where + F: FnOnce(&T) -> &R, + { + unsafe { + if let Some(ref value) = *self.ptr.get() { + Some(cb(value)) + } else { + None + } + } + } } impl PartialEq for MutNullableDom { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index db946f6a8e6..067b8f0b4c9 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -796,8 +796,15 @@ impl Node { self.inclusive_descendants_version(), doc.inclusive_descendants_version(), ) + 1; - for ancestor in self.inclusive_ancestors(ShadowIncluding::No) { - ancestor.inclusive_descendants_version.set(version); + + // This `while` loop is equivalent to iterating over the non-shadow-inclusive ancestors + // without creating intermediate rooted DOM objects. + let mut node = &MutNullableDom::new(Some(self)); + while let Some(p) = node.if_is_some(|p| { + p.inclusive_descendants_version.set(version); + &p.parent_node + }) { + node = p } doc.inclusive_descendants_version.set(version); }