| 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 crate::{LocalName, Namespace}; | 
|---|
| 16 | use std::borrow::Cow; | 
|---|
| 17 | use std::fmt::Debug; | 
|---|
| 18 | use tendril::StrTendril; | 
|---|
| 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 | /// 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)] | 
|---|
| 50 | pub 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] | 
|---|
| 60 | pub 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>`: | 
|---|
| 83 | pub fn create_element<Sink>(sink: &Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle | 
|---|
| 84 | where | 
|---|
| 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. | 
|---|
| 103 | pub 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. | 
|---|
| 120 | pub 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. | 
|---|
| 282 | pub 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 |  | 
|---|