1use std::cmp::Ordering;
2
3use style::{dom::TNode as _, values::specified::box_::DisplayInside};
4
5use crate::{BaseDocument, Node};
6
7#[derive(Clone)]
8pub struct TreeTraverser<'a> {
10 doc: &'a BaseDocument,
11 stack: Vec<usize>,
12}
13
14impl<'a> TreeTraverser<'a> {
15 pub fn new(doc: &'a BaseDocument) -> Self {
17 Self::new_with_root(doc, 0)
18 }
19
20 pub fn new_with_root(doc: &'a BaseDocument, root: usize) -> Self {
22 let mut stack = Vec::with_capacity(32);
23 stack.push(root);
24 TreeTraverser { doc, stack }
25 }
26}
27impl Iterator for TreeTraverser<'_> {
28 type Item = usize;
29
30 fn next(&mut self) -> Option<Self::Item> {
31 let id = self.stack.pop()?;
32 let node = self.doc.get_node(id)?;
33 self.stack.extend(node.children.iter().rev());
34 Some(id)
35 }
36}
37
38#[derive(Clone)]
39pub struct AncestorTraverser<'a> {
41 doc: &'a BaseDocument,
42 current: usize,
43}
44impl<'a> AncestorTraverser<'a> {
45 pub fn new(doc: &'a BaseDocument, node_id: usize) -> Self {
47 AncestorTraverser {
48 doc,
49 current: node_id,
50 }
51 }
52}
53impl Iterator for AncestorTraverser<'_> {
54 type Item = usize;
55
56 fn next(&mut self) -> Option<Self::Item> {
57 let current_node = self.doc.get_node(self.current)?;
58 self.current = current_node.parent?;
59 Some(self.current)
60 }
61}
62
63impl Node {
64 #[allow(dead_code)]
65 pub(crate) fn should_traverse_layout_children(&mut self) -> bool {
66 let prefer_layout_children = match self.display_constructed_as.inside() {
67 DisplayInside::None => return false,
68 DisplayInside::Contents => false,
69 DisplayInside::Flow | DisplayInside::FlowRoot | DisplayInside::TableCell => {
70 self.element_data()
72 .is_none_or(|el| el.inline_layout_data.is_none())
73 }
74 DisplayInside::Flex | DisplayInside::Grid => true,
75 DisplayInside::Table => false,
76 DisplayInside::TableRowGroup => false,
77 DisplayInside::TableColumn => false,
78 DisplayInside::TableColumnGroup => false,
79 DisplayInside::TableHeaderGroup => false,
80 DisplayInside::TableFooterGroup => false,
81 DisplayInside::TableRow => false,
82 };
83 let has_layout_children = self.layout_children.get_mut().is_some();
84 prefer_layout_children & has_layout_children
85 }
86}
87
88impl BaseDocument {
89 pub fn node_chain(&self, node_id: usize) -> Vec<usize> {
91 let mut chain = Vec::with_capacity(16);
92 chain.push(node_id);
93 chain.extend(
94 AncestorTraverser::new(self, node_id).filter(|id| self.nodes[*id].is_element()),
95 );
96 chain
97 }
98
99 pub fn visit<F>(&self, mut visit: F)
100 where
101 F: FnMut(usize, &Node),
102 {
103 TreeTraverser::new(self).for_each(|node_id| visit(node_id, &self.nodes[node_id]));
104 }
105
106 pub fn non_anon_ancestor_if_anon(&self, mut node_id: usize) -> usize {
109 loop {
110 let node = &self.nodes[node_id];
111
112 if !node.is_anonymous() {
113 return node.id;
114 }
115
116 let Some(parent_id) = node.layout_parent.get() else {
117 return node.id;
121 };
122
123 node_id = parent_id;
124 }
125 }
126
127 pub fn iter_children_mut(
128 &mut self,
129 node_id: usize,
130 mut cb: impl FnMut(usize, &mut BaseDocument),
131 ) {
132 let children = std::mem::take(&mut self.nodes[node_id].children);
133 for child_id in children.iter().cloned() {
134 cb(child_id, self);
135 }
136 self.nodes[node_id].children = children;
137 }
138
139 pub fn iter_subtree_mut(
140 &mut self,
141 node_id: usize,
142 mut cb: impl FnMut(usize, &mut BaseDocument),
143 ) {
144 cb(node_id, self);
145 iter_subtree_mut_inner(self, node_id, &mut cb);
146 fn iter_subtree_mut_inner(
147 doc: &mut BaseDocument,
148 node_id: usize,
149 cb: &mut impl FnMut(usize, &mut BaseDocument),
150 ) {
151 let children = std::mem::take(&mut doc.nodes[node_id].children);
152 for child_id in children.iter().cloned() {
153 cb(child_id, doc);
154 iter_subtree_mut_inner(doc, child_id, cb);
155 }
156 doc.nodes[node_id].children = children;
157 }
158 }
159
160 pub fn iter_children_and_pseudos_mut(
161 &mut self,
162 node_id: usize,
163 mut cb: impl FnMut(usize, &mut BaseDocument),
164 ) {
165 let before = self.nodes[node_id].before.take();
166 if let Some(before_node_id) = before {
167 cb(before_node_id, self)
168 }
169 self.nodes[node_id].before = before;
170
171 self.iter_children_mut(node_id, &mut cb);
172
173 let after = self.nodes[node_id].after.take();
174 if let Some(after_node_id) = after {
175 cb(after_node_id, self)
176 }
177 self.nodes[node_id].after = after;
178 }
179
180 pub fn prev_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<usize> {
181 let start_id = start.id;
182 let mut node = start;
183 loop {
184 let next = if let Some(parent) = node.parent_node() {
186 let self_idx = parent
187 .children
188 .iter()
189 .position(|id| *id == node.id)
190 .unwrap();
191 if self_idx > 0 {
193 let mut sibling = &self.nodes[parent.children[self_idx - 1]];
194 while !sibling.children.is_empty() {
196 sibling = &self.nodes[*sibling.children.last().unwrap()];
197 }
198 sibling
199 }
200 else {
202 parent
203 }
204 }
205 else {
207 self.last_node_in_tree()
208 };
209
210 if filter(next) {
211 return Some(next.id);
212 } else if next.id == start_id {
213 return None;
214 }
215
216 node = next;
217 }
218 }
219
220 fn last_node_in_tree(&self) -> &Node {
222 let mut node = self.root_node();
223 while !node.children.is_empty() {
224 node = &self.nodes[*node.children.last().unwrap()];
225 }
226 node
227 }
228
229 pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<usize> {
230 let start_id = start.id;
231 let mut node = start;
232 let mut look_in_children = true;
233 loop {
234 let next = if look_in_children && !node.children.is_empty() {
236 let node_id = node.children[0];
237 &self.nodes[node_id]
238 }
239 else if let Some(parent) = node.parent_node() {
241 let self_idx = parent
242 .children
243 .iter()
244 .position(|id| *id == node.id)
245 .unwrap();
246 if let Some(sibling_id) = parent.children.get(self_idx + 1) {
248 look_in_children = true;
249 &self.nodes[*sibling_id]
250 }
251 else {
253 look_in_children = false;
254 node = parent;
255 continue;
256 }
257 }
258 else {
260 look_in_children = true;
261 self.root_node()
262 };
263
264 if filter(next) {
265 return Some(next.id);
266 } else if next.id == start_id {
267 return None;
268 }
269
270 node = next;
271 }
272 }
273
274 pub fn node_layout_ancestors(&self, node_id: usize) -> Vec<usize> {
275 let mut ancestors = Vec::with_capacity(12);
276 let mut maybe_id = Some(node_id);
277 while let Some(id) = maybe_id {
278 ancestors.push(id);
279 maybe_id = self.nodes[id].layout_parent.get();
280 }
281 ancestors.reverse();
282 ancestors
283 }
284
285 pub fn maybe_node_layout_ancestors(&self, node_id: Option<usize>) -> Vec<usize> {
286 node_id
287 .map(|id| self.node_layout_ancestors(id))
288 .unwrap_or_default()
289 }
290
291 pub fn compare_document_order(&self, node_a: usize, node_b: usize) -> Ordering {
296 if node_a == node_b {
297 return Ordering::Equal;
298 }
299
300 let chain_a = self.ancestor_chain_from_root(node_a);
302 let chain_b = self.ancestor_chain_from_root(node_b);
303
304 let mut common_depth = 0;
306 for (a, b) in chain_a.iter().zip(chain_b.iter()) {
307 if a != b {
308 break;
309 }
310 common_depth += 1;
311 }
312
313 if common_depth == chain_a.len() {
315 return Ordering::Less; }
317 if common_depth == chain_b.len() {
318 return Ordering::Greater; }
320
321 debug_assert!(
325 common_depth > 0,
326 "nodes must share a common ancestor (the root)"
327 );
328
329 let divergent_a = chain_a[common_depth];
331 let divergent_b = chain_b[common_depth];
332 let parent_id = chain_a[common_depth - 1];
333 let parent = &self.nodes[parent_id];
334
335 for &child_id in &parent.children {
336 if child_id == divergent_a {
337 return Ordering::Less;
338 }
339 if child_id == divergent_b {
340 return Ordering::Greater;
341 }
342 }
343
344 Ordering::Equal
346 }
347
348 fn ancestor_chain_from_root(&self, node_id: usize) -> Vec<usize> {
350 let mut ancestors = Vec::with_capacity(16);
351 let mut current = Some(node_id);
352 while let Some(id) = current {
353 ancestors.push(id);
354 current = self.nodes[id].parent;
355 }
356 ancestors.reverse();
357 ancestors
358 }
359
360 pub fn collect_inline_roots_in_range(&self, start_node: usize, end_node: usize) -> Vec<usize> {
364 let (start_anchor, start_anon) = self.resolve_for_traversal(start_node);
366 let (end_anchor, end_anon) = self.resolve_for_traversal(end_node);
367
368 if start_anon.is_some() && end_anon.is_some() && start_anchor == end_anchor {
370 return self.collect_anonymous_siblings(start_anchor, start_node, end_node);
371 }
372
373 let (first_anchor, first_anon, last_anchor, last_anon) = match self
375 .compare_document_order(start_anchor, end_anchor)
376 {
377 Ordering::Less | Ordering::Equal => (start_anchor, start_anon, end_anchor, end_anon),
378 Ordering::Greater => (end_anchor, end_anon, start_anchor, start_anon),
379 };
380
381 let mut result = Vec::new();
382 let mut found_first = false;
383
384 for node_id in TreeTraverser::new(self) {
386 if !found_first && node_id == first_anchor {
387 found_first = true;
388 if let Some(anon_id) = first_anon {
389 let stop_at = if first_anchor == last_anchor {
392 last_anon
394 } else {
395 Some(last_anchor)
397 };
398 self.collect_layout_children_inline_roots(
399 node_id,
400 Some(anon_id),
401 stop_at,
402 &mut result,
403 );
404 if result.last() == Some(&last_anchor)
406 || last_anon.is_some_and(|la| result.last() == Some(&la))
407 {
408 break;
409 }
410 continue;
411 }
412 }
413
414 if found_first {
415 if node_id == last_anchor {
416 if let Some(anon_id) = last_anon {
417 self.collect_layout_children_inline_roots(
419 node_id,
420 None,
421 Some(anon_id),
422 &mut result,
423 );
424 if !result.contains(&anon_id) {
426 result.push(anon_id);
427 }
428 } else {
429 let node = &self.nodes[node_id];
431 if node.flags.is_inline_root() && !result.contains(&node_id) {
432 result.push(node_id);
433 }
434 }
435 break;
436 }
437
438 let node = &self.nodes[node_id];
439 if node.flags.is_inline_root() && !result.contains(&node_id) {
440 result.push(node_id);
441 } else {
442 self.collect_layout_children_inline_roots(
445 node_id,
446 None,
447 Some(last_anchor),
448 &mut result,
449 );
450 }
451 }
452 }
453
454 result
455 }
456
457 fn resolve_for_traversal(&self, node_id: usize) -> (usize, Option<usize>) {
461 let node = &self.nodes[node_id];
462 if node.is_anonymous() {
463 (node.parent.unwrap_or(node_id), Some(node_id))
464 } else {
465 (node_id, None)
466 }
467 }
468
469 fn collect_anonymous_siblings(&self, parent_id: usize, start: usize, end: usize) -> Vec<usize> {
472 let parent = &self.nodes[parent_id];
473 let layout_children = parent.layout_children.borrow();
474 let Some(children) = layout_children.as_ref() else {
475 return Vec::new();
476 };
477
478 let start_idx = children.iter().position(|&id| id == start);
479 let end_idx = children.iter().position(|&id| id == end);
480
481 let (first_idx, last_idx) = match (start_idx, end_idx) {
482 (Some(s), Some(e)) if s <= e => (s, e),
483 (Some(s), Some(e)) => (e, s),
484 _ => return Vec::new(),
485 };
486
487 let mut result = Vec::new();
488 for &child_id in &children[first_idx..=last_idx] {
489 let child = &self.nodes[child_id];
490 if child.flags.is_inline_root() {
491 result.push(child_id);
492 } else {
493 self.collect_all_inline_roots_in_subtree(child_id, &mut result);
495 }
496 }
497 result
498 }
499
500 fn collect_all_inline_roots_in_subtree(&self, node_id: usize, result: &mut Vec<usize>) {
502 let node = &self.nodes[node_id];
503 let layout_children = node.layout_children.borrow();
504 let Some(children) = layout_children.as_ref() else {
505 return;
506 };
507
508 for &child_id in children.iter() {
509 let child = &self.nodes[child_id];
510 if child.flags.is_inline_root() {
511 result.push(child_id);
512 } else {
513 self.collect_all_inline_roots_in_subtree(child_id, result);
515 }
516 }
517 }
518
519 fn collect_layout_children_inline_roots(
523 &self,
524 parent_id: usize,
525 from: Option<usize>,
526 until: Option<usize>,
527 result: &mut Vec<usize>,
528 ) {
529 let parent = &self.nodes[parent_id];
530 let layout_children = parent.layout_children.borrow();
531 let Some(children) = layout_children.as_ref() else {
532 return;
533 };
534
535 let mut collecting = from.is_none(); for &child_id in children.iter() {
537 if from == Some(child_id) {
538 collecting = true;
539 }
540 if collecting {
541 if let Some(until_id) = until {
543 if self.is_ancestor_of(child_id, until_id) {
544 break;
545 }
546 }
547 if until == Some(child_id) {
549 break;
550 }
551 let child = &self.nodes[child_id];
552 if child.flags.is_inline_root() {
553 result.push(child_id);
554 } else {
555 self.collect_all_inline_roots_in_subtree(child_id, result);
557 }
558 }
559 }
560 }
561
562 fn is_ancestor_of(&self, ancestor_id: usize, descendant_id: usize) -> bool {
564 let mut current = descendant_id;
565 while let Some(parent) = self.nodes[current].parent {
566 if parent == ancestor_id {
567 return true;
568 }
569 current = parent;
570 }
571 false
572 }
573}