Skip to content

Commit

Permalink
LibWeb: Use right interface for custom SVG and MathML elements
Browse files Browse the repository at this point in the history
The DOM spec gets overridden by both the SVG2 and MathML core specs in
that unknown elements should not inherit DOM::Element, but
SVG::SVGElement and MathML::MathMLElement respectively.
  • Loading branch information
gmta authored and tcl3 committed Oct 31, 2024
1 parent 84fe8d6 commit 76e638b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Element nodeName: FOO namespaceURI: http://www.w3.org/1999/xhtml __proto__: [object HTMLUnknownElement]
Element nodeName: foo namespaceURI: http://www.w3.org/2000/svg __proto__: [object SVGElement]
Element nodeName: foo namespaceURI: http://www.w3.org/1998/Math/MathML __proto__: [object MathMLElement]
13 changes: 13 additions & 0 deletions Tests/LibWeb/Text/input/DOM/Document-createElementNS-custom.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<script src="../include.js"></script>
<script>
test(() => {
const printElement = (element) => {
println(`Element nodeName: ${element.nodeName} namespaceURI: ${element.namespaceURI} __proto__: ${element.__proto__}`);
};

printElement(document.createElementNS('http://www.w3.org/1999/xhtml', 'foo'));
printElement(document.createElementNS('http://www.w3.org/2000/svg', 'foo'));
printElement(document.createElementNS('http://www.w3.org/1998/Math/MathML', 'foo'));
});
</script>
35 changes: 18 additions & 17 deletions Userland/Libraries/LibWeb/DOM/ElementFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ static JS::NonnullGCPtr<Element> create_html_element(JS::Realm& realm, Document&
return realm.heap().allocate<HTML::HTMLUnknownElement>(realm, document, move(qualified_name));
}

static JS::GCPtr<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
static JS::NonnullGCPtr<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
{
auto const& local_name = qualified_name.local_name();

Expand Down Expand Up @@ -492,17 +492,22 @@ static JS::GCPtr<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document&
if (local_name == SVG::TagNames::image)
return realm.heap().allocate<SVG::SVGImageElement>(realm, document, move(qualified_name));

return nullptr;
// https://svgwg.org/svg2-draft/types.html#ElementsInTheSVGDOM
// Elements in the SVG namespace whose local name does not match an element defined in any
// specification supported by the software must nonetheless implement the SVGElement interface.
return realm.heap().allocate<SVG::SVGElement>(realm, document, move(qualified_name));
}

static JS::GCPtr<MathML::MathMLElement> create_mathml_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
static JS::NonnullGCPtr<MathML::MathMLElement> create_mathml_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
{
auto const& local_name = qualified_name.local_name();
// https://w3c.github.io/mathml-core/#dom-and-javascript
// All the nodes representing MathML elements in the DOM must implement, and expose to scripts,
// the following MathMLElement interface.

if (local_name.is_one_of(MathML::TagNames::annotation, MathML::TagNames::annotation_xml, MathML::TagNames::maction, MathML::TagNames::math, MathML::TagNames::merror, MathML::TagNames::mfrac, MathML::TagNames::mi, MathML::TagNames::mmultiscripts, MathML::TagNames::mn, MathML::TagNames::mo, MathML::TagNames::mover, MathML::TagNames::mpadded, MathML::TagNames::mphantom, MathML::TagNames::mprescripts, MathML::TagNames::mroot, MathML::TagNames::mrow, MathML::TagNames::ms, MathML::TagNames::mspace, MathML::TagNames::msqrt, MathML::TagNames::mstyle, MathML::TagNames::msub, MathML::TagNames::msubsup, MathML::TagNames::msup, MathML::TagNames::mtable, MathML::TagNames::mtd, MathML::TagNames::mtext, MathML::TagNames::mtr, MathML::TagNames::munder, MathML::TagNames::munderover, MathML::TagNames::semantics))
return realm.heap().allocate<MathML::MathMLElement>(realm, document, move(qualified_name));
// https://w3c.github.io/mathml-core/#mathml-elements-and-attributes
// The term MathML element refers to any element in the MathML namespace.

return nullptr;
return realm.heap().allocate<MathML::MathMLElement>(realm, document, move(qualified_name));
}
// https://dom.spec.whatwg.org/#concept-create-element
WebIDL::ExceptionOr<JS::NonnullGCPtr<Element>> create_element(Document& document, FlyString local_name, Optional<FlyString> namespace_, Optional<FlyString> prefix, Optional<String> is_value, bool synchronous_custom_elements_flag)
Expand Down Expand Up @@ -654,20 +659,16 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Element>> create_element(Document& document

if (namespace_ == Namespace::SVG) {
auto element = create_svg_element(realm, document, qualified_name);
if (element) {
element->set_is_value(move(is_value));
element->set_custom_element_state(CustomElementState::Uncustomized);
return JS::NonnullGCPtr<Element> { *element };
}
element->set_is_value(move(is_value));
element->set_custom_element_state(CustomElementState::Uncustomized);
return element;
}

if (namespace_ == Namespace::MathML) {
auto element = create_mathml_element(realm, document, qualified_name);
if (element) {
element->set_is_value(move(is_value));
element->set_custom_element_state(CustomElementState::Uncustomized);
return JS::NonnullGCPtr<Element> { *element };
}
element->set_is_value(move(is_value));
element->set_custom_element_state(CustomElementState::Uncustomized);
return element;
}

// 8. Return result.
Expand Down

0 comments on commit 76e638b

Please sign in to comment.