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
57impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
59 fn CreateDocumentType(
61 &self,
62 qualified_name: DOMString,
63 pubid: DOMString,
64 sysid: DOMString,
65 can_gc: CanGc,
66 ) -> Fallible<DomRoot<DocumentType>> {
67 if !is_valid_doctype_name(&qualified_name) {
70 debug!("Not a valid doctype name");
71 return Err(Error::InvalidCharacter(None));
72 }
73
74 Ok(DocumentType::new(
75 qualified_name,
76 Some(pubid),
77 Some(sysid),
78 &self.document,
79 can_gc,
80 ))
81 }
82
83 fn CreateDocument(
85 &self,
86 maybe_namespace: Option<DOMString>,
87 qname: DOMString,
88 maybe_doctype: Option<&DocumentType>,
89 can_gc: CanGc,
90 ) -> Fallible<DomRoot<XMLDocument>> {
91 let win = self.document.window();
92 let loader = DocumentLoader::new(&self.document.loader());
93 let namespace = namespace_from_domstring(maybe_namespace.to_owned());
94
95 let content_type = match namespace {
96 ns!(html) => "application/xhtml+xml",
97 ns!(svg) => "image/svg+xml",
98 _ => "application/xml",
99 }
100 .parse()
101 .unwrap();
102
103 let doc = XMLDocument::new(
105 win,
106 HasBrowsingContext::No,
107 None,
108 self.document.origin().clone(),
109 IsHTMLDocument::NonHTMLDocument,
110 Some(content_type),
111 None,
112 DocumentActivity::Inactive,
113 DocumentSource::NotFromParser,
114 loader,
115 Some(self.document.insecure_requests_policy()),
116 self.document.has_trustworthy_ancestor_or_current_origin(),
117 self.document.custom_element_reaction_stack(),
118 can_gc,
119 );
120
121 let maybe_elem = if qname.is_empty() {
125 None
126 } else {
127 let options =
128 StringOrElementCreationOptions::ElementCreationOptions(ElementCreationOptions {
129 is: None,
130 });
131 match doc
132 .upcast::<Document>()
133 .CreateElementNS(maybe_namespace, qname, options, can_gc)
134 {
135 Err(error) => return Err(error),
136 Ok(elem) => Some(elem),
137 }
138 };
139
140 {
141 let doc_node = doc.upcast::<Node>();
142
143 if let Some(doc_type) = maybe_doctype {
145 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
146 }
147
148 if let Some(ref elem) = maybe_elem {
150 doc_node.AppendChild(elem.upcast(), can_gc).unwrap();
151 }
152 }
153
154 Ok(doc)
159 }
160
161 fn CreateHTMLDocument(&self, title: Option<DOMString>, can_gc: CanGc) -> DomRoot<Document> {
163 let win = self.document.window();
164 let loader = DocumentLoader::new(&self.document.loader());
165
166 let doc = Document::new(
168 win,
169 HasBrowsingContext::No,
170 None,
171 self.document.origin().clone(),
172 IsHTMLDocument::HTMLDocument,
173 None,
174 None,
175 DocumentActivity::Inactive,
176 DocumentSource::NotFromParser,
177 loader,
178 None,
179 None,
180 Default::default(),
181 false,
182 self.document.allow_declarative_shadow_roots(),
183 Some(self.document.insecure_requests_policy()),
184 self.document.has_trustworthy_ancestor_or_current_origin(),
185 self.document.custom_element_reaction_stack(),
186 self.document.creation_sandboxing_flag_set(),
187 can_gc,
188 );
189
190 {
191 let doc_node = doc.upcast::<Node>();
193 let doc_type = DocumentType::new(DOMString::from("html"), None, None, &doc, can_gc);
194 doc_node.AppendChild(doc_type.upcast(), can_gc).unwrap();
195 }
196
197 {
198 let doc_node = doc.upcast::<Node>();
200 let doc_html = DomRoot::upcast::<Node>(Element::create(
201 QualName::new(None, ns!(html), local_name!("html")),
202 None,
203 &doc,
204 ElementCreator::ScriptCreated,
205 CustomElementCreationMode::Asynchronous,
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>(Element::create(
216 QualName::new(None, ns!(html), local_name!("head")),
217 None,
218 &doc,
219 ElementCreator::ScriptCreated,
220 CustomElementCreationMode::Asynchronous,
221 None,
222 can_gc,
223 ));
224 doc_html.AppendChild(&doc_head, can_gc).unwrap();
225
226 if let Some(title_str) = title {
228 let doc_title = DomRoot::upcast::<Node>(Element::create(
230 QualName::new(None, ns!(html), local_name!("title")),
231 None,
232 &doc,
233 ElementCreator::ScriptCreated,
234 CustomElementCreationMode::Asynchronous,
235 None,
236 can_gc,
237 ));
238 doc_head.AppendChild(&doc_title, can_gc).unwrap();
239
240 let title_text = Text::new(title_str, &doc, can_gc);
242 doc_title.AppendChild(title_text.upcast(), can_gc).unwrap();
243 }
244 }
245
246 let doc_body = Element::create(
248 QualName::new(None, ns!(html), local_name!("body")),
249 None,
250 &doc,
251 ElementCreator::ScriptCreated,
252 CustomElementCreationMode::Asynchronous,
253 None,
254 can_gc,
255 );
256 doc_html.AppendChild(doc_body.upcast(), can_gc).unwrap();
257 }
258
259 doc
264 }
265
266 fn HasFeature(&self) -> bool {
268 true
269 }
270}