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