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};
10use script_traits::DocumentActivity;
11
12use crate::dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
13use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
14 DocumentMethods, ElementCreationOptions,
15};
16use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
17use crate::dom::bindings::codegen::UnionTypes::StringOrElementCreationOptions;
18use crate::dom::bindings::domname::{is_valid_doctype_name, namespace_from_domstring};
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::inheritance::Castable;
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::DOMString;
23use crate::dom::document::{Document, 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::event_loop::document_loader::DocumentLoader;
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(
50 cx,
51 Box::new(DOMImplementation::new_inherited(document)),
52 window,
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 return Err(Error::InvalidCharacter(Some(
71 "Doctype name contains ASCII whitespace".into(),
72 )));
73 }
74
75 Ok(DocumentType::new(
76 cx,
77 qualified_name,
78 Some(pubid),
79 Some(sysid),
80 &self.document,
81 ))
82 }
83
84 fn CreateDocument(
86 &self,
87 cx: &mut JSContext,
88 maybe_namespace: Option<DOMString>,
89 qname: DOMString,
90 maybe_doctype: Option<&DocumentType>,
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 cx,
107 win,
108 HasBrowsingContext::No,
109 None,
110 self.document.origin().clone(),
111 IsHTMLDocument::NonHTMLDocument,
112 Some(content_type),
113 None,
114 DocumentActivity::Inactive,
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 Some(
133 doc.upcast::<Document>()
134 .CreateElementNS(cx, maybe_namespace, qname, options)?,
135 )
136 };
137
138 {
139 let doc_node = doc.upcast::<Node>();
140
141 if let Some(doc_type) = maybe_doctype {
143 doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
144 }
145
146 if let Some(ref elem) = maybe_elem {
148 doc_node.AppendChild(cx, elem.upcast()).unwrap();
149 }
150 }
151
152 Ok(doc)
157 }
158
159 fn CreateHTMLDocument(
161 &self,
162 cx: &mut JSContext,
163 title: Option<DOMString>,
164 ) -> DomRoot<Document> {
165 let win = self.document.window();
166 let loader = DocumentLoader::new(&self.document.loader());
167
168 let doc = Document::new(
171 cx,
172 win,
173 HasBrowsingContext::No,
174 None,
175 None,
176 self.document.origin().clone(),
178 IsHTMLDocument::HTMLDocument,
179 None,
180 None,
181 DocumentActivity::Inactive,
182 loader,
183 None,
184 None,
185 Default::default(),
186 false,
187 self.document.allow_declarative_shadow_roots(),
188 Some(self.document.insecure_requests_policy()),
189 self.document.has_trustworthy_ancestor_or_current_origin(),
190 self.document.custom_element_reaction_stack(),
191 self.document.creation_sandboxing_flag_set(),
192 self.document.pipeline_id(),
193 self.document.image_cache(),
194 );
195
196 {
197 let doc_node = doc.upcast::<Node>();
199 let doc_type = DocumentType::new(cx, DOMString::from_static("html"), None, None, &doc);
200 doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
201 }
202
203 {
204 let doc_node = doc.upcast::<Node>();
207 let doc_html = DomRoot::upcast::<Node>(Element::create(
208 cx,
209 QualName::new(None, ns!(html), local_name!("html")),
210 None,
211 &doc,
212 ElementCreator::ScriptCreated,
213 CustomElementCreationMode::Asynchronous,
214 None,
215 ));
216 doc_node
217 .AppendChild(cx, &doc_html)
218 .expect("Appending failed");
219
220 {
221 let doc_head = DomRoot::upcast::<Node>(Element::create(
224 cx,
225 QualName::new(None, ns!(html), local_name!("head")),
226 None,
227 &doc,
228 ElementCreator::ScriptCreated,
229 CustomElementCreationMode::Asynchronous,
230 None,
231 ));
232 doc_html.AppendChild(cx, &doc_head).unwrap();
233
234 if let Some(title_str) = title {
236 let doc_title = DomRoot::upcast::<Node>(Element::create(
239 cx,
240 QualName::new(None, ns!(html), local_name!("title")),
241 None,
242 &doc,
243 ElementCreator::ScriptCreated,
244 CustomElementCreationMode::Asynchronous,
245 None,
246 ));
247 doc_head.AppendChild(cx, &doc_title).unwrap();
248
249 let title_text = Text::new(cx, title_str, &doc);
252 doc_title.AppendChild(cx, title_text.upcast()).unwrap();
253 }
254 }
255
256 let doc_body = Element::create(
259 cx,
260 QualName::new(None, ns!(html), local_name!("body")),
261 None,
262 &doc,
263 ElementCreator::ScriptCreated,
264 CustomElementCreationMode::Asynchronous,
265 None,
266 );
267 doc_html.AppendChild(cx, doc_body.upcast()).unwrap();
268 }
269
270 doc
272 }
273
274 fn HasFeature(&self) -> bool {
276 true
277 }
278}