Skip to main content

script/dom/element/
create.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use html5ever::{LocalName, Prefix, QualName, local_name, ns};
6use js::context::JSContext;
7use js::rust::HandleObject;
8
9use crate::dom::bindings::error::{report_pending_exception, throw_dom_exception};
10use crate::dom::bindings::inheritance::Castable;
11use crate::dom::bindings::reflector::DomGlobal;
12use crate::dom::bindings::root::DomRoot;
13use crate::dom::customelementregistry::{
14    CustomElementRegistry, CustomElementState, is_valid_custom_element_name, upgrade_element,
15};
16use crate::dom::document::Document;
17use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::html::form_controls::htmlinputelement::HTMLInputElement;
20use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
21use crate::dom::html::htmlareaelement::HTMLAreaElement;
22use crate::dom::html::htmlaudioelement::HTMLAudioElement;
23use crate::dom::html::htmlbaseelement::HTMLBaseElement;
24use crate::dom::html::htmlbodyelement::HTMLBodyElement;
25use crate::dom::html::htmlbrelement::HTMLBRElement;
26use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
27use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
28use crate::dom::html::htmldataelement::HTMLDataElement;
29use crate::dom::html::htmldatalistelement::HTMLDataListElement;
30use crate::dom::html::htmldetailselement::HTMLDetailsElement;
31use crate::dom::html::htmldialogelement::HTMLDialogElement;
32use crate::dom::html::htmldirectoryelement::HTMLDirectoryElement;
33use crate::dom::html::htmldivelement::HTMLDivElement;
34use crate::dom::html::htmldlistelement::HTMLDListElement;
35use crate::dom::html::htmlelement::HTMLElement;
36use crate::dom::html::htmlembedelement::HTMLEmbedElement;
37use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
38use crate::dom::html::htmlfontelement::HTMLFontElement;
39use crate::dom::html::htmlformelement::HTMLFormElement;
40use crate::dom::html::htmlframeelement::HTMLFrameElement;
41use crate::dom::html::htmlframesetelement::HTMLFrameSetElement;
42use crate::dom::html::htmlheadelement::HTMLHeadElement;
43use crate::dom::html::htmlheadingelement::{HTMLHeadingElement, HeadingLevel};
44use crate::dom::html::htmlhrelement::HTMLHRElement;
45use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
46use crate::dom::html::htmliframeelement::HTMLIFrameElement;
47use crate::dom::html::htmlimageelement::HTMLImageElement;
48use crate::dom::html::htmllabelelement::HTMLLabelElement;
49use crate::dom::html::htmllegendelement::HTMLLegendElement;
50use crate::dom::html::htmllielement::HTMLLIElement;
51use crate::dom::html::htmllinkelement::HTMLLinkElement;
52use crate::dom::html::htmlmapelement::HTMLMapElement;
53use crate::dom::html::htmlmenuelement::HTMLMenuElement;
54use crate::dom::html::htmlmetaelement::HTMLMetaElement;
55use crate::dom::html::htmlmeterelement::HTMLMeterElement;
56use crate::dom::html::htmlmodelement::HTMLModElement;
57use crate::dom::html::htmlobjectelement::HTMLObjectElement;
58use crate::dom::html::htmlolistelement::HTMLOListElement;
59use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
60use crate::dom::html::htmloptionelement::HTMLOptionElement;
61use crate::dom::html::htmloutputelement::HTMLOutputElement;
62use crate::dom::html::htmlparagraphelement::HTMLParagraphElement;
63use crate::dom::html::htmlparamelement::HTMLParamElement;
64use crate::dom::html::htmlpictureelement::HTMLPictureElement;
65use crate::dom::html::htmlpreelement::HTMLPreElement;
66use crate::dom::html::htmlprogresselement::HTMLProgressElement;
67use crate::dom::html::htmlquoteelement::HTMLQuoteElement;
68use crate::dom::html::htmlscriptelement::HTMLScriptElement;
69use crate::dom::html::htmlselectelement::HTMLSelectElement;
70use crate::dom::html::htmlslotelement::HTMLSlotElement;
71use crate::dom::html::htmlsourceelement::HTMLSourceElement;
72use crate::dom::html::htmlspanelement::HTMLSpanElement;
73use crate::dom::html::htmlstyleelement::HTMLStyleElement;
74use crate::dom::html::htmltablecaptionelement::HTMLTableCaptionElement;
75use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
76use crate::dom::html::htmltablecolelement::HTMLTableColElement;
77use crate::dom::html::htmltableelement::HTMLTableElement;
78use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
79use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
80use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
81use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
82use crate::dom::html::htmltimeelement::HTMLTimeElement;
83use crate::dom::html::htmltitleelement::HTMLTitleElement;
84use crate::dom::html::htmltrackelement::HTMLTrackElement;
85use crate::dom::html::htmlulistelement::HTMLUListElement;
86use crate::dom::html::htmlunknownelement::HTMLUnknownElement;
87use crate::dom::html::htmlvideoelement::HTMLVideoElement;
88use crate::dom::htmlmarqueeelement::HTMLMarqueeElement;
89use crate::dom::svg::svgaelement::SVGAElement;
90use crate::dom::svg::svgcircleelement::SVGCircleElement;
91use crate::dom::svg::svgdefselement::SVGDefsElement;
92use crate::dom::svg::svgelement::SVGElement;
93use crate::dom::svg::svgellipseelement::SVGEllipseElement;
94use crate::dom::svg::svggelement::SVGGElement;
95use crate::dom::svg::svgimageelement::SVGImageElement;
96use crate::dom::svg::svglineargradientelement::SVGLinearGradientElement;
97use crate::dom::svg::svglineelement::SVGLineElement;
98use crate::dom::svg::svgpathelement::SVGPathElement;
99use crate::dom::svg::svgpatternelement::SVGPatternElement;
100use crate::dom::svg::svgpolygonelement::SVGPolygonElement;
101use crate::dom::svg::svgpolylineelement::SVGPolylineElement;
102use crate::dom::svg::svgradialgradientelement::SVGRadialGradientElement;
103use crate::dom::svg::svgrectelement::SVGRectElement;
104use crate::dom::svg::svgstopelement::SVGStopElement;
105use crate::dom::svg::svgsvgelement::SVGSVGElement;
106use crate::dom::svg::svgsymbolelement::SVGSymbolElement;
107use crate::dom::svg::svgtextelement::SVGTextElement;
108use crate::dom::svg::svgtspanelement::SVGTSpanElement;
109use crate::dom::svg::svguseelement::SVGUseElement;
110use crate::event_loop::script_thread::ScriptThread;
111use crate::realms::enter_auto_realm;
112
113fn create_svg_element(
114    cx: &mut JSContext,
115    name: QualName,
116    prefix: Option<Prefix>,
117    document: &Document,
118    proto: Option<HandleObject>,
119) -> DomRoot<Element> {
120    assert_eq!(name.ns, ns!(svg));
121
122    macro_rules! make(
123        ($ctor:ident) => ({
124            let obj = $ctor::new(cx, name.local, prefix, document, proto);
125            DomRoot::upcast(obj)
126        });
127    );
128
129    match name.local {
130        local_name!("a") => make!(SVGAElement),
131        local_name!("circle") => make!(SVGCircleElement),
132        local_name!("defs") => make!(SVGDefsElement),
133        local_name!("ellipse") => make!(SVGEllipseElement),
134        local_name!("g") => make!(SVGGElement),
135        local_name!("image") => make!(SVGImageElement),
136        local_name!("line") => make!(SVGLineElement),
137        local_name!("linearGradient") => make!(SVGLinearGradientElement),
138        local_name!("path") => make!(SVGPathElement),
139        local_name!("pattern") => make!(SVGPatternElement),
140        local_name!("polygon") => make!(SVGPolygonElement),
141        local_name!("polyline") => make!(SVGPolylineElement),
142        local_name!("radialGradient") => make!(SVGRadialGradientElement),
143        local_name!("stop") => make!(SVGStopElement),
144        local_name!("rect") => make!(SVGRectElement),
145        local_name!("svg") => make!(SVGSVGElement),
146        local_name!("symbol") => make!(SVGSymbolElement),
147        local_name!("text") => make!(SVGTextElement),
148        local_name!("tspan") => make!(SVGTSpanElement),
149        local_name!("use") => make!(SVGUseElement),
150        _ => make!(SVGElement),
151    }
152}
153
154/// <https://dom.spec.whatwg.org/#concept-create-element>
155#[expect(clippy::too_many_arguments)]
156fn create_html_element(
157    cx: &mut JSContext,
158    name: QualName,
159    prefix: Option<Prefix>,
160    is: Option<LocalName>,
161    document: &Document,
162    creator: ElementCreator,
163    mode: CustomElementCreationMode,
164    proto: Option<HandleObject>,
165) -> DomRoot<Element> {
166    assert_eq!(name.ns, ns!(html));
167
168    // Step 2. If registry is "default", then set registry
169    // to the result of looking up a custom element registry given document.
170    // TODO: We don't pass in any other value than "default" atm
171    let registry = CustomElementRegistry::lookup_a_custom_element_registry(document.upcast());
172
173    // Step 3. Let definition be the result of looking up a custom element
174    // definition given registry, namespace, localName, and is.
175    let definition = CustomElementRegistry::lookup_custom_element_definition(
176        registry.as_deref(),
177        &name.ns,
178        &name.local,
179        is.as_ref(),
180    );
181
182    // Step 4. If definition is non-null...
183    if let Some(definition) = definition {
184        // ...and definition’s name is not equal to its local name
185        // (i.e., definition represents a customized built-in element):
186        if !definition.is_autonomous() {
187            // Step 4.1. Let interface be the element interface for localName and the HTML namespace.
188            // Step 4.2. Set result to the result of creating an element internal given document,
189            // interface, localName, the HTML namespace, prefix, "undefined", is, and registry.
190            let element = create_native_html_element(cx, name, prefix, document, creator, proto);
191            element.set_is(definition.name.clone());
192            element.set_custom_element_state(CustomElementState::Undefined, cx.no_gc());
193            element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
194
195            match mode {
196                // Step 4.3. If synchronousCustomElements is true, then run this step while catching any exceptions:
197                CustomElementCreationMode::Synchronous => {
198                    // Step 4.3.1. Upgrade result using definition.
199                    upgrade_element(cx, definition, &element);
200                    // TODO: "If this step threw an exception exception:" steps.
201                },
202                // Step 4.4. Otherwise, enqueue a custom element upgrade reaction given result and definition.
203                CustomElementCreationMode::Asynchronous => {
204                    ScriptThread::enqueue_upgrade_reaction(cx, &element, definition)
205                },
206            }
207            return element;
208        } else {
209            // Step 5. Otherwise, if definition is non-null:
210            match mode {
211                // Step 5.1. If synchronousCustomElements is true, then run these
212                // steps while catching any exceptions:
213                CustomElementCreationMode::Synchronous => {
214                    let local_name = name.local;
215                    // TODO(jdm) Pass proto to create_element?
216                    // Steps 4.1.1-4.1.11
217                    return match definition.create_element(
218                        cx,
219                        document,
220                        prefix.clone(),
221                        registry.as_deref(),
222                    ) {
223                        Ok(element) => {
224                            element.set_custom_element_definition(definition.clone(), cx.no_gc());
225                            element
226                        },
227                        Err(error) => {
228                            // If any of these steps threw an exception exception:
229                            let global =
230                                GlobalScope::current().unwrap_or_else(|| document.global());
231
232                            let mut realm = enter_auto_realm(cx, &*global);
233                            let cx = &mut realm.current_realm();
234
235                            // Substep 1. Report exception for definition’s constructor’s corresponding
236                            // JavaScript object’s associated realm’s global object.
237                            throw_dom_exception(cx, &global, error);
238                            report_pending_exception(cx);
239
240                            // Substep 2. Set result to the result of creating an element internal given document,
241                            // HTMLUnknownElement, localName, the HTML namespace, prefix, "failed", null, and registry.
242                            let element = DomRoot::upcast::<Element>(HTMLUnknownElement::new(
243                                cx, local_name, prefix, document, proto,
244                            ));
245                            element
246                                .set_custom_element_state(CustomElementState::Failed, cx.no_gc());
247                            element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
248                            element
249                        },
250                    };
251                },
252                // Step 4.2. Otherwise:
253                CustomElementCreationMode::Asynchronous => {
254                    // Step 4.2.1. Set result to a new element that implements the HTMLElement interface,
255                    // with no attributes, namespace set to the HTML namespace, namespace prefix set to
256                    // prefix, local name set to localName, custom element state set to "undefined",
257                    // custom element definition set to null, is value set to null, and node document
258                    // set to document.
259                    let result = DomRoot::upcast::<Element>(HTMLElement::new(
260                        cx, name.local, prefix, document, proto,
261                    ));
262                    result.set_custom_element_state(CustomElementState::Undefined, cx.no_gc());
263                    result.set_custom_element_registry(registry.as_deref(), cx.no_gc());
264                    // Step 4.2.2. Enqueue a custom element upgrade reaction given result and definition.
265                    ScriptThread::enqueue_upgrade_reaction(cx, &result, definition);
266                    return result;
267                },
268            }
269        }
270    }
271
272    // Step 5. Otherwise:
273    // Step 5.1. Let interface be the element interface for localName and namespace.
274    // Step 5.2. Set result to a new element that implements interface, with no attributes,
275    // namespace set to namespace, namespace prefix set to prefix, local name set to localName,
276    // custom element state set to "uncustomized", custom element definition set to null,
277    // is value set to is, and node document set to document.
278    let result = create_native_html_element(cx, name.clone(), prefix, document, creator, proto);
279    // Step 5.3. If namespace is the HTML namespace, and either localName is a valid custom element name or
280    // is is non-null, then set result’s custom element state to "undefined".
281    match is {
282        Some(is) => {
283            result.set_is(is);
284            result.set_custom_element_state(CustomElementState::Undefined, cx.no_gc());
285            result.set_custom_element_registry(registry.as_deref(), cx.no_gc());
286        },
287        None => {
288            if is_valid_custom_element_name(&name.local) {
289                result.set_custom_element_state(CustomElementState::Undefined, cx.no_gc());
290                result.set_custom_element_registry(registry.as_deref(), cx.no_gc());
291            } else {
292                // Note: This is a performance optimization. See the doc comment of the method for
293                // more information.
294                result.set_initial_custom_element_state_to_uncustomized();
295            }
296        },
297    };
298
299    // Step 6. Return result.
300    result
301}
302
303pub(crate) fn create_native_html_element(
304    cx: &mut JSContext,
305    name: QualName,
306    prefix: Option<Prefix>,
307    document: &Document,
308    creator: ElementCreator,
309    proto: Option<HandleObject>,
310) -> DomRoot<Element> {
311    assert_eq!(name.ns, ns!(html));
312
313    macro_rules! make(
314        ($ctor:ident) => ({
315            let obj = $ctor::new(cx, name.local, prefix, document, proto);
316            DomRoot::upcast(obj)
317        });
318        ($ctor:ident, $($arg:expr),+) => ({
319            let obj = $ctor::new(cx, name.local, prefix, document, proto, $($arg),+);
320            DomRoot::upcast(obj)
321        })
322    );
323
324    // This is a big match, and the IDs for inline-interned atoms are not very structured.
325    // Perhaps we should build a perfect hash from those IDs instead.
326    // https://html.spec.whatwg.org/multipage/#elements-in-the-dom
327    match name.local {
328        local_name!("a") => make!(HTMLAnchorElement),
329        local_name!("abbr") => make!(HTMLElement),
330        local_name!("acronym") => make!(HTMLElement),
331        local_name!("address") => make!(HTMLElement),
332        local_name!("area") => make!(HTMLAreaElement),
333        local_name!("article") => make!(HTMLElement),
334        local_name!("aside") => make!(HTMLElement),
335        local_name!("audio") => make!(HTMLAudioElement),
336        local_name!("b") => make!(HTMLElement),
337        local_name!("base") => make!(HTMLBaseElement),
338        local_name!("bdi") => make!(HTMLElement),
339        local_name!("bdo") => make!(HTMLElement),
340        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:bgsound
341        local_name!("bgsound") => make!(HTMLUnknownElement),
342        local_name!("big") => make!(HTMLElement),
343        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:blink
344        local_name!("blink") => make!(HTMLUnknownElement),
345        // https://html.spec.whatwg.org/multipage/#the-blockquote-element
346        local_name!("blockquote") => make!(HTMLQuoteElement),
347        local_name!("body") => make!(HTMLBodyElement),
348        local_name!("br") => make!(HTMLBRElement),
349        local_name!("button") => make!(HTMLButtonElement),
350        local_name!("canvas") => make!(HTMLCanvasElement),
351        local_name!("caption") => make!(HTMLTableCaptionElement),
352        local_name!("center") => make!(HTMLElement),
353        local_name!("cite") => make!(HTMLElement),
354        local_name!("code") => make!(HTMLElement),
355        local_name!("col") => make!(HTMLTableColElement),
356        local_name!("colgroup") => make!(HTMLTableColElement),
357        local_name!("data") => make!(HTMLDataElement),
358        local_name!("datalist") => make!(HTMLDataListElement),
359        local_name!("dd") => make!(HTMLElement),
360        local_name!("del") => make!(HTMLModElement),
361        local_name!("details") => make!(HTMLDetailsElement),
362        local_name!("dfn") => make!(HTMLElement),
363        local_name!("dialog") => make!(HTMLDialogElement),
364        local_name!("dir") => make!(HTMLDirectoryElement),
365        local_name!("div") => make!(HTMLDivElement),
366        local_name!("dl") => make!(HTMLDListElement),
367        local_name!("dt") => make!(HTMLElement),
368        local_name!("em") => make!(HTMLElement),
369        local_name!("embed") => make!(HTMLEmbedElement),
370        local_name!("fieldset") => make!(HTMLFieldSetElement),
371        local_name!("figcaption") => make!(HTMLElement),
372        local_name!("figure") => make!(HTMLElement),
373        local_name!("font") => make!(HTMLFontElement),
374        local_name!("footer") => make!(HTMLElement),
375        local_name!("form") => make!(HTMLFormElement),
376        local_name!("frame") => make!(HTMLFrameElement),
377        local_name!("frameset") => make!(HTMLFrameSetElement),
378        local_name!("h1") => make!(HTMLHeadingElement, HeadingLevel::Heading1),
379        local_name!("h2") => make!(HTMLHeadingElement, HeadingLevel::Heading2),
380        local_name!("h3") => make!(HTMLHeadingElement, HeadingLevel::Heading3),
381        local_name!("h4") => make!(HTMLHeadingElement, HeadingLevel::Heading4),
382        local_name!("h5") => make!(HTMLHeadingElement, HeadingLevel::Heading5),
383        local_name!("h6") => make!(HTMLHeadingElement, HeadingLevel::Heading6),
384        local_name!("head") => make!(HTMLHeadElement),
385        local_name!("header") => make!(HTMLElement),
386        local_name!("hgroup") => make!(HTMLElement),
387        local_name!("hr") => make!(HTMLHRElement),
388        local_name!("html") => make!(HTMLHtmlElement),
389        local_name!("i") => make!(HTMLElement),
390        local_name!("iframe") => make!(HTMLIFrameElement),
391        local_name!("img") => make!(HTMLImageElement, creator),
392        local_name!("input") => make!(HTMLInputElement),
393        local_name!("ins") => make!(HTMLModElement),
394        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:isindex-2
395        local_name!("isindex") => make!(HTMLUnknownElement),
396        local_name!("kbd") => make!(HTMLElement),
397        // https://html.spec.whatwg.org/multipage/#keygen
398        local_name!("keygen") => make!(HTMLUnknownElement),
399        local_name!("label") => make!(HTMLLabelElement),
400        local_name!("legend") => make!(HTMLLegendElement),
401        local_name!("li") => make!(HTMLLIElement),
402        local_name!("link") => make!(HTMLLinkElement, creator),
403        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:listing
404        local_name!("listing") => make!(HTMLPreElement),
405        local_name!("main") => make!(HTMLElement),
406        local_name!("map") => make!(HTMLMapElement),
407        local_name!("mark") => make!(HTMLElement),
408        local_name!("marquee") => make!(HTMLMarqueeElement),
409        local_name!("menu") => make!(HTMLMenuElement),
410        local_name!("meta") => make!(HTMLMetaElement),
411        local_name!("meter") => make!(HTMLMeterElement),
412        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:multicol
413        local_name!("multicol") => make!(HTMLUnknownElement),
414        local_name!("nav") => make!(HTMLElement),
415        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:nextid
416        local_name!("nextid") => make!(HTMLUnknownElement),
417        local_name!("nobr") => make!(HTMLElement),
418        local_name!("noframes") => make!(HTMLElement),
419        local_name!("noscript") => make!(HTMLElement),
420        local_name!("object") => make!(HTMLObjectElement),
421        local_name!("ol") => make!(HTMLOListElement),
422        local_name!("optgroup") => make!(HTMLOptGroupElement),
423        local_name!("option") => make!(HTMLOptionElement),
424        local_name!("output") => make!(HTMLOutputElement),
425        local_name!("p") => make!(HTMLParagraphElement),
426        local_name!("param") => make!(HTMLParamElement),
427        local_name!("picture") => make!(HTMLPictureElement),
428        local_name!("plaintext") => make!(HTMLPreElement),
429        local_name!("pre") => make!(HTMLPreElement),
430        local_name!("progress") => make!(HTMLProgressElement),
431        local_name!("q") => make!(HTMLQuoteElement),
432        local_name!("rp") => make!(HTMLElement),
433        local_name!("rt") => make!(HTMLElement),
434        local_name!("ruby") => make!(HTMLElement),
435        local_name!("s") => make!(HTMLElement),
436        local_name!("samp") => make!(HTMLElement),
437        local_name!("script") => make!(HTMLScriptElement, creator),
438        local_name!("section") => make!(HTMLElement),
439        local_name!("select") => make!(HTMLSelectElement),
440        local_name!("slot") => make!(HTMLSlotElement),
441        local_name!("small") => make!(HTMLElement),
442        local_name!("source") => make!(HTMLSourceElement),
443        // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:spacer
444        local_name!("spacer") => make!(HTMLUnknownElement),
445        local_name!("span") => make!(HTMLSpanElement),
446        local_name!("strike") => make!(HTMLElement),
447        local_name!("strong") => make!(HTMLElement),
448        local_name!("style") => make!(HTMLStyleElement, creator),
449        local_name!("sub") => make!(HTMLElement),
450        local_name!("summary") => make!(HTMLElement),
451        local_name!("sup") => make!(HTMLElement),
452        local_name!("table") => make!(HTMLTableElement),
453        local_name!("tbody") => make!(HTMLTableSectionElement),
454        local_name!("td") => make!(HTMLTableCellElement),
455        local_name!("template") => make!(HTMLTemplateElement),
456        local_name!("textarea") => make!(HTMLTextAreaElement),
457        // https://html.spec.whatwg.org/multipage/#the-tfoot-element:concept-element-dom
458        local_name!("tfoot") => make!(HTMLTableSectionElement),
459        local_name!("th") => make!(HTMLTableCellElement),
460        // https://html.spec.whatwg.org/multipage/#the-thead-element:concept-element-dom
461        local_name!("thead") => make!(HTMLTableSectionElement),
462        local_name!("time") => make!(HTMLTimeElement),
463        local_name!("title") => make!(HTMLTitleElement, creator),
464        local_name!("tr") => make!(HTMLTableRowElement),
465        local_name!("tt") => make!(HTMLElement),
466        local_name!("track") => make!(HTMLTrackElement),
467        local_name!("u") => make!(HTMLElement),
468        local_name!("ul") => make!(HTMLUListElement),
469        local_name!("var") => make!(HTMLElement),
470        local_name!("video") => make!(HTMLVideoElement),
471        local_name!("wbr") => make!(HTMLElement),
472        local_name!("xmp") => make!(HTMLPreElement),
473        _ if is_valid_custom_element_name(&name.local) => make!(HTMLElement),
474        _ => make!(HTMLUnknownElement),
475    }
476}
477
478pub(crate) fn create_element(
479    cx: &mut JSContext,
480    name: QualName,
481    is: Option<LocalName>,
482    document: &Document,
483    creator: ElementCreator,
484    mode: CustomElementCreationMode,
485    proto: Option<HandleObject>,
486) -> DomRoot<Element> {
487    let prefix = name.prefix.clone();
488    match name.ns {
489        ns!(html) => create_html_element(cx, name, prefix, is, document, creator, mode, proto),
490        ns!(svg) => create_svg_element(cx, name, prefix, document, proto),
491        _ => Element::new(cx, name.local, name.ns, prefix, document, proto),
492    }
493}