ladybird/Libraries/LibWeb/DOM/ElementFactory.cpp

785 lines
47 KiB
C++
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.

/*
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2020-2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/ElementFactory.h>
#include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
#include <LibWeb/HTML/CustomElements/CustomElementName.h>
#include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLAreaElement.h>
#include <LibWeb/HTML/HTMLAudioElement.h>
#include <LibWeb/HTML/HTMLBRElement.h>
#include <LibWeb/HTML/HTMLBaseElement.h>
#include <LibWeb/HTML/HTMLBodyElement.h>
#include <LibWeb/HTML/HTMLButtonElement.h>
#include <LibWeb/HTML/HTMLCanvasElement.h>
#include <LibWeb/HTML/HTMLDListElement.h>
#include <LibWeb/HTML/HTMLDataElement.h>
#include <LibWeb/HTML/HTMLDataListElement.h>
#include <LibWeb/HTML/HTMLDetailsElement.h>
#include <LibWeb/HTML/HTMLDialogElement.h>
#include <LibWeb/HTML/HTMLDirectoryElement.h>
#include <LibWeb/HTML/HTMLDivElement.h>
#include <LibWeb/HTML/HTMLEmbedElement.h>
#include <LibWeb/HTML/HTMLFieldSetElement.h>
#include <LibWeb/HTML/HTMLFontElement.h>
#include <LibWeb/HTML/HTMLFormElement.h>
#include <LibWeb/HTML/HTMLFrameElement.h>
#include <LibWeb/HTML/HTMLFrameSetElement.h>
#include <LibWeb/HTML/HTMLHRElement.h>
#include <LibWeb/HTML/HTMLHeadElement.h>
#include <LibWeb/HTML/HTMLHeadingElement.h>
#include <LibWeb/HTML/HTMLHtmlElement.h>
#include <LibWeb/HTML/HTMLIFrameElement.h>
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/HTML/HTMLLIElement.h>
#include <LibWeb/HTML/HTMLLabelElement.h>
#include <LibWeb/HTML/HTMLLegendElement.h>
#include <LibWeb/HTML/HTMLLinkElement.h>
#include <LibWeb/HTML/HTMLMapElement.h>
#include <LibWeb/HTML/HTMLMarqueeElement.h>
#include <LibWeb/HTML/HTMLMenuElement.h>
#include <LibWeb/HTML/HTMLMetaElement.h>
#include <LibWeb/HTML/HTMLMeterElement.h>
#include <LibWeb/HTML/HTMLModElement.h>
#include <LibWeb/HTML/HTMLOListElement.h>
#include <LibWeb/HTML/HTMLObjectElement.h>
#include <LibWeb/HTML/HTMLOptGroupElement.h>
#include <LibWeb/HTML/HTMLOptionElement.h>
#include <LibWeb/HTML/HTMLOutputElement.h>
#include <LibWeb/HTML/HTMLParagraphElement.h>
#include <LibWeb/HTML/HTMLParamElement.h>
#include <LibWeb/HTML/HTMLPictureElement.h>
#include <LibWeb/HTML/HTMLPreElement.h>
#include <LibWeb/HTML/HTMLProgressElement.h>
#include <LibWeb/HTML/HTMLQuoteElement.h>
#include <LibWeb/HTML/HTMLScriptElement.h>
#include <LibWeb/HTML/HTMLSelectElement.h>
#include <LibWeb/HTML/HTMLSelectedContentElement.h>
#include <LibWeb/HTML/HTMLSlotElement.h>
#include <LibWeb/HTML/HTMLSourceElement.h>
#include <LibWeb/HTML/HTMLSpanElement.h>
#include <LibWeb/HTML/HTMLStyleElement.h>
#include <LibWeb/HTML/HTMLSummaryElement.h>
#include <LibWeb/HTML/HTMLTableCaptionElement.h>
#include <LibWeb/HTML/HTMLTableCellElement.h>
#include <LibWeb/HTML/HTMLTableColElement.h>
#include <LibWeb/HTML/HTMLTableElement.h>
#include <LibWeb/HTML/HTMLTableRowElement.h>
#include <LibWeb/HTML/HTMLTableSectionElement.h>
#include <LibWeb/HTML/HTMLTemplateElement.h>
#include <LibWeb/HTML/HTMLTextAreaElement.h>
#include <LibWeb/HTML/HTMLTimeElement.h>
#include <LibWeb/HTML/HTMLTitleElement.h>
#include <LibWeb/HTML/HTMLTrackElement.h>
#include <LibWeb/HTML/HTMLUListElement.h>
#include <LibWeb/HTML/HTMLUnknownElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
#include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
#include <LibWeb/Infra/Strings.h>
#include <LibWeb/MathML/MathMLElement.h>
#include <LibWeb/MathML/MathMLMiElement.h>
#include <LibWeb/MathML/MathMLMspaceElement.h>
#include <LibWeb/MathML/TagNames.h>
#include <LibWeb/Namespace.h>
#include <LibWeb/SVG/SVGAElement.h>
#include <LibWeb/SVG/SVGCircleElement.h>
#include <LibWeb/SVG/SVGClipPathElement.h>
#include <LibWeb/SVG/SVGDefsElement.h>
#include <LibWeb/SVG/SVGDescElement.h>
#include <LibWeb/SVG/SVGEllipseElement.h>
#include <LibWeb/SVG/SVGFEBlendElement.h>
#include <LibWeb/SVG/SVGFEColorMatrixElement.h>
#include <LibWeb/SVG/SVGFEComponentTransferElement.h>
#include <LibWeb/SVG/SVGFECompositeElement.h>
#include <LibWeb/SVG/SVGFEDisplacementMapElement.h>
#include <LibWeb/SVG/SVGFEDropShadowElement.h>
#include <LibWeb/SVG/SVGFEFloodElement.h>
#include <LibWeb/SVG/SVGFEFuncAElement.h>
#include <LibWeb/SVG/SVGFEFuncBElement.h>
#include <LibWeb/SVG/SVGFEFuncGElement.h>
#include <LibWeb/SVG/SVGFEFuncRElement.h>
#include <LibWeb/SVG/SVGFEGaussianBlurElement.h>
#include <LibWeb/SVG/SVGFEImageElement.h>
#include <LibWeb/SVG/SVGFEMergeElement.h>
#include <LibWeb/SVG/SVGFEMergeNodeElement.h>
#include <LibWeb/SVG/SVGFEMorphologyElement.h>
#include <LibWeb/SVG/SVGFEOffsetElement.h>
#include <LibWeb/SVG/SVGFETurbulenceElement.h>
#include <LibWeb/SVG/SVGFilterElement.h>
#include <LibWeb/SVG/SVGForeignObjectElement.h>
#include <LibWeb/SVG/SVGGElement.h>
#include <LibWeb/SVG/SVGImageElement.h>
#include <LibWeb/SVG/SVGLineElement.h>
#include <LibWeb/SVG/SVGLinearGradientElement.h>
#include <LibWeb/SVG/SVGMaskElement.h>
#include <LibWeb/SVG/SVGMetadataElement.h>
#include <LibWeb/SVG/SVGPathElement.h>
#include <LibWeb/SVG/SVGPatternElement.h>
#include <LibWeb/SVG/SVGPolygonElement.h>
#include <LibWeb/SVG/SVGPolylineElement.h>
#include <LibWeb/SVG/SVGRadialGradientElement.h>
#include <LibWeb/SVG/SVGRectElement.h>
#include <LibWeb/SVG/SVGSVGElement.h>
#include <LibWeb/SVG/SVGScriptElement.h>
#include <LibWeb/SVG/SVGStopElement.h>
#include <LibWeb/SVG/SVGStyleElement.h>
#include <LibWeb/SVG/SVGSymbolElement.h>
#include <LibWeb/SVG/SVGTSpanElement.h>
#include <LibWeb/SVG/SVGTextElement.h>
#include <LibWeb/SVG/SVGTextPathElement.h>
#include <LibWeb/SVG/SVGTitleElement.h>
#include <LibWeb/SVG/SVGUseElement.h>
#include <LibWeb/SVG/SVGViewElement.h>
#include <LibWeb/SVG/TagNames.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
namespace Web::DOM {
ErrorOr<FixedArray<FlyString>> valid_local_names_for_given_html_element_interface(StringView html_element_interface_name)
{
if (html_element_interface_name == "HTMLAnchorElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::a });
if (html_element_interface_name == "HTMLAreaElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::area });
if (html_element_interface_name == "HTMLAudioElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::audio });
if (html_element_interface_name == "HTMLBaseElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::base });
if (html_element_interface_name == "HTMLBodyElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::body });
if (html_element_interface_name == "HTMLBRElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::br });
if (html_element_interface_name == "HTMLButtonElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::button });
if (html_element_interface_name == "HTMLCanvasElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::canvas });
if (html_element_interface_name == "HTMLDataElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::data });
if (html_element_interface_name == "HTMLDataListElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::datalist });
if (html_element_interface_name == "HTMLDetailsElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::details });
if (html_element_interface_name == "HTMLDialogElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::dialog });
if (html_element_interface_name == "HTMLDirectoryElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::dir });
if (html_element_interface_name == "HTMLDivElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::div });
if (html_element_interface_name == "HTMLDListElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::dl });
if (html_element_interface_name == "HTMLEmbedElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::embed });
if (html_element_interface_name == "HTMLFieldSetElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::fieldset });
if (html_element_interface_name == "HTMLFontElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::font });
if (html_element_interface_name == "HTMLFormElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::form });
if (html_element_interface_name == "HTMLFrameElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::frame });
if (html_element_interface_name == "HTMLFrameSetElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::frameset });
if (html_element_interface_name == "HTMLHeadElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::head });
if (html_element_interface_name == "HTMLHeadingElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6 });
if (html_element_interface_name == "HTMLHRElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::hr });
if (html_element_interface_name == "HTMLHtmlElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::html });
if (html_element_interface_name == "HTMLIFrameElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::iframe });
if (html_element_interface_name == "HTMLImageElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::img });
if (html_element_interface_name == "HTMLInputElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::input });
if (html_element_interface_name == "HTMLLabelElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::label });
if (html_element_interface_name == "HTMLLegendElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::legend });
if (html_element_interface_name == "HTMLLIElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::li });
if (html_element_interface_name == "HTMLLinkElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::link });
if (html_element_interface_name == "HTMLMapElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::map });
if (html_element_interface_name == "HTMLMarqueeElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::marquee });
if (html_element_interface_name == "HTMLMenuElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::menu });
if (html_element_interface_name == "HTMLMetaElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::meta });
if (html_element_interface_name == "HTMLMeterElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::meter });
if (html_element_interface_name == "HTMLModElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::ins, HTML::TagNames::del });
if (html_element_interface_name == "HTMLOListElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::ol });
if (html_element_interface_name == "HTMLObjectElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::object });
if (html_element_interface_name == "HTMLOptGroupElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::optgroup });
if (html_element_interface_name == "HTMLOptionElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::option });
if (html_element_interface_name == "HTMLOutputElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::output });
if (html_element_interface_name == "HTMLParagraphElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::p });
if (html_element_interface_name == "HTMLParamElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::param });
if (html_element_interface_name == "HTMLPictureElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::picture });
if (html_element_interface_name == "HTMLPreElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::pre, HTML::TagNames::listing, HTML::TagNames::xmp });
if (html_element_interface_name == "HTMLProgressElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::progress });
if (html_element_interface_name == "HTMLQuoteElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::blockquote, HTML::TagNames::q });
if (html_element_interface_name == "HTMLScriptElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::script });
if (html_element_interface_name == "HTMLSelectedContentElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::selectedcontent });
if (html_element_interface_name == "HTMLSelectElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::select });
if (html_element_interface_name == "HTMLSlotElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::slot });
if (html_element_interface_name == "HTMLSourceElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::source });
if (html_element_interface_name == "HTMLSpanElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::span });
if (html_element_interface_name == "HTMLStyleElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::style });
if (html_element_interface_name == "HTMLTableCaptionElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::caption });
if (html_element_interface_name == "HTMLTableCellElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::td, HTML::TagNames::th });
if (html_element_interface_name == "HTMLTableColElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::colgroup, HTML::TagNames::col });
if (html_element_interface_name == "HTMLTableRowElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::tr });
if (html_element_interface_name == "HTMLTableElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::table });
if (html_element_interface_name == "HTMLTableSectionElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::tbody, HTML::TagNames::thead, HTML::TagNames::tfoot });
if (html_element_interface_name == "HTMLTemplateElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::template_ });
if (html_element_interface_name == "HTMLTextAreaElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::textarea });
if (html_element_interface_name == "HTMLTimeElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::time });
if (html_element_interface_name == "HTMLTitleElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::title });
if (html_element_interface_name == "HTMLTrackElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::track });
if (html_element_interface_name == "HTMLUListElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::ul });
if (html_element_interface_name == "HTMLVideoElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::video });
if (html_element_interface_name == "HTMLElement"sv)
return FixedArray<FlyString>::create({ HTML::TagNames::article, HTML::TagNames::search, HTML::TagNames::section, HTML::TagNames::nav, HTML::TagNames::aside, HTML::TagNames::hgroup, HTML::TagNames::header, HTML::TagNames::footer, HTML::TagNames::address, HTML::TagNames::dt, HTML::TagNames::dd, HTML::TagNames::figure, HTML::TagNames::figcaption, HTML::TagNames::main, HTML::TagNames::em, HTML::TagNames::strong, HTML::TagNames::small, HTML::TagNames::s, HTML::TagNames::cite, HTML::TagNames::dfn, HTML::TagNames::abbr, HTML::TagNames::ruby, HTML::TagNames::rt, HTML::TagNames::rp, HTML::TagNames::code, HTML::TagNames::var, HTML::TagNames::samp, HTML::TagNames::kbd, HTML::TagNames::sub, HTML::TagNames::sup, HTML::TagNames::i, HTML::TagNames::b, HTML::TagNames::u, HTML::TagNames::mark, HTML::TagNames::bdi, HTML::TagNames::bdo, HTML::TagNames::wbr, HTML::TagNames::summary, HTML::TagNames::noscript, HTML::TagNames::acronym, HTML::TagNames::basefont, HTML::TagNames::big, HTML::TagNames::center, HTML::TagNames::nobr, HTML::TagNames::noembed, HTML::TagNames::noframes, HTML::TagNames::plaintext, HTML::TagNames::rb, HTML::TagNames::rtc, HTML::TagNames::strike, HTML::TagNames::tt });
return FixedArray<FlyString>::create({});
}
// https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom%3Aelement-interface
bool is_unknown_html_element(FlyString const& tag_name)
{
// NOTE: This is intentionally case-sensitive.
// 1. If name is applet, bgsound, blink, isindex, keygen, multicol, nextid, or spacer, then return HTMLUnknownElement.
if (tag_name.is_one_of(HTML::TagNames::applet, HTML::TagNames::bgsound, HTML::TagNames::blink, HTML::TagNames::isindex, HTML::TagNames::keygen, HTML::TagNames::multicol, HTML::TagNames::nextid, HTML::TagNames::spacer))
return true;
// 2. If name is acronym, basefont, big, center, nobr, noembed, noframes, plaintext, rb, rtc, strike, or tt, then return HTMLElement.
// 3. If name is listing or xmp, then return HTMLPreElement.
// 4. Otherwise, if this specification defines an interface appropriate for the element type corresponding to the local name name, then return that interface.
// 5. If other applicable specifications define an appropriate interface for name, then return the interface they define.
#define __ENUMERATE_HTML_TAG(name, tag) \
if (tag_name == HTML::TagNames::name) \
return false;
ENUMERATE_HTML_TAGS
#undef __ENUMERATE_HTML_TAG
// 6. If name is a valid custom element name, then return HTMLElement.
if (HTML::is_valid_custom_element_name(tag_name))
return false;
// 7. Return HTMLUnknownElement.
return true;
}
// https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom%3Aelement-interface
static GC::Ref<Element> create_html_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
{
FlyString tag_name = qualified_name.local_name();
if (tag_name == HTML::TagNames::a)
return realm.create<HTML::HTMLAnchorElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::area)
return realm.create<HTML::HTMLAreaElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::audio)
return realm.create<HTML::HTMLAudioElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::base)
return realm.create<HTML::HTMLBaseElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::body)
return realm.create<HTML::HTMLBodyElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::br)
return realm.create<HTML::HTMLBRElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::button)
return realm.create<HTML::HTMLButtonElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::canvas)
return realm.create<HTML::HTMLCanvasElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::data)
return realm.create<HTML::HTMLDataElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::datalist)
return realm.create<HTML::HTMLDataListElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::details)
return realm.create<HTML::HTMLDetailsElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::dialog)
return realm.create<HTML::HTMLDialogElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::dir)
return realm.create<HTML::HTMLDirectoryElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::div)
return realm.create<HTML::HTMLDivElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::dl)
return realm.create<HTML::HTMLDListElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::embed)
return realm.create<HTML::HTMLEmbedElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::fieldset)
return realm.create<HTML::HTMLFieldSetElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::font)
return realm.create<HTML::HTMLFontElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::form)
return realm.create<HTML::HTMLFormElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::frame)
return realm.create<HTML::HTMLFrameElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::frameset)
return realm.create<HTML::HTMLFrameSetElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::head)
return realm.create<HTML::HTMLHeadElement>(document, move(qualified_name));
if (tag_name.is_one_of(HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6))
return realm.create<HTML::HTMLHeadingElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::hr)
return realm.create<HTML::HTMLHRElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::html)
return realm.create<HTML::HTMLHtmlElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::iframe)
return realm.create<HTML::HTMLIFrameElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::img)
return realm.create<HTML::HTMLImageElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::input)
return realm.create<HTML::HTMLInputElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::label)
return realm.create<HTML::HTMLLabelElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::legend)
return realm.create<HTML::HTMLLegendElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::li)
return realm.create<HTML::HTMLLIElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::link)
return realm.create<HTML::HTMLLinkElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::map)
return realm.create<HTML::HTMLMapElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::marquee)
return realm.create<HTML::HTMLMarqueeElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::menu)
return realm.create<HTML::HTMLMenuElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::meta)
return realm.create<HTML::HTMLMetaElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::meter)
return realm.create<HTML::HTMLMeterElement>(document, move(qualified_name));
if (tag_name.is_one_of(HTML::TagNames::ins, HTML::TagNames::del))
return realm.create<HTML::HTMLModElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::object)
return realm.create<HTML::HTMLObjectElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::ol)
return realm.create<HTML::HTMLOListElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::optgroup)
return realm.create<HTML::HTMLOptGroupElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::option)
return realm.create<HTML::HTMLOptionElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::output)
return realm.create<HTML::HTMLOutputElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::p)
return realm.create<HTML::HTMLParagraphElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::param)
return realm.create<HTML::HTMLParamElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::picture)
return realm.create<HTML::HTMLPictureElement>(document, move(qualified_name));
// NOTE: The obsolete elements "listing" and "xmp" are explicitly mapped to HTMLPreElement in the specification.
if (tag_name.is_one_of(HTML::TagNames::pre, HTML::TagNames::listing, HTML::TagNames::xmp))
return realm.create<HTML::HTMLPreElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::progress)
return realm.create<HTML::HTMLProgressElement>(document, move(qualified_name));
if (tag_name.is_one_of(HTML::TagNames::blockquote, HTML::TagNames::q))
return realm.create<HTML::HTMLQuoteElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::script)
return realm.create<HTML::HTMLScriptElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::selectedcontent)
return realm.create<HTML::HTMLSelectedContentElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::select)
return realm.create<HTML::HTMLSelectElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::slot)
return realm.create<HTML::HTMLSlotElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::source)
return realm.create<HTML::HTMLSourceElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::span)
return realm.create<HTML::HTMLSpanElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::style)
return realm.create<HTML::HTMLStyleElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::summary)
return realm.create<HTML::HTMLSummaryElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::caption)
return realm.create<HTML::HTMLTableCaptionElement>(document, move(qualified_name));
if (tag_name.is_one_of(Web::HTML::TagNames::td, Web::HTML::TagNames::th))
return realm.create<HTML::HTMLTableCellElement>(document, move(qualified_name));
if (tag_name.is_one_of(HTML::TagNames::colgroup, HTML::TagNames::col))
return realm.create<HTML::HTMLTableColElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::table)
return realm.create<HTML::HTMLTableElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::tr)
return realm.create<HTML::HTMLTableRowElement>(document, move(qualified_name));
if (tag_name.is_one_of(HTML::TagNames::tbody, HTML::TagNames::thead, HTML::TagNames::tfoot))
return realm.create<HTML::HTMLTableSectionElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::template_)
return realm.create<HTML::HTMLTemplateElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::textarea)
return realm.create<HTML::HTMLTextAreaElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::time)
return realm.create<HTML::HTMLTimeElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::title)
return realm.create<HTML::HTMLTitleElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::track)
return realm.create<HTML::HTMLTrackElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::ul)
return realm.create<HTML::HTMLUListElement>(document, move(qualified_name));
if (tag_name == HTML::TagNames::video)
return realm.create<HTML::HTMLVideoElement>(document, move(qualified_name));
if (tag_name.is_one_of(
HTML::TagNames::article, HTML::TagNames::search, HTML::TagNames::section, HTML::TagNames::nav, HTML::TagNames::aside, HTML::TagNames::hgroup, HTML::TagNames::header, HTML::TagNames::footer, HTML::TagNames::address, HTML::TagNames::dt, HTML::TagNames::dd, HTML::TagNames::figure, HTML::TagNames::figcaption, HTML::TagNames::main, HTML::TagNames::em, HTML::TagNames::strong, HTML::TagNames::small, HTML::TagNames::s, HTML::TagNames::cite, HTML::TagNames::dfn, HTML::TagNames::abbr, HTML::TagNames::ruby, HTML::TagNames::rt, HTML::TagNames::rp, HTML::TagNames::code, HTML::TagNames::var, HTML::TagNames::samp, HTML::TagNames::kbd, HTML::TagNames::sub, HTML::TagNames::sup, HTML::TagNames::i, HTML::TagNames::b, HTML::TagNames::u, HTML::TagNames::mark, HTML::TagNames::bdi, HTML::TagNames::bdo, HTML::TagNames::wbr, HTML::TagNames::noscript,
// Obsolete
HTML::TagNames::acronym, HTML::TagNames::basefont, HTML::TagNames::big, HTML::TagNames::center, HTML::TagNames::nobr, HTML::TagNames::noembed, HTML::TagNames::noframes, HTML::TagNames::plaintext, HTML::TagNames::rb, HTML::TagNames::rtc, HTML::TagNames::strike, HTML::TagNames::tt))
return realm.create<HTML::HTMLElement>(document, move(qualified_name));
if (HTML::is_valid_custom_element_name(qualified_name.local_name()))
return realm.create<HTML::HTMLElement>(document, move(qualified_name));
return realm.create<HTML::HTMLUnknownElement>(document, move(qualified_name));
}
static GC::Ref<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
{
auto const& local_name = qualified_name.local_name();
if (local_name == SVG::TagNames::svg)
return realm.create<SVG::SVGSVGElement>(document, move(qualified_name));
// FIXME: Support SVG's mixedCase tag names properly.
if (local_name.equals_ignoring_ascii_case(SVG::TagNames::clipPath))
return realm.create<SVG::SVGClipPathElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::circle)
return realm.create<SVG::SVGCircleElement>(document, move(qualified_name));
if (local_name.equals_ignoring_ascii_case(SVG::TagNames::defs))
return realm.create<SVG::SVGDefsElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::desc)
return realm.create<SVG::SVGDescElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::ellipse)
return realm.create<SVG::SVGEllipseElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feBlend)
return realm.create<SVG::SVGFEBlendElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feColorMatrix)
return realm.create<SVG::SVGFEColorMatrixElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feComponentTransfer)
return realm.create<SVG::SVGFEComponentTransferElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feComposite)
return realm.create<SVG::SVGFECompositeElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feDisplacementMap)
return realm.create<SVG::SVGFEDisplacementMapElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feDropShadow)
return realm.create<SVG::SVGFEDropShadowElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFlood)
return realm.create<SVG::SVGFEFloodElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFuncA)
return realm.create<SVG::SVGFEFuncAElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFuncB)
return realm.create<SVG::SVGFEFuncBElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFuncG)
return realm.create<SVG::SVGFEFuncGElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFuncR)
return realm.create<SVG::SVGFEFuncRElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feGaussianBlur)
return realm.create<SVG::SVGFEGaussianBlurElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feImage)
return realm.create<SVG::SVGFEImageElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feMerge)
return realm.create<SVG::SVGFEMergeElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feMergeNode)
return realm.create<SVG::SVGFEMergeNodeElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feMorphology)
return realm.create<SVG::SVGFEMorphologyElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feOffset)
return realm.create<SVG::SVGFEOffsetElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feTurbulence)
return realm.create<SVG::SVGFETurbulenceElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::filter)
return realm.create<SVG::SVGFilterElement>(document, move(qualified_name));
if (local_name.equals_ignoring_ascii_case(SVG::TagNames::foreignObject))
return realm.create<SVG::SVGForeignObjectElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::line)
return realm.create<SVG::SVGLineElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::linearGradient)
return realm.create<SVG::SVGLinearGradientElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::mask)
return realm.create<SVG::SVGMaskElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::metadata)
return realm.create<SVG::SVGMetadataElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::path)
return realm.create<SVG::SVGPathElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::pattern)
return realm.create<SVG::SVGPatternElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::polygon)
return realm.create<SVG::SVGPolygonElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::polyline)
return realm.create<SVG::SVGPolylineElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::radialGradient)
return realm.create<SVG::SVGRadialGradientElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::rect)
return realm.create<SVG::SVGRectElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::g)
return realm.create<SVG::SVGGElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::stop)
return realm.create<SVG::SVGStopElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::style)
return realm.create<SVG::SVGStyleElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::symbol)
return realm.create<SVG::SVGSymbolElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::text)
return realm.create<SVG::SVGTextElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::textPath)
return realm.create<SVG::SVGTextPathElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::title)
return realm.create<SVG::SVGTitleElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::tspan)
return realm.create<SVG::SVGTSpanElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::use)
return realm.create<SVG::SVGUseElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::script)
return realm.create<SVG::SVGScriptElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::view)
return realm.create<SVG::SVGViewElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::a)
return realm.create<SVG::SVGAElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::image)
return realm.create<SVG::SVGImageElement>(document, move(qualified_name));
// 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.create<SVG::SVGElement>(document, move(qualified_name));
}
static GC::Ref<MathML::MathMLElement> create_mathml_element(JS::Realm& realm, Document& document, QualifiedName qualified_name)
{
auto const& local_name = qualified_name.local_name();
if (local_name == MathML::TagNames::mi)
return realm.create<MathML::MathMLMiElement>(document, move(qualified_name));
if (local_name == MathML::TagNames::mspace)
return realm.create<MathML::MathMLMspaceElement>(document, move(qualified_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.
// https://w3c.github.io/mathml-core/#mathml-elements-and-attributes
// The term MathML element refers to any element in the MathML namespace.
return realm.create<MathML::MathMLElement>(document, move(qualified_name));
}
// https://dom.spec.whatwg.org/#concept-create-element
WebIDL::ExceptionOr<GC::Ref<Element>> create_element(Document& document, FlyString local_name, Optional<FlyString> namespace_, Optional<FlyString> prefix, Optional<String> is_value, bool synchronous_custom_elements_flag)
{
auto& realm = document.realm();
// 1. Let result be null.
// NOTE: We collapse this into just returning an element where necessary.
// 2. If registry is "default", then set registry to the result of looking up a custom element registry given document.
// FIXME: Implement this.
// 3. Let definition be the result of looking up a custom element definition given registry, document, namespace, localName, and is.
auto definition = document.lookup_custom_element_definition(namespace_, local_name, is_value);
// 4. If definition is non-null, and definitions name is not equal to its local name (i.e., definition represents a customized built-in element), then:
if (definition && definition->name() != definition->local_name()) {
// 1. Let interface be the element interface for localName and the HTML namespace.
// 2. Set result to the result of creating an element internal given document, interface, localName, the HTML
// namespace, prefix, "undefined", is, and registry.
auto element = create_element_internal(document, local_name, Namespace::HTML, prefix, CustomElementState::Undefined, is_value);
// 3. If the synchronous custom elements flag is set, then run this step while catching any exceptions:
if (synchronous_custom_elements_flag) {
// 1. Upgrade element using definition.
auto upgrade_result = element->upgrade_element(*definition);
// If this step threw an exception, then:
if (upgrade_result.is_throw_completion()) {
// 1. Report exception for definitions constructors corresponding JavaScript objects associated realms global object.
auto& window_or_worker = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(definition->constructor().callback));
window_or_worker.report_an_exception(upgrade_result.error_value());
// 2. Set results custom element state to "failed".
element->set_custom_element_state(CustomElementState::Failed);
}
}
// 4. Otherwise, enqueue a custom element upgrade reaction given result and definition.
else {
element->enqueue_a_custom_element_upgrade_reaction(*definition);
}
return element;
}
// 5. Otherwise, if definition is non-null, then:
if (definition) {
// 1. If synchronousCustomElements is true:
if (synchronous_custom_elements_flag) {
// 1. Let C be definitions constructor.
auto& constructor = definition->constructor();
// 2. Set the surrounding agents active custom element constructor map[C] to registry.
// FIXME: Implement this.
// 3. Run these steps while catching any exceptions:
auto synchronously_upgrade_custom_element = [&]() -> JS::ThrowCompletionOr<GC::Ref<HTML::HTMLElement>> {
// 1. Set result to the result of constructing C, with no arguments.
auto result = TRY(WebIDL::construct(constructor, {}));
// NOTE: IDL does not currently convert the object for us, so we will have to do it here.
auto element = result.as_if<HTML::HTMLElement>();
if (!element)
return JS::throw_completion(JS::TypeError::create(realm, "Custom element constructor must return an object that implements HTMLElement"_string));
// FIXME: 2. Assert: results custom element state and custom element definition are initialized.
// 3. Assert: results namespace is the HTML namespace.
// Note: IDL enforces that result is an HTMLElement object, which all use the HTML namespace.
VERIFY(element->namespace_uri() == Namespace::HTML);
// 4. If results attribute list is not empty, then throw a "NotSupportedError" DOMException.
if (element->has_attributes())
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element cannot have attributes"_utf16));
// 5. If result has children, then throw a "NotSupportedError" DOMException.
if (element->has_children())
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element cannot have children"_utf16));
// 6. If results parent is not null, then throw a "NotSupportedError" DOMException.
if (element->parent())
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element cannot have a parent"_utf16));
// 7. If results node document is not document, then throw a "NotSupportedError" DOMException.
if (&element->document() != &document)
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element must be in the same document that element creation was invoked in"_utf16));
// 8. If results local name is not equal to localName, then throw a "NotSupportedError" DOMException.
if (element->local_name() != local_name)
return JS::throw_completion(WebIDL::NotSupportedError::create(realm, "Synchronously created custom element must have the same local name that element creation was invoked with"_utf16));
// 9. Set results namespace prefix to prefix.
element->set_prefix(prefix);
// 10. Set results is value to null.
element->set_is_value(Optional<String> {});
// 11. Set results custom element registry to registry.
// FIXME: Implement this.
return *element;
};
auto result = synchronously_upgrade_custom_element();
// If any of these steps threw an exception, then:
if (result.is_throw_completion()) {
// 1. Report exception for definitions constructors corresponding JavaScript objects associated realms global object.
auto& window_or_worker = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(definition->constructor().callback));
window_or_worker.report_an_exception(result.error_value());
// 2. Set result to the result of creating an element internal given document, HTMLUnknownElement, localName, the HTML namespace, prefix, "failed", null, and registry.
// FIXME: Actually use create_element_internal here once it can take an interface.
GC::Ref<Element> element = realm.create<HTML::HTMLUnknownElement>(document, QualifiedName { local_name, prefix, Namespace::HTML });
element->set_custom_element_state(CustomElementState::Failed);
return element;
}
// 4. Remove the surrounding agents active custom element constructor map[C].
// FIXME: Implement this.
return result.release_value();
}
// 2. Otherwise:
// 1. Set result to the result of creating an element internal given document, HTMLElement, localName, the HTML namespace, prefix, "undefined", null, and registry.
// FIXME: Actually use create_element_internal here once it can take an interface.
auto element = realm.create<HTML::HTMLElement>(document, QualifiedName { local_name, prefix, Namespace::HTML });
element->set_custom_element_state(CustomElementState::Undefined);
// 2. Enqueue a custom element upgrade reaction given result and definition.
element->enqueue_a_custom_element_upgrade_reaction(*definition);
return element;
}
// 6. Otherwise:
// 1. Let interface be the element interface for localName and namespace.
// 2. Set result to the result of creating an element internal given document, interface, localName, namespace,
// prefix, "uncustomized", is, and registry.
auto element = create_element_internal(document, local_name, namespace_, prefix, CustomElementState::Uncustomized, is_value);
// 3. If namespace is the HTML namespace, and either localName is a valid custom element name or is is non-null,
// then set results custom element state to "undefined".
if (namespace_ == Namespace::HTML && (HTML::is_valid_custom_element_name(local_name) || is_value.has_value())) {
element->set_custom_element_state(CustomElementState::Undefined);
}
return element;
// 7. Return result.
// NOTE: See step 1.
}
// https://dom.spec.whatwg.org/#create-an-element-internal
// FIXME: This needs to take interface and registry, like the spec says.
GC::Ref<Element> create_element_internal(Document& document, FlyString local_name, Optional<FlyString> namespace_, Optional<FlyString> prefix, CustomElementState state, Optional<String> is_value)
{
auto& realm = document.realm();
// 1. Let element be a new element that implements interface, with namespace set to namespace, namespace prefix set
// to prefix, local name set to localName, custom element registry set to registry, custom element state set to
// state, custom element definition set to null, is value set to is, and node document set to document.
GC::Ptr<Element> element;
auto qualified_name = QualifiedName { local_name, prefix, namespace_ };
if (namespace_ == Namespace::HTML) {
element = create_html_element(realm, document, move(qualified_name));
} else if (namespace_ == Namespace::SVG) {
element = create_svg_element(realm, document, move(qualified_name));
} else if (namespace_ == Namespace::MathML) {
element = create_mathml_element(realm, document, move(qualified_name));
} else {
// https://dom.spec.whatwg.org/#concept-element-interface
// The element interface for any name and namespace is Element, unless stated otherwise.
element = realm.create<DOM::Element>(document, move(qualified_name));
}
element->set_custom_element_state(state);
element->set_is_value(is_value);
// 2. Assert: elements attribute list is empty.
VERIFY(!element->has_attributes());
// 3. Return element.
return GC::Ref { *element };
}
}