Coverage Report

Created: 2026-07-13 08:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ammonia-4.1.2/src/rcdom.rs
Line
Count
Source
1
// Copyright 2014-2017 The html5ever Project Developers.
2
// Copyright Michael Howell and others.
3
//
4
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7
// option. This file may not be copied, modified, or distributed
8
// except according to those terms.
9
10
#![allow(missing_docs)]
11
12
//! A simple reference-counted DOM.
13
//!
14
//! This is sufficient as a static parse tree, but don't build a
15
//! web browser using it. :)
16
//!
17
//! A DOM is a [tree structure] with ordered children that can be represented in an XML-like
18
//! format. For example, the following graph
19
//!
20
//! ```text
21
//! div
22
//!  +- "text node"
23
//!  +- span
24
//! ```
25
//! in HTML would be serialized as
26
//!
27
//! ```html
28
//! <div>text node<span></span></div>
29
//! ```
30
//!
31
//! See the [document object model article on wikipedia][dom wiki] for more information.
32
//!
33
//! This implementation stores the information associated with each node once, and then hands out
34
//! refs to children. The nodes themselves are reference-counted to avoid copying - you can create
35
//! a new ref and then a node will outlive the document. Nodes own their children, but only have
36
//! weak references to their parents.
37
//!
38
//! [tree structure]: https://en.wikipedia.org/wiki/Tree_(data_structure)
39
//! [dom wiki]: https://en.wikipedia.org/wiki/Document_Object_Model
40
41
use std::borrow::Cow;
42
use std::cell::{Cell, RefCell};
43
use std::collections::{HashSet, VecDeque};
44
use std::default::Default;
45
use std::fmt;
46
use std::io;
47
use std::mem;
48
use std::rc::{Rc, Weak};
49
50
use tendril::StrTendril;
51
52
use html5ever::interface::tree_builder;
53
use html5ever::interface::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
54
use html5ever::serialize::TraversalScope;
55
use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
56
use html5ever::serialize::{Serialize, Serializer};
57
use html5ever::Attribute;
58
use html5ever::ExpandedName;
59
use html5ever::QualName;
60
61
/// The different kinds of nodes in the DOM.
62
#[derive(Debug)]
63
pub enum NodeData {
64
    /// The `Document` itself - the root node of a HTML document.
65
    Document,
66
67
    /// A `DOCTYPE` with name, public id, and system id. See
68
    /// [document type declaration on wikipedia][dtd wiki].
69
    ///
70
    /// [dtd wiki]: https://en.wikipedia.org/wiki/Document_type_declaration
71
    Doctype {
72
        name: StrTendril,
73
    },
74
75
    /// A text node.
76
    Text { contents: RefCell<StrTendril> },
77
78
    /// A comment.
79
    Comment { contents: StrTendril },
80
81
    /// An element with attributes.
82
    Element {
83
        name: QualName,
84
        attrs: RefCell<Vec<Attribute>>,
85
86
        /// For HTML \<template\> elements, the [template contents].
87
        ///
88
        /// [template contents]: https://html.spec.whatwg.org/multipage/#template-contents
89
        template_contents: RefCell<Option<Handle>>,
90
91
        /// Whether the node is a [HTML integration point].
92
        ///
93
        /// [HTML integration point]: https://html.spec.whatwg.org/multipage/#html-integration-point
94
        mathml_annotation_xml_integration_point: bool,
95
    },
96
97
    /// A Processing instruction.
98
    ProcessingInstruction {
99
        target: StrTendril,
100
        contents: StrTendril,
101
    },
102
}
103
104
/// A DOM node.
105
pub struct Node {
106
    /// Parent node.
107
    pub parent: Cell<Option<WeakHandle>>,
108
    /// Child nodes of this node.
109
    pub children: RefCell<Vec<Handle>>,
110
    /// Represents this node's data.
111
    pub data: NodeData,
112
}
113
114
impl Node {
115
    /// Create a new node from its contents
116
0
    pub fn new(data: NodeData) -> Rc<Self> {
117
0
        Rc::new(Node {
118
0
            data,
119
0
            parent: Cell::new(None),
120
0
            children: RefCell::new(Vec::new()),
121
0
        })
122
0
    }
123
}
124
125
impl Drop for Node {
126
0
    fn drop(&mut self) {
127
0
        let mut nodes = mem::take(&mut *self.children.borrow_mut());
128
0
        while let Some(node) = nodes.pop() {
129
0
            let children = mem::take(&mut *node.children.borrow_mut());
130
0
            nodes.extend(children.into_iter());
131
            if let NodeData::Element {
132
0
                ref template_contents,
133
                ..
134
0
            } = node.data
135
            {
136
0
                if let Some(template_contents) = template_contents.borrow_mut().take() {
137
0
                    nodes.push(template_contents);
138
0
                }
139
0
            }
140
        }
141
0
    }
142
}
143
144
impl fmt::Debug for Node {
145
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
146
0
        fmt.debug_struct("Node")
147
0
            .field("data", &self.data)
148
0
            .field("children", &self.children)
149
0
            .finish()
150
0
    }
151
}
152
153
/// Reference to a DOM node.
154
pub type Handle = Rc<Node>;
155
156
/// Weak reference to a DOM node, used for parent pointers.
157
pub type WeakHandle = Weak<Node>;
158
159
/// Append a parentless node to another nodes' children
160
0
fn append(new_parent: &Handle, child: Handle) {
161
0
    let previous_parent = child.parent.replace(Some(Rc::downgrade(new_parent)));
162
    // Invariant: child cannot have existing parent
163
0
    assert!(previous_parent.is_none());
164
0
    new_parent.children.borrow_mut().push(child);
165
0
}
166
167
/// If the node has a parent, get it and this node's position in its children
168
0
fn get_parent_and_index(target: &Handle) -> Option<(Handle, usize)> {
169
0
    if let Some(weak) = target.parent.take() {
170
0
        let parent = weak.upgrade().expect("dangling weak pointer");
171
0
        target.parent.set(Some(weak));
172
0
        let i = match parent
173
0
            .children
174
0
            .borrow()
175
0
            .iter()
176
0
            .enumerate()
177
0
            .find(|&(_, child)| Rc::ptr_eq(child, target))
178
        {
179
0
            Some((i, _)) => i,
180
0
            None => panic!("have parent but couldn't find in parent's children!"),
181
        };
182
0
        Some((parent, i))
183
    } else {
184
0
        None
185
    }
186
0
}
187
188
0
fn append_to_existing_text(prev: &Handle, text: &str) -> bool {
189
0
    match prev.data {
190
0
        NodeData::Text { ref contents } => {
191
0
            contents.borrow_mut().push_slice(text);
192
0
            true
193
        }
194
0
        _ => false,
195
    }
196
0
}
197
198
0
fn remove_from_parent(target: &Handle) {
199
0
    if let Some((parent, i)) = get_parent_and_index(target) {
200
0
        parent.children.borrow_mut().remove(i);
201
0
        target.parent.set(None);
202
0
    }
203
0
}
204
205
/// The DOM itself; the result of parsing.
206
pub struct RcDom {
207
    /// The `Document` itself.
208
    pub document: Handle,
209
210
    /// Errors that occurred during parsing.
211
    pub errors: RefCell<Vec<Cow<'static, str>>>,
212
213
    /// The document's quirks mode.
214
    pub quirks_mode: Cell<QuirksMode>,
215
}
216
217
impl TreeSink for RcDom {
218
    type Output = Self;
219
0
    fn finish(self) -> Self {
220
0
        self
221
0
    }
222
223
    type Handle = Handle;
224
225
    type ElemName<'a> = ExpandedName<'a>;
226
227
0
    fn parse_error(&self, msg: Cow<'static, str>) {
228
0
        self.errors.borrow_mut().push(msg);
229
0
    }
230
231
0
    fn get_document(&self) -> Handle {
232
0
        self.document.clone()
233
0
    }
234
235
0
    fn get_template_contents(&self, target: &Handle) -> Handle {
236
        if let NodeData::Element {
237
0
            ref template_contents,
238
            ..
239
0
        } = target.data
240
        {
241
0
            template_contents
242
0
                .borrow()
243
0
                .as_ref()
244
0
                .expect("not a template element!")
245
0
                .clone()
246
        } else {
247
0
            panic!("not a template element!")
248
        }
249
0
    }
250
251
0
    fn set_quirks_mode(&self, mode: QuirksMode) {
252
0
        self.quirks_mode.set(mode);
253
0
    }
254
255
0
    fn same_node(&self, x: &Handle, y: &Handle) -> bool {
256
0
        Rc::ptr_eq(x, y)
257
0
    }
258
259
0
    fn elem_name<'a>(&self, target: &'a Handle) -> ExpandedName<'a> {
260
0
        return match target.data {
261
0
            NodeData::Element { ref name, .. } => name.expanded(),
262
0
            _ => panic!("not an element!"),
263
        };
264
0
    }
265
266
0
    fn create_element(
267
0
        &self,
268
0
        name: QualName,
269
0
        attrs: Vec<Attribute>,
270
0
        flags: ElementFlags,
271
0
    ) -> Handle {
272
0
        Node::new(NodeData::Element {
273
0
            name,
274
0
            attrs: RefCell::new(attrs),
275
0
            template_contents: RefCell::new(if flags.template {
276
0
                Some(Node::new(NodeData::Document))
277
            } else {
278
0
                None
279
            }),
280
0
            mathml_annotation_xml_integration_point: flags.mathml_annotation_xml_integration_point,
281
        })
282
0
    }
283
284
0
    fn create_comment(&self, text: StrTendril) -> Handle {
285
0
        Node::new(NodeData::Comment { contents: text })
286
0
    }
287
288
0
    fn create_pi(&self, target: StrTendril, data: StrTendril) -> Handle {
289
0
        Node::new(NodeData::ProcessingInstruction {
290
0
            target,
291
0
            contents: data,
292
0
        })
293
0
    }
294
295
0
    fn append(&self, parent: &Handle, child: NodeOrText<Handle>) {
296
        // Append to an existing Text node if we have one.
297
0
        if let NodeOrText::AppendText(ref text) = child {
298
0
            if let Some(h) = parent.children.borrow().last() {
299
0
                if append_to_existing_text(h, text) {
300
0
                    return;
301
0
                }
302
0
            }
303
0
        }
304
305
0
        append(
306
0
            parent,
307
0
            match child {
308
0
                NodeOrText::AppendText(text) => Node::new(NodeData::Text {
309
0
                    contents: RefCell::new(text),
310
0
                }),
311
0
                NodeOrText::AppendNode(node) => node,
312
            },
313
        );
314
0
    }
315
316
0
    fn append_before_sibling(&self, sibling: &Handle, child: NodeOrText<Handle>) {
317
0
        let (parent, i) = get_parent_and_index(sibling)
318
0
            .expect("append_before_sibling called on node without parent");
319
320
0
        let child = match (child, i) {
321
            // No previous node.
322
0
            (NodeOrText::AppendText(text), 0) => Node::new(NodeData::Text {
323
0
                contents: RefCell::new(text),
324
0
            }),
325
326
            // Look for a text node before the insertion point.
327
0
            (NodeOrText::AppendText(text), i) => {
328
0
                let children = parent.children.borrow();
329
0
                let prev = &children[i - 1];
330
0
                if append_to_existing_text(prev, &text) {
331
0
                    return;
332
0
                }
333
0
                Node::new(NodeData::Text {
334
0
                    contents: RefCell::new(text),
335
0
                })
336
            }
337
338
            // The tree builder promises we won't have a text node after
339
            // the insertion point.
340
341
            // Any other kind of node.
342
0
            (NodeOrText::AppendNode(node), _) => node,
343
        };
344
345
0
        remove_from_parent(&child);
346
347
0
        child.parent.set(Some(Rc::downgrade(&parent)));
348
0
        parent.children.borrow_mut().insert(i, child);
349
0
    }
350
351
0
    fn append_based_on_parent_node(
352
0
        &self,
353
0
        element: &Self::Handle,
354
0
        prev_element: &Self::Handle,
355
0
        child: NodeOrText<Self::Handle>,
356
0
    ) {
357
0
        let parent = element.parent.take();
358
0
        let has_parent = parent.is_some();
359
0
        element.parent.set(parent);
360
361
0
        if has_parent {
362
0
            self.append_before_sibling(element, child);
363
0
        } else {
364
0
            self.append(prev_element, child);
365
0
        }
366
0
    }
367
368
0
    fn append_doctype_to_document(
369
0
        &self,
370
0
        name: StrTendril,
371
0
        _public_id: StrTendril,
372
0
        _system_id: StrTendril,
373
0
    ) {
374
0
        append(
375
0
            &self.document,
376
0
            Node::new(NodeData::Doctype {
377
0
                name,
378
0
            }),
379
        );
380
0
    }
381
382
0
    fn add_attrs_if_missing(&self, target: &Handle, attrs: Vec<Attribute>) {
383
0
        let mut existing = if let NodeData::Element { ref attrs, .. } = target.data {
384
0
            attrs.borrow_mut()
385
        } else {
386
0
            panic!("not an element")
387
        };
388
389
0
        let existing_names = existing
390
0
            .iter()
391
0
            .map(|e| e.name.clone())
392
0
            .collect::<HashSet<_>>();
393
0
        existing.extend(
394
0
            attrs
395
0
                .into_iter()
396
0
                .filter(|attr| !existing_names.contains(&attr.name)),
397
        );
398
0
    }
399
400
0
    fn remove_from_parent(&self, target: &Handle) {
401
0
        remove_from_parent(target);
402
0
    }
403
404
0
    fn reparent_children(&self, node: &Handle, new_parent: &Handle) {
405
0
        let mut children = node.children.borrow_mut();
406
0
        let mut new_children = new_parent.children.borrow_mut();
407
0
        for child in children.iter() {
408
0
            let previous_parent = child.parent.replace(Some(Rc::downgrade(new_parent)));
409
0
            assert!(Rc::ptr_eq(
410
0
                node,
411
0
                &previous_parent.unwrap().upgrade().expect("dangling weak")
412
            ))
413
        }
414
0
        new_children.extend(mem::take(&mut *children));
415
0
    }
416
417
0
    fn is_mathml_annotation_xml_integration_point(&self, target: &Handle) -> bool {
418
        if let NodeData::Element {
419
0
            mathml_annotation_xml_integration_point,
420
            ..
421
0
        } = target.data
422
        {
423
0
            mathml_annotation_xml_integration_point
424
        } else {
425
0
            panic!("not an element!")
426
        }
427
0
    }
428
}
429
430
impl Default for RcDom {
431
0
    fn default() -> RcDom {
432
0
        RcDom {
433
0
            document: Node::new(NodeData::Document),
434
0
            errors: vec![].into(),
435
0
            quirks_mode: tree_builder::NoQuirks.into(),
436
0
        }
437
0
    }
438
}
439
440
enum SerializeOp {
441
    Open(Handle),
442
    Close(QualName),
443
}
444
445
pub struct SerializableHandle(Handle);
446
447
impl From<Handle> for SerializableHandle {
448
0
    fn from(h: Handle) -> SerializableHandle {
449
0
        SerializableHandle(h)
450
0
    }
451
}
452
453
impl Serialize for SerializableHandle {
454
0
    fn serialize<S>(&self, serializer: &mut S, traversal_scope: TraversalScope) -> io::Result<()>
455
0
    where
456
0
        S: Serializer,
457
    {
458
0
        let mut ops = VecDeque::new();
459
0
        match traversal_scope {
460
0
            IncludeNode => ops.push_back(SerializeOp::Open(self.0.clone())),
461
0
            ChildrenOnly(_) => ops.extend(
462
0
                self.0
463
0
                    .children
464
0
                    .borrow()
465
0
                    .iter()
466
0
                    .map(|h| SerializeOp::Open(h.clone())),
467
            ),
468
        }
469
470
0
        while let Some(op) = ops.pop_front() {
471
0
            match op {
472
0
                SerializeOp::Open(handle) => match handle.data {
473
                    NodeData::Element {
474
0
                        ref name,
475
0
                        ref attrs,
476
                        ..
477
                    } => {
478
0
                        serializer.start_elem(
479
0
                            name.clone(),
480
0
                            attrs.borrow().iter().map(|at| (&at.name, &at.value[..])),
481
0
                        )?;
482
483
0
                        ops.reserve(1 + handle.children.borrow().len());
484
0
                        ops.push_front(SerializeOp::Close(name.clone()));
485
486
0
                        for child in handle.children.borrow().iter().rev() {
487
0
                            ops.push_front(SerializeOp::Open(child.clone()));
488
0
                        }
489
                    }
490
491
0
                    NodeData::Doctype { ref name, .. } => serializer.write_doctype(name)?,
492
493
0
                    NodeData::Text { ref contents } => serializer.write_text(&contents.borrow())?,
494
495
0
                    NodeData::Comment { ref contents } => serializer.write_comment(contents)?,
496
497
                    NodeData::ProcessingInstruction {
498
0
                        ref target,
499
0
                        ref contents,
500
0
                    } => serializer.write_processing_instruction(target, contents)?,
501
502
0
                    NodeData::Document => panic!("Can't serialize Document node itself"),
503
                },
504
505
0
                SerializeOp::Close(name) => {
506
0
                    serializer.end_elem(name)?;
507
                }
508
            }
509
        }
510
511
0
        Ok(())
512
0
    }
513
}