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