Changeset 285740 in webkit


Ignore:
Timestamp:
Nov 12, 2021 2:11:13 PM (8 months ago)
Author:
commit-queue@webkit.org
Message:

Implement custom element definition's *disable shadow* flag
https://bugs.webkit.org/show_bug.cgi?id=233023

Patch by Alexey Shvayka <ashvayka@apple.com> on 2021-11-12
Reviewed by Geoffrey Garen.

LayoutTests/imported/w3c:

Rebaseline WPT tests now that more checks are passing or failing later on.

  • web-platform-tests/custom-elements/CustomElementRegistry-expected.txt:
  • web-platform-tests/custom-elements/upgrading-expected.txt:
  • web-platform-tests/shadow-dom/Element-interface-attachShadow-custom-element-expected.txt:

Source/WebCore:

This change implements *disable shadow* flag that precludes attachShadow() [1]
as well as upgrading an element with already attached shadow root [2].

Aligns WebKit with Blink and Gecko.
Preserves the fast path for non-custom elements.

[1] https://dom.spec.whatwg.org/#ref-for-concept-custom-element-definition-disable-shadow
[2] https://html.spec.whatwg.org/multipage/custom-elements.html#upgrades:concept-custom-element-definition-disable-shadow

Tests: imported/w3c/web-platform-tests/custom-elements/CustomElementRegistry.html

imported/w3c/web-platform-tests/custom-elements/upgrading.html
imported/w3c/web-platform-tests/shadow-dom/Element-interface-attachShadow-custom-element.html

  • bindings/js/JSCustomElementInterface.cpp:

(WebCore::JSCustomElementInterface::JSCustomElementInterface):
(WebCore::JSCustomElementInterface::upgradeElement):

  • bindings/js/JSCustomElementInterface.h:

(WebCore::JSCustomElementInterface::disableShadow):
(WebCore::JSCustomElementInterface::isShadowDisabled const):

  • bindings/js/JSCustomElementRegistryCustom.cpp:

(WebCore::JSCustomElementRegistry::define):

  • dom/CustomElementRegistry.cpp:

(WebCore::CustomElementRegistry::addElementDefinition):

  • dom/CustomElementRegistry.h:

(WebCore::CustomElementRegistry::isShadowDisabled const):

  • dom/Element.cpp:

(WebCore::canAttachAuthorShadowRoot):

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r285738 r285740  
     12021-11-12  Alexey Shvayka  <ashvayka@apple.com>
     2
     3        Implement custom element definition's *disable shadow* flag
     4        https://bugs.webkit.org/show_bug.cgi?id=233023
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Rebaseline WPT tests now that more checks are passing or failing later on.
     9
     10        * web-platform-tests/custom-elements/CustomElementRegistry-expected.txt:
     11        * web-platform-tests/custom-elements/upgrading-expected.txt:
     12        * web-platform-tests/shadow-dom/Element-interface-attachShadow-custom-element-expected.txt:
     13
    1142021-11-12  Commit Queue  <commit-queue@webkit.org>
    215
  • trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/CustomElementRegistry-expected.txt

    r267651 r285740  
    1010PASS customElements.define must validate the custom element name before checking the element definition is running flag
    1111PASS customElements.define unset the element definition is running flag before upgrading custom elements
    12 FAIL customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype") assert_array_equals: customElements.define must get "prototype", "disabledFeatures", and "formAssociated" on the constructor lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype"] length 1
     12FAIL customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype") assert_array_equals: customElements.define must get "prototype", "disabledFeatures", and "formAssociated" on the constructor lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype", "disabledFeatures"] length 2
    1313PASS Custom Elements: CustomElementRegistry interface
    14 FAIL customElements.define must get "prototype", "disabledFeatures", and "formAssociated" property of the constructor assert_array_equals: lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype"] length 1
     14FAIL customElements.define must get "prototype", "disabledFeatures", and "formAssociated" property of the constructor assert_array_equals: lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype", "disabledFeatures"] length 2
    1515PASS customElements.define must rethrow an exception thrown while getting "prototype" property of the constructor
    1616PASS customElements.define must throw when "prototype" property of the constructor is not an object
     
    1818PASS customElements.define must rethrow an exception thrown while getting callbacks on the constructor prototype
    1919PASS customElements.define must rethrow an exception thrown while converting a callback value to Function callback type
    20 FAIL customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present assert_array_equals: lengths differ, expected array [0, "prototype", 5, "observedAttributes", 6, "disabledFeatures", 7, "formAssociated"] length 8, got [0, "prototype", 5, "observedAttributes"] length 4
     20FAIL customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present assert_array_equals: lengths differ, expected array [0, "prototype", 5, "observedAttributes", 6, "disabledFeatures", 7, "formAssociated"] length 8, got [0, "prototype", 5, "observedAttributes", 6, "disabledFeatures"] length 6
    2121PASS customElements.define must rethrow an exception thrown while getting observedAttributes on the constructor prototype
    2222PASS customElements.define must rethrow an exception thrown while converting the value of observedAttributes to sequence<DOMString>
     
    2424PASS customElements.define must rethrow an exception thrown while retrieving Symbol.iterator on observedAttributes
    2525PASS customElements.define must not throw even if "observedAttributes" fails to convert if "attributeChangedCallback" is not defined
    26 FAIL customElements.define must rethrow an exception thrown while getting disabledFeatures on the constructor prototype assert_throws_exactly: function "() => customElements.define('element-with-throwing-disabled-features', proxy)" did not throw
    27 FAIL customElements.define must rethrow an exception thrown while converting the value of disabledFeatures to sequence<DOMString> assert_throws_js: function "() => customElements.define('element-with-invalid-disabled-features', proxy)" did not throw
    28 FAIL customElements.define must rethrow an exception thrown while iterating over disabledFeatures to sequence<DOMString> assert_throws_exactly: function "() => customElements.define('element-with-generator-disabled-features', constructor)" did not throw
    29 FAIL customElements.define must rethrow an exception thrown while retrieving Symbol.iterator on disabledFeatures assert_throws_js: function "() => customElements.define('element-with-disabled-features-with-uncallable-iterator', constructor)" did not throw
     26PASS customElements.define must rethrow an exception thrown while getting disabledFeatures on the constructor prototype
     27PASS customElements.define must rethrow an exception thrown while converting the value of disabledFeatures to sequence<DOMString>
     28PASS customElements.define must rethrow an exception thrown while iterating over disabledFeatures to sequence<DOMString>
     29PASS customElements.define must rethrow an exception thrown while retrieving Symbol.iterator on disabledFeatures
    3030FAIL customElements.define must rethrow an exception thrown while getting formAssociated on the constructor prototype assert_throws_exactly: function "() => customElements.define('element-with-throwing-form-associated', proxy)" did not throw
    31 FAIL customElements.define must get four additional callbacks on the prototype if formAssociated is converted to true assert_array_equals: customElements.define must get "prototype", "disabledFeatures", and "formAssociated" on the constructor lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype"] length 1
     31FAIL customElements.define must get four additional callbacks on the prototype if formAssociated is converted to true assert_array_equals: customElements.define must get "prototype", "disabledFeatures", and "formAssociated" on the constructor lengths differ, expected array ["prototype", "disabledFeatures", "formAssociated"] length 3, got ["prototype", "disabledFeatures"] length 2
    3232FAIL customElements.define must rethrow an exception thrown while getting additional formAssociated callbacks on the constructor prototype assert_throws_exactly: function "() => customElements.define('element-with-throwing-callback-2', proxy)" did not throw
    3333PASS customElements.define must define an instantiatable custom element
  • trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/upgrading-expected.txt

    r267651 r285740  
     1CONSOLE MESSAGE: NotSupportedError: Failed to upgrade an element with shadow root: the custom element definition disallows shadow roots.
    12
    23PASS Creating an element in the document of the template elements must not enqueue a custom element upgrade reaction because the document does not have a browsing context
     
    2526PASS Adopting (and leaving disconnceted) an unresolved custom element into the document of an iframe must not enqueue a custom element upgrade reaction
    2627PASS Adopting and inserting an unresolved custom element into the document of an iframe must enqueue a custom element upgrade reaction
    27 FAIL If definition's disable shadow is true and element's shadow root is non-null, then throw a "NotSupportedError" DOMException. assert_false: Upgrading should fail. expected false got true
     28PASS If definition's disable shadow is true and element's shadow root is non-null, then throw a "NotSupportedError" DOMException.
    2829PASS Infinite constructor recursion with upgrade(this) should not be possible
    2930PASS Infinite constructor recursion with appendChild should not be possible
  • trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/Element-interface-attachShadow-custom-element-expected.txt

    r267647 r285740  
    22PASS Element.attachShadow must create an instance of ShadowRoot for autonomous custom elements
    33PASS Element.attachShadow must create an instance of ShadowRoot for undefined autonomous custom elements
    4 FAIL Element.attachShadow for an autonomous custom element with disabledFeatures=["shadow"] should throw a NotSupportedError assert_throws_dom: Definition, not a host function "() => {
    5     document.createElement('shadow-disabled-element').attachShadow({mode: 'closed'});
    6   }" did not throw
     4PASS Element.attachShadow for an autonomous custom element with disabledFeatures=["shadow"] should throw a NotSupportedError
    75FAIL Element.attachShadow for a customized built-in element with disabledFeatures=["shadow"] should throw a NotSupportedError assert_throws_dom: Definition, not a host function "() => {
    86    h2.attachShadow({mode: 'closed'});
  • trunk/Source/WebCore/ChangeLog

    r285738 r285740  
     12021-11-12  Alexey Shvayka  <ashvayka@apple.com>
     2
     3        Implement custom element definition's *disable shadow* flag
     4        https://bugs.webkit.org/show_bug.cgi?id=233023
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This change implements *disable shadow* flag that precludes attachShadow() [1]
     9        as well as upgrading an element with already attached shadow root [2].
     10
     11        Aligns WebKit with Blink and Gecko.
     12        Preserves the fast path for non-custom elements.
     13
     14        [1] https://dom.spec.whatwg.org/#ref-for-concept-custom-element-definition-disable-shadow
     15        [2] https://html.spec.whatwg.org/multipage/custom-elements.html#upgrades:concept-custom-element-definition-disable-shadow
     16
     17        Tests: imported/w3c/web-platform-tests/custom-elements/CustomElementRegistry.html
     18               imported/w3c/web-platform-tests/custom-elements/upgrading.html
     19               imported/w3c/web-platform-tests/shadow-dom/Element-interface-attachShadow-custom-element.html
     20
     21        * bindings/js/JSCustomElementInterface.cpp:
     22        (WebCore::JSCustomElementInterface::JSCustomElementInterface):
     23        (WebCore::JSCustomElementInterface::upgradeElement):
     24        * bindings/js/JSCustomElementInterface.h:
     25        (WebCore::JSCustomElementInterface::disableShadow):
     26        (WebCore::JSCustomElementInterface::isShadowDisabled const):
     27        * bindings/js/JSCustomElementRegistryCustom.cpp:
     28        (WebCore::JSCustomElementRegistry::define):
     29        * dom/CustomElementRegistry.cpp:
     30        (WebCore::CustomElementRegistry::addElementDefinition):
     31        * dom/CustomElementRegistry.h:
     32        (WebCore::CustomElementRegistry::isShadowDisabled const):
     33        * dom/Element.cpp:
     34        (WebCore::canAttachAuthorShadowRoot):
     35
    1362021-11-12  Commit Queue  <commit-queue@webkit.org>
    237
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp

    r284857 r285740  
    5151    , m_constructor(constructor)
    5252    , m_isolatedWorld(globalObject->world())
     53    , m_isShadowDisabled(false)
    5354{
    5455}
     
    208209    m_constructionStack.append(&element);
    209210
     211    if (m_isShadowDisabled && element.shadowRoot()) {
     212        element.clearReactionQueueFromFailedCustomElement();
     213        reportException(lexicalGlobalObject, createDOMException(lexicalGlobalObject, NotSupportedError, "Failed to upgrade an element with shadow root: the custom element definition disallows shadow roots."));
     214        return;
     215    }
     216
    210217    MarkedArgumentBuffer args;
    211218    ASSERT(!args.hasOverflowed());
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h

    r284857 r285740  
    7979    void invokeAttributeChangedCallback(Element&, const QualifiedName&, const AtomString& oldValue, const AtomString& newValue);
    8080
     81    void disableShadow() { m_isShadowDisabled = true; }
     82    bool isShadowDisabled() const { return m_isShadowDisabled; }
     83
    8184    ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }
    8285    JSC::JSObject* constructor() { return m_constructor.get(); }
     
    106109    Vector<RefPtr<Element>, 1> m_constructionStack;
    107110    HashSet<AtomString> m_observedAttributes;
     111    bool m_isShadowDisabled : 1;
    108112};
    109113
  • trunk/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp

    r266142 r285740  
    157157    }
    158158
     159    auto disabledFeaturesValue = constructor->get(&lexicalGlobalObject, Identifier::fromString(vm, "disabledFeatures"));
     160    RETURN_IF_EXCEPTION(scope, { });
     161    if (!disabledFeaturesValue.isUndefined()) {
     162        auto disabledFeatures = convert<IDLSequence<IDLDOMString>>(lexicalGlobalObject, disabledFeaturesValue);
     163        RETURN_IF_EXCEPTION(scope, { });
     164        if (disabledFeatures.contains("shadow"_s))
     165            elementInterface->disableShadow();
     166    }
     167
    159168    auto addToGlobalObjectWithPrivateName = [&] (JSObject* objectToAdd) {
    160169        if (objectToAdd) {
  • trunk/Source/WebCore/dom/CustomElementRegistry.cpp

    r266269 r285740  
    7474    m_nameMap.add(localName, elementInterface.copyRef());
    7575
     76    if (elementInterface->isShadowDisabled())
     77        m_disabledShadowSet.add(localName);
     78
    7679    if (auto* document = m_window.document())
    7780        enqueueUpgradeInShadowIncludingTreeOrder(*document, elementInterface.get());
  • trunk/Source/WebCore/dom/CustomElementRegistry.h

    r266142 r285740  
    2929#include "QualifiedName.h"
    3030#include <wtf/HashMap.h>
     31#include <wtf/HashSet.h>
    3132#include <wtf/text/AtomString.h>
    3233#include <wtf/text/AtomStringHash.h>
     
    6869
    6970    HashMap<AtomString, Ref<DeferredPromise>>& promiseMap() { return m_promiseMap; }
     71    bool isShadowDisabled(const AtomString& name) const { return m_disabledShadowSet.contains(name); }
    7072
    7173private:
     
    7678    HashMap<const JSC::JSObject*, JSCustomElementInterface*> m_constructorMap;
    7779    HashMap<AtomString, Ref<DeferredPromise>> m_promiseMap;
     80    HashSet<AtomString> m_disabledShadowSet;
    7881
    7982    bool m_elementDefinitionIsRunning { false };
  • trunk/Source/WebCore/dom/Element.cpp

    r285640 r285740  
    24862486
    24872487    const auto& localName = element.localName();
    2488     return tagNames.get().contains(localName) || Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid;
     2488    if (tagNames.get().contains(localName))
     2489        return true;
     2490
     2491    if (Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid) {
     2492        if (auto* window = element.document().domWindow()) {
     2493            auto* registry = window->customElementRegistry();
     2494            if (registry && registry->isShadowDisabled(localName))
     2495                return false;
     2496        }
     2497
     2498        return true;
     2499    }
     2500
     2501    return false;
    24892502}
    24902503
Note: See TracChangeset for help on using the changeset viewer.