1use blitz_traits::node_id::NodeId;
2use std::cmp::Ordering;
3
4use style::{dom::TNode as _, values::specified::box_::DisplayInside};
5
6use crate::{BaseDocument, Node};
7
8macro_rules! iter_children {
9 ($node_expr:expr, $cb:expr) => {{
10 #[cfg(feature = "shadow-dom")]
13 if $node_expr.flattened_children.is_some() {
14 let children = $node_expr.flattened_children.clone().unwrap();
15 for child_id in children {
16 $cb(child_id)
17 }
18 } else {
19 let node = &mut $node_expr;
20 let children = core::mem::take(&mut node.children);
21 for child_id in children.iter().copied() {
22 $cb(child_id)
23 }
24 $node_expr.children = children;
25 }
26 #[cfg(not(feature = "shadow-dom"))]
27 {
28 let node = &mut $node_expr;
29 let children = core::mem::take(&mut node.children);
30 for child_id in children.iter().copied() {
31 $cb(child_id)
32 }
33 $node_expr.children = children;
34 }
35 }};
36}
37pub(crate) use iter_children;
38
39macro_rules! iter_children_and_pseudos {
40 ($node_expr:expr, $cb:expr) => {{
41 let node = &mut $node_expr;
43
44 let before = node.before();
48 let after = node.after();
49
50 if let Some(before) = before {
51 $cb(before)
52 }
53
54 #[cfg(feature = "shadow-dom")]
56 if $node_expr.flattened_children.is_some() {
57 let children = $node_expr.flattened_children.clone().unwrap();
58 for child_id in children {
59 $cb(child_id)
60 }
61 } else {
62 let children = core::mem::take(&mut $node_expr.children);
63 for child_id in children.iter().copied() {
64 $cb(child_id)
65 }
66 $node_expr.children = children;
67 }
68 #[cfg(not(feature = "shadow-dom"))]
69 {
70 let children = core::mem::take(&mut $node_expr.children);
71 for child_id in children.iter().copied() {
72 $cb(child_id)
73 }
74 $node_expr.children = children;
75 }
76
77 if let Some(after) = after {
78 $cb(after)
79 }
80 }};
81}
82pub(crate) use iter_children_and_pseudos;
83
84#[derive(Clone)]
85pub struct TreeTraverser<'a> {
87 doc: &'a BaseDocument,
88 stack: Vec<NodeId>,
89}
90
91impl<'a> TreeTraverser<'a> {
92 pub fn new(doc: &'a BaseDocument) -> Self {
94 Self::new_with_root(doc, doc.root_node().id)
95 }
96
97 pub fn new_with_root(doc: &'a BaseDocument, root: NodeId) -> Self {
99 let mut stack = Vec::with_capacity(32);
100 stack.push(root);
101 TreeTraverser { doc, stack }
102 }
103}
104impl Iterator for TreeTraverser<'_> {
105 type Item = NodeId;
106
107 fn next(&mut self) -> Option<Self::Item> {
108 let id = self.stack.pop()?;
109 let node = self.doc.get_node(id)?;
110 self.stack.extend(node.children.iter().rev());
111 Some(id)
112 }
113}
114
115#[derive(Clone)]
116pub struct AncestorTraverser<'a> {
118 doc: &'a BaseDocument,
119 current: NodeId,
120}
121impl<'a> AncestorTraverser<'a> {
122 pub fn new(doc: &'a BaseDocument, node_id: NodeId) -> Self {
124 AncestorTraverser {
125 doc,
126 current: node_id,
127 }
128 }
129}
130impl Iterator for AncestorTraverser<'_> {
131 type Item = NodeId;
132
133 fn next(&mut self) -> Option<Self::Item> {
134 let current_node = self.doc.get_node(self.current)?;
135 self.current = current_node.parent?;
136 Some(self.current)
137 }
138}
139
140impl Node {
141 #[allow(dead_code)]
142 pub(crate) fn should_traverse_layout_children(&mut self) -> bool {
143 let prefer_layout_children = match self.display_constructed_as().inside() {
144 DisplayInside::None => return false,
145 DisplayInside::Contents => false,
146 DisplayInside::Flow | DisplayInside::FlowRoot | DisplayInside::TableCell => {
147 self.element_data()
149 .is_none_or(|el| el.inline_layout_data.is_none())
150 }
151 DisplayInside::Flex | DisplayInside::Grid => true,
152 DisplayInside::Table => false,
153 DisplayInside::TableRowGroup => false,
154 DisplayInside::TableColumn => false,
155 DisplayInside::TableColumnGroup => false,
156 DisplayInside::TableHeaderGroup => false,
157 DisplayInside::TableFooterGroup => false,
158 DisplayInside::TableRow => false,
159 };
160 let has_layout_children = self.layout_children.get_mut().is_some();
161 prefer_layout_children & has_layout_children
162 }
163}
164
165impl BaseDocument {
166 pub fn node_chain(&self, node_id: NodeId) -> Vec<NodeId> {
168 let mut chain = Vec::with_capacity(16);
169 chain.push(node_id);
170 chain.extend(
171 AncestorTraverser::new(self, node_id).filter(|id| self.nodes[*id].is_element()),
172 );
173 let document_id = self.root_node().id;
179 if chain.last().copied() != Some(document_id) {
180 chain.push(document_id);
181 }
182 chain
183 }
184
185 pub fn visit<F>(&self, mut visit: F)
186 where
187 F: FnMut(NodeId, &Node),
188 {
189 TreeTraverser::new(self).for_each(|node_id| visit(node_id, &self.nodes[node_id]));
190 }
191
192 pub fn visit_flattened<F>(&self, mut visit: F)
196 where
197 F: FnMut(NodeId, Option<NodeId>, &Node),
198 {
199 let mut stack = vec![(self.root_node_id, None)];
200 while let Some((id, parent)) = stack.pop() {
201 let Some(node) = self.get_node(id) else {
202 continue;
203 };
204 visit(id, parent, node);
205 stack.extend(
206 node.layout_dom_children()
207 .iter()
208 .rev()
209 .map(|&child| (child, Some(id))),
210 );
211 }
212 }
213
214 pub fn non_anon_ancestor_if_anon(&self, mut node_id: NodeId) -> NodeId {
217 loop {
218 let node = &self.nodes[node_id];
219
220 if !node.is_anonymous() {
221 return node.id;
222 }
223
224 let Some(parent_id) = node.layout_parent.get() else {
225 panic!("Node does not exist or does not have a non-anonymous parent");
228 };
229
230 node_id = parent_id;
231 }
232 }
233
234 pub fn iter_children_mut(
235 &mut self,
236 node_id: NodeId,
237 mut cb: impl FnMut(NodeId, &mut BaseDocument),
238 ) {
239 let children = std::mem::take(&mut self.nodes[node_id].children);
240 for child_id in children.iter().cloned() {
241 cb(child_id, self);
242 }
243 self.nodes[node_id].children = children;
244 }
245
246 pub fn iter_shadow_including_subtree_mut(
249 &mut self,
250 node_id: NodeId,
251 mut cb: impl FnMut(NodeId, &mut BaseDocument),
252 ) {
253 let mut stack = vec![node_id];
254 while let Some(id) = stack.pop() {
255 let Some(node) = self.get_node(id) else {
256 continue;
257 };
258 #[cfg_attr(not(feature = "shadow-dom"), allow(unused_mut))]
259 let mut children = node.children.to_vec();
260 #[cfg(feature = "shadow-dom")]
261 if let Some(root_id) = node.shadow_root_id() {
262 children.push(root_id);
263 }
264 cb(id, self);
265 stack.extend(children.into_iter().rev());
266 }
267 }
268
269 pub fn iter_subtree_mut(
270 &mut self,
271 node_id: NodeId,
272 mut cb: impl FnMut(NodeId, &mut BaseDocument),
273 ) {
274 cb(node_id, self);
275 iter_subtree_mut_inner(self, node_id, &mut cb);
276 fn iter_subtree_mut_inner(
277 doc: &mut BaseDocument,
278 node_id: NodeId,
279 cb: &mut impl FnMut(NodeId, &mut BaseDocument),
280 ) {
281 let children = std::mem::take(&mut doc.nodes[node_id].children);
282 for child_id in children.iter().cloned() {
283 cb(child_id, doc);
284 iter_subtree_mut_inner(doc, child_id, cb);
285 }
286 doc.nodes[node_id].children = children;
287 }
288 }
289
290 pub fn iter_children_and_pseudos_mut(
291 &mut self,
292 node_id: NodeId,
293 mut cb: impl FnMut(NodeId, &mut BaseDocument),
294 ) {
295 let before = self.nodes[node_id].before();
296 self.nodes[node_id].set_pe_by_index(1, None);
297 if let Some(before_node_id) = before {
298 cb(before_node_id, self)
299 }
300 self.nodes[node_id].set_pe_by_index(1, before);
301
302 self.iter_children_mut(node_id, &mut cb);
303
304 let after = self.nodes[node_id].after();
305 self.nodes[node_id].set_pe_by_index(0, None);
306 if let Some(after_node_id) = after {
307 cb(after_node_id, self)
308 }
309 self.nodes[node_id].set_pe_by_index(0, after);
310 }
311
312 pub fn iter_layout_children_mut(
316 &mut self,
317 node_id: NodeId,
318 mut cb: impl FnMut(NodeId, &mut BaseDocument),
319 ) {
320 let children = self.nodes[node_id].layout_dom_children().to_vec();
321 for child_id in children {
322 cb(child_id, self);
323 }
324 }
325
326 pub fn iter_layout_children_and_pseudos_mut(
329 &mut self,
330 node_id: NodeId,
331 mut cb: impl FnMut(NodeId, &mut BaseDocument),
332 ) {
333 if let Some(before_node_id) = self.nodes[node_id].before() {
334 cb(before_node_id, self)
335 }
336
337 self.iter_layout_children_mut(node_id, &mut cb);
338
339 if let Some(after_node_id) = self.nodes[node_id].after() {
340 cb(after_node_id, self)
341 }
342 }
343
344 pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
345 let start_id = start.id;
346 let mut node = start;
347 let mut look_in_children = true;
348 loop {
349 let next = if look_in_children && !node.children.is_empty() {
351 let node_id = node.children[0];
352 &self.nodes[node_id]
353 }
354 else if let Some(parent) = node.parent_node() {
356 let self_idx = parent
357 .children
358 .iter()
359 .position(|id| *id == node.id)
360 .unwrap();
361 if let Some(sibling_id) = parent.children.get(self_idx + 1) {
363 look_in_children = true;
364 &self.nodes[*sibling_id]
365 }
366 else {
368 look_in_children = false;
369 node = parent;
370 continue;
371 }
372 }
373 else {
375 look_in_children = true;
376 self.root_node()
377 };
378
379 if filter(next) {
380 return Some(next.id);
381 } else if next.id == start_id {
382 return None;
383 }
384
385 node = next;
386 }
387 }
388
389 fn deepest_last_descendant<'a>(&'a self, mut node: &'a Node) -> &'a Node {
392 while let Some(last_child_id) = node.children.last() {
393 node = &self.nodes[*last_child_id];
394 }
395 node
396 }
397
398 pub fn prev_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
401 let start_id = start.id;
402 let mut node = start;
403 loop {
404 let prev = if let Some(parent) = node.parent_node() {
405 let self_idx = parent
406 .children
407 .iter()
408 .position(|id| *id == node.id)
409 .unwrap();
410 if self_idx > 0 {
413 self.deepest_last_descendant(&self.nodes[parent.children[self_idx - 1]])
414 } else {
415 parent
416 }
417 }
418 else {
420 self.deepest_last_descendant(self.root_node())
421 };
422
423 if filter(prev) {
424 return Some(prev.id);
425 } else if prev.id == start_id {
426 return None;
427 }
428
429 node = prev;
430 }
431 }
432
433 pub fn node_layout_ancestors(&self, node_id: NodeId) -> Vec<NodeId> {
434 let mut ancestors = Vec::with_capacity(12);
435 let mut maybe_id = Some(node_id);
436 while let Some(id) = maybe_id {
437 ancestors.push(id);
438 maybe_id = self.nodes[id].layout_parent.get();
439 }
440 ancestors.reverse();
441 ancestors
442 }
443
444 pub fn maybe_node_layout_ancestors(&self, node_id: Option<NodeId>) -> Vec<NodeId> {
445 node_id
446 .map(|id| self.node_layout_ancestors(id))
447 .unwrap_or_default()
448 }
449
450 pub fn compare_document_order(&self, node_a: NodeId, node_b: NodeId) -> Ordering {
455 if node_a == node_b {
456 return Ordering::Equal;
457 }
458
459 let chain_a = self.ancestor_chain_from_root(node_a);
461 let chain_b = self.ancestor_chain_from_root(node_b);
462
463 let mut common_depth = 0;
465 for (a, b) in chain_a.iter().zip(chain_b.iter()) {
466 if a != b {
467 break;
468 }
469 common_depth += 1;
470 }
471
472 if common_depth == chain_a.len() {
474 return Ordering::Less; }
476 if common_depth == chain_b.len() {
477 return Ordering::Greater; }
479
480 debug_assert!(
484 common_depth > 0,
485 "nodes must share a common ancestor (the root)"
486 );
487
488 let divergent_a = chain_a[common_depth];
490 let divergent_b = chain_b[common_depth];
491 let parent_id = chain_a[common_depth - 1];
492 let parent = &self.nodes[parent_id];
493
494 for &child_id in &parent.children {
495 if child_id == divergent_a {
496 return Ordering::Less;
497 }
498 if child_id == divergent_b {
499 return Ordering::Greater;
500 }
501 }
502
503 Ordering::Equal
505 }
506
507 fn ancestor_chain_from_root(&self, node_id: NodeId) -> Vec<NodeId> {
509 let mut ancestors = Vec::with_capacity(16);
510 let mut current = Some(node_id);
511 while let Some(id) = current {
512 ancestors.push(id);
513 current = self.nodes[id].parent;
514 }
515 ancestors.reverse();
516 ancestors
517 }
518
519 pub fn collect_inline_roots_in_range(
523 &self,
524 start_node: NodeId,
525 end_node: NodeId,
526 ) -> Vec<NodeId> {
527 let (start_anchor, start_anon) = self.resolve_for_traversal(start_node);
529 let (end_anchor, end_anon) = self.resolve_for_traversal(end_node);
530
531 if start_anon.is_some() && end_anon.is_some() && start_anchor == end_anchor {
533 return self.collect_anonymous_siblings(start_anchor, start_node, end_node);
534 }
535
536 let (first_anchor, first_anon, last_anchor, last_anon) = match self
538 .compare_document_order(start_anchor, end_anchor)
539 {
540 Ordering::Less | Ordering::Equal => (start_anchor, start_anon, end_anchor, end_anon),
541 Ordering::Greater => (end_anchor, end_anon, start_anchor, start_anon),
542 };
543
544 let mut result = Vec::new();
545 let mut found_first = false;
546
547 for node_id in TreeTraverser::new(self) {
549 if !found_first {
550 if node_id == first_anchor {
551 found_first = true;
552 if let Some(anon_id) = first_anon {
553 let stop_at = if first_anchor == last_anchor {
556 last_anon
558 } else {
559 Some(last_anchor)
561 };
562 self.collect_layout_children_inline_roots(
563 node_id,
564 Some(anon_id),
565 stop_at,
566 &mut result,
567 );
568 if result.last() == Some(&last_anchor)
570 || last_anon.is_some_and(|la| result.last() == Some(&la))
571 {
572 break;
573 }
574 continue;
575 }
576 }
577 }
578
579 if found_first {
580 if node_id == last_anchor {
581 if let Some(anon_id) = last_anon {
582 self.collect_layout_children_inline_roots(
584 node_id,
585 None,
586 Some(anon_id),
587 &mut result,
588 );
589 if !result.contains(&anon_id) {
591 result.push(anon_id);
592 }
593 } else {
594 let node = &self.nodes[node_id];
596 if node.flags.is_inline_root() && !result.contains(&node_id) {
597 result.push(node_id);
598 }
599 }
600 break;
601 }
602
603 let node = &self.nodes[node_id];
604 if node.flags.is_inline_root() && !result.contains(&node_id) {
605 result.push(node_id);
606 } else {
607 self.collect_layout_children_inline_roots(
610 node_id,
611 None,
612 Some(last_anchor),
613 &mut result,
614 );
615 }
616 }
617 }
618
619 result
620 }
621
622 fn resolve_for_traversal(&self, node_id: NodeId) -> (NodeId, Option<NodeId>) {
626 let node = &self.nodes[node_id];
627 if node.is_anonymous() {
628 (node.parent.unwrap_or(node_id), Some(node_id))
629 } else {
630 (node_id, None)
631 }
632 }
633
634 fn collect_anonymous_siblings(
637 &self,
638 parent_id: NodeId,
639 start: NodeId,
640 end: NodeId,
641 ) -> Vec<NodeId> {
642 let parent = &self.nodes[parent_id];
643 let layout_children = parent.layout_children.borrow();
644 let Some(children) = layout_children.as_ref() else {
645 return Vec::new();
646 };
647
648 let start_idx = children.iter().position(|&id| id == start);
649 let end_idx = children.iter().position(|&id| id == end);
650
651 let (first_idx, last_idx) = match (start_idx, end_idx) {
652 (Some(s), Some(e)) if s <= e => (s, e),
653 (Some(s), Some(e)) => (e, s),
654 _ => return Vec::new(),
655 };
656
657 let mut result = Vec::new();
658 for &child_id in &children[first_idx..=last_idx] {
659 let child = &self.nodes[child_id];
660 if child.flags.is_inline_root() {
661 result.push(child_id);
662 } else {
663 self.collect_all_inline_roots_in_subtree(child_id, &mut result);
665 }
666 }
667 result
668 }
669
670 fn collect_all_inline_roots_in_subtree(&self, node_id: NodeId, result: &mut Vec<NodeId>) {
672 let node = &self.nodes[node_id];
673 let layout_children = node.layout_children.borrow();
674 let Some(children) = layout_children.as_ref() else {
675 return;
676 };
677
678 for &child_id in children.iter() {
679 let child = &self.nodes[child_id];
680 if child.flags.is_inline_root() {
681 result.push(child_id);
682 } else {
683 self.collect_all_inline_roots_in_subtree(child_id, result);
685 }
686 }
687 }
688
689 fn collect_layout_children_inline_roots(
693 &self,
694 parent_id: NodeId,
695 from: Option<NodeId>,
696 until: Option<NodeId>,
697 result: &mut Vec<NodeId>,
698 ) {
699 let parent = &self.nodes[parent_id];
700 let layout_children = parent.layout_children.borrow();
701 let Some(children) = layout_children.as_ref() else {
702 return;
703 };
704
705 let mut collecting = from.is_none(); for &child_id in children.iter() {
707 if from == Some(child_id) {
708 collecting = true;
709 }
710 if collecting {
711 if let Some(until_id) = until {
713 if self.is_ancestor_of(child_id, until_id) {
714 break;
715 }
716 }
717 if until == Some(child_id) {
719 break;
720 }
721 let child = &self.nodes[child_id];
722 if child.flags.is_inline_root() {
723 result.push(child_id);
724 } else {
725 self.collect_all_inline_roots_in_subtree(child_id, result);
727 }
728 }
729 }
730 }
731
732 fn is_ancestor_of(&self, ancestor_id: NodeId, descendant_id: NodeId) -> bool {
734 let mut current = descendant_id;
735 while let Some(parent) = self.nodes[current].parent {
736 if parent == ancestor_id {
737 return true;
738 }
739 current = parent;
740 }
741 false
742 }
743}