Coverage Report

Created: 2025-05-08 06:13

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