1use blitz_traits::node_id::NodeId;
2use std::cmp::Ordering;
3
4use style::dom::TNode as _;
5
6use crate::{BaseDocument, Node};
7
8macro_rules! iter_children {
9 ($node_expr:expr, $cb:expr) => {{
10 let node = &mut $node_expr;
11 let children = core::mem::take(&mut node.children);
12 for child_id in children.iter().copied() {
13 $cb(child_id)
14 }
15 $node_expr.children = children;
16 }};
17}
18pub(crate) use iter_children;
19
20macro_rules! iter_children_and_pseudos {
21 ($node_expr:expr, $cb:expr) => {{
22 let node = &mut $node_expr;
24
25 let before = node.before();
27 let after = node.after();
28 let children = core::mem::take(&mut node.children);
29
30 if let Some(before) = before {
31 $cb(before)
32 }
33 for child_id in children.iter().copied() {
34 $cb(child_id)
35 }
36 if let Some(after) = after {
37 $cb(after)
38 }
39
40 $node_expr.children = children;
42 }};
43}
44pub(crate) use iter_children_and_pseudos;
45
46#[derive(Clone)]
47pub struct TreeTraverser<'a> {
49 doc: &'a BaseDocument,
50 stack: Vec<NodeId>,
51}
52
53impl<'a> TreeTraverser<'a> {
54 pub fn new(doc: &'a BaseDocument) -> Self {
56 Self::new_with_root(doc, doc.root_node().id)
57 }
58
59 pub fn new_with_root(doc: &'a BaseDocument, root: NodeId) -> Self {
61 let mut stack = Vec::with_capacity(32);
62 stack.push(root);
63 TreeTraverser { doc, stack }
64 }
65}
66impl Iterator for TreeTraverser<'_> {
67 type Item = NodeId;
68
69 fn next(&mut self) -> Option<Self::Item> {
70 let id = self.stack.pop()?;
71 let node = self.doc.get_node(id)?;
72 self.stack.extend(node.children.iter().rev());
73 Some(id)
74 }
75}
76
77#[derive(Clone)]
78pub struct AncestorTraverser<'a> {
80 doc: &'a BaseDocument,
81 current: NodeId,
82}
83impl<'a> AncestorTraverser<'a> {
84 pub fn new(doc: &'a BaseDocument, node_id: NodeId) -> Self {
86 AncestorTraverser {
87 doc,
88 current: node_id,
89 }
90 }
91}
92impl Iterator for AncestorTraverser<'_> {
93 type Item = NodeId;
94
95 fn next(&mut self) -> Option<Self::Item> {
96 let current_node = self.doc.get_node(self.current)?;
97 self.current = current_node.parent?;
98 Some(self.current)
99 }
100}
101
102impl BaseDocument {
103 pub fn node_chain(&self, node_id: NodeId) -> Vec<NodeId> {
105 let mut chain = Vec::with_capacity(16);
106 chain.push(node_id);
107 chain.extend(
108 AncestorTraverser::new(self, node_id).filter(|id| self.nodes[*id].is_element()),
109 );
110 chain
111 }
112
113 pub fn visit<F>(&self, mut visit: F)
114 where
115 F: FnMut(NodeId, &Node),
116 {
117 TreeTraverser::new(self).for_each(|node_id| visit(node_id, &self.nodes[node_id]));
118 }
119
120 pub fn non_anon_ancestor_if_anon(&self, mut node_id: NodeId) -> NodeId {
123 loop {
124 let node = &self.nodes[node_id];
125
126 if !node.is_anonymous() {
127 return node.id;
128 }
129
130 let Some(parent_id) = node.layout_parent.get() else {
131 panic!("Node does not exist or does not have a non-anonymous parent");
134 };
135
136 node_id = parent_id;
137 }
138 }
139
140 pub fn iter_children_mut(
141 &mut self,
142 node_id: NodeId,
143 mut cb: impl FnMut(NodeId, &mut BaseDocument),
144 ) {
145 let children = std::mem::take(&mut self.nodes[node_id].children);
146 for child_id in children.iter().cloned() {
147 cb(child_id, self);
148 }
149 self.nodes[node_id].children = children;
150 }
151
152 pub fn iter_subtree_mut(
153 &mut self,
154 node_id: NodeId,
155 mut cb: impl FnMut(NodeId, &mut BaseDocument),
156 ) {
157 cb(node_id, self);
158 iter_subtree_mut_inner(self, node_id, &mut cb);
159 fn iter_subtree_mut_inner(
160 doc: &mut BaseDocument,
161 node_id: NodeId,
162 cb: &mut impl FnMut(NodeId, &mut BaseDocument),
163 ) {
164 let children = std::mem::take(&mut doc.nodes[node_id].children);
165 for child_id in children.iter().cloned() {
166 cb(child_id, doc);
167 iter_subtree_mut_inner(doc, child_id, cb);
168 }
169 doc.nodes[node_id].children = children;
170 }
171 }
172
173 pub fn iter_children_and_pseudos_mut(
174 &mut self,
175 node_id: NodeId,
176 mut cb: impl FnMut(NodeId, &mut BaseDocument),
177 ) {
178 let before = self.nodes[node_id].before();
179 self.nodes[node_id].set_pe_by_index(1, None);
180 if let Some(before_node_id) = before {
181 cb(before_node_id, self)
182 }
183 self.nodes[node_id].set_pe_by_index(1, before);
184
185 self.iter_children_mut(node_id, &mut cb);
186
187 let after = self.nodes[node_id].after();
188 self.nodes[node_id].set_pe_by_index(0, None);
189 if let Some(after_node_id) = after {
190 cb(after_node_id, self)
191 }
192 self.nodes[node_id].set_pe_by_index(0, after);
193 }
194
195 pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
196 let start_id = start.id;
197 let mut node = start;
198 let mut look_in_children = true;
199 loop {
200 let next = if look_in_children && !node.children.is_empty() {
202 let node_id = node.children[0];
203 &self.nodes[node_id]
204 }
205 else if let Some(parent) = node.parent_node() {
207 let self_idx = parent
208 .children
209 .iter()
210 .position(|id| *id == node.id)
211 .unwrap();
212 if let Some(sibling_id) = parent.children.get(self_idx + 1) {
214 look_in_children = true;
215 &self.nodes[*sibling_id]
216 }
217 else {
219 look_in_children = false;
220 node = parent;
221 continue;
222 }
223 }
224 else {
226 look_in_children = true;
227 self.root_node()
228 };
229
230 if filter(next) {
231 return Some(next.id);
232 } else if next.id == start_id {
233 return None;
234 }
235
236 node = next;
237 }
238 }
239
240 fn deepest_last_descendant<'a>(&'a self, mut node: &'a Node) -> &'a Node {
243 while let Some(last_child_id) = node.children.last() {
244 node = &self.nodes[*last_child_id];
245 }
246 node
247 }
248
249 pub fn prev_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<NodeId> {
252 let start_id = start.id;
253 let mut node = start;
254 loop {
255 let prev = if let Some(parent) = node.parent_node() {
256 let self_idx = parent
257 .children
258 .iter()
259 .position(|id| *id == node.id)
260 .unwrap();
261 if self_idx > 0 {
264 self.deepest_last_descendant(&self.nodes[parent.children[self_idx - 1]])
265 } else {
266 parent
267 }
268 }
269 else {
271 self.deepest_last_descendant(self.root_node())
272 };
273
274 if filter(prev) {
275 return Some(prev.id);
276 } else if prev.id == start_id {
277 return None;
278 }
279
280 node = prev;
281 }
282 }
283
284 pub fn node_element_ancestors(&self, node_id: NodeId) -> Vec<NodeId> {
287 let mut ancestors = Vec::with_capacity(12);
288 let mut maybe_id = Some(node_id);
289 while let Some(id) = maybe_id {
290 let node = &self.nodes[id];
291 if !node.is_element() {
292 break;
293 }
294 ancestors.push(id);
295 maybe_id = node.parent;
296 }
297 ancestors.reverse();
298 ancestors
299 }
300
301 pub fn maybe_node_element_ancestors(&self, node_id: Option<NodeId>) -> Vec<NodeId> {
302 node_id
303 .map(|id| self.node_element_ancestors(id))
304 .unwrap_or_default()
305 }
306
307 pub fn compare_document_order(&self, node_a: NodeId, node_b: NodeId) -> Ordering {
312 if node_a == node_b {
313 return Ordering::Equal;
314 }
315
316 let chain_a = self.ancestor_chain_from_root(node_a);
318 let chain_b = self.ancestor_chain_from_root(node_b);
319
320 let mut common_depth = 0;
322 for (a, b) in chain_a.iter().zip(chain_b.iter()) {
323 if a != b {
324 break;
325 }
326 common_depth += 1;
327 }
328
329 if common_depth == chain_a.len() {
331 return Ordering::Less; }
333 if common_depth == chain_b.len() {
334 return Ordering::Greater; }
336
337 debug_assert!(
341 common_depth > 0,
342 "nodes must share a common ancestor (the root)"
343 );
344
345 let divergent_a = chain_a[common_depth];
347 let divergent_b = chain_b[common_depth];
348 let parent_id = chain_a[common_depth - 1];
349 let parent = &self.nodes[parent_id];
350
351 for &child_id in &parent.children {
352 if child_id == divergent_a {
353 return Ordering::Less;
354 }
355 if child_id == divergent_b {
356 return Ordering::Greater;
357 }
358 }
359
360 Ordering::Equal
362 }
363
364 fn ancestor_chain_from_root(&self, node_id: NodeId) -> Vec<NodeId> {
366 let mut ancestors = Vec::with_capacity(16);
367 let mut current = Some(node_id);
368 while let Some(id) = current {
369 ancestors.push(id);
370 current = self.nodes[id].parent;
371 }
372 ancestors.reverse();
373 ancestors
374 }
375
376 pub fn collect_inline_roots_in_range(
380 &self,
381 start_node: NodeId,
382 end_node: NodeId,
383 ) -> Vec<NodeId> {
384 let (start_anchor, start_anon) = self.resolve_for_traversal(start_node);
386 let (end_anchor, end_anon) = self.resolve_for_traversal(end_node);
387
388 if start_anon.is_some() && end_anon.is_some() && start_anchor == end_anchor {
390 return self.collect_anonymous_siblings(start_anchor, start_node, end_node);
391 }
392
393 let (first_anchor, first_anon, last_anchor, last_anon) = match self
395 .compare_document_order(start_anchor, end_anchor)
396 {
397 Ordering::Less | Ordering::Equal => (start_anchor, start_anon, end_anchor, end_anon),
398 Ordering::Greater => (end_anchor, end_anon, start_anchor, start_anon),
399 };
400
401 let mut result = Vec::new();
402 let mut found_first = false;
403
404 for node_id in TreeTraverser::new(self) {
406 if !found_first {
407 if node_id == first_anchor {
408 found_first = true;
409 if let Some(anon_id) = first_anon {
410 let stop_at = if first_anchor == last_anchor {
413 last_anon
415 } else {
416 Some(last_anchor)
418 };
419 self.collect_layout_children_inline_roots(
420 node_id,
421 Some(anon_id),
422 stop_at,
423 &mut result,
424 );
425 if result.last() == Some(&last_anchor)
427 || last_anon.is_some_and(|la| result.last() == Some(&la))
428 {
429 break;
430 }
431 continue;
432 }
433 }
434 }
435
436 if found_first {
437 if node_id == last_anchor {
438 if let Some(anon_id) = last_anon {
439 self.collect_layout_children_inline_roots(
441 node_id,
442 None,
443 Some(anon_id),
444 &mut result,
445 );
446 if !result.contains(&anon_id) {
448 result.push(anon_id);
449 }
450 } else {
451 let node = &self.nodes[node_id];
453 if node.flags.is_inline_root() && !result.contains(&node_id) {
454 result.push(node_id);
455 }
456 }
457 break;
458 }
459
460 let node = &self.nodes[node_id];
461 if node.flags.is_inline_root() && !result.contains(&node_id) {
462 result.push(node_id);
463 } else {
464 self.collect_layout_children_inline_roots(
467 node_id,
468 None,
469 Some(last_anchor),
470 &mut result,
471 );
472 }
473 }
474 }
475
476 result
477 }
478
479 fn resolve_for_traversal(&self, node_id: NodeId) -> (NodeId, Option<NodeId>) {
483 let node = &self.nodes[node_id];
484 if node.is_anonymous() {
485 (node.parent.unwrap_or(node_id), Some(node_id))
486 } else {
487 (node_id, None)
488 }
489 }
490
491 fn collect_anonymous_siblings(
494 &self,
495 parent_id: NodeId,
496 start: NodeId,
497 end: NodeId,
498 ) -> Vec<NodeId> {
499 let parent = &self.nodes[parent_id];
500 let layout_children = parent.layout_children.borrow();
501 let Some(children) = layout_children.as_ref() else {
502 return Vec::new();
503 };
504
505 let start_idx = children.iter().position(|&id| id == start);
506 let end_idx = children.iter().position(|&id| id == end);
507
508 let (first_idx, last_idx) = match (start_idx, end_idx) {
509 (Some(s), Some(e)) if s <= e => (s, e),
510 (Some(s), Some(e)) => (e, s),
511 _ => return Vec::new(),
512 };
513
514 let mut result = Vec::new();
515 for &child_id in &children[first_idx..=last_idx] {
516 let child = &self.nodes[child_id];
517 if child.flags.is_inline_root() {
518 result.push(child_id);
519 } else {
520 self.collect_all_inline_roots_in_subtree(child_id, &mut result);
522 }
523 }
524 result
525 }
526
527 fn collect_all_inline_roots_in_subtree(&self, node_id: NodeId, result: &mut Vec<NodeId>) {
529 let node = &self.nodes[node_id];
530 let layout_children = node.layout_children.borrow();
531 let Some(children) = layout_children.as_ref() else {
532 return;
533 };
534
535 for &child_id in children.iter() {
536 let child = &self.nodes[child_id];
537 if child.flags.is_inline_root() {
538 result.push(child_id);
539 } else {
540 self.collect_all_inline_roots_in_subtree(child_id, result);
542 }
543 }
544 }
545
546 fn collect_layout_children_inline_roots(
550 &self,
551 parent_id: NodeId,
552 from: Option<NodeId>,
553 until: Option<NodeId>,
554 result: &mut Vec<NodeId>,
555 ) {
556 let parent = &self.nodes[parent_id];
557 let layout_children = parent.layout_children.borrow();
558 let Some(children) = layout_children.as_ref() else {
559 return;
560 };
561
562 let mut collecting = from.is_none(); for &child_id in children.iter() {
564 if from == Some(child_id) {
565 collecting = true;
566 }
567 if collecting {
568 if let Some(until_id) = until {
570 if self.is_ancestor_of(child_id, until_id) {
571 break;
572 }
573 }
574 if until == Some(child_id) {
576 break;
577 }
578 let child = &self.nodes[child_id];
579 if child.flags.is_inline_root() {
580 result.push(child_id);
581 } else {
582 self.collect_all_inline_roots_in_subtree(child_id, result);
584 }
585 }
586 }
587 }
588
589 fn is_ancestor_of(&self, ancestor_id: NodeId, descendant_id: NodeId) -> bool {
591 let mut current = descendant_id;
592 while let Some(parent) = self.nodes[current].parent {
593 if parent == ancestor_id {
594 return true;
595 }
596 current = parent;
597 }
598 false
599 }
600}