From d796c13dd1aba550330c529a608ca6cf98a32f7d Mon Sep 17 00:00:00 2001 From: sideshowbarker Date: Tue, 10 Mar 2026 17:18:52 +0900 Subject: [PATCH] LibWeb: Make DOM::validate_and_extract() preserve entire local name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change local-name computation in DOM::validate_and_extract() to preserve everything after the first colon in a qualified name — matching a recent spec change made in https://github.com/whatwg/dom/pull/1455 (and replacing a previous spec requirement to use the “strictly split” algorithm, which resulted in throwing away any other part of the name after any second colon the name might have). For the qualified name “f:o:o”, this change now gives localName=“o:o”. Otherwise, without this change, it’d instead give localName=“o”. --- Libraries/LibWeb/DOM/Element.cpp | 16 ++++++++-------- .../nodes/DOMImplementation-createDocument.txt | 14 +++++++++----- .../dom/nodes/Document-createElementNS.txt | 18 +++++++++--------- .../DOMImplementation-createDocument.html | 2 +- .../dom/nodes/Document-createElementNS.html | 8 +++----- .../dom/nodes/Document-createElementNS.js | 6 +++--- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 79d02af5820b1..3cc81c50748e1 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -463,16 +463,16 @@ WebIDL::ExceptionOr validate_and_extract(JS::Realm& realm, Option auto local_name = qualified_name; // 4. If qualifiedName contains a U+003A (:): - auto split_result = qualified_name.bytes_as_string_view().split_view(':', SplitBehavior::KeepEmpty); - if (split_result.size() > 1) { - // 1. Let splitResult be the result of running strictly split given qualifiedName and U+003A (:). - // 2. Set prefix to splitResult[0]. - prefix = MUST(FlyString::from_utf8(split_result[0])); + auto qualified_name_view = qualified_name.bytes_as_string_view(); + auto colon_position = qualified_name_view.find(':'); + if (colon_position.has_value()) { + // 1. Set prefix to the part of qualifiedName before the first U+003A (:). + prefix = MUST(FlyString::from_utf8(qualified_name_view.substring_view(0, *colon_position))); - // 3. Set localName to splitResult[1]. - local_name = MUST(FlyString::from_utf8(split_result[1])); + // 2. Set localName to the part of qualifiedName after the first U+003A (:). + local_name = MUST(FlyString::from_utf8(qualified_name_view.substring_view(*colon_position + 1))); - // 4. If prefix is not a valid namespace prefix, then throw an "InvalidCharacterError" DOMException. + // 3. If prefix is not a valid namespace prefix, then throw an "InvalidCharacterError" DOMException. if (!is_valid_namespace_prefix(*prefix)) return WebIDL::InvalidCharacterError::create(realm, "Prefix not a valid namespace prefix."_utf16); } diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/DOMImplementation-createDocument.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/DOMImplementation-createDocument.txt index 545058716898e..fe54ed676c5eb 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/DOMImplementation-createDocument.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/DOMImplementation-createDocument.txt @@ -1,8 +1,8 @@ Harness status: OK -Found 430 tests +Found 434 tests -430 Pass +434 Pass Pass DOMImplementation.createDocument(namespace, qualifiedName, doctype) Pass createDocument test: null,null,null,null Pass createDocument test: metadata for null,null,null @@ -93,7 +93,7 @@ Pass createDocument test: characterSet aliases for undefined,"foo1",null Pass createDocument test: undefined,":foo",null,"INVALID_CHARACTER_ERR" Pass createDocument test: undefined,"f:oo",null,"NAMESPACE_ERR" Pass createDocument test: undefined,"foo:",null,"INVALID_CHARACTER_ERR" -Pass createDocument test: undefined,"f::oo",null,"INVALID_CHARACTER_ERR" +Pass createDocument test: undefined,"f::oo",null,"NAMESPACE_ERR" Pass createDocument test: undefined,"xml",null,null Pass createDocument test: metadata for undefined,"xml",null Pass createDocument test: characterSet aliases for undefined,"xml",null @@ -128,7 +128,9 @@ Pass createDocument test: "http://example.com/","f:o:o",null,null Pass createDocument test: metadata for "http://example.com/","f:o:o",null Pass createDocument test: characterSet aliases for "http://example.com/","f:o:o",null Pass createDocument test: "http://example.com/","foo:",null,"INVALID_CHARACTER_ERR" -Pass createDocument test: "http://example.com/","f::oo",null,"INVALID_CHARACTER_ERR" +Pass createDocument test: "http://example.com/","f::oo",null,null +Pass createDocument test: metadata for "http://example.com/","f::oo",null +Pass createDocument test: characterSet aliases for "http://example.com/","f::oo",null Pass createDocument test: "http://example.com/","a:0",null,"INVALID_CHARACTER_ERR" Pass createDocument test: "http://example.com/","0:a",null,null Pass createDocument test: metadata for "http://example.com/","0:a",null @@ -213,7 +215,9 @@ Pass createDocument test: characterSet aliases for "http://example.com/","XMLNS: Pass createDocument test: "http://example.com/","xmlfoo:bar",null,null Pass createDocument test: metadata for "http://example.com/","xmlfoo:bar",null Pass createDocument test: characterSet aliases for "http://example.com/","xmlfoo:bar",null -Pass createDocument test: "http://example.com/","prefix::local",null,"INVALID_CHARACTER_ERR" +Pass createDocument test: "http://example.com/","prefix::local",null,null +Pass createDocument test: metadata for "http://example.com/","prefix::local",null +Pass createDocument test: characterSet aliases for "http://example.com/","prefix::local",null Pass createDocument test: "http://example.com/","namespaceURI:{",null,"INVALID_CHARACTER_ERR" Pass createDocument test: "http://example.com/","namespaceURI:}",null,"INVALID_CHARACTER_ERR" Pass createDocument test: "http://example.com/","namespaceURI:~",null,"INVALID_CHARACTER_ERR" diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createElementNS.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createElementNS.txt index e30db6cb8b537..c7d0bcddf42c6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createElementNS.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createElementNS.txt @@ -144,9 +144,9 @@ Pass createElementNS test in XHTML document: undefined,"f:oo","NAMESPACE_ERR" Pass createElementNS test in HTML document: undefined,"foo:","INVALID_CHARACTER_ERR" Pass createElementNS test in XML document: undefined,"foo:","INVALID_CHARACTER_ERR" Pass createElementNS test in XHTML document: undefined,"foo:","INVALID_CHARACTER_ERR" -Pass createElementNS test in HTML document: undefined,"f::oo","INVALID_CHARACTER_ERR" -Pass createElementNS test in XML document: undefined,"f::oo","INVALID_CHARACTER_ERR" -Pass createElementNS test in XHTML document: undefined,"f::oo","INVALID_CHARACTER_ERR" +Pass createElementNS test in HTML document: undefined,"f::oo","NAMESPACE_ERR" +Pass createElementNS test in XML document: undefined,"f::oo","NAMESPACE_ERR" +Pass createElementNS test in XHTML document: undefined,"f::oo","NAMESPACE_ERR" Pass createElementNS test in HTML document: undefined,"xml",null Pass createElementNS test in XML document: undefined,"xml",null Pass createElementNS test in XHTML document: undefined,"xml",null @@ -201,9 +201,9 @@ Pass createElementNS test in XHTML document: "http://example.com/","f:o:o",null Pass createElementNS test in HTML document: "http://example.com/","foo:","INVALID_CHARACTER_ERR" Pass createElementNS test in XML document: "http://example.com/","foo:","INVALID_CHARACTER_ERR" Pass createElementNS test in XHTML document: "http://example.com/","foo:","INVALID_CHARACTER_ERR" -Pass createElementNS test in HTML document: "http://example.com/","f::oo","INVALID_CHARACTER_ERR" -Pass createElementNS test in XML document: "http://example.com/","f::oo","INVALID_CHARACTER_ERR" -Pass createElementNS test in XHTML document: "http://example.com/","f::oo","INVALID_CHARACTER_ERR" +Pass createElementNS test in HTML document: "http://example.com/","f::oo",null +Pass createElementNS test in XML document: "http://example.com/","f::oo",null +Pass createElementNS test in XHTML document: "http://example.com/","f::oo",null Pass createElementNS test in HTML document: "http://example.com/","a:0","INVALID_CHARACTER_ERR" Pass createElementNS test in XML document: "http://example.com/","a:0","INVALID_CHARACTER_ERR" Pass createElementNS test in XHTML document: "http://example.com/","a:0","INVALID_CHARACTER_ERR" @@ -300,9 +300,9 @@ Pass createElementNS test in XHTML document: "http://example.com/","XMLNS:foo",n Pass createElementNS test in HTML document: "http://example.com/","xmlfoo:bar",null Pass createElementNS test in XML document: "http://example.com/","xmlfoo:bar",null Pass createElementNS test in XHTML document: "http://example.com/","xmlfoo:bar",null -Pass createElementNS test in HTML document: "http://example.com/","prefix::local","INVALID_CHARACTER_ERR" -Pass createElementNS test in XML document: "http://example.com/","prefix::local","INVALID_CHARACTER_ERR" -Pass createElementNS test in XHTML document: "http://example.com/","prefix::local","INVALID_CHARACTER_ERR" +Pass createElementNS test in HTML document: "http://example.com/","prefix::local",null +Pass createElementNS test in XML document: "http://example.com/","prefix::local",null +Pass createElementNS test in XHTML document: "http://example.com/","prefix::local",null Pass createElementNS test in HTML document: "http://example.com/","namespaceURI:{","INVALID_CHARACTER_ERR" Pass createElementNS test in XML document: "http://example.com/","namespaceURI:{","INVALID_CHARACTER_ERR" Pass createElementNS test in XHTML document: "http://example.com/","namespaceURI:{","INVALID_CHARACTER_ERR" diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/DOMImplementation-createDocument.html b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/DOMImplementation-createDocument.html index 3b3a26a641683..260882c3f04a8 100644 --- a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/DOMImplementation-createDocument.html +++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/DOMImplementation-createDocument.html @@ -116,7 +116,7 @@ var names = [] var firstColonIndex = qualified.indexOf(":") if (firstColonIndex >= 0) { - names = qualifiedName.split(":", 2); + names = [qualified.substring(0, firstColonIndex), qualified.substring(firstColonIndex + 1)]; } else { names = [null, qualified] } diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.html b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.html index 8dc7ca4b4f672..66f612baab239 100644 --- a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.html +++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.html @@ -59,19 +59,17 @@ assert_equals(element.nodeValue, null) assert_equals(element.ownerDocument, doc) var qualified = String(qualifiedName) - var tagName = String(qualifiedName) var names = []; var firstColonIndex = qualified.indexOf(":") if (firstColonIndex >= 0) { - names = qualifiedName.split(":", 2); - tagName = names.join(":"); + names = [qualified.substring(0, firstColonIndex), qualified.substring(firstColonIndex + 1)]; } else { names = [null, qualified] } assert_equals(element.prefix, names[0], 'element.prefix') assert_equals(element.localName, names[1], 'element.localName') - assert_equals(element.tagName, tagName, 'element.tagName') - assert_equals(element.nodeName, tagName, 'element.nodeName') + assert_equals(element.tagName, qualified, 'element.tagName') + assert_equals(element.nodeName, qualified, 'element.nodeName') assert_equals(element.namespaceURI, namespace === undefined || namespace === "" ? null : namespace, diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.js b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.js index 21902ec504e76..14b22220ad91c 100644 --- a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.js +++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createElementNS.js @@ -51,7 +51,7 @@ var createElementNS_tests = [ [undefined, ":foo", "INVALID_CHARACTER_ERR"], [undefined, "f:oo", "NAMESPACE_ERR"], [undefined, "foo:", "INVALID_CHARACTER_ERR"], - [undefined, "f::oo", "INVALID_CHARACTER_ERR"], + [undefined, "f::oo", "NAMESPACE_ERR"], [undefined, "xml", null], [undefined, "xmlns", "NAMESPACE_ERR"], [undefined, "xmlfoo", null], @@ -70,7 +70,7 @@ var createElementNS_tests = [ ["http://example.com/", "f:oo", null], ["http://example.com/", "f:o:o", null], ["http://example.com/", "foo:", "INVALID_CHARACTER_ERR"], - ["http://example.com/", "f::oo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "f::oo", null], ["http://example.com/", "a:0", "INVALID_CHARACTER_ERR"], ["http://example.com/", "0:a", null], ["http://example.com/", "a:_", null], @@ -103,7 +103,7 @@ var createElementNS_tests = [ ["http://example.com/", "xmlns:foo", "NAMESPACE_ERR"], ["http://example.com/", "XMLNS:foo", null], ["http://example.com/", "xmlfoo:bar", null], - ["http://example.com/", "prefix::local", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "prefix::local", null], ["http://example.com/", "namespaceURI:{", "INVALID_CHARACTER_ERR"], ["http://example.com/", "namespaceURI:}", "INVALID_CHARACTER_ERR"], ["http://example.com/", "namespaceURI:~", "INVALID_CHARACTER_ERR"],