Changeset 208716 in webkit


Ignore:
Timestamp:
Nov 14, 2016 4:27:01 PM (7 years ago)
Author:
rniwa@webkit.org
Message:

document.createElementNS doesn't construct a custom element
https://bugs.webkit.org/show_bug.cgi?id=164700

Reviewed by Darin Adler.

Source/WebCore:

Fixed the bug that document.createElementNS doesn't create a custom element or enqueue it to upgrade.

Also made constructCustomElementSynchronously not call the custom element constructors with the element's
local name as the first argument, which was a non-standard behavior added during prototyping.

Test: fast/custom-elements/DOMImplementation-createDocument.html

fast/custom-elements/document-createElementNS.html

  • bindings/js/JSCustomElementInterface.cpp:

(WebCore::JSCustomElementInterface::constructElementWithFallback): Added a variant that takes QualifiedName
instead of AtomicString.
(WebCore::constructCustomElementSynchronously): Don't add the local name as an argument.

  • bindings/js/JSCustomElementInterface.h:
  • dom/CustomElementRegistry.cpp:

(WebCore::CustomElementRegistry::findInterface): Just find the interface based on the local name after
checking the namespace URI to be that of the XHTML. We need to ignore the prefix for the purpose of looking
up the custom element definition as specified in the latest HTML specification:
https://html.spec.whatwg.org/multipage/scripting.html#look-up-a-custom-element-definition

  • dom/DOMImplementation.cpp:

(WebCore::DOMImplementation::createDocument): Added an assertion to make sure we don't invoke scripts while
constructing the document element.

  • dom/Document.cpp:

(WebCore::createUpgradeCandidateElement): Made this function create a HTMLUnknownElement instead of returning
nullptr to share more code. Also added a variant which takes QualifiedName.
(WebCore::isValidHTMLElementName): Added; helpers for createHTMLElementWithNameValidation to call isValidName
on Document with the right argument.
(WebCore::createHTMLElementWithNameValidation): Templatized the function to be called with either AtomicString
or QualifiedName for the name.
(WebCore::createFallbackHTMLElement):
(WebCore::Document::createElementNS): Call createHTMLElementWithNameValidation to create a custom element if
possible. This function ends up re-validating the element name before creating a HTMLUnknownElement but that
shouldn't be a common scenario to matter. In fact, createElementNS is a rarely used API.

LayoutTests:

Added W3C style testharness.js tests for createElementNS and DOMImplementation's createDocument.

  • fast/custom-elements/DOMImplementation-createDocument-expected.txt: Added.
  • fast/custom-elements/DOMImplementation-createDocument.html: Added.
  • fast/custom-elements/document-createElementNS-expected.txt: Added.
  • fast/custom-elements/document-createElementNS.html: Added.
Location:
trunk
Files:
4 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r208700 r208716  
     12016-11-14  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        document.createElementNS doesn't construct a custom element
     4        https://bugs.webkit.org/show_bug.cgi?id=164700
     5
     6        Reviewed by Darin Adler.
     7
     8        Added W3C style testharness.js tests for createElementNS and DOMImplementation's createDocument.
     9
     10        * fast/custom-elements/DOMImplementation-createDocument-expected.txt: Added.
     11        * fast/custom-elements/DOMImplementation-createDocument.html: Added.
     12        * fast/custom-elements/document-createElementNS-expected.txt: Added.
     13        * fast/custom-elements/document-createElementNS.html: Added.
     14
    1152016-11-14  Dean Jackson  <dino@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r208711 r208716  
     12016-11-14  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        document.createElementNS doesn't construct a custom element
     4        https://bugs.webkit.org/show_bug.cgi?id=164700
     5
     6        Reviewed by Darin Adler.
     7
     8        Fixed the bug that document.createElementNS doesn't create a custom element or enqueue it to upgrade.
     9
     10        Also made constructCustomElementSynchronously not call the custom element constructors with the element's
     11        local name as the first argument, which was a non-standard behavior added during prototyping.
     12
     13        Test: fast/custom-elements/DOMImplementation-createDocument.html
     14              fast/custom-elements/document-createElementNS.html
     15
     16        * bindings/js/JSCustomElementInterface.cpp:
     17        (WebCore::JSCustomElementInterface::constructElementWithFallback): Added a variant that takes QualifiedName
     18        instead of AtomicString.
     19        (WebCore::constructCustomElementSynchronously): Don't add the local name as an argument.
     20        * bindings/js/JSCustomElementInterface.h:
     21
     22        * dom/CustomElementRegistry.cpp:
     23        (WebCore::CustomElementRegistry::findInterface): Just find the interface based on the local name after
     24        checking the namespace URI to be that of the XHTML. We need to ignore the prefix for the purpose of looking
     25        up the custom element definition as specified in the latest HTML specification:
     26        https://html.spec.whatwg.org/multipage/scripting.html#look-up-a-custom-element-definition
     27
     28        * dom/DOMImplementation.cpp:
     29        (WebCore::DOMImplementation::createDocument): Added an assertion to make sure we don't invoke scripts while
     30        constructing the document element.
     31
     32        * dom/Document.cpp:
     33        (WebCore::createUpgradeCandidateElement): Made this function create a HTMLUnknownElement instead of returning
     34        nullptr to share more code. Also added a variant which takes QualifiedName.
     35        (WebCore::isValidHTMLElementName): Added; helpers for createHTMLElementWithNameValidation to call isValidName
     36        on Document with the right argument.
     37        (WebCore::createHTMLElementWithNameValidation): Templatized the function to be called with either AtomicString
     38        or QualifiedName for the name.
     39        (WebCore::createFallbackHTMLElement):
     40        (WebCore::Document::createElementNS): Call createHTMLElementWithNameValidation to create a custom element if
     41        possible. This function ends up re-validating the element name before creating a HTMLUnknownElement but that
     42        shouldn't be a common scenario to matter. In fact, createElementNS is a rarely used API.
     43
    1442016-11-14  Chris Dumez  <cdumez@apple.com>
    245
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp

    r208256 r208716  
    6868    element->setIsFailedCustomElement(*this);
    6969
    70     return element.get();
     70    return WTFMove(element);
     71}
     72
     73Ref<Element> JSCustomElementInterface::constructElementWithFallback(Document& document, const QualifiedName& name)
     74{
     75    if (auto element = tryToConstructCustomElement(document, name.localName())) {
     76        if (name.prefix() != nullAtom)
     77            element->setPrefix(name.prefix());
     78        return element.releaseNonNull();
     79    }
     80
     81    auto element = HTMLUnknownElement::create(name, document);
     82    element->setIsCustomElementUpgradeCandidate();
     83    element->setIsFailedCustomElement(*this);
     84
     85    return WTFMove(element);
    7186}
    7287
     
    111126    }
    112127
     128    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionConstruct(&document, constructType, constructData);
    113129    MarkedArgumentBuffer args;
    114     args.append(jsStringWithCache(&state, localName));
    115 
    116     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionConstruct(&document, constructType, constructData);
    117130    JSValue newElement = construct(&state, constructor, constructType, constructData, args);
    118131    InspectorInstrumentation::didCallFunction(cookie, &document);
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h

    r208256 r208716  
    6060
    6161    Ref<Element> constructElementWithFallback(Document&, const AtomicString&);
     62    Ref<Element> constructElementWithFallback(Document&, const QualifiedName&);
    6263
    6364    void upgradeElement(Element&);
  • trunk/Source/WebCore/dom/CustomElementRegistry.cpp

    r208256 r208716  
    8888JSCustomElementInterface* CustomElementRegistry::findInterface(const QualifiedName& name) const
    8989{
    90     ASSERT(!name.hasPrefix());
    9190    if (name.namespaceURI() != HTMLNames::xhtmlNamespaceURI)
    9291        return nullptr;
    93     auto it = m_nameMap.find(name.localName());
    94     return it == m_nameMap.end() || it->value->name() != name ? nullptr : const_cast<JSCustomElementInterface*>(it->value.ptr());
     92    return m_nameMap.get(name.localName());
    9593}
    9694
  • trunk/Source/WebCore/dom/DOMImplementation.cpp

    r208688 r208716  
    115115    RefPtr<Element> documentElement;
    116116    if (!qualifiedName.isEmpty()) {
     117        ASSERT(!document->domWindow()); // If domWindow is not null, createElementNS could find CustomElementRegistry and arbitrary scripts.
    117118        auto result = document->createElementNS(namespaceURI, qualifiedName);
    118119        if (result.hasException())
  • trunk/Source/WebCore/dom/Document.cpp

    r208660 r208716  
    862862}
    863863
    864 static ALWAYS_INLINE RefPtr<HTMLElement> createUpgradeCandidateElement(Document& document, const QualifiedName& name)
    865 {
    866     if (!RuntimeEnabledFeatures::sharedFeatures().customElementsEnabled())
    867         return nullptr;
    868 
    869     if (Document::validateCustomElementName(name.localName()) != CustomElementNameValidationStatus::Valid)
    870         return nullptr;
     864static ALWAYS_INLINE Ref<HTMLElement> createUpgradeCandidateElement(Document& document, const QualifiedName& name)
     865{
     866    if (!RuntimeEnabledFeatures::sharedFeatures().customElementsEnabled()
     867        || Document::validateCustomElementName(name.localName()) != CustomElementNameValidationStatus::Valid)
     868        return HTMLUnknownElement::create(name, document);
    871869
    872870    auto element = HTMLElement::create(name, document);
    873871    element->setIsCustomElementUpgradeCandidate();
    874     return WTFMove(element);
    875 }
    876 
    877 static ExceptionOr<Ref<Element>> createHTMLElementWithNameValidation(Document& document, const AtomicString& localName)
    878 {
    879     auto element = HTMLElementFactory::createKnownElement(localName, document);
     872    return element;
     873}
     874
     875static ALWAYS_INLINE Ref<HTMLElement> createUpgradeCandidateElement(Document& document, const AtomicString& localName)
     876{
     877    return createUpgradeCandidateElement(document, QualifiedName { nullAtom, localName, xhtmlNamespaceURI });
     878}
     879
     880static inline bool isValidHTMLElementName(const AtomicString& localName)
     881{
     882    return Document::isValidName(localName);
     883}
     884
     885static inline bool isValidHTMLElementName(const QualifiedName& name)
     886{
     887    return Document::isValidName(name.localName());
     888}
     889
     890template<typename NameType>
     891static ExceptionOr<Ref<Element>> createHTMLElementWithNameValidation(Document& document, const NameType& name)
     892{
     893    auto element = HTMLElementFactory::createKnownElement(name, document);
    880894    if (LIKELY(element))
    881895        return Ref<Element> { element.releaseNonNull() };
     
    884898        auto* registry = window->customElementRegistry();
    885899        if (UNLIKELY(registry)) {
    886             if (auto* elementInterface = registry->findInterface(localName))
    887                 return elementInterface->constructElementWithFallback(document, localName);
     900            if (auto* elementInterface = registry->findInterface(name))
     901                return elementInterface->constructElementWithFallback(document, name);
    888902        }
    889903    }
    890904
    891     if (UNLIKELY(!Document::isValidName(localName)))
     905    if (UNLIKELY(!isValidHTMLElementName(name)))
    892906        return Exception { INVALID_CHARACTER_ERR };
    893907
    894     QualifiedName qualifiedName { nullAtom, localName, xhtmlNamespaceURI };
    895 
    896     if (auto element = createUpgradeCandidateElement(document, qualifiedName))
    897         return Ref<Element> { element.releaseNonNull() };
    898 
    899     return Ref<Element> { HTMLUnknownElement::create(qualifiedName, document) };
     908    return Ref<Element> { createUpgradeCandidateElement(document, name) };
    900909}
    901910
     
    10561065    }
    10571066    // FIXME: Should we also check the equality of prefix between the custom element and name?
    1058     if (auto element = createUpgradeCandidateElement(document, name))
    1059         return element.releaseNonNull();
    1060     return HTMLUnknownElement::create(name, document);
     1067    return createUpgradeCandidateElement(document, name);
    10611068}
    10621069
     
    11601167    if (!hasValidNamespaceForElements(parsedName))
    11611168        return Exception { NAMESPACE_ERR };
     1169
     1170    if (parsedName.namespaceURI() == xhtmlNamespaceURI)
     1171        return createHTMLElementWithNameValidation(*this, parsedName);
     1172
    11621173    return createElement(parsedName, false);
    11631174}
Note: See TracChangeset for help on using the changeset viewer.