1use dom_struct::dom_struct;
6use html5ever::{QualName, 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::element::{CustomElementCreationMode, ElementCreator};
26use crate::dom::node::Node;
27use crate::dom::text::Text;
28use crate::dom::types::Element;
29use crate::dom::xmldocument::XMLDocument;
30use crate::script_runtime::CanGc;
31
32#[dom_struct]
34pub(crate) struct DOMImplementation {
35 reflector_: Reflector,
36 document: Dom<Document>,
37}
38
39impl DOMImplementation {
40 fn new_inherited(document: &Document) -> DOMImplementation {
41 DOMImplementation {
42 reflector_: Reflector::new(),
43 document: Dom::from_ref(document),
44 }
45 }
46
47 pub(crate) fn new(document: &Document, can_gc: CanGc) -> DomRoot<DOMImplementation> {
48 let window = document.window();
49 reflect_dom_object(
50 Box::new(DOMImplementation::new_inherited(document)),
51 window,
52 can_gc,
53 )
54 }
55}
56
57#[allow(non_snake_case)]
59impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
60 fn CreateDocumentType(
62 &self,
63 qualified_name: DOMString,
64 pubid: DOMString,
65 sysid: DOMString,
66 can_gc: CanGc,
67 ) -> Fallible<DomRoot<DocumentType>> {
68 if !is_valid_doctype_name(&qualified_name) {
71 debug!("Not a valid doctype name");
72 return Err(Error::InvalidCharacter);
73 }
74
75 Ok(DocumentType::new(
76 qualified_name,
77 Some(pubid),
78 Some(sysid),
79 &self.document,
80 can_gc,
81 ))
82 }
83
84 fn CreateDocument(
86 &self,
87 maybe_namespace: Option<DOMString>,
88 qname: DOMString,
89 maybe_doctype: Option<&DocumentType>,
90 can_gc: CanGc,
91 ) -> Fallible<DomRoot<XMLDocument>> {
92 let win = self.document.window();
93 let loader = DocumentLoader::new(&self.document.loader());
94 let namespace = namespace_from_domstring(maybe_namespace.to_owned());
95
96 let content_type = match namespace {
97 ns!(html) => "application/xhtml+xml",
98 ns!(svg) => "image/svg+xml",
99 _ => "application/xml",
100 }
101 .parse()
102 .unwrap();
103
104 let doc = XMLDocument::new(
106 win,
107 HasBrowsingContext::No,
108 None,
109 self.document.origin().clone(),
110 IsHTMLDocument::NonHTMLDocument,
111 Some(content_type),
112 None,
113 DocumentActivity::Inactive,
114 DocumentSource::NotFromParser,
115 loader,
116 Some(self.document.insecure_requests_policy()),
117 self.document.has_trustworthy_ancestor_or_current_origin(),
118 self.document.custom_element_reaction_stack(),
119 can_gc,
120 );
121
122 let maybe_elem = if qname.is_empty() {
126 None
127 } else {
128 let options =
129 StringOrElementCreationOptions::ElementCreationOptions(ElementCreationOptions {
130 is: None,
131 });
132 match doc
133 .upcast::<Document>()
134 .CreateElementNS(maybe_namespace, qname, options, can_gc)
135 {
136 Err(error) => return Err(error),
137 Ok(elem) => Some(elem),
138 }
139 };
140
141 {
142 let doc_node = doc.upcast::<Node>();
143
144 if let Some(doc_type) = maybe_doctype {
146 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
147 }
148
149 if let Some(ref elem) = maybe_elem {
151 doc_node.AppendChild(elem.upcast(), can_gc).unwrap();
152 }
153 }
154
155 Ok(doc)
160 }
161
162 fn CreateHTMLDocument(&self, title: Option<DOMString>, can_gc: CanGc) -> DomRoot<Document> {
164 let win = self.document.window();
165 let loader = DocumentLoader::new(&self.document.loader());
166
167 let doc = Document::new(
169 win,
170 HasBrowsingContext::No,
171 None,
172 self.document.origin().clone(),
173 IsHTMLDocument::HTMLDocument,
174 None,
175 None,
176 DocumentActivity::Inactive,
177 DocumentSource::NotFromParser,
178 loader,
179 None,
180 None,
181 Default::default(),
182 false,
183 self.document.allow_declarative_shadow_roots(),
184 Some(self.document.insecure_requests_policy()),
185 self.document.has_trustworthy_ancestor_or_current_origin(),
186 self.document.custom_element_reaction_stack(),
187 self.document.creation_sandboxing_flag_set(),
188 can_gc,
189 );
190
191 {
192 let doc_node = doc.upcast::<Node>();
194 let doc_type = DocumentType::new(DOMString::from("html"), None, None, &doc, can_gc);
195 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
196 }
197
198 {
199 let doc_node = doc.upcast::<Node>();
201 let doc_html = DomRoot::upcast::<Node>(Element::create(
202 QualName::new(None, ns!(html), local_name!("html")),
203 None,
204 &doc,
205 ElementCreator::ScriptCreated,
206 CustomElementCreationMode::Asynchronous,
207 None,
208 can_gc,
209 ));
210 doc_node
211 .AppendChild(&doc_html, can_gc)
212 .expect("Appending failed");
213
214 {
215 let doc_head = DomRoot::upcast::<Node>(Element::create(
217 QualName::new(None, ns!(html), local_name!("head")),
218 None,
219 &doc,
220 ElementCreator::ScriptCreated,
221 CustomElementCreationMode::Asynchronous,
222 None,
223 can_gc,
224 ));
225 doc_html.AppendChild(&doc_head, can_gc).unwrap();
226
227 if let Some(title_str) = title {
229 let doc_title = DomRoot::upcast::<Node>(Element::create(
231 QualName::new(None, ns!(html), local_name!("title")),
232 None,
233 &doc,
234 ElementCreator::ScriptCreated,
235 CustomElementCreationMode::Asynchronous,
236 None,
237 can_gc,
238 ));
239 doc_head.AppendChild(&doc_title, can_gc).unwrap();
240
241 let title_text = Text::new(title_str, &doc, can_gc);
243 doc_title.AppendChild(title_text.upcast(), can_gc).unwrap();
244 }
245 }
246
247 let doc_body = Element::create(
249 QualName::new(None, ns!(html), local_name!("body")),
250 None,
251 &doc,
252 ElementCreator::ScriptCreated,
253 CustomElementCreationMode::Asynchronous,
254 None,
255 can_gc,
256 );
257 doc_html.AppendChild(doc_body.upcast(), can_gc).unwrap();
258 }
259
260 doc
265 }
266
267 fn HasFeature(&self) -> bool {
269 true
270 }
271}