Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/markup5ever-0.12.1/interface/tree_builder.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2014-2017 The html5ever Project Developers. See the
2
// COPYRIGHT file at the top-level directory of this distribution.
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
//! This module contains functionality for managing the DOM, including adding/removing nodes.
11
//!
12
//! It can be used by a parser to create the DOM graph structure in memory.
13
14
use crate::interface::{Attribute, ExpandedName, QualName};
15
use std::borrow::Cow;
16
use tendril::StrTendril;
17
18
pub use self::NodeOrText::{AppendNode, AppendText};
19
pub use self::QuirksMode::{LimitedQuirks, NoQuirks, Quirks};
20
21
/// Something which can be inserted into the DOM.
22
///
23
/// Adjacent sibling text nodes are merged into a single node, so
24
/// the sink may not want to allocate a `Handle` for each.
25
pub enum NodeOrText<Handle> {
26
    AppendNode(Handle),
27
    AppendText(StrTendril),
28
}
29
30
/// A document's quirks mode, for compatibility with old browsers. See [quirks mode on wikipedia]
31
/// for more information.
32
///
33
/// [quirks mode on wikipedia]: https://en.wikipedia.org/wiki/Quirks_mode
34
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
35
pub enum QuirksMode {
36
    /// Full quirks mode
37
    Quirks,
38
    /// Almost standards mode
39
    LimitedQuirks,
40
    /// Standards mode
41
    NoQuirks,
42
}
43
44
/// Whether to interrupt further parsing of the current input until
45
/// the next explicit resumption of the tokenizer, or continue without
46
/// any interruption.
47
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
48
pub enum NextParserState {
49
    /// Stop further parsing.
50
    Suspend,
51
    /// Continue without interruptions.
52
    Continue,
53
}
54
55
/// Special properties of an element, useful for tagging elements with this information.
56
#[derive(Default)]
57
#[non_exhaustive]
58
pub struct ElementFlags {
59
    /// A document fragment should be created, associated with the element,
60
    /// and returned in TreeSink::get_template_contents.
61
    ///
62
    /// See [template-contents in the whatwg spec][whatwg template-contents].
63
    ///
64
    /// [whatwg template-contents]: https://html.spec.whatwg.org/multipage/#template-contents
65
    pub template: bool,
66
67
    /// This boolean should be recorded with the element and returned
68
    /// in TreeSink::is_mathml_annotation_xml_integration_point
69
    ///
70
    /// See [html-integration-point in the whatwg spec][whatwg integration-point].
71
    ///
72
    /// [whatwg integration-point]: https://html.spec.whatwg.org/multipage/#html-integration-point
73
    pub mathml_annotation_xml_integration_point: bool,
74
}
75
76
/// A constructor for an element.
77
///
78
/// # Examples
79
///
80
/// Create an element like `<div class="test-class-name"></div>`:
81
0
pub fn create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle
82
0
where
83
0
    Sink: TreeSink,
84
0
{
85
0
    let mut flags = ElementFlags::default();
86
0
    match name.expanded() {
87
0
        expanded_name!(html "template") => flags.template = true,
88
        expanded_name!(mathml "annotation-xml") => {
89
0
            flags.mathml_annotation_xml_integration_point = attrs.iter().any(|attr| {
90
0
                attr.name.expanded() == expanded_name!("", "encoding")
91
0
                    && (attr.value.eq_ignore_ascii_case("text/html")
92
0
                        || attr.value.eq_ignore_ascii_case("application/xhtml+xml"))
93
0
            })
Unexecuted instantiation: markup5ever::interface::tree_builder::create_element::<ammonia::rcdom::RcDom>::{closure#0}
Unexecuted instantiation: markup5ever::interface::tree_builder::create_element::<_>::{closure#0}
94
        },
95
0
        _ => {},
96
    }
97
0
    sink.create_element(name, attrs, flags)
98
0
}
Unexecuted instantiation: markup5ever::interface::tree_builder::create_element::<ammonia::rcdom::RcDom>
Unexecuted instantiation: markup5ever::interface::tree_builder::create_element::<_>
99
100
/// Methods a parser can use to create the DOM. The DOM provider implements this trait.
101
///
102
/// Having this as a trait potentially allows multiple implementations of the DOM to be used with
103
/// the same parser.
104
pub trait TreeSink {
105
    /// `Handle` is a reference to a DOM node.  The tree builder requires
106
    /// that a `Handle` implements `Clone` to get another reference to
107
    /// the same node.
108
    type Handle: Clone;
109
110
    /// The overall result of parsing.
111
    ///
112
    /// This should default to Self, but default associated types are not stable yet.
113
    /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661)
114
    type Output;
115
116
    /// Consume this sink and return the overall result of parsing.
117
    ///
118
    /// TODO:This should default to `fn finish(self) -> Self::Output { self }`,
119
    /// but default associated types are not stable yet.
120
    /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661)
121
    fn finish(self) -> Self::Output;
122
123
    /// Signal a parse error.
124
    fn parse_error(&mut self, msg: Cow<'static, str>);
125
126
    /// Get a handle to the `Document` node.
127
    fn get_document(&mut self) -> Self::Handle;
128
129
    /// What is the name of this element?
130
    ///
131
    /// Should never be called on a non-element node;
132
    /// feel free to `panic!`.
133
    fn elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>;
134
135
    /// Create an element.
136
    ///
137
    /// When creating a template element (`name.ns.expanded() == expanded_name!(html "template")`),
138
    /// an associated document fragment called the "template contents" should
139
    /// also be created. Later calls to self.get_template_contents() with that
140
    /// given element return it.
141
    /// See [the template element in the whatwg spec][whatwg template].
142
    ///
143
    /// [whatwg template]: https://html.spec.whatwg.org/multipage/#the-template-element
144
    fn create_element(
145
        &mut self,
146
        name: QualName,
147
        attrs: Vec<Attribute>,
148
        flags: ElementFlags,
149
    ) -> Self::Handle;
150
151
    /// Create a comment node.
152
    fn create_comment(&mut self, text: StrTendril) -> Self::Handle;
153
154
    /// Create a Processing Instruction node.
155
    fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle;
156
157
    /// Append a node as the last child of the given node.  If this would
158
    /// produce adjacent sibling text nodes, it should concatenate the text
159
    /// instead.
160
    ///
161
    /// The child node will not already have a parent.
162
    fn append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>);
163
164
    /// When the insertion point is decided by the existence of a parent node of the
165
    /// element, we consider both possibilities and send the element which will be used
166
    /// if a parent node exists, along with the element to be used if there isn't one.
167
    fn append_based_on_parent_node(
168
        &mut self,
169
        element: &Self::Handle,
170
        prev_element: &Self::Handle,
171
        child: NodeOrText<Self::Handle>,
172
    );
173
174
    /// Append a `DOCTYPE` element to the `Document` node.
175
    fn append_doctype_to_document(
176
        &mut self,
177
        name: StrTendril,
178
        public_id: StrTendril,
179
        system_id: StrTendril,
180
    );
181
182
    /// Mark a HTML `<script>` as "already started".
183
0
    fn mark_script_already_started(&mut self, _node: &Self::Handle) {}
Unexecuted instantiation: <ammonia::rcdom::RcDom as markup5ever::interface::tree_builder::TreeSink>::mark_script_already_started
Unexecuted instantiation: <_ as markup5ever::interface::tree_builder::TreeSink>::mark_script_already_started
184
185
    /// Indicate that a node was popped off the stack of open elements.
186
0
    fn pop(&mut self, _node: &Self::Handle) {}
Unexecuted instantiation: <ammonia::rcdom::RcDom as markup5ever::interface::tree_builder::TreeSink>::pop
Unexecuted instantiation: <_ as markup5ever::interface::tree_builder::TreeSink>::pop
187
188
    /// Get a handle to a template's template contents. The tree builder
189
    /// promises this will never be called with something else than
190
    /// a template element.
191
    fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle;
192
193
    /// Do two handles refer to the same node?
194
    fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool;
195
196
    /// Set the document's quirks mode.
197
    fn set_quirks_mode(&mut self, mode: QuirksMode);
198
199
    /// Append a node as the sibling immediately before the given node.
200
    ///
201
    /// The tree builder promises that `sibling` is not a text node.  However its
202
    /// old previous sibling, which would become the new node's previous sibling,
203
    /// could be a text node.  If the new node is also a text node, the two should
204
    /// be merged, as in the behavior of `append`.
205
    ///
206
    /// NB: `new_node` may have an old parent, from which it should be removed.
207
    fn append_before_sibling(&mut self, sibling: &Self::Handle, new_node: NodeOrText<Self::Handle>);
208
209
    /// Add each attribute to the given element, if no attribute with that name
210
    /// already exists. The tree builder promises this will never be called
211
    /// with something else than an element.
212
    fn add_attrs_if_missing(&mut self, target: &Self::Handle, attrs: Vec<Attribute>);
213
214
    /// Associate the given form-associatable element with the form element
215
0
    fn associate_with_form(
216
0
        &mut self,
217
0
        _target: &Self::Handle,
218
0
        _form: &Self::Handle,
219
0
        _nodes: (&Self::Handle, Option<&Self::Handle>),
220
0
    ) {
221
0
    }
Unexecuted instantiation: <ammonia::rcdom::RcDom as markup5ever::interface::tree_builder::TreeSink>::associate_with_form
Unexecuted instantiation: <_ as markup5ever::interface::tree_builder::TreeSink>::associate_with_form
222
223
    /// Detach the given node from its parent.
224
    fn remove_from_parent(&mut self, target: &Self::Handle);
225
226
    /// Remove all the children from node and append them to new_parent.
227
    fn reparent_children(&mut self, node: &Self::Handle, new_parent: &Self::Handle);
228
229
    /// Returns true if the adjusted current node is an HTML integration point
230
    /// and the token is a start tag.
231
0
    fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool {
232
0
        false
233
0
    }
234
235
    /// Called whenever the line number changes.
236
0
    fn set_current_line(&mut self, _line_number: u64) {}
Unexecuted instantiation: <ammonia::rcdom::RcDom as markup5ever::interface::tree_builder::TreeSink>::set_current_line
Unexecuted instantiation: <_ as markup5ever::interface::tree_builder::TreeSink>::set_current_line
237
238
    /// Indicate that a `script` element is complete.
239
0
    fn complete_script(&mut self, _node: &Self::Handle) -> NextParserState {
240
0
        NextParserState::Continue
241
0
    }
242
}
243
244
/// Trace hooks for a garbage-collected DOM.
245
pub trait Tracer {
246
    type Handle;
247
248
    /// Upon a call to `trace_handles`, the tree builder will call this method
249
    /// for each handle in its internal state.
250
    fn trace_handle(&self, node: &Self::Handle);
251
}