@@ -354,7 +354,9 @@ WebIDL::ExceptionOr<GC::Ref<Document>> Document::create_and_initialize(Type type
354
354
// current document readiness: "loading"
355
355
// about base URL: navigationParams's about base URL
356
356
// allow declarative shadow roots: true
357
- auto document = HTML::HTMLDocument::create (window->realm ());
357
+ // custom element registry: A new CustomElementRegistry object.
358
+ auto & realm = window->realm ();
359
+ auto document = HTML::HTMLDocument::create (realm);
358
360
document->m_type = type;
359
361
document->m_content_type = move (content_type);
360
362
document->set_origin (navigation_params.origin );
@@ -367,6 +369,7 @@ WebIDL::ExceptionOr<GC::Ref<Document>> Document::create_and_initialize(Type type
367
369
document->m_readiness = HTML::DocumentReadyState::Loading;
368
370
document->m_about_base_url = navigation_params.about_base_url ;
369
371
document->set_allow_declarative_shadow_roots (true );
372
+ document->set_custom_element_registry (realm.create <HTML::CustomElementRegistry>(realm));
370
373
371
374
document->m_window = window;
372
375
@@ -597,6 +600,7 @@ void Document::visit_edges(Cell::Visitor& visitor)
597
600
visitor.visit (m_session_storage_holder);
598
601
visitor.visit (m_render_blocking_elements);
599
602
visitor.visit (m_policy_container);
603
+ visitor.visit (m_custom_element_registry);
600
604
}
601
605
602
606
// https://w3c.github.io/selection-api/#dom-document-getselection
@@ -2084,23 +2088,16 @@ WebIDL::ExceptionOr<GC::Ref<Element>> Document::create_element(String const& loc
2084
2088
? local_name.to_ascii_lowercase ()
2085
2089
: local_name;
2086
2090
2087
- // 3. Let is be null .
2088
- Optional<String> is_value;
2091
+ // 3. Let registry and is be the result of flattening element creation options given options and this .
2092
+ auto [registry, is_value] = TRY ( flatten_element_creation_options (options)) ;
2089
2093
2090
- // 4. If options is a dictionary and options["is"] exists, then set is to it.
2091
- if (options.has <ElementCreationOptions>()) {
2092
- auto const & element_creation_options = options.get <ElementCreationOptions>();
2093
- if (element_creation_options.is .has_value ())
2094
- is_value = element_creation_options.is .value ();
2095
- }
2096
-
2097
- // 5. Let namespace be the HTML namespace, if this is an HTML document or this’s content type is "application/xhtml+xml"; otherwise null.
2094
+ // 4. Let namespace be the HTML namespace, if this is an HTML document or this’s content type is "application/xhtml+xml"; otherwise null.
2098
2095
Optional<FlyString> namespace_;
2099
2096
if (document_type () == Type::HTML || content_type () == " application/xhtml+xml" sv)
2100
2097
namespace_ = Namespace::HTML;
2101
2098
2102
- // 6 . Return the result of creating an element given this, localName, namespace, null, is, and with the synchronous custom elements flag set .
2103
- return TRY (DOM::create_element (*this , FlyString::from_utf8_without_validation (local_name_lower.bytes ()), move (namespace_), {}, move (is_value), true ));
2099
+ // 5 . Return the result of creating an element given this, localName, namespace, null, is, true, and registry .
2100
+ return TRY (DOM::create_element (*this , FlyString::from_utf8_without_validation (local_name_lower.bytes ()), move (namespace_), {}, move (is_value), true , registry ));
2104
2101
}
2105
2102
2106
2103
// https://dom.spec.whatwg.org/#dom-document-createelementns
@@ -2110,18 +2107,11 @@ WebIDL::ExceptionOr<GC::Ref<Element>> Document::create_element_ns(Optional<FlySt
2110
2107
// 1. Let namespace, prefix, and localName be the result of passing namespace and qualifiedName to validate and extract.
2111
2108
auto extracted_qualified_name = TRY (validate_and_extract (realm (), namespace_, qualified_name));
2112
2109
2113
- // 2. Let is be null .
2114
- Optional<String> is_value;
2110
+ // 2. Let registry and is be the result of flattening element creation options given options and this .
2111
+ auto [registry, is_value] = TRY ( flatten_element_creation_options (options)) ;
2115
2112
2116
- // 3. If options is a dictionary and options["is"] exists, then set is to it.
2117
- if (options.has <ElementCreationOptions>()) {
2118
- auto const & element_creation_options = options.get <ElementCreationOptions>();
2119
- if (element_creation_options.is .has_value ())
2120
- is_value = element_creation_options.is .value ();
2121
- }
2122
-
2123
- // 4. Return the result of creating an element given document, localName, namespace, prefix, is, and with the synchronous custom elements flag set.
2124
- return TRY (DOM::create_element (*this , extracted_qualified_name.local_name (), extracted_qualified_name.namespace_ (), extracted_qualified_name.prefix (), move (is_value), true ));
2113
+ // 3. Return the result of creating an element given document, localName, namespace, prefix, is, true, and registry.
2114
+ return TRY (DOM::create_element (*this , extracted_qualified_name.local_name (), extracted_qualified_name.namespace_ (), extracted_qualified_name.prefix (), move (is_value), true , registry));
2125
2115
}
2126
2116
2127
2117
GC::Ref<DocumentFragment> Document::create_document_fragment ()
@@ -2305,14 +2295,39 @@ Vector<GC::Root<HTML::HTMLScriptElement>> Document::take_scripts_to_execute_in_o
2305
2295
}
2306
2296
2307
2297
// https://dom.spec.whatwg.org/#dom-document-importnode
2308
- WebIDL::ExceptionOr<GC::Ref<Node>> Document::import_node (GC::Ref<Node> node, bool deep )
2298
+ WebIDL::ExceptionOr<GC::Ref<Node>> Document::import_node (GC::Ref<Node> node, Variant< bool , ImportNodeOptions> options )
2309
2299
{
2310
2300
// 1. If node is a document or shadow root, then throw a "NotSupportedError" DOMException.
2311
2301
if (is<Document>(*node) || is<ShadowRoot>(*node))
2312
2302
return WebIDL::NotSupportedError::create (realm (), " Cannot import a document or shadow root." _string);
2313
2303
2314
- // 2. Return a clone of node, with this and the clone children flag set if deep is true.
2315
- return node->clone_node (this , deep);
2304
+ // 2. Let subtree be false.
2305
+ bool subtree = false ;
2306
+
2307
+ // 3. Let registry be null.
2308
+ GC::Ptr <HTML::CustomElementRegistry> registry;
2309
+
2310
+ options.visit (
2311
+ // 4. If options is a boolean, then set subtree to options.
2312
+ [&subtree](bool const & value) {
2313
+ subtree = value;
2314
+ },
2315
+ // 5. Otherwise:
2316
+ [&subtree, ®istry](ImportNodeOptions const & options) {
2317
+ // 1. Set subtree to the negation of options["selfOnly"].
2318
+ subtree = !options.self_only ;
2319
+
2320
+ // 2. If options["customElementRegistry"] exists, then set registry to it.
2321
+ if (options.custom_element_registry )
2322
+ registry = options.custom_element_registry ;
2323
+ });
2324
+
2325
+ // 6. If registry is null, then set registry to the result of looking up a custom element registry given this.
2326
+ if (!registry)
2327
+ registry = HTML::look_up_a_custom_element_registry (*this );
2328
+
2329
+ // 7. Return the result of cloning a node given node with document set to this, subtree set to subtree, and fallbackRegistry set to registry.
2330
+ return node->clone_node (this , subtree, nullptr , registry);
2316
2331
}
2317
2332
2318
2333
// https://dom.spec.whatwg.org/#concept-node-adopt
@@ -3690,36 +3705,6 @@ void Document::set_window(HTML::Window& window)
3690
3705
m_window = &window;
3691
3706
}
3692
3707
3693
- // https://html.spec.whatwg.org/multipage/custom-elements.html#look-up-a-custom-element-definition
3694
- GC::Ptr <HTML::CustomElementDefinition> Document::lookup_custom_element_definition (Optional<FlyString> const & namespace_, FlyString const & local_name, Optional<String> const & is) const
3695
- {
3696
- // 1. If namespace is not the HTML namespace, then return null.
3697
- if (namespace_ != Namespace::HTML)
3698
- return nullptr ;
3699
-
3700
- // 2. If document's browsing context is null, then return null.
3701
- if (!browsing_context ())
3702
- return nullptr ;
3703
-
3704
- // 3. Let registry be document's relevant global object's custom element registry.
3705
- auto registry = as<HTML::Window>(relevant_global_object (*this )).custom_elements ();
3706
-
3707
- // 4. If registry's custom element definition set contains an item with name and local name both equal to localName, then return that item.
3708
- auto converted_local_name = local_name.to_string ();
3709
- auto maybe_definition = registry->get_definition_with_name_and_local_name (converted_local_name, converted_local_name);
3710
- if (maybe_definition)
3711
- return maybe_definition;
3712
-
3713
- // 5. If registry's custom element definition set contains an item with name equal to is and local name equal to localName, then return that item.
3714
- // 6. Return null.
3715
-
3716
- // NOTE: If `is` has no value, it can never match as custom element definitions always have a name and localName (i.e. not stored as Optional<String>)
3717
- if (!is.has_value ())
3718
- return nullptr ;
3719
-
3720
- return registry->get_definition_with_name_and_local_name (is.value (), converted_local_name);
3721
- }
3722
-
3723
3708
CSS::StyleSheetList& Document::style_sheets ()
3724
3709
{
3725
3710
if (!m_style_sheets)
@@ -6440,6 +6425,38 @@ void Document::run_csp_initialization() const
6440
6425
}
6441
6426
}
6442
6427
6428
+ // https://dom.spec.whatwg.org/#flatten-element-creation-options
6429
+ WebIDL::ExceptionOr<Document::RegistryAndIs> Document::flatten_element_creation_options (Variant<String, ElementCreationOptions> options) const
6430
+ {
6431
+ // 1. Let registry be null.
6432
+ GC::Ptr <HTML::CustomElementRegistry> registry;
6433
+
6434
+ // 2. Let is be null.
6435
+ Optional<String> is;
6436
+
6437
+ // 3. If options is a dictionary:
6438
+ if (auto * dictionary = options.get_pointer <ElementCreationOptions>()) {
6439
+ // 1. If options["customElementRegistry"] exists, then set registry to it.
6440
+ if (dictionary->custom_element_registry )
6441
+ registry = dictionary->custom_element_registry ;
6442
+
6443
+ // 2. If options["is"] exists, then set is to it.
6444
+ if (dictionary->is .has_value ())
6445
+ is = dictionary->is .value ();
6446
+
6447
+ // 3. If registry is non-null and is is non-null, then throw a "NotSupportedError" DOMException.
6448
+ if (registry && is.has_value ())
6449
+ return WebIDL::NotSupportedError::create (realm (), " Cannot provide both 'is' and 'customElementRegistry' in ElementCreationOptions." _string);
6450
+ }
6451
+
6452
+ // 4. If registry is null, then set registry to the result of looking up a custom element registry given document.
6453
+ if (!registry)
6454
+ registry = HTML::look_up_a_custom_element_registry (*this );
6455
+
6456
+ // 5. Return registry and is.
6457
+ return RegistryAndIs { registry, move (is) };
6458
+ }
6459
+
6443
6460
WebIDL::CallbackType* Document::onreadystatechange ()
6444
6461
{
6445
6462
return event_handler_attribute (HTML::EventNames::readystatechange);
@@ -6460,6 +6477,51 @@ void Document::set_onvisibilitychange(WebIDL::CallbackType* value)
6460
6477
set_event_handler_attribute (HTML::EventNames::visibilitychange, value);
6461
6478
}
6462
6479
6480
+ // https://dom.spec.whatwg.org/#dom-documentorshadowroot-customelementregistry
6481
+ GC::Ptr <HTML::CustomElementRegistry> Document::custom_element_registry () const
6482
+ {
6483
+ // 1. If this is a document, then return this’s custom element registry.
6484
+ // NB: Always true.
6485
+ return m_custom_element_registry;
6486
+
6487
+ // 2. Assert: this is a ShadowRoot node.
6488
+ // 3. Return this’s custom element registry.
6489
+ }
6490
+
6491
+ // https://html.spec.whatwg.org/multipage/custom-elements.html#upgrade-particular-elements-within-a-document
6492
+ void Document::upgrade_particular_elements (GC::Ref<HTML::CustomElementDefinition> definition, String local_name, Optional<String> maybe_name)
6493
+ {
6494
+ // To upgrade particular elements within a document given a Document object document, a string localName, and
6495
+ // optionally a string name (default localName):
6496
+ auto name = maybe_name.value_or (local_name);
6497
+
6498
+ // FIXME: We pass in the definition but the spec doesn't. Spec issue: https://github.com/whatwg/html/issues/11222
6499
+
6500
+ // 1. Let upgradeCandidates be all elements that are shadow-including descendants of document, whose namespace is
6501
+ // the HTML namespace and whose local name is localName, in shadow-including tree order.
6502
+ // Additionally, if name is not localName, only include elements whose is value is equal to name.
6503
+ Vector<GC::Root<Element>> upgrade_candidates;
6504
+ for_each_shadow_including_descendant ([&](Node& inclusive_descendant) {
6505
+ auto * element = as_if<Element>(inclusive_descendant);
6506
+ if (!element)
6507
+ return TraversalDecision::Continue;
6508
+
6509
+ if (element->namespace_uri () != Namespace::HTML || element->local_name () != local_name)
6510
+ return TraversalDecision::Continue;
6511
+
6512
+ if (name != local_name && element->is_value () != name)
6513
+ return TraversalDecision::Continue;
6514
+
6515
+ upgrade_candidates.append (GC::make_root (element));
6516
+ return TraversalDecision::Continue;
6517
+ });
6518
+
6519
+ // 2. For each element element of upgradeCandidates:
6520
+ // enqueue a custom element upgrade reaction given element and definition.
6521
+ for (auto & element : upgrade_candidates)
6522
+ element->enqueue_a_custom_element_upgrade_reaction (definition);
6523
+ }
6524
+
6463
6525
ElementByIdMap& Document::element_by_id () const
6464
6526
{
6465
6527
if (!m_element_by_id)
0 commit comments