Skip to content

Commit 8d72f61

Browse files
mfreed7Commit Bot
authored and
Commit Bot
committed
Clean up Element::attachShadow() variants
This CL cleans up the variations of element::attachShadow(), refactoring the common subset back into attachShadow(). It also replaces the bool delegates_focus and manual_slotting parameters with enum versions that are common across declarative and imperative calls. This CL should not change any functionality. The spec text comes from my two PRs against DOM [1] and HTML [2]. [1] whatwg/dom#858 [2] whatwg/html#5465 Bug: 1042130 Change-Id: I3835b9d344d8005b6854909f287083cd984e832e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2155144 Commit-Queue: Mason Freed <[email protected]> Auto-Submit: Mason Freed <[email protected]> Reviewed-by: Kouhei Ueno <[email protected]> Cr-Commit-Position: refs/heads/master@{#760704}
1 parent 07ba894 commit 8d72f61

File tree

4 files changed

+117
-82
lines changed

4 files changed

+117
-82
lines changed

third_party/blink/renderer/core/dom/element.cc

+93-60
Original file line numberDiff line numberDiff line change
@@ -3513,29 +3513,6 @@ ShadowRoot& Element::CreateAndAttachShadowRoot(ShadowRootType type) {
35133513
return *shadow_root;
35143514
}
35153515

3516-
void Element::AttachDeclarativeShadowRoot(HTMLTemplateElement* template_element,
3517-
ShadowRootType type,
3518-
FocusDelegation focus_delegation,
3519-
SlotAssignmentMode slot_assignment) {
3520-
DCHECK(template_element);
3521-
DCHECK(type == ShadowRootType::kOpen || type == ShadowRootType::kClosed);
3522-
if (!CanAttachShadowRoot()) {
3523-
// TODO(1067488): Eventually, this should be a DOMException.
3524-
LOG(ERROR) << "Invalid shadow root host element";
3525-
return;
3526-
}
3527-
if (GetShadowRoot()) {
3528-
// TODO(1067488): Eventually, this should be a DOMException.
3529-
LOG(ERROR) << "Shadow root already present!";
3530-
return;
3531-
}
3532-
ShadowRoot* shadow_root = &AttachShadowRootInternal(
3533-
type, focus_delegation == FocusDelegation::kDelegateFocus,
3534-
slot_assignment == SlotAssignmentMode::kManual);
3535-
shadow_root->appendChild(template_element->DeclarativeShadowContent());
3536-
template_element->remove();
3537-
}
3538-
35393516
ShadowRoot* Element::GetShadowRoot() const {
35403517
return HasRareData() ? GetElementRareData()->GetShadowRoot() : nullptr;
35413518
}
@@ -3644,6 +3621,7 @@ ElementInternals& Element::EnsureElementInternals() {
36443621
}
36453622

36463623
ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) {
3624+
DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled(&GetDocument()));
36473625
if (ShadowRoot* root = GetShadowRoot()) {
36483626
if (root->IsUserAgent()) {
36493627
exception_state.ThrowDOMException(
@@ -3677,6 +3655,15 @@ ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) {
36773655
return &CreateShadowRootInternal();
36783656
}
36793657

3658+
ShadowRoot& Element::CreateShadowRootInternal() {
3659+
DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled(&GetDocument()));
3660+
DCHECK(!ClosedShadowRoot());
3661+
DCHECK(AreAuthorShadowsAllowed());
3662+
DCHECK(!AlwaysCreateUserAgentShadowRoot());
3663+
GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
3664+
return CreateAndAttachShadowRoot(ShadowRootType::V0);
3665+
}
3666+
36803667
bool Element::CanAttachShadowRoot() const {
36813668
const AtomicString& tag_name = localName();
36823669
// Checking Is{V0}CustomElement() here is just an optimization
@@ -3696,17 +3683,26 @@ bool Element::CanAttachShadowRoot() const {
36963683
tag_name == html_names::kSpanTag;
36973684
}
36983685

3699-
ShadowRoot* Element::attachShadow(const ShadowRootInit* shadow_root_init_dict,
3700-
ExceptionState& exception_state) {
3701-
DCHECK(shadow_root_init_dict->hasMode());
3686+
const char* Element::ErrorMessageForAttachShadow() const {
3687+
// https://dom.spec.whatwg.org/#concept-attach-a-shadow-root
3688+
// 1. If shadow host’s namespace is not the HTML namespace, then throw a
3689+
// "NotSupportedError" DOMException.
3690+
// 2. If shadow host’s local name is not a valid custom element name,
3691+
// "article", "aside", "blockquote", "body", "div", "footer", "h1", "h2",
3692+
// "h3", "h4", "h5", "h6", "header", "main", "nav", "p", "section", or "span",
3693+
// then throw a "NotSupportedError" DOMException.
37023694
if (!CanAttachShadowRoot()) {
3703-
exception_state.ThrowDOMException(
3704-
DOMExceptionCode::kNotSupportedError,
3705-
"This element does not support attachShadow");
3706-
return nullptr;
3695+
return "This element does not support attachShadow";
37073696
}
37083697

3709-
// Checking IsCustomElement() here is just an optimization because
3698+
// 3. If shadow host’s local name is a valid custom element name, or shadow
3699+
// host’s is value is not null, then:
3700+
// 3.1 Let definition be the result of looking up a custom element
3701+
// definition given shadow host’s node document, its namespace, its local
3702+
// name, and its is value.
3703+
// 3.2 If definition is not null and definition’s
3704+
// disable shadow is true, then throw a "NotSupportedError" DOMException.
3705+
// Note: Checking IsCustomElement() is just an optimization because
37103706
// IsValidName() is not cheap.
37113707
if (IsCustomElement() &&
37123708
(CustomElement::IsValidName(localName()) || !IsValue().IsNull())) {
@@ -3716,55 +3712,86 @@ ShadowRoot* Element::attachShadow(const ShadowRootInit* shadow_root_init_dict,
37163712
: IsValue())
37173713
: nullptr;
37183714
if (definition && definition->DisableShadow()) {
3719-
exception_state.ThrowDOMException(
3720-
DOMExceptionCode::kNotSupportedError,
3721-
"attachShadow() is disabled by disabledFeatures static field.");
3722-
return nullptr;
3715+
return "attachShadow() is disabled by disabledFeatures static field.";
37233716
}
37243717
}
37253718

3719+
// 4. If shadow host has a non-null shadow root whose is declarative shadow
3720+
// root property is false, then throw an "NotSupportedError" DOMException.
3721+
// 5. TODO(masonfreed): If shadow host has a non-null shadow root whose is
3722+
// declarative shadow root property is true, then remove all of shadow root’s
3723+
// children, in tree order. Return shadow host’s shadow root.
37263724
if (GetShadowRoot()) {
3727-
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
3728-
"Shadow root cannot be created on a host "
3729-
"which already hosts a shadow tree.");
3730-
return nullptr;
3725+
return "Shadow root cannot be created on a host "
3726+
"which already hosts a shadow tree.";
37313727
}
3728+
return nullptr;
3729+
}
37323730

3731+
ShadowRoot* Element::attachShadow(const ShadowRootInit* shadow_root_init_dict,
3732+
ExceptionState& exception_state) {
3733+
DCHECK(shadow_root_init_dict->hasMode());
37333734
ShadowRootType type = shadow_root_init_dict->mode() == "open"
37343735
? ShadowRootType::kOpen
37353736
: ShadowRootType::kClosed;
3736-
37373737
if (type == ShadowRootType::kOpen)
37383738
UseCounter::Count(GetDocument(), WebFeature::kElementAttachShadowOpen);
37393739
else
37403740
UseCounter::Count(GetDocument(), WebFeature::kElementAttachShadowClosed);
37413741

3742-
DCHECK(!shadow_root_init_dict->hasMode() || !GetShadowRoot());
3743-
bool delegates_focus = shadow_root_init_dict->hasDelegatesFocus() &&
3744-
shadow_root_init_dict->delegatesFocus();
3745-
bool manual_slotting = false;
3746-
if (shadow_root_init_dict->hasSlotAssignment()) {
3747-
manual_slotting = (shadow_root_init_dict->slotAssignment() == "manual");
3742+
auto focus_delegation = (shadow_root_init_dict->hasDelegatesFocus() &&
3743+
shadow_root_init_dict->delegatesFocus())
3744+
? FocusDelegation::kDelegateFocus
3745+
: FocusDelegation::kNone;
3746+
auto slot_assignment = (shadow_root_init_dict->hasSlotAssignment() &&
3747+
shadow_root_init_dict->slotAssignment() == "manual")
3748+
? SlotAssignmentMode::kManual
3749+
: SlotAssignmentMode::kAuto;
3750+
3751+
if (const char* error_message = ErrorMessageForAttachShadow()) {
3752+
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
3753+
error_message);
3754+
return nullptr;
37483755
}
3749-
return &AttachShadowRootInternal(type, delegates_focus, manual_slotting);
3756+
return &AttachShadowRootInternal(type, focus_delegation, slot_assignment);
37503757
}
37513758

3752-
ShadowRoot& Element::CreateShadowRootInternal() {
3753-
DCHECK(!ClosedShadowRoot());
3754-
DCHECK(AreAuthorShadowsAllowed());
3755-
DCHECK(!AlwaysCreateUserAgentShadowRoot());
3756-
GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
3757-
return CreateAndAttachShadowRoot(ShadowRootType::V0);
3759+
void Element::AttachDeclarativeShadowRoot(HTMLTemplateElement* template_element,
3760+
ShadowRootType type,
3761+
FocusDelegation focus_delegation,
3762+
SlotAssignmentMode slot_assignment) {
3763+
DCHECK(template_element);
3764+
DCHECK(type == ShadowRootType::kOpen || type == ShadowRootType::kClosed);
3765+
3766+
// 12. Run attach a shadow root with shadow host equal to declarative shadow
3767+
// host element, mode equal to declarative shadow mode, and delegates focus
3768+
// equal to declarative shadow delegates focus. If an exception was thrown by
3769+
// attach a shadow root, catch it, and report the exception.
3770+
if (const char* error_message = ErrorMessageForAttachShadow()) {
3771+
// TODO(1067488): Fire this exception at Window.
3772+
LOG(ERROR) << error_message;
3773+
return;
3774+
}
3775+
ShadowRoot& shadow_root =
3776+
AttachShadowRootInternal(type, focus_delegation, slot_assignment);
3777+
// 13.1. TODO(masonfreed): Set declarative shadow host element's shadow host's
3778+
// is declarative shadow root property to true.
3779+
// 13.2. Append the declarative template element's DocumentFragment to the
3780+
// newly-created shadow root.
3781+
shadow_root.appendChild(template_element->DeclarativeShadowContent());
3782+
// 13.3. Remove the declarative template element from the document.
3783+
template_element->remove();
37583784
}
37593785

37603786
ShadowRoot& Element::CreateUserAgentShadowRoot() {
37613787
DCHECK(!GetShadowRoot());
37623788
return CreateAndAttachShadowRoot(ShadowRootType::kUserAgent);
37633789
}
37643790

3765-
ShadowRoot& Element::AttachShadowRootInternal(ShadowRootType type,
3766-
bool delegates_focus,
3767-
bool manual_slotting) {
3791+
ShadowRoot& Element::AttachShadowRootInternal(
3792+
ShadowRootType type,
3793+
FocusDelegation focus_delegation,
3794+
SlotAssignmentMode slot_assignment_mode) {
37683795
// SVG <use> is a special case for using this API to create a closed shadow
37693796
// root.
37703797
DCHECK(CanAttachShadowRoot() || IsA<SVGUseElement>(*this));
@@ -3773,11 +3800,17 @@ ShadowRoot& Element::AttachShadowRootInternal(ShadowRootType type,
37733800
DCHECK(!AlwaysCreateUserAgentShadowRoot());
37743801

37753802
GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV1);
3803+
3804+
// 6. Let shadow be a new shadow root whose node document is shadow host’s
3805+
// node document, host is shadow host, and mode is mode.
3806+
// 9. Set shadow host’s shadow root to shadow.
37763807
ShadowRoot& shadow_root = CreateAndAttachShadowRoot(type);
3777-
shadow_root.SetDelegatesFocus(delegates_focus);
3778-
shadow_root.SetSlotAssignmentMode(manual_slotting
3779-
? SlotAssignmentMode::kManual
3780-
: SlotAssignmentMode::kAuto);
3808+
// 7. Set shadow’s delegates focus to delegates focus.
3809+
// 8. TODO(masonfreed): Set shadow’s is declarative shadow root property to
3810+
// false.
3811+
shadow_root.SetDelegatesFocus(focus_delegation ==
3812+
FocusDelegation::kDelegateFocus);
3813+
shadow_root.SetSlotAssignmentMode(slot_assignment_mode);
37813814
return shadow_root;
37823815
}
37833816

third_party/blink/renderer/core/dom/element.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ enum class ElementFlags {
113113
};
114114

115115
enum class ShadowRootType;
116-
enum class FocusDelegation;
117-
enum class SlotAssignmentMode;
116+
117+
enum class SlotAssignmentMode { kManual, kAuto };
118+
enum class FocusDelegation { kNone, kDelegateFocus };
118119

119120
enum class SelectionBehaviorOnFocus {
120121
kReset,
@@ -565,6 +566,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
565566
// throws an exception. Multiple shadow roots are allowed only when
566567
// createShadowRoot() is used without any parameters from JavaScript.
567568
ShadowRoot* createShadowRoot(ExceptionState&);
569+
568570
ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&);
569571

570572
void AttachDeclarativeShadowRoot(HTMLTemplateElement*,
@@ -576,9 +578,10 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
576578
return CreateShadowRootInternal();
577579
}
578580
ShadowRoot& CreateUserAgentShadowRoot();
579-
ShadowRoot& AttachShadowRootInternal(ShadowRootType,
580-
bool delegates_focus = false,
581-
bool manual_slotting = false);
581+
ShadowRoot& AttachShadowRootInternal(
582+
ShadowRootType,
583+
FocusDelegation focus_delegation = FocusDelegation::kNone,
584+
SlotAssignmentMode slot_assignment_mode = SlotAssignmentMode::kAuto);
582585

583586
// Returns the shadow root attached to this element if it is a shadow host.
584587
ShadowRoot* GetShadowRoot() const;
@@ -1031,8 +1034,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
10311034
bool IsDocumentNode() const =
10321035
delete; // This will catch anyone doing an unnecessary check.
10331036

1034-
bool CanAttachShadowRoot() const;
10351037
ShadowRoot& CreateShadowRootInternal();
1038+
bool CanAttachShadowRoot() const;
1039+
const char* ErrorMessageForAttachShadow() const;
10361040

10371041
void StyleAttributeChanged(const AtomicString& new_style_string,
10381042
AttributeModificationReason);

third_party/blink/renderer/core/dom/shadow_root.h

-4
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ class WhitespaceAttacher;
4646

4747
enum class ShadowRootType { V0, kOpen, kClosed, kUserAgent };
4848

49-
enum class SlotAssignmentMode { kManual, kAuto };
50-
51-
enum class FocusDelegation { kNone, kDelegateFocus };
52-
5349
class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
5450
DEFINE_WRAPPERTYPEINFO();
5551
USING_GARBAGE_COLLECTED_MIXIN(ShadowRoot);

third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc

+14-12
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,23 @@ class WebFrameSerializerSanitizationTest : public testing::Test {
9494
test::RunPendingTasks();
9595
}
9696

97-
ShadowRoot* SetShadowContent(TreeScope& scope,
98-
const char* host,
99-
ShadowRootType shadow_type,
100-
const char* shadow_content,
101-
bool delegates_focus = false) {
97+
ShadowRoot* SetShadowContent(
98+
TreeScope& scope,
99+
const char* host,
100+
ShadowRootType shadow_type,
101+
const char* shadow_content,
102+
FocusDelegation focus_delegation = FocusDelegation::kNone) {
102103
Element* host_element = scope.getElementById(AtomicString::FromUTF8(host));
103104
ShadowRoot* shadow_root;
104105
if (shadow_type == ShadowRootType::V0) {
105-
DCHECK(!delegates_focus);
106+
DCHECK_EQ(focus_delegation, FocusDelegation::kNone);
106107
shadow_root = &host_element->CreateV0ShadowRootForTesting();
107108
} else {
108-
shadow_root =
109-
&host_element->AttachShadowRootInternal(shadow_type, delegates_focus);
109+
shadow_root = &host_element->AttachShadowRootInternal(shadow_type,
110+
focus_delegation);
110111
}
111-
shadow_root->SetDelegatesFocus(delegates_focus);
112+
shadow_root->SetDelegatesFocus(focus_delegation ==
113+
FocusDelegation::kDelegateFocus);
112114
shadow_root->setInnerHTML(String::FromUTF8(shadow_content),
113115
ASSERT_NO_EXCEPTION);
114116
scope.GetDocument().View()->UpdateAllLifecyclePhases(
@@ -337,9 +339,9 @@ TEST_F(WebFrameSerializerSanitizationTest, ShadowDOM) {
337339
LoadFrame("http://www.test.com", "shadow_dom.html", "text/html");
338340
Document* document = MainFrameImpl()->GetFrame()->GetDocument();
339341
SetShadowContent(*document, "h1", ShadowRootType::V0, "V0 shadow");
340-
ShadowRoot* shadowRoot =
341-
SetShadowContent(*document, "h2", ShadowRootType::kOpen,
342-
"Parent shadow\n<p id=\"h3\">Foo</p>", true);
342+
ShadowRoot* shadowRoot = SetShadowContent(
343+
*document, "h2", ShadowRootType::kOpen,
344+
"Parent shadow\n<p id=\"h3\">Foo</p>", FocusDelegation::kDelegateFocus);
343345
SetShadowContent(*shadowRoot, "h3", ShadowRootType::kClosed, "Nested shadow");
344346
String mhtml = WebFrameSerializerTestHelper::GenerateMHTML(MainFrameImpl());
345347

0 commit comments

Comments
 (0)