/src/serenity/Userland/Libraries/LibWeb/DOM/DOMImplementation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, the SerenityOS developers. |
3 | | * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <LibURL/Origin.h> |
9 | | #include <LibWeb/Bindings/DOMImplementationPrototype.h> |
10 | | #include <LibWeb/Bindings/Intrinsics.h> |
11 | | #include <LibWeb/Bindings/MainThreadVM.h> |
12 | | #include <LibWeb/DOM/DOMImplementation.h> |
13 | | #include <LibWeb/DOM/DocumentType.h> |
14 | | #include <LibWeb/DOM/ElementFactory.h> |
15 | | #include <LibWeb/DOM/Text.h> |
16 | | #include <LibWeb/DOM/XMLDocument.h> |
17 | | #include <LibWeb/HTML/HTMLDocument.h> |
18 | | #include <LibWeb/Namespace.h> |
19 | | |
20 | | namespace Web::DOM { |
21 | | |
22 | | JS_DEFINE_ALLOCATOR(DOMImplementation); |
23 | | |
24 | | JS::NonnullGCPtr<DOMImplementation> DOMImplementation::create(Document& document) |
25 | 0 | { |
26 | 0 | auto& realm = document.realm(); |
27 | 0 | return realm.heap().allocate<DOMImplementation>(realm, document); |
28 | 0 | } |
29 | | |
30 | | DOMImplementation::DOMImplementation(Document& document) |
31 | 0 | : PlatformObject(document.realm()) |
32 | 0 | , m_document(document) |
33 | 0 | { |
34 | 0 | } |
35 | | |
36 | 0 | DOMImplementation::~DOMImplementation() = default; |
37 | | |
38 | | void DOMImplementation::initialize(JS::Realm& realm) |
39 | 0 | { |
40 | 0 | Base::initialize(realm); |
41 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(DOMImplementation); |
42 | 0 | } |
43 | | |
44 | | void DOMImplementation::visit_edges(Cell::Visitor& visitor) |
45 | 0 | { |
46 | 0 | Base::visit_edges(visitor); |
47 | 0 | visitor.visit(m_document); |
48 | 0 | } |
49 | | |
50 | | // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument |
51 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<XMLDocument>> DOMImplementation::create_document(Optional<FlyString> const& namespace_, String const& qualified_name, JS::GCPtr<DocumentType> doctype) const |
52 | 0 | { |
53 | | // 1. Let document be a new XMLDocument |
54 | 0 | auto xml_document = XMLDocument::create(realm()); |
55 | |
|
56 | 0 | xml_document->set_ready_for_post_load_tasks(true); |
57 | | |
58 | | // 2. Let element be null. |
59 | 0 | JS::GCPtr<Element> element; |
60 | | |
61 | | // 3. If qualifiedName is not the empty string, then set element to the result of running the internal createElementNS steps, given document, namespace, qualifiedName, and an empty dictionary. |
62 | 0 | if (!qualified_name.is_empty()) |
63 | 0 | element = TRY(xml_document->create_element_ns(namespace_, qualified_name, ElementCreationOptions {})); |
64 | | |
65 | | // 4. If doctype is non-null, append doctype to document. |
66 | 0 | if (doctype) |
67 | 0 | TRY(xml_document->append_child(*doctype)); |
68 | | |
69 | | // 5. If element is non-null, append element to document. |
70 | 0 | if (element) |
71 | 0 | TRY(xml_document->append_child(*element)); |
72 | | |
73 | | // 6. document’s origin is this’s associated document’s origin. |
74 | 0 | xml_document->set_origin(document().origin()); |
75 | | |
76 | | // 7. document’s content type is determined by namespace: |
77 | 0 | if (namespace_ == Namespace::HTML) { |
78 | | // -> HTML namespace |
79 | 0 | xml_document->set_content_type("application/xhtml+xml"_string); |
80 | 0 | } else if (namespace_ == Namespace::SVG) { |
81 | | // -> SVG namespace |
82 | 0 | xml_document->set_content_type("image/svg+xml"_string); |
83 | 0 | } else { |
84 | | // -> Any other namespace |
85 | 0 | xml_document->set_content_type("application/xml"_string); |
86 | 0 | } |
87 | | |
88 | | // 8. Return document. |
89 | 0 | return xml_document; |
90 | 0 | } |
91 | | |
92 | | // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument |
93 | | JS::NonnullGCPtr<Document> DOMImplementation::create_html_document(Optional<String> const& title) const |
94 | 0 | { |
95 | | // 1. Let doc be a new document that is an HTML document. |
96 | 0 | auto html_document = HTML::HTMLDocument::create(realm()); |
97 | | |
98 | | // 2. Set doc’s content type to "text/html". |
99 | 0 | html_document->set_content_type("text/html"_string); |
100 | 0 | html_document->set_document_type(DOM::Document::Type::HTML); |
101 | |
|
102 | 0 | html_document->set_ready_for_post_load_tasks(true); |
103 | | |
104 | | // 3. Append a new doctype, with "html" as its name and with its node document set to doc, to doc. |
105 | 0 | auto doctype = heap().allocate<DocumentType>(realm(), html_document); |
106 | 0 | doctype->set_name("html"_string); |
107 | 0 | MUST(html_document->append_child(*doctype)); |
108 | | |
109 | | // 4. Append the result of creating an element given doc, html, and the HTML namespace, to doc. |
110 | 0 | auto html_element = create_element(html_document, HTML::TagNames::html, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |
111 | 0 | MUST(html_document->append_child(html_element)); |
112 | | |
113 | | // 5. Append the result of creating an element given doc, head, and the HTML namespace, to the html element created earlier. |
114 | 0 | auto head_element = create_element(html_document, HTML::TagNames::head, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |
115 | 0 | MUST(html_element->append_child(head_element)); |
116 | | |
117 | | // 6. If title is given: |
118 | 0 | if (title.has_value()) { |
119 | | // 1. Append the result of creating an element given doc, title, and the HTML namespace, to the head element created earlier. |
120 | 0 | auto title_element = create_element(html_document, HTML::TagNames::title, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |
121 | 0 | MUST(head_element->append_child(title_element)); |
122 | | |
123 | | // 2. Append a new Text node, with its data set to title (which could be the empty string) and its node document set to doc, to the title element created earlier. |
124 | 0 | auto text_node = heap().allocate<Text>(realm(), html_document, title.value()); |
125 | 0 | MUST(title_element->append_child(*text_node)); |
126 | 0 | } |
127 | | |
128 | | // 7. Append the result of creating an element given doc, body, and the HTML namespace, to the html element created earlier. |
129 | 0 | auto body_element = create_element(html_document, HTML::TagNames::body, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |
130 | 0 | MUST(html_element->append_child(body_element)); |
131 | | |
132 | | // 8. doc’s origin is this’s associated document’s origin. |
133 | 0 | html_document->set_origin(document().origin()); |
134 | | |
135 | | // 9. Return doc. |
136 | 0 | return html_document; |
137 | 0 | } |
138 | | |
139 | | // https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype |
140 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<DocumentType>> DOMImplementation::create_document_type(String const& qualified_name, String const& public_id, String const& system_id) |
141 | 0 | { |
142 | | // 1. Validate qualifiedName. |
143 | 0 | TRY(Document::validate_qualified_name(realm(), qualified_name)); |
144 | | |
145 | | // 2. Return a new doctype, with qualifiedName as its name, publicId as its public ID, and systemId as its system ID, and with its node document set to the associated document of this. |
146 | 0 | auto document_type = DocumentType::create(document()); |
147 | 0 | document_type->set_name(qualified_name); |
148 | 0 | document_type->set_public_id(public_id); |
149 | 0 | document_type->set_system_id(system_id); |
150 | 0 | return document_type; |
151 | 0 | } |
152 | | |
153 | | } |