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 pub 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>`:
create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle where Sink: TreeSink,83 pub fn create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle
84 where
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.
106 pub 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)
finish(self) -> Self::Output123     fn finish(self) -> Self::Output;
124 
125     /// Signal a parse error.
parse_error(&mut self, msg: Cow<'static, str>)126     fn parse_error(&mut self, msg: Cow<'static, str>);
127 
128     /// Get a handle to the `Document` node.
get_document(&mut self) -> Self::Handle129     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!`.
elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>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
create_element( &mut self, name: QualName, attrs: Vec<Attribute>, flags: ElementFlags, ) -> Self::Handle146     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.
create_comment(&mut self, text: StrTendril) -> Self::Handle154     fn create_comment(&mut self, text: StrTendril) -> Self::Handle;
155 
156     /// Create a Processing Instruction node.
create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle157     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.
append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>)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.
append_based_on_parent_node( &mut self, element: &Self::Handle, prev_element: &Self::Handle, child: NodeOrText<Self::Handle>, )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.
append_doctype_to_document( &mut self, name: StrTendril, public_id: StrTendril, system_id: StrTendril, )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".
mark_script_already_started(&mut self, _node: &Self::Handle)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.
pop(&mut self, _node: &Self::Handle)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.
get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle193     fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle;
194 
195     /// Do two handles refer to the same node?
same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool196     fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool;
197 
198     /// Set the document's quirks mode.
set_quirks_mode(&mut self, mode: QuirksMode)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.
append_before_sibling(&mut self, sibling: &Self::Handle, new_node: NodeOrText<Self::Handle>)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.
add_attrs_if_missing(&mut self, target: &Self::Handle, attrs: Vec<Attribute>)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
associate_with_form( &mut self, _target: &Self::Handle, _form: &Self::Handle, _nodes: (&Self::Handle, Option<&Self::Handle>), )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.
remove_from_parent(&mut self, target: &Self::Handle)226     fn remove_from_parent(&mut self, target: &Self::Handle);
227 
228     /// Remove all the children from node and append them to new_parent.
reparent_children(&mut self, node: &Self::Handle, new_parent: &Self::Handle)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.
is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool233     fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool {
234         false
235     }
236 
237     /// Called whenever the line number changes.
set_current_line(&mut self, _line_number: u64)238     fn set_current_line(&mut self, _line_number: u64) {}
239 
240     /// Indicate that a `script` element is complete.
complete_script(&mut self, _node: &Self::Handle) -> NextParserState241     fn complete_script(&mut self, _node: &Self::Handle) -> NextParserState {
242         NextParserState::Continue
243     }
244 }
245 
246 /// Trace hooks for a garbage-collected DOM.
247 pub 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.
trace_handle(&self, node: &Self::Handle)252     fn trace_handle(&self, node: &Self::Handle);
253 }
254