fast_markup5ever/interface/
tree_builder.rs

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
14use crate::interface::{Attribute, ExpandedName, QualName};
15use std::borrow::Cow;
16use tendril::StrTendril;
17
18pub use self::NodeOrText::{AppendNode, AppendText};
19pub 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.
25pub 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)]
35pub 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)]
48pub 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)]
57pub struct ElementFlags {
58    /// A document fragment should be created, associated with the element,
59    /// and returned in TreeSink::get_template_contents.
60    ///
61    /// See [template-contents in the whatwg spec][whatwg template-contents].
62    ///
63    /// [whatwg template-contents]: https://html.spec.whatwg.org/multipage/#template-contents
64    pub template: bool,
65
66    /// This boolean should be recorded with the element and returned
67    /// in TreeSink::is_mathml_annotation_xml_integration_point
68    ///
69    /// See [html-integration-point in the whatwg spec][whatwg integration-point].
70    ///
71    /// [whatwg integration-point]: https://html.spec.whatwg.org/multipage/#html-integration-point
72    pub mathml_annotation_xml_integration_point: bool,
73
74    // Prevent construction from outside module
75    _private: (),
76}
77
78/// A constructor for an element.
79///
80/// # Examples
81///
82/// Create an element like `<div class="test-class-name"></div>`:
83pub fn create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle
84where
85    Sink: TreeSink,
86{
87    let mut flags = ElementFlags::default();
88    match name.expanded() {
89        expanded_name!(html "template") => flags.template = true,
90        expanded_name!(mathml "annotation-xml") => {
91            flags.mathml_annotation_xml_integration_point = attrs.iter().any(|attr| {
92                attr.name.expanded() == expanded_name!("", "encoding")
93                    && (attr.value.eq_ignore_ascii_case("text/html")
94                        || attr.value.eq_ignore_ascii_case("application/xhtml+xml"))
95            })
96        },
97        _ => {},
98    }
99    sink.create_element(name, attrs, flags)
100}
101
102/// Methods a parser can use to create the DOM. The DOM provider implements this trait.
103///
104/// Having this as a trait potentially allows multiple implementations of the DOM to be used with
105/// the same parser.
106pub trait TreeSink {
107    /// `Handle` is a reference to a DOM node.  The tree builder requires
108    /// that a `Handle` implements `Clone` to get another reference to
109    /// the same node.
110    type Handle: Clone;
111
112    /// The overall result of parsing.
113    ///
114    /// This should default to Self, but default associated types are not stable yet.
115    /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661)
116    type Output;
117
118    /// Consume this sink and return the overall result of parsing.
119    ///
120    /// TODO:This should default to `fn finish(self) -> Self::Output { self }`,
121    /// but default associated types are not stable yet.
122    /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661)
123    fn finish(self) -> Self::Output;
124
125    /// Signal a parse error.
126    fn parse_error(&mut self, msg: Cow<'static, str>);
127
128    /// Get a handle to the `Document` node.
129    fn get_document(&mut self) -> Self::Handle;
130
131    /// What is the name of this element?
132    ///
133    /// Should never be called on a non-element node;
134    /// feel free to `panic!`.
135    fn elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>;
136
137    /// Create an element.
138    ///
139    /// When creating a template element (`name.ns.expanded() == expanded_name!(html "template")`),
140    /// an associated document fragment called the "template contents" should
141    /// also be created. Later calls to self.get_template_contents() with that
142    /// given element return it.
143    /// See [the template element in the whatwg spec][whatwg template].
144    ///
145    /// [whatwg template]: https://html.spec.whatwg.org/multipage/#the-template-element
146    fn create_element(
147        &mut self,
148        name: QualName,
149        attrs: Vec<Attribute>,
150        flags: ElementFlags,
151    ) -> Self::Handle;
152
153    /// Create a comment node.
154    fn create_comment(&mut self, text: StrTendril);
155
156    /// Create a Processing Instruction node.
157    fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle;
158
159    /// Append a node as the last child of the given node.  If this would
160    /// produce adjacent sibling text nodes, it should concatenate the text
161    /// instead.
162    ///
163    /// The child node will not already have a parent.
164    fn append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>);
165
166    /// When the insertion point is decided by the existence of a parent node of the
167    /// element, we consider both possibilities and send the element which will be used
168    /// if a parent node exists, along with the element to be used if there isn't one.
169    fn append_based_on_parent_node(
170        &mut self,
171        element: &Self::Handle,
172        prev_element: &Self::Handle,
173        child: NodeOrText<Self::Handle>,
174    );
175
176    /// Append a `DOCTYPE` element to the `Document` node.
177    fn append_doctype_to_document(
178        &mut self,
179        name: StrTendril,
180        public_id: StrTendril,
181        system_id: StrTendril,
182    );
183
184    /// Mark a HTML `<script>` as "already started".
185    fn mark_script_already_started(&mut self, _node: &Self::Handle) {}
186
187    /// Indicate that a node was popped off the stack of open elements.
188    fn pop(&mut self, _node: &Self::Handle) {}
189
190    /// Get a handle to a template's template contents. The tree builder
191    /// promises this will never be called with something else than
192    /// a template element.
193    fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle;
194
195    /// Do two handles refer to the same node?
196    fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool;
197
198    /// Set the document's quirks mode.
199    fn set_quirks_mode(&mut self, mode: QuirksMode);
200
201    /// Append a node as the sibling immediately before the given node.
202    ///
203    /// The tree builder promises that `sibling` is not a text node.  However its
204    /// old previous sibling, which would become the new node's previous sibling,
205    /// could be a text node.  If the new node is also a text node, the two should
206    /// be merged, as in the behavior of `append`.
207    ///
208    /// NB: `new_node` may have an old parent, from which it should be removed.
209    fn append_before_sibling(&mut self, sibling: &Self::Handle, new_node: NodeOrText<Self::Handle>);
210
211    /// Add each attribute to the given element, if no attribute with that name
212    /// already exists. The tree builder promises this will never be called
213    /// with something else than an element.
214    fn add_attrs_if_missing(&mut self, target: &Self::Handle, attrs: Vec<Attribute>);
215
216    /// Associate the given form-associatable element with the form element
217    fn associate_with_form(
218        &mut self,
219        _target: &Self::Handle,
220        _form: &Self::Handle,
221        _nodes: (&Self::Handle, Option<&Self::Handle>),
222    ) {
223    }
224
225    /// Detach the given node from its parent.
226    fn remove_from_parent(&mut self, target: &Self::Handle);
227
228    /// Remove all the children from node and append them to new_parent.
229    fn reparent_children(&mut self, node: &Self::Handle, new_parent: &Self::Handle);
230
231    /// Returns true if the adjusted current node is an HTML integration point
232    /// and the token is a start tag.
233    fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool {
234        false
235    }
236
237    /// Called whenever the line number changes.
238    fn set_current_line(&mut self, _line_number: u64) {}
239
240    /// Indicate that a `script` element is complete.
241    fn complete_script(&mut self, _node: &Self::Handle) -> NextParserState {
242        NextParserState::Continue
243    }
244}
245
246/// Trace hooks for a garbage-collected DOM.
247pub trait Tracer {
248    type Handle;
249
250    /// Upon a call to `trace_handles`, the tree builder will call this method
251    /// for each handle in its internal state.
252    fn trace_handle(&self, node: &Self::Handle);
253}