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 non_anon_ancestor_if_anon(&self, mut node_id: NodeId) -> NodeId {
195 loop {
196 let node = &self.nodes[node_id];
197
198 if !node.is_anonymous() {
199 return node.id;
200 }
201
202 let Some(parent_id) = node.layout_parent.get() else {
203 panic!("Node does not exist or does not have a non-anonymous parent");
206 };
207
208 node_id = parent_id;
209 }
210 }
211
212 pub fn iter_children_mut(
213 &mut self,
214 node_id: NodeId,
215 mut cb: impl FnMut(NodeId, &mut BaseDocument),
216 ) {
217 let children = std::mem::take(&mut self.nodes[node_id].children);
218 for child_id in children.iter().cloned() {
219 cb(child_id, self);
220 }
221 self.nodes[node_id].children = children;
222 }
223
224 pub fn iter_subtree_mut(
225 &mut self,
226 node_id: NodeId,
227 mut cb: impl FnMut(NodeId, &mut BaseDocument),
228 ) {
229 cb(node_id, self);
230 iter_subtree_mut_inner(self, node_id, &mut cb);
231 fn iter_subtree_mut_inner(
232 doc: &mut BaseDocument,
233 node_id: NodeId,
234 cb: &mut impl FnMut(NodeId, &mut BaseDocument),
235 ) {
236 let children = std::mem::take(&mut doc.nodes[node_id].children);
237 for child_id in children.iter().cloned() {
238 cb(child_id, doc);
239 iter_subtree_mut_inner(doc, child_id, cb);
240 }
241 doc.nodes[node_id].children = children;
242 }
243 }
244
245 pub fn iter_children_and_pseudos_mut(
246 &mut self,
247 node_id: NodeId,
248 mut cb: impl FnMut(NodeId, &mut BaseDocument),
249 ) {
250 let before = self.nodes[node_id].before();
251 self.nodes[node_id].set_pe_by_index(1, None);
252 if let Some(before_node_id) = before {
253 cb(before_node_id, self)
254 }
255 self.nodes[node_id].set_pe_by_index(1, before);
256
257 self.iter_children_mut(node_id, &mut cb);
258
259 let after = self.nodes[node_id].after();
260 self.nodes[node_id].set_pe_by_index(0, None);
261 if let Some(after_node_id) = after {
262 cb(after_node_id, self)
263 }
264 self.nodes[node_id].set_pe_by_index(0, after);
265 }
266
267 pub fn iter_layout_children_mut(
271 &mut self,
272 node_id: NodeId,
273 mut cb: impl FnMut(NodeId, &mut BaseDocument),
274 ) {
275 let children = self.nodes[node_id].layout_dom_children().to_vec();
276 for child_id in children {
277 cb(child_id, self);
278 }
279 }
280
281 pub fn iter_layout_children_and_pseudos_mut(
284 &mut self,
285 node_id: NodeId,
286 mut cb: impl FnMut(NodeId, &mut BaseDocument),
287 ) {
288 if let Some(before_node_id) = self.nodes[node_id].before() {
289 cb(before_node_id, self)
290 }
291
292 self.iter_layout_children_mut(node_id, &mut cb);
293
294 if let Some(after_node_id) = self.nodes[node_id].after() {
295 cb(after_node_id, self)
296 }
297 }
298
299 pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
300 let start_id = start.id;
301 let mut node = start;
302 let mut look_in_children = true;
303 loop {
304 let next = if look_in_children && !node.children.is_empty() {
306 let node_id = node.children[0];
307 &self.nodes[node_id]
308 }
309 else if let Some(parent) = node.parent_node() {
311 let self_idx = parent
312 .children
313 .iter()
314 .position(|id| *id == node.id)
315 .unwrap();
316 if let Some(sibling_id) = parent.children.get(self_idx + 1) {
318 look_in_children = true;
319 &self.nodes[*sibling_id]
320 }
321 else {
323 look_in_children = false;
324 node = parent;
325 continue;
326 }
327 }
328 else {
330 look_in_children = true;
331 self.root_node()
332 };
333
334 if filter(next) {
335 return Some(next.id);
336 } else if next.id == start_id {
337 return None;
338 }
339
340 node = next;
341 }
342 }
343
344 fn deepest_last_descendant<'a>(&'a self, mut node: &'a Node) -> &'a Node {
347 while let Some(last_child_id) = node.children.last() {
348 node = &self.nodes[*last_child_id];
349 }
350 node
351 }
352
353 pub fn prev_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
356 let start_id = start.id;
357 let mut node = start;
358 loop {
359 let prev = if let Some(parent) = node.parent_node() {
360 let self_idx = parent
361 .children
362 .iter()
363 .position(|id| *id == node.id)
364 .unwrap();
365 if self_idx > 0 {
368 self.deepest_last_descendant(&self.nodes[parent.children[self_idx - 1]])
369 } else {
370 parent
371 }
372 }
373 else {
375 self.deepest_last_descendant(self.root_node())
376 };
377
378 if filter(prev) {
379 return Some(prev.id);
380 } else if prev.id == start_id {
381 return None;
382 }
383
384 node = prev;
385 }
386 }
387
388 pub fn node_layout_ancestors(&self, node_id: NodeId) -> Vec<NodeId> {
389 let mut ancestors = Vec::with_capacity(12);
390 let mut maybe_id = Some(node_id);
391 while let Some(id) = maybe_id {
392 ancestors.push(id);
393 maybe_id = self.nodes[id].layout_parent.get();
394 }
395 ancestors.reverse();
396 ancestors
397 }
398
399 pub fn maybe_node_layout_ancestors(&self, node_id: Option<NodeId>) -> Vec<NodeId> {
400 node_id
401 .map(|id| self.node_layout_ancestors(id))
402 .unwrap_or_default()
403 }
404
405 pub fn compare_document_order(&self, node_a: NodeId, node_b: NodeId) -> Ordering {
410 if node_a == node_b {
411 return Ordering::Equal;
412 }
413
414 let chain_a = self.ancestor_chain_from_root(node_a);
416 let chain_b = self.ancestor_chain_from_root(node_b);
417
418 let mut common_depth = 0;
420 for (a, b) in chain_a.iter().zip(chain_b.iter()) {
421 if a != b {
422 break;
423 }
424 common_depth += 1;
425 }
426
427 if common_depth == chain_a.len() {
429 return Ordering::Less; }
431 if common_depth == chain_b.len() {
432 return Ordering::Greater; }
434
435 debug_assert!(
439 common_depth > 0,
440 "nodes must share a common ancestor (the root)"
441 );
442
443 let divergent_a = chain_a[common_depth];
445 let divergent_b = chain_b[common_depth];
446 let parent_id = chain_a[common_depth - 1];
447 let parent = &self.nodes[parent_id];
448
449 for &child_id in &parent.children {
450 if child_id == divergent_a {
451 return Ordering::Less;
452 }
453 if child_id == divergent_b {
454 return Ordering::Greater;
455 }
456 }
457
458 Ordering::Equal
460 }
461
462 fn ancestor_chain_from_root(&self, node_id: NodeId) -> Vec<NodeId> {
464 let mut ancestors = Vec::with_capacity(16);
465 let mut current = Some(node_id);
466 while let Some(id) = current {
467 ancestors.push(id);
468 current = self.nodes[id].parent;
469 }
470 ancestors.reverse();
471 ancestors
472 }
473
474 pub fn collect_inline_roots_in_range(
478 &self,
479 start_node: NodeId,
480 end_node: NodeId,
481 ) -> Vec<NodeId> {
482 let (start_anchor, start_anon) = self.resolve_for_traversal(start_node);
484 let (end_anchor, end_anon) = self.resolve_for_traversal(end_node);
485
486 if start_anon.is_some() && end_anon.is_some() && start_anchor == end_anchor {
488 return self.collect_anonymous_siblings(start_anchor, start_node, end_node);
489 }
490
491 let (first_anchor, first_anon, last_anchor, last_anon) = match self
493 .compare_document_order(start_anchor, end_anchor)
494 {
495 Ordering::Less | Ordering::Equal => (start_anchor, start_anon, end_anchor, end_anon),
496 Ordering::Greater => (end_anchor, end_anon, start_anchor, start_anon),
497 };
498
499 let mut result = Vec::new();
500 let mut found_first = false;
501
502 for node_id in TreeTraverser::new(self) {
504 if !found_first {
505 if node_id == first_anchor {
506 found_first = true;
507 if let Some(anon_id) = first_anon {
508 let stop_at = if first_anchor == last_anchor {
511 last_anon
513 } else {
514 Some(last_anchor)
516 };
517 self.collect_layout_children_inline_roots(
518 node_id,
519 Some(anon_id),
520 stop_at,
521 &mut result,
522 );
523 if result.last() == Some(&last_anchor)
525 || last_anon.is_some_and(|la| result.last() == Some(&la))
526 {
527 break;
528 }
529 continue;
530 }
531 }
532 }
533
534 if found_first {
535 if node_id == last_anchor {
536 if let Some(anon_id) = last_anon {
537 self.collect_layout_children_inline_roots(
539 node_id,
540 None,
541 Some(anon_id),
542 &mut result,
543 );
544 if !result.contains(&anon_id) {
546 result.push(anon_id);
547 }
548 } else {
549 let node = &self.nodes[node_id];
551 if node.flags.is_inline_root() && !result.contains(&node_id) {
552 result.push(node_id);
553 }
554 }
555 break;
556 }
557
558 let node = &self.nodes[node_id];
559 if node.flags.is_inline_root() && !result.contains(&node_id) {
560 result.push(node_id);
561 } else {
562 self.collect_layout_children_inline_roots(
565 node_id,
566 None,
567 Some(last_anchor),
568 &mut result,
569 );
570 }
571 }
572 }
573
574 result
575 }
576
577 fn resolve_for_traversal(&self, node_id: NodeId) -> (NodeId, Option<NodeId>) {
581 let node = &self.nodes[node_id];
582 if node.is_anonymous() {
583 (node.parent.unwrap_or(node_id), Some(node_id))
584 } else {
585 (node_id, None)
586 }
587 }
588
589 fn collect_anonymous_siblings(
592 &self,
593 parent_id: NodeId,
594 start: NodeId,
595 end: NodeId,
596 ) -> Vec<NodeId> {
597 let parent = &self.nodes[parent_id];
598 let layout_children = parent.layout_children.borrow();
599 let Some(children) = layout_children.as_ref() else {
600 return Vec::new();
601 };
602
603 let start_idx = children.iter().position(|&id| id == start);
604 let end_idx = children.iter().position(|&id| id == end);
605
606 let (first_idx, last_idx) = match (start_idx, end_idx) {
607 (Some(s), Some(e)) if s <= e => (s, e),
608 (Some(s), Some(e)) => (e, s),
609 _ => return Vec::new(),
610 };
611
612 let mut result = Vec::new();
613 for &child_id in &children[first_idx..=last_idx] {
614 let child = &self.nodes[child_id];
615 if child.flags.is_inline_root() {
616 result.push(child_id);
617 } else {
618 self.collect_all_inline_roots_in_subtree(child_id, &mut result);
620 }
621 }
622 result
623 }
624
625 fn collect_all_inline_roots_in_subtree(&self, node_id: NodeId, result: &mut Vec<NodeId>) {
627 let node = &self.nodes[node_id];
628 let layout_children = node.layout_children.borrow();
629 let Some(children) = layout_children.as_ref() else {
630 return;
631 };
632
633 for &child_id in children.iter() {
634 let child = &self.nodes[child_id];
635 if child.flags.is_inline_root() {
636 result.push(child_id);
637 } else {
638 self.collect_all_inline_roots_in_subtree(child_id, result);
640 }
641 }
642 }
643
644 fn collect_layout_children_inline_roots(
648 &self,
649 parent_id: NodeId,
650 from: Option<NodeId>,
651 until: Option<NodeId>,
652 result: &mut Vec<NodeId>,
653 ) {
654 let parent = &self.nodes[parent_id];
655 let layout_children = parent.layout_children.borrow();
656 let Some(children) = layout_children.as_ref() else {
657 return;
658 };
659
660 let mut collecting = from.is_none(); for &child_id in children.iter() {
662 if from == Some(child_id) {
663 collecting = true;
664 }
665 if collecting {
666 if let Some(until_id) = until {
668 if self.is_ancestor_of(child_id, until_id) {
669 break;
670 }
671 }
672 if until == Some(child_id) {
674 break;
675 }
676 let child = &self.nodes[child_id];
677 if child.flags.is_inline_root() {
678 result.push(child_id);
679 } else {
680 self.collect_all_inline_roots_in_subtree(child_id, result);
682 }
683 }
684 }
685 }
686
687 fn is_ancestor_of(&self, ancestor_id: NodeId, descendant_id: NodeId) -> bool {
689 let mut current = descendant_id;
690 while let Some(parent) = self.nodes[current].parent {
691 if parent == ancestor_id {
692 return true;
693 }
694 current = parent;
695 }
696 false
697 }
698}