198198#include " MouseEventWithHitTestResults.h"
199199#include " MutationEvent.h"
200200#include " NameNodeList.h"
201+ #include " NameValidation.h"
201202#include " Navigation.h"
202203#include " NavigationActivation.h"
203204#include " NavigationDisabler.h"
@@ -517,24 +518,6 @@ static void CallbackForContainIntrinsicSize(const Vector<Ref<ResizeObserverEntry
517518 }
518519}
519520
520- // https://www.w3.org/TR/xml/#NT-NameStartChar
521- // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
522- static inline bool isValidNameStart (char32_t c)
523- {
524- return c == ' :' || (c >= ' A' && c <= ' Z' ) || c == ' _' || (c >= ' a' && c <= ' z' ) || (c >= 0x00C0 && c <= 0x00D6 )
525- || (c >= 0x00D8 && c <= 0x00F6 ) || (c >= 0x00F8 && c <= 0x02FF ) || (c >= 0x0370 && c <= 0x037D ) || (c >= 0x037F && c <= 0x1FFF )
526- || (c >= 0x200C && c <= 0x200D ) || (c >= 0x2070 && c <= 0x218F ) || (c >= 0x2C00 && c <= 0x2FeF ) || (c >= 0x3001 && c <= 0xD7FF )
527- || (c >= 0xF900 && c <= 0xFDCF ) || (c >= 0xFDF0 && c <= 0xFFFD ) || (c >= 0x10000 && c <= 0xEFFFF );
528- }
529-
530- // https://www.w3.org/TR/xml/#NT-NameChar
531- // NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
532- static inline bool isValidNamePart (char32_t c)
533- {
534- return isValidNameStart (c) || c == ' -' || c == ' .' || (c >= ' 0' && c <= ' 9' ) || c == 0x00B7
535- || (c >= 0x0300 && c <= 0x036F ) || (c >= 0x203F && c <= 0x2040 );
536- }
537-
538521static Widget* widgetForElement (Element* focusedElement)
539522{
540523 auto * renderer = focusedElement ? dynamicDowncast<RenderWidget>(focusedElement->renderer ()) : nullptr ;
@@ -1565,16 +1548,6 @@ static ALWAYS_INLINE Ref<HTMLElement> createUpgradeCandidateElement(Document& do
15651548 return createUpgradeCandidateElement (document, registry, QualifiedName { nullAtom (), localName, xhtmlNamespaceURI });
15661549}
15671550
1568- static inline bool isValidHTMLElementName (const AtomString& localName)
1569- {
1570- return Document::isValidName (localName);
1571- }
1572-
1573- static inline bool isValidHTMLElementName (const QualifiedName& name)
1574- {
1575- return Document::isValidName (name.localName ());
1576- }
1577-
15781551template <typename NameType>
15791552static ExceptionOr<Ref<Element>> createHTMLElementWithNameValidation (Document& document, const NameType& name, CustomElementRegistry* registry)
15801553{
@@ -1590,7 +1563,7 @@ static ExceptionOr<Ref<Element>> createHTMLElementWithNameValidation(Document& d
15901563 return elementInterface->constructElementWithFallback (document, *registry, name);
15911564 }
15921565
1593- if (!isValidHTMLElementName (name)) [[unlikely]]
1566+ if (!NameValidation::isValidElementName (name)) [[unlikely]]
15941567 return Exception { ExceptionCode::InvalidCharacterError };
15951568
15961569 return Ref<Element> { createUpgradeCandidateElement (document, registry, name) };
@@ -1620,7 +1593,7 @@ ExceptionOr<Ref<Element>> Document::createElementForBindings(const AtomString& n
16201593 if (document->isXHTMLDocument ())
16211594 return createHTMLElementWithNameValidation (document, name, registry.get ());
16221595
1623- if (!document-> isValidName (name))
1596+ if (!NameValidation::isValidElementName (name))
16241597 return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid qualified name: '" _s, name, ' \' ' ) };
16251598
16261599 return createElement (QualifiedName (nullAtom (), name, nullAtom ()), false , registry.get ());
@@ -1671,8 +1644,8 @@ ExceptionOr<Ref<CDATASection>> Document::createCDATASection(String&& data)
16711644
16721645ExceptionOr<Ref<ProcessingInstruction>> Document::createProcessingInstruction (String&& target, String&& data)
16731646{
1674- if (!isValidName (target))
1675- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid qualified name : '" _s, target, ' \' ' ) };
1647+ if (!NameValidation::isValidXMLName (target))
1648+ return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid processing instruction target : '" _s, target, ' \' ' ) };
16761649
16771650 if (data.contains (" ?>" _s))
16781651 return Exception { ExceptionCode::InvalidCharacterError };
@@ -1765,28 +1738,6 @@ ExceptionOr<Ref<Node>> Document::adoptNode(Node& source)
17651738 return Ref<Node> { source };
17661739}
17671740
1768- bool Document::hasValidNamespaceForElements (const QualifiedName& qName)
1769- {
1770- // These checks are from DOM Core Level 2, createElementNS
1771- // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
1772- if (!qName.prefix ().isEmpty () && qName.namespaceURI ().isNull ()) // createElementNS(null, "html:div")
1773- return false ;
1774- if (qName.prefix () == xmlAtom () && qName.namespaceURI () != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang")
1775- return false ;
1776-
1777- // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
1778- // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1779- // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar"), createElementNS(null, "xmlns")
1780- if (qName.prefix () == xmlnsAtom () || (qName.prefix ().isEmpty () && qName.localName () == xmlnsAtom ()))
1781- return qName.namespaceURI () == XMLNSNames::xmlnsNamespaceURI;
1782- return qName.namespaceURI () != XMLNSNames::xmlnsNamespaceURI;
1783- }
1784-
1785- bool Document::hasValidNamespaceForAttributes (const QualifiedName& qName)
1786- {
1787- return hasValidNamespaceForElements (qName);
1788- }
1789-
17901741static Ref<HTMLElement> createFallbackHTMLElement (Document& document, CustomElementRegistry* registry, const QualifiedName& name)
17911742{
17921743 if (registry) {
@@ -2058,11 +2009,11 @@ ExceptionOr<Ref<Element>> Document::createElementNS(const AtomString& namespaceU
20582009 if (opportunisticallyMatchedBuiltinElement) [[likely]]
20592010 return opportunisticallyMatchedBuiltinElement.releaseNonNull ();
20602011
2061- auto parseResult = Document::parseQualifiedName (namespaceURI, qualifiedName);
2012+ auto parseResult = NameValidation::parseQualifiedElementName (namespaceURI, qualifiedName);
20622013 if (parseResult.hasException ())
20632014 return parseResult.releaseException ();
20642015 QualifiedName parsedName { parseResult.releaseReturnValue () };
2065- if (!Document ::hasValidNamespaceForElements (parsedName))
2016+ if (!NameValidation ::hasValidNamespaceForElements (parsedName))
20662017 return Exception { ExceptionCode::NamespaceError };
20672018
20682019 if (parsedName.namespaceURI () == xhtmlNamespaceURI)
@@ -7520,138 +7471,6 @@ void Document::updateCachedCookiesEnabled()
75207471 });
75217472}
75227473
7523- static bool isValidNameNonASCII (std::span<const Latin1Character> characters)
7524- {
7525- if (!isValidNameStart (characters[0 ]))
7526- return false ;
7527-
7528- for (size_t i = 1 ; i < characters.size (); ++i) {
7529- if (!isValidNamePart (characters[i]))
7530- return false ;
7531- }
7532-
7533- return true ;
7534- }
7535-
7536- static bool isValidNameNonASCII (std::span<const char16_t > characters)
7537- {
7538- for (size_t i = 0 ; i < characters.size ();) {
7539- bool first = !i;
7540- char32_t c;
7541- U16_NEXT (characters, i, characters.size (), c); // Increments i.
7542- if (first ? !isValidNameStart (c) : !isValidNamePart (c))
7543- return false ;
7544- }
7545-
7546- return true ;
7547- }
7548-
7549- template <typename CharType>
7550- static inline bool isValidNameASCII (std::span<const CharType> characters)
7551- {
7552- CharType c = characters[0 ];
7553- if (!(isASCIIAlpha (c) || c == ' :' || c == ' _' ))
7554- return false ;
7555-
7556- for (size_t i = 1 ; i < characters.size (); ++i) {
7557- c = characters[i];
7558- if (!(isASCIIAlphanumeric (c) || c == ' :' || c == ' _' || c == ' -' || c == ' .' ))
7559- return false ;
7560- }
7561-
7562- return true ;
7563- }
7564-
7565- static bool isValidNameASCIIWithoutColon (std::span<const Latin1Character> characters)
7566- {
7567- auto c = characters.front ();
7568- if (!(isASCIIAlpha (c) || c == ' _' ))
7569- return false ;
7570-
7571- for (size_t i = 1 ; i < characters.size (); ++i) {
7572- c = characters[i];
7573- if (!(isASCIIAlphanumeric (c) || c == ' _' || c == ' -' || c == ' .' ))
7574- return false ;
7575- }
7576-
7577- return true ;
7578- }
7579-
7580- bool Document::isValidName (const String& name)
7581- {
7582- unsigned length = name.length ();
7583- if (!length)
7584- return false ;
7585-
7586- if (name.is8Bit ()) {
7587- auto characters = name.span8 ();
7588-
7589- if (isValidNameASCII (characters))
7590- return true ;
7591-
7592- return isValidNameNonASCII (characters);
7593- }
7594-
7595- auto characters = name.span16 ();
7596-
7597- if (isValidNameASCII (characters))
7598- return true ;
7599-
7600- return isValidNameNonASCII (characters);
7601- }
7602-
7603- ExceptionOr<std::pair<AtomString, AtomString>> Document::parseQualifiedName (const AtomString& qualifiedName)
7604- {
7605- unsigned length = qualifiedName.length ();
7606-
7607- if (!length)
7608- return Exception { ExceptionCode::InvalidCharacterError };
7609-
7610- bool nameStart = true ;
7611- bool sawColon = false ;
7612- unsigned colonPosition = 0 ;
7613-
7614- bool isValidLocalName = qualifiedName.is8Bit () && isValidNameASCIIWithoutColon (qualifiedName.span8 ());
7615- if (isValidLocalName) [[likely]]
7616- return std::pair<AtomString, AtomString> { { }, { qualifiedName } };
7617-
7618- for (unsigned i = 0 ; i < length; ) {
7619- char32_t c;
7620- U16_NEXT (qualifiedName, i, length, c);
7621- if (c == ' :' ) {
7622- if (sawColon)
7623- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Unexpected colon in qualified name '" _s, qualifiedName, ' \' ' ) };
7624- nameStart = true ;
7625- sawColon = true ;
7626- colonPosition = i - 1 ;
7627- } else if (nameStart) {
7628- if (!isValidNameStart (c))
7629- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid qualified name start in '" _s, qualifiedName, ' \' ' ) };
7630- nameStart = false ;
7631- } else {
7632- if (!isValidNamePart (c))
7633- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid qualified name part in '" _s, qualifiedName, ' \' ' ) };
7634- }
7635- }
7636-
7637- if (!sawColon)
7638- return std::pair<AtomString, AtomString> { { }, { qualifiedName } };
7639-
7640- if (!colonPosition || length - colonPosition <= 1 )
7641- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Namespace in qualified name '" _s, qualifiedName, " ' is too short" _s) };
7642-
7643- return std::pair<AtomString, AtomString> { StringView { qualifiedName }.left (colonPosition).toAtomString (), StringView { qualifiedName }.substring (colonPosition + 1 ).toAtomString () };
7644- }
7645-
7646- ExceptionOr<QualifiedName> Document::parseQualifiedName (const AtomString& namespaceURI, const AtomString& qualifiedName)
7647- {
7648- auto parseResult = parseQualifiedName (qualifiedName);
7649- if (parseResult.hasException ())
7650- return parseResult.releaseException ();
7651- auto parsedPieces = parseResult.releaseReturnValue ();
7652- return QualifiedName { parsedPieces.first , parsedPieces.second , namespaceURI };
7653- }
7654-
76557474void Document::setDecoder (RefPtr<TextResourceDecoder>&& decoder)
76567475{
76577476 m_decoder = WTF::move (decoder);
@@ -8227,18 +8046,18 @@ Ref<ScriptRunner> Document::protectedScriptRunner()
82278046
82288047ExceptionOr<Ref<Attr>> Document::createAttribute (const AtomString& localName)
82298048{
8230- if (!isValidName (localName))
8231- return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid qualified name: '" _s, localName, ' \' ' ) };
8049+ if (!NameValidation::isValidAttributeName (localName))
8050+ return Exception { ExceptionCode::InvalidCharacterError, makeString (" Invalid attribute name: '" _s, localName, ' \' ' ) };
82328051 return Attr::create (*this , QualifiedName { nullAtom (), isHTMLDocument () ? localName.convertToASCIILowercase () : localName, nullAtom () }, emptyAtom ());
82338052}
82348053
82358054ExceptionOr<Ref<Attr>> Document::createAttributeNS (const AtomString& namespaceURI, const AtomString& qualifiedName, bool shouldIgnoreNamespaceChecks)
82368055{
8237- auto parseResult = parseQualifiedName (namespaceURI, qualifiedName);
8056+ auto parseResult = NameValidation::parseQualifiedAttributeName (namespaceURI, qualifiedName);
82388057 if (parseResult.hasException ())
82398058 return parseResult.releaseException ();
82408059 QualifiedName parsedName { parseResult.releaseReturnValue () };
8241- if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes (parsedName))
8060+ if (!shouldIgnoreNamespaceChecks && !NameValidation:: hasValidNamespaceForAttributes (parsedName))
82428061 return Exception { ExceptionCode::NamespaceError };
82438062 return Attr::create (*this , parsedName, emptyAtom ());
82448063}
0 commit comments