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::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;
31use crate::script_runtime::CanGc;
32
33#[dom_struct]
35pub(crate) struct DOMImplementation {
36 reflector_: Reflector,
37 document: Dom<Document>,
38}
39
40impl DOMImplementation {
41 fn new_inherited(document: &Document) -> DOMImplementation {
42 DOMImplementation {
43 reflector_: Reflector::new(),
44 document: Dom::from_ref(document),
45 }
46 }
47
48 pub(crate) fn new(document: &Document, can_gc: CanGc) -> DomRoot<DOMImplementation> {
49 let window = document.window();
50 reflect_dom_object(
51 Box::new(DOMImplementation::new_inherited(document)),
52 window,
53 can_gc,
54 )
55 }
56}
57
58impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
60 fn CreateDocumentType(
62 &self,
63 cx: &mut js::context::JSContext,
64 qualified_name: DOMString,
65 pubid: DOMString,
66 sysid: DOMString,
67 ) -> Fallible<DomRoot<DocumentType>> {
68 if !is_valid_doctype_name(&qualified_name) {
71 debug!("Not a valid doctype name");
72 return Err(Error::InvalidCharacter(None));
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 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 CanGc::from_cx(cx),
121 );
122
123 let maybe_elem = if qname.is_empty() {
127 None
128 } else {
129 let options =
130 StringOrElementCreationOptions::ElementCreationOptions(ElementCreationOptions {
131 is: None,
132 });
133 match doc
134 .upcast::<Document>()
135 .CreateElementNS(cx, maybe_namespace, qname, options)
136 {
137 Err(error) => return Err(error),
138 Ok(elem) => Some(elem),
139 }
140 };
141
142 {
143 let doc_node = doc.upcast::<Node>();
144
145 if let Some(doc_type) = maybe_doctype {
147 doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
148 }
149
150 if let Some(ref elem) = maybe_elem {
152 doc_node.AppendChild(cx, elem.upcast()).unwrap();
153 }
154 }
155
156 Ok(doc)
161 }
162
163 fn CreateHTMLDocument(
165 &self,
166 cx: &mut JSContext,
167 title: Option<DOMString>,
168 ) -> DomRoot<Document> {
169 let win = self.document.window();
170 let loader = DocumentLoader::new(&self.document.loader());
171
172 let doc = Document::new(
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 CanGc::from_cx(cx),
199 );
200
201 {
202 let doc_node = doc.upcast::<Node>();
204 let doc_type = DocumentType::new(cx, DOMString::from("html"), None, None, &doc);
205 doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
206 }
207
208 {
209 let doc_node = doc.upcast::<Node>();
212 let doc_html = DomRoot::upcast::<Node>(Element::create(
213 cx,
214 QualName::new(None, ns!(html), local_name!("html")),
215 None,
216 &doc,
217 ElementCreator::ScriptCreated,
218 CustomElementCreationMode::Asynchronous,
219 None,
220 ));
221 doc_node
222 .AppendChild(cx, &doc_html)
223 .expect("Appending failed");
224
225 {
226 let doc_head = DomRoot::upcast::<Node>(Element::create(
229 cx,
230 QualName::new(None, ns!(html), local_name!("head")),
231 None,
232 &doc,
233 ElementCreator::ScriptCreated,
234 CustomElementCreationMode::Asynchronous,
235 None,
236 ));
237 doc_html.AppendChild(cx, &doc_head).unwrap();
238
239 if let Some(title_str) = title {
241 let doc_title = DomRoot::upcast::<Node>(Element::create(
244 cx,
245 QualName::new(None, ns!(html), local_name!("title")),
246 None,
247 &doc,
248 ElementCreator::ScriptCreated,
249 CustomElementCreationMode::Asynchronous,
250 None,
251 ));
252 doc_head.AppendChild(cx, &doc_title).unwrap();
253
254 let title_text = Text::new(cx, title_str, &doc);
257 doc_title.AppendChild(cx, title_text.upcast()).unwrap();
258 }
259 }
260
261 let doc_body = Element::create(
264 cx,
265 QualName::new(None, ns!(html), local_name!("body")),
266 None,
267 &doc,
268 ElementCreator::ScriptCreated,
269 CustomElementCreationMode::Asynchronous,
270 None,
271 );
272 doc_html.AppendChild(cx, doc_body.upcast()).unwrap();
273 }
274
275 doc
277 }
278
279 fn HasFeature(&self) -> bool {
281 true
282 }
283}