1use dom_struct::dom_struct;
6use html5ever::{local_name, ns};
7use script_bindings::error::Error;
8use script_traits::DocumentActivity;
9
10use crate::document_loader::DocumentLoader;
11use crate::dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
12use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
13 DocumentMethods, ElementCreationOptions,
14};
15use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
16use crate::dom::bindings::codegen::UnionTypes::StringOrElementCreationOptions;
17use crate::dom::bindings::domname::{is_valid_doctype_name, namespace_from_domstring};
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::inheritance::Castable;
20use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::DOMString;
23use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
24use crate::dom::documenttype::DocumentType;
25use crate::dom::html::htmlbodyelement::HTMLBodyElement;
26use crate::dom::html::htmlheadelement::HTMLHeadElement;
27use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
28use crate::dom::html::htmltitleelement::HTMLTitleElement;
29use crate::dom::node::Node;
30use crate::dom::text::Text;
31use crate::dom::xmldocument::XMLDocument;
32use crate::script_runtime::CanGc;
33
34#[dom_struct]
36pub(crate) struct DOMImplementation {
37 reflector_: Reflector,
38 document: Dom<Document>,
39}
40
41impl DOMImplementation {
42 fn new_inherited(document: &Document) -> DOMImplementation {
43 DOMImplementation {
44 reflector_: Reflector::new(),
45 document: Dom::from_ref(document),
46 }
47 }
48
49 pub(crate) fn new(document: &Document, can_gc: CanGc) -> DomRoot<DOMImplementation> {
50 let window = document.window();
51 reflect_dom_object(
52 Box::new(DOMImplementation::new_inherited(document)),
53 window,
54 can_gc,
55 )
56 }
57}
58
59#[allow(non_snake_case)]
61impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
62 fn CreateDocumentType(
64 &self,
65 qualified_name: DOMString,
66 pubid: DOMString,
67 sysid: DOMString,
68 can_gc: CanGc,
69 ) -> Fallible<DomRoot<DocumentType>> {
70 if !is_valid_doctype_name(&qualified_name) {
73 debug!("Not a valid doctype name");
74 return Err(Error::InvalidCharacter);
75 }
76
77 Ok(DocumentType::new(
78 qualified_name,
79 Some(pubid),
80 Some(sysid),
81 &self.document,
82 can_gc,
83 ))
84 }
85
86 fn CreateDocument(
88 &self,
89 maybe_namespace: Option<DOMString>,
90 qname: DOMString,
91 maybe_doctype: Option<&DocumentType>,
92 can_gc: CanGc,
93 ) -> Fallible<DomRoot<XMLDocument>> {
94 let win = self.document.window();
95 let loader = DocumentLoader::new(&self.document.loader());
96 let namespace = namespace_from_domstring(maybe_namespace.to_owned());
97
98 let content_type = match namespace {
99 ns!(html) => "application/xhtml+xml",
100 ns!(svg) => "image/svg+xml",
101 _ => "application/xml",
102 }
103 .parse()
104 .unwrap();
105
106 let doc = XMLDocument::new(
108 win,
109 HasBrowsingContext::No,
110 None,
111 self.document.origin().clone(),
112 IsHTMLDocument::NonHTMLDocument,
113 Some(content_type),
114 None,
115 DocumentActivity::Inactive,
116 DocumentSource::NotFromParser,
117 loader,
118 Some(self.document.insecure_requests_policy()),
119 self.document.has_trustworthy_ancestor_or_current_origin(),
120 self.document.custom_element_reaction_stack(),
121 can_gc,
122 );
123
124 let maybe_elem = if qname.is_empty() {
128 None
129 } else {
130 let options =
131 StringOrElementCreationOptions::ElementCreationOptions(ElementCreationOptions {
132 is: None,
133 });
134 match doc
135 .upcast::<Document>()
136 .CreateElementNS(maybe_namespace, qname, options, can_gc)
137 {
138 Err(error) => return Err(error),
139 Ok(elem) => Some(elem),
140 }
141 };
142
143 {
144 let doc_node = doc.upcast::<Node>();
145
146 if let Some(doc_type) = maybe_doctype {
148 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
149 }
150
151 if let Some(ref elem) = maybe_elem {
153 doc_node.AppendChild(elem.upcast(), can_gc).unwrap();
154 }
155 }
156
157 Ok(doc)
162 }
163
164 fn CreateHTMLDocument(&self, title: Option<DOMString>, can_gc: CanGc) -> DomRoot<Document> {
166 let win = self.document.window();
167 let loader = DocumentLoader::new(&self.document.loader());
168
169 let doc = Document::new(
171 win,
172 HasBrowsingContext::No,
173 None,
174 self.document.origin().clone(),
175 IsHTMLDocument::HTMLDocument,
176 None,
177 None,
178 DocumentActivity::Inactive,
179 DocumentSource::NotFromParser,
180 loader,
181 None,
182 None,
183 Default::default(),
184 false,
185 self.document.allow_declarative_shadow_roots(),
186 Some(self.document.insecure_requests_policy()),
187 self.document.has_trustworthy_ancestor_or_current_origin(),
188 self.document.custom_element_reaction_stack(),
189 can_gc,
190 );
191
192 {
193 let doc_node = doc.upcast::<Node>();
195 let doc_type = DocumentType::new(DOMString::from("html"), None, None, &doc, can_gc);
196 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
197 }
198
199 {
200 let doc_node = doc.upcast::<Node>();
202 let doc_html = DomRoot::upcast::<Node>(HTMLHtmlElement::new(
203 local_name!("html"),
204 None,
205 &doc,
206 None,
207 can_gc,
208 ));
209 doc_node
210 .AppendChild(&doc_html, can_gc)
211 .expect("Appending failed");
212
213 {
214 let doc_head = DomRoot::upcast::<Node>(HTMLHeadElement::new(
216 local_name!("head"),
217 None,
218 &doc,
219 None,
220 can_gc,
221 ));
222 doc_html.AppendChild(&doc_head, can_gc).unwrap();
223
224 if let Some(title_str) = title {
226 let doc_title = DomRoot::upcast::<Node>(HTMLTitleElement::new(
228 local_name!("title"),
229 None,
230 &doc,
231 None,
232 can_gc,
233 ));
234 doc_head.AppendChild(&doc_title, can_gc).unwrap();
235
236 let title_text = Text::new(title_str, &doc, can_gc);
238 doc_title.AppendChild(title_text.upcast(), can_gc).unwrap();
239 }
240 }
241
242 let doc_body = HTMLBodyElement::new(local_name!("body"), None, &doc, None, can_gc);
244 doc_html.AppendChild(doc_body.upcast(), can_gc).unwrap();
245 }
246
247 doc
252 }
253
254 fn HasFeature(&self) -> bool {
256 true
257 }
258}