diff --git a/blink/renderer/core/dom/element.cc b/blink/renderer/core/dom/element.cc index 04f84b3b2c6f..16db88c24e5c 100644 --- a/blink/renderer/core/dom/element.cc +++ b/blink/renderer/core/dom/element.cc @@ -656,6 +656,13 @@ Node* Element::Clone(Document& factory, CloneChildrenFlag flag) const { // set copy’s shadow root’s "is declarative shadow root" property to true. cloned_shadow_root.SetIsDeclarativeShadowRoot( shadow_root->IsDeclarativeShadowRoot()); + + // 7.NEW If node’s shadow root’s "is available to element internals" is + // true, then set copy’s shadow root’s "is available to element internals" + // property to true. + cloned_shadow_root.SetAvailableToElementInternals( + shadow_root->IsAvailableToElementInternals()); + // 7.3 If the clone children flag is set, clone all the children of node’s // shadow root and append them to copy’s shadow root, with document as // specified, the clone children flag being set, and the clone shadows @@ -3591,6 +3598,15 @@ ShadowRoot& Element::AttachShadowRootInternal( FocusDelegation::kDelegateFocus); // 8. Set shadow’s "is declarative shadow root" property to false. shadow_root.SetIsDeclarativeShadowRoot(false); + + // NEW. If shadow host is a custom element, and if custom element state is + // not "precustomized" or "custom", set shadow root's + // IsAvailableToElementInternals flag to false. Otherwise, set it to true. + shadow_root.SetAvailableToElementInternals( + !(IsCustomElement() && + GetCustomElementState() != CustomElementState::kCustom && + GetCustomElementState() != CustomElementState::kPreCustomized)); + shadow_root.SetSlotAssignmentMode(slot_assignment_mode); return shadow_root; } diff --git a/blink/renderer/core/dom/shadow_root.h b/blink/renderer/core/dom/shadow_root.h index 909c14203dcf..3392b4da69b8 100644 --- a/blink/renderer/core/dom/shadow_root.h +++ b/blink/renderer/core/dom/shadow_root.h @@ -163,6 +163,15 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope { } bool IsDeclarativeShadowRoot() const { return is_declarative_shadow_root_; } + void SetAvailableToElementInternals(bool flag) { + DCHECK(!flag || GetType() == ShadowRootType::kOpen || + GetType() == ShadowRootType::kClosed); + available_to_element_internals_ = flag; + } + bool IsAvailableToElementInternals() const { + return available_to_element_internals_ || is_declarative_shadow_root_; + } + bool ContainsShadowRoots() const { return child_shadow_root_count_; } StyleSheetList& StyleSheets(); @@ -195,8 +204,9 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope { unsigned delegates_focus_ : 1; unsigned slot_assignment_mode_ : 1; unsigned is_declarative_shadow_root_ : 1; + unsigned available_to_element_internals_ : 1; unsigned needs_distribution_recalc_ : 1; - unsigned unused_ : 9; + unsigned unused_ : 8; }; inline Element* ShadowRoot::ActiveElement() const { diff --git a/blink/renderer/core/html/custom/element_internals.cc b/blink/renderer/core/html/custom/element_internals.cc index 9f6f846d02a6..f579182ddd47 100644 --- a/blink/renderer/core/html/custom/element_internals.cc +++ b/blink/renderer/core/html/custom/element_internals.cc @@ -239,7 +239,10 @@ bool ElementInternals::HasState(const AtomicString& state) const { } ShadowRoot* ElementInternals::shadowRoot() const { - return Target().AuthorShadowRoot(); + if (ShadowRoot* shadow_root = Target().AuthorShadowRoot()) { + return shadow_root->IsAvailableToElementInternals() ? shadow_root : nullptr; + } + return nullptr; } const AtomicString& ElementInternals::FastGetAttribute( diff --git a/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html b/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html index 8469a6c1f1ff..aeaa322a31c2 100644 --- a/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html +++ b/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html @@ -108,6 +108,23 @@ assert_throws_dom('NotSupportedError', () => element.attachInternals(), 'attachInternals forbidden by disabledFeatures, post-upgrade'); }, 'ElementInternals disabled by disabledFeatures'); - - +test(() => { + let constructed = false; + const element = document.createElement('x-6'); + const sr = element.attachShadow({mode: 'closed'}); + assert_true(sr instanceof ShadowRoot); + customElements.define('x-6', class extends HTMLElement { + constructor() { + super(); + assert_throws_dom('NotSupportedError', () => this.attachShadow({mode:'open'}), 'attachShadow already called'); + const elementInternals = this.attachInternals(); + assert_equals(elementInternals.shadowRoot, null, 'ElementInternals.shadowRoot should not be available for pre-attached shadow'); + constructed = true; + } + }); + assert_false(constructed); + customElements.upgrade(element); + assert_true(constructed,'Failed to construct - test failed'); + assert_equals(element.shadowRoot, null, 'shadow root is closed'); +}, 'ElementInternals.shadowRoot doesn\'t reveal pre-attached closed shadowRoot');