Files
servo/components/script/dom/domimplementation.rs
Tim van der Lippe a1c8896eda script: Pass &mut JSContext to reflect_node_with_proto (#43952)
A lot (and I mean, really a lot) depends on these constructors.
Therefore, this is the one spaghetti ball that I could extract and
convert all `can_gc` to `cx`. There are some new introductions of
`temp_cx` in the callbacks of the servo parser, but we already had some
in other callbacks.

Part of #40600

Testing: It compiles

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2026-04-05 18:07:30 +00:00

281 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
use html5ever::{QualName, local_name, ns};
use js::context::JSContext;
use script_bindings::error::Error;
use script_traits::DocumentActivity;
use crate::document_loader::DocumentLoader;
use crate::dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, ElementCreationOptions,
};
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::UnionTypes::StringOrElementCreationOptions;
use crate::dom::bindings::domname::{is_valid_doctype_name, namespace_from_domstring};
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
use crate::dom::documenttype::DocumentType;
use crate::dom::element::{CustomElementCreationMode, ElementCreator};
use crate::dom::node::Node;
use crate::dom::text::Text;
use crate::dom::types::Element;
use crate::dom::xmldocument::XMLDocument;
use crate::script_runtime::CanGc;
// https://dom.spec.whatwg.org/#domimplementation
#[dom_struct]
pub(crate) struct DOMImplementation {
reflector_: Reflector,
document: Dom<Document>,
}
impl DOMImplementation {
fn new_inherited(document: &Document) -> DOMImplementation {
DOMImplementation {
reflector_: Reflector::new(),
document: Dom::from_ref(document),
}
}
pub(crate) fn new(document: &Document, can_gc: CanGc) -> DomRoot<DOMImplementation> {
let window = document.window();
reflect_dom_object(
Box::new(DOMImplementation::new_inherited(document)),
window,
can_gc,
)
}
}
// https://dom.spec.whatwg.org/#domimplementation
impl DOMImplementationMethods<crate::DomTypeHolder> for DOMImplementation {
/// <https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype>
fn CreateDocumentType(
&self,
cx: &mut js::context::JSContext,
qualified_name: DOMString,
pubid: DOMString,
sysid: DOMString,
) -> Fallible<DomRoot<DocumentType>> {
// Step 1. If name is not a valid doctype name, then throw an
// "InvalidCharacterError" DOMException.
if !is_valid_doctype_name(&qualified_name) {
debug!("Not a valid doctype name");
return Err(Error::InvalidCharacter(None));
}
Ok(DocumentType::new(
cx,
qualified_name,
Some(pubid),
Some(sysid),
&self.document,
))
}
/// <https://dom.spec.whatwg.org/#dom-domimplementation-createdocument>
fn CreateDocument(
&self,
cx: &mut JSContext,
maybe_namespace: Option<DOMString>,
qname: DOMString,
maybe_doctype: Option<&DocumentType>,
) -> Fallible<DomRoot<XMLDocument>> {
let win = self.document.window();
let loader = DocumentLoader::new(&self.document.loader());
let namespace = namespace_from_domstring(maybe_namespace.to_owned());
let content_type = match namespace {
ns!(html) => "application/xhtml+xml",
ns!(svg) => "image/svg+xml",
_ => "application/xml",
}
.parse()
.unwrap();
// Step 1. Let document be a new XMLDocument.
let doc = XMLDocument::new(
win,
HasBrowsingContext::No,
None,
self.document.origin().clone(),
IsHTMLDocument::NonHTMLDocument,
Some(content_type),
None,
DocumentActivity::Inactive,
DocumentSource::NotFromParser,
loader,
Some(self.document.insecure_requests_policy()),
self.document.has_trustworthy_ancestor_or_current_origin(),
self.document.custom_element_reaction_stack(),
CanGc::from_cx(cx),
);
// Step 2. Let element be null.
// Step 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.
let maybe_elem = if qname.is_empty() {
None
} else {
let options =
StringOrElementCreationOptions::ElementCreationOptions(ElementCreationOptions {
is: None,
});
match doc
.upcast::<Document>()
.CreateElementNS(cx, maybe_namespace, qname, options)
{
Err(error) => return Err(error),
Ok(elem) => Some(elem),
}
};
{
let doc_node = doc.upcast::<Node>();
// Step 4.
if let Some(doc_type) = maybe_doctype {
doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
}
// Step 5.
if let Some(ref elem) = maybe_elem {
doc_node.AppendChild(cx, elem.upcast()).unwrap();
}
}
// Step 6.
// The origin is already set
// Step 7.
Ok(doc)
}
/// <https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument>
fn CreateHTMLDocument(
&self,
cx: &mut JSContext,
title: Option<DOMString>,
) -> DomRoot<Document> {
let win = self.document.window();
let loader = DocumentLoader::new(&self.document.loader());
// Step 1. Let doc be a new document that is an HTML document.
// Step 2. Set docs content type to "text/html".
let doc = Document::new(
win,
HasBrowsingContext::No,
None,
None,
// Step 8. docs origin is thiss associated documents origin.
self.document.origin().clone(),
IsHTMLDocument::HTMLDocument,
None,
None,
DocumentActivity::Inactive,
DocumentSource::NotFromParser,
loader,
None,
None,
Default::default(),
false,
self.document.allow_declarative_shadow_roots(),
Some(self.document.insecure_requests_policy()),
self.document.has_trustworthy_ancestor_or_current_origin(),
self.document.custom_element_reaction_stack(),
self.document.creation_sandboxing_flag_set(),
CanGc::from_cx(cx),
);
{
// Step 3. Append a new doctype, with "html" as its name and with its node document set to doc, to doc.
let doc_node = doc.upcast::<Node>();
let doc_type = DocumentType::new(cx, DOMString::from("html"), None, None, &doc);
doc_node.AppendChild(cx, doc_type.upcast()).unwrap();
}
{
// Step 4. Append the result of creating an element given doc, "html",
// and the HTML namespace, to doc.
let doc_node = doc.upcast::<Node>();
let doc_html = DomRoot::upcast::<Node>(Element::create(
cx,
QualName::new(None, ns!(html), local_name!("html")),
None,
&doc,
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
));
doc_node
.AppendChild(cx, &doc_html)
.expect("Appending failed");
{
// Step 5. Append the result of creating an element given doc, "head",
// and the HTML namespace, to the html element created earlier.
let doc_head = DomRoot::upcast::<Node>(Element::create(
cx,
QualName::new(None, ns!(html), local_name!("head")),
None,
&doc,
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
));
doc_html.AppendChild(cx, &doc_head).unwrap();
// Step 6. If title is given:
if let Some(title_str) = title {
// Step 6.1. Append the result of creating an element given doc, "title",
// and the HTML namespace, to the head element created earlier.
let doc_title = DomRoot::upcast::<Node>(Element::create(
cx,
QualName::new(None, ns!(html), local_name!("title")),
None,
&doc,
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
));
doc_head.AppendChild(cx, &doc_title).unwrap();
// Step 6.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.
let title_text = Text::new(cx, title_str, &doc);
doc_title.AppendChild(cx, title_text.upcast()).unwrap();
}
}
// Step 7. Append the result of creating an element given doc, "body",
// and the HTML namespace, to the html element created earlier.
let doc_body = Element::create(
cx,
QualName::new(None, ns!(html), local_name!("body")),
None,
&doc,
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
);
doc_html.AppendChild(cx, doc_body.upcast()).unwrap();
}
// Step 9. Return doc.
doc
}
/// <https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature>
fn HasFeature(&self) -> bool {
true
}
}