1use dom_struct::dom_struct;
6use html5ever::{QualName, local_name, ns};
7use js::context::JSContext;
8use script_bindings::error::Error;
9use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
10use script_traits::DocumentActivity;
11
12use crate::document_loader::DocumentLoader;
13use crate::dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
14use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
15 DocumentMethods, ElementCreationOptions,
16};
17use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
18use crate::dom::bindings::codegen::UnionTypes::StringOrElementCreationOptions;
19use crate::dom::bindings::domname::{is_valid_doctype_name, namespace_from_domstring};
20use crate::dom::bindings::error::Fallible;
21use crate::dom::bindings::inheritance::Castable;
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::DOMString;
24use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
25use crate::dom::documenttype::DocumentType;
26use crate::dom::element::{CustomElementCreationMode, ElementCreator};
27use crate::dom::node::Node;
28use crate::dom::text::Text;
29use crate::dom::types::Element;
30use crate::dom::xmldocument::XMLDocument;
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(cx: &mut JSContext, document: &Document) -> DomRoot<DOMImplementation> {
48 let window = document.window();
49 reflect_dom_object_with_cx(
50 Box::new(DOMImplementation::new_inherited(document)),
51 window,
52 cx,
53 )
54 }
55}
56
57impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
59 fn CreateDocumentType(
61 &self,
62 cx: &mut js::context::JSContext,
63 qualified_name: DOMString,
64 pubid: DOMString,
65 sysid: DOMString,
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 cx,
76 qualified_name,
77 Some(pubid),
78 Some(sysid),
79 &self.document,
80 ))
81 }
82
83 fn CreateDocument(
85 &self,
86 cx: &mut JSContext,
87 maybe_namespace: Option<DOMString>,
88 qname: DOMString,
89 maybe_doctype: Option<&DocumentType>,
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 cx,
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 self.document.image_cache(),
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(cx, maybe_namespace, qname, options)
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(cx, doc_type.upcast()).unwrap();
147 }
148
149 if let Some(ref elem) = maybe_elem {
151 doc_node.AppendChild(cx, elem.upcast()).unwrap();
152 }
153 }
154
155 Ok(doc)
160 }
161
162 fn CreateHTMLDocument(
164 &self,
165 cx: &mut JSContext,
166 title: Option<DOMString>,
167 ) -> DomRoot<Document> {
168 let win = self.document.window();
169 let loader = DocumentLoader::new(&self.document.loader());
170
171 let doc = Document::new(
174 cx,
175 win,
176 HasBrowsingContext::No,
177 None,
178 None,
179 self.document.origin().clone(),
181 IsHTMLDocument::HTMLDocument,
182 None,
183 None,
184 DocumentActivity::Inactive,
185 DocumentSource::NotFromParser,
186 loader,
187 None,
188 None,
189 Default::default(),
190 false,
191 self.document.allow_declarative_shadow_roots(),
192 Some(self.document.insecure_requests_policy()),
193 self.document.has_trustworthy_ancestor_or_current_origin(),
194 self.document.custom_element_reaction_stack(),
195 self.document.creation_sandboxing_flag_set(),
196 self.document.pipeline_id(),
197 self.document.image_cache(),
198 );
199
200 {
201 let doc_node = doc.upcast::<Node>();
203 let doc_type = DocumentType::new(cx, DOMString::from("html"), None, None, &doc);
204 doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
205 }
206
207 {
208 let doc_node = doc.upcast::<Node>();
211 let doc_html = DomRoot::upcast::<Node>(Element::create(
212 cx,
213 QualName::new(None, ns!(html), local_name!("html")),
214 None,
215 &doc,
216 ElementCreator::ScriptCreated,
217 CustomElementCreationMode::Asynchronous,
218 None,
219 ));
220 doc_node
221 .AppendChild(cx, &doc_html)
222 .expect("Appending failed");
223
224 {
225 let doc_head = DomRoot::upcast::<Node>(Element::create(
228 cx,
229 QualName::new(None, ns!(html), local_name!("head")),
230 None,
231 &doc,
232 ElementCreator::ScriptCreated,
233 CustomElementCreationMode::Asynchronous,
234 None,
235 ));
236 doc_html.AppendChild(cx, &doc_head).unwrap();
237
238 if let Some(title_str) = title {
240 let doc_title = DomRoot::upcast::<Node>(Element::create(
243 cx,
244 QualName::new(None, ns!(html), local_name!("title")),
245 None,
246 &doc,
247 ElementCreator::ScriptCreated,
248 CustomElementCreationMode::Asynchronous,
249 None,
250 ));
251 doc_head.AppendChild(cx, &doc_title).unwrap();
252
253 let title_text = Text::new(cx, title_str, &doc);
256 doc_title.AppendChild(cx, title_text.upcast()).unwrap();
257 }
258 }
259
260 let doc_body = Element::create(
263 cx,
264 QualName::new(None, ns!(html), local_name!("body")),
265 None,
266 &doc,
267 ElementCreator::ScriptCreated,
268 CustomElementCreationMode::Asynchronous,
269 None,
270 );
271 doc_html.AppendChild(cx, doc_body.upcast()).unwrap();
272 }
273
274 doc
276 }
277
278 fn HasFeature(&self) -> bool {
280 true
281 }
282}