From a49eb14615b12960b0bb35cc2b5c59e46f47d869 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 25 Jul 2015 02:13:35 +0200 Subject: [PATCH] Cache the number of children of each node --- components/layout/parallel.rs | 3 +- components/layout/wrapper.rs | 4 +++ components/script/dom/node.rs | 56 +++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index efe49165850..ad0517b6d1b 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -123,8 +123,7 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { // Perform the appropriate traversal. self.process(node); - // NB: O(n). - let child_count = node.children().count(); + let child_count = node.children_count(); // Reset the count of children. { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 26378daf40c..bde6f39970e 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -237,6 +237,10 @@ impl<'ln> LayoutNode<'ln> { self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) } } + + pub fn children_count(&self) -> u32 { + unsafe { self.node.children_count() } + } } impl<'ln> LayoutNode<'ln> { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 1f6a681e582..e8cb5641e29 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -106,6 +106,9 @@ pub struct Node { /// The live list of children return by .childNodes. child_list: MutNullableHeap>, + /// The live count of children of this node. + children_count: Cell, + /// A bitfield of flags for node items. flags: Cell, @@ -430,6 +433,7 @@ pub trait NodeHelpers { fn type_id(self) -> NodeTypeId; fn len(self) -> u32; fn index(self) -> u32; + fn children_count(self) -> u32; fn owner_doc(self) -> Root; fn set_owner_doc(self, document: &Document); @@ -567,7 +571,7 @@ impl<'a> NodeHelpers for &'a Node { NodeTypeId::CharacterData(_) => { CharacterDataCast::to_ref(self).unwrap().Length() }, - _ => self.children().count() as u32 + _ => self.children_count(), } } @@ -576,6 +580,10 @@ impl<'a> NodeHelpers for &'a Node { self.preceding_siblings().count() as u32 } + fn children_count(self) -> u32 { + self.children_count.get() + } + #[inline] fn is_anchor_element(self) -> bool { self.type_id == NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) @@ -1076,36 +1084,26 @@ pub fn from_untrusted_node_address(_runtime: *mut JSRuntime, candidate: Untruste } } +#[allow(unsafe_code)] pub trait LayoutNodeHelpers { - #[allow(unsafe_code)] unsafe fn type_id_for_layout(&self) -> NodeTypeId; - #[allow(unsafe_code)] unsafe fn parent_node_ref(&self) -> Option>; - #[allow(unsafe_code)] unsafe fn first_child_ref(&self) -> Option>; - #[allow(unsafe_code)] unsafe fn last_child_ref(&self) -> Option>; - #[allow(unsafe_code)] unsafe fn prev_sibling_ref(&self) -> Option>; - #[allow(unsafe_code)] unsafe fn next_sibling_ref(&self) -> Option>; - #[allow(unsafe_code)] unsafe fn owner_doc_for_layout(&self) -> LayoutJS; - #[allow(unsafe_code)] unsafe fn is_element_for_layout(&self) -> bool; - #[allow(unsafe_code)] unsafe fn get_flag(&self, flag: NodeFlags) -> bool; - #[allow(unsafe_code)] unsafe fn set_flag(&self, flag: NodeFlags, value: bool); - #[allow(unsafe_code)] + unsafe fn children_count(&self) -> u32; + unsafe fn layout_data(&self) -> Ref>; - #[allow(unsafe_code)] unsafe fn layout_data_mut(&self) -> RefMut>; - #[allow(unsafe_code)] unsafe fn layout_data_unchecked(&self) -> *const Option; fn get_hover_state_for_layout(&self) -> bool; @@ -1184,6 +1182,12 @@ impl LayoutNodeHelpers for LayoutJS { (*this).flags.set(flags); } + #[inline] + #[allow(unsafe_code)] + unsafe fn children_count(&self) -> u32 { + (*self.unsafe_get()).children_count.get() + } + #[inline] #[allow(unsafe_code)] unsafe fn layout_data(&self) -> Ref> { @@ -1482,6 +1486,7 @@ impl Node { prev_sibling: Default::default(), owner_doc: MutNullableHeap::new(doc.map(JS::from_ref)), child_list: Default::default(), + children_count: Cell::new(0u32), flags: Cell::new(NodeFlags::new(type_id)), layout_data: LayoutDataRef::new(), @@ -2404,7 +2409,7 @@ impl<'a> NodeMethods for &'a Node { } // Step 5. - if this.children().count() != node.children().count() { + if this.children_count() != node.children_count() { return false; } @@ -2557,6 +2562,27 @@ impl<'a> VirtualMethods for &'a Node { let eventtarget: &&EventTarget = EventTargetCast::from_borrowed_ref(self); Some(eventtarget as &VirtualMethods) } + + fn children_changed(&self, mutation: &ChildrenMutation) { + if let Some(ref s) = self.super_type() { + s.children_changed(mutation); + } + match *mutation { + ChildrenMutation::Append { added, .. } | + ChildrenMutation::Insert { added, .. } | + ChildrenMutation::Prepend { added, .. } => { + self.children_count.set( + self.children_count.get() + added.len() as u32); + }, + ChildrenMutation::Replace { added, .. } => { + self.children_count.set( + self.children_count.get() - 1u32 + added.len() as u32); + }, + ChildrenMutation::ReplaceAll { added, .. } => { + self.children_count.set(added.len() as u32); + }, + } + } } pub trait DisabledStateHelpers {