diff --git a/packages/dom/src/document.rs b/packages/dom/src/document.rs index 0f54c177c..e0cf88b7f 100644 --- a/packages/dom/src/document.rs +++ b/packages/dom/src/document.rs @@ -310,6 +310,21 @@ impl Document { new_node_id } + /// Used for cleaning invalid anonymous blocks + fn clean_anonymous_blocks(&mut self, node_id: usize) { + let children = &mut self.nodes[node_id].children.clone(); + for child_id in children.iter() { + self.clean_anonymous_blocks(*child_id); + } + + let node = &mut self.nodes[node_id]; + node.anonymous_block_id = None; + if let Some(anonymous_block_id) = node.anonymous_block_id { + // Removing does pattern matching so removing the same node multiple times is ok + self.remove_node(anonymous_block_id); + } + } + pub fn insert_before(&mut self, node_id: usize, inserted_node_ids: &[usize]) { // let count = inserted_node_ids.len(); @@ -319,6 +334,7 @@ impl Document { let node_child_idx = node.child_idx; let parent_id = node.parent.unwrap(); + self.clean_anonymous_blocks(parent_id); let parent = &mut self.nodes[parent_id]; // Mark the node's parent as changed. @@ -347,6 +363,7 @@ impl Document { let node = &self.nodes[node_id]; // let node_child_idx = node.child_idx; let parent_id = node.parent.unwrap(); + self.clean_anonymous_blocks(parent_id); let parent = &mut self.nodes[parent_id]; let mut children = std::mem::take(&mut parent.children); @@ -383,6 +400,7 @@ impl Document { if let Some(Node { mut child_idx, parent: Some(parent_id), + anonymous_block_id, .. }) = node { @@ -399,7 +417,20 @@ impl Document { child_idx += 1; } - self.nodes[parent_id].children = children; + // remove unneeded anonymous blocks + if let Some(anonymous_block_id) = anonymous_block_id { + let is_block_used = children.iter().any(|child_id| { + let child = self.get_node(*child_id); + matches!(child, Some(child) if child.anonymous_block_id == Some(anonymous_block_id)) + }); + + self.nodes[parent_id].children = children; + if !is_block_used { + self.remove_node(anonymous_block_id); + } + } else { + self.nodes[parent_id].children = children; + } } node diff --git a/packages/dom/src/layout/construct.rs b/packages/dom/src/layout/construct.rs index bf62b0a3a..63897c93f 100644 --- a/packages/dom/src/layout/construct.rs +++ b/packages/dom/src/layout/construct.rs @@ -235,6 +235,13 @@ fn collect_complex_layout_children( else if needs_wrap(child_node_kind, display_outside) { use style::selector_parser::PseudoElement; + // TODO: once let chaining lends in stable, make nicer + if anonymous_block_id.is_none() { + if let Some(child) = doc.get_node(child_id) { + *anonymous_block_id = child.anonymous_block_id; + } + } + if anonymous_block_id.is_none() { const NAME: QualName = QualName { prefix: None, @@ -246,6 +253,9 @@ fn collect_complex_layout_children( Vec::new(), ))); + let child = doc.get_node_mut(child_id).unwrap(); + child.anonymous_block_id = Some(node_id); + // Set style data let parent_style = doc.nodes[container_node_id].primary_styles().unwrap(); let read_guard = doc.guard.read(); @@ -262,6 +272,9 @@ fn collect_complex_layout_children( layout_children.push(node_id); *anonymous_block_id = Some(node_id); + + #[cfg(feature = "tracing")] + tracing::info!("Created anonymous block container with id {}", node_id); } doc.nodes[anonymous_block_id.unwrap()] diff --git a/packages/dom/src/node.rs b/packages/dom/src/node.rs index 36c657b46..fc56ea5a7 100644 --- a/packages/dom/src/node.rs +++ b/packages/dom/src/node.rs @@ -53,6 +53,10 @@ pub struct Node { pub child_idx: usize, // What are our children? pub children: Vec, + // What anonymous block are we a part of + // Changing order of nodes requires unsetting + // using the "clean_anonymous_blocks" method with parent_id + pub anonymous_block_id: Option, /// A separate child list that includes anonymous collections of inline elements pub layout_children: RefCell>>, @@ -90,6 +94,7 @@ impl Node { id, parent: None, children: vec![], + anonymous_block_id: None, layout_children: RefCell::new(None), child_idx: 0,