Commit 0fd72b87 authored by Kyoko Muto's avatar Kyoko Muto Committed by Commit Bot

Add Assign function

As the second step of implementing "Imperative Shadow DOM Distribution API",
this CL make assign function to assign nodes to slot in manual slotting mode.

This CL also introduces HeapVector for each slot
to store the nodes that assign introduced.

BUG=869308

Change-Id: I9b02a70f601364123fb565221d3def760408bc2a
Reviewed-on: https://chromium-review.googlesource.com/1166925Reviewed-by: default avatarHayato Ito <hayato@chromium.org>
Commit-Queue: Kyoko Muto <kymuto@google.com>
Cr-Commit-Position: refs/heads/master@{#583178}
parent 3fac86d9
...@@ -6,21 +6,47 @@ See https://crbug.com/869308 ...@@ -6,21 +6,47 @@ See https://crbug.com/869308
<script src="../resources/testharness.js"></script> <script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<div id="host"> <div id="host">
<div id="child1"></div>
<div id="child2"></div>
<div id="child3"></div>
</div> </div>
<div id="host1"> <div id="host1">
</div> </div>
</div>
<div id="host2">
</div>
</div>
<div id="host3">
</div>
<script> <script>
const host = document.querySelector('#host'); const host = document.querySelector('#host');
const host1 = document.querySelector('#host1'); const host1 = document.querySelector('#host1');
const host2 = document.querySelector('#host2');
const host3 = document.querySelector('#host3');
const child1 = document.querySelector('#child1');
const child2 = document.querySelector('#child2');
const child3 = document.querySelector('#child3');
const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' });
const slot1 = document.createElement('slot');
shadow_root.appendChild(slot1);
test(() => { test(() => {
assert_not_equals(host.attachShadow({ mode: 'open', slotting: 'manual' }), assert_not_equals(host1.attachShadow({ mode: 'open', slotting: 'manual' }),
null, 'slotting manual should work'); null, 'slotting manual should work');
assert_not_equals(host1.attachShadow({ mode: 'open', slotting: 'auto' }), assert_not_equals(host2.attachShadow({ mode: 'open', slotting: 'auto' }),
null, 'slotting auto should work'); null, 'slotting auto should work');
assert_throws(new TypeError(), () => { assert_throws(new TypeError(), () => {
host.attachShadow({ mode: 'open', slotting: 'exceptional' })}, host3.attachShadow({ mode: 'open', slotting: 'exceptional' })},
'others should throw exception'); 'others should throw exception');
}, 'attachShadow can take slotting parameter'); }, 'attachShadow can take slotting parameter');
test(() => {
assert_array_equals(slot1.assignedElements(), []);
slot1.assign([child1]);
assert_array_equals(slot1.assignedNodes(), [child1]);
slot1.assign([child2,child3]);
assert_array_equals(slot1.assignedNodes(), [child2,child3]);
}, 'assignedNodes can be used in manual slotting');
</script> </script>
...@@ -919,6 +919,7 @@ html element select ...@@ -919,6 +919,7 @@ html element select
html element shadow html element shadow
property getDistributedNodes property getDistributedNodes
html element slot html element slot
property assign
property assignedElements property assignedElements
property assignedNodes property assignedNodes
property name property name
......
...@@ -3497,6 +3497,7 @@ interface HTMLShadowElement : HTMLElement ...@@ -3497,6 +3497,7 @@ interface HTMLShadowElement : HTMLElement
interface HTMLSlotElement : HTMLElement interface HTMLSlotElement : HTMLElement
attribute @@toStringTag attribute @@toStringTag
getter name getter name
method assign
method assignedElements method assignedElements
method assignedNodes method assignedNodes
method constructor method constructor
......
...@@ -112,6 +112,10 @@ Node* ShadowRoot::Clone(Document&, CloneChildrenFlag) const { ...@@ -112,6 +112,10 @@ Node* ShadowRoot::Clone(Document&, CloneChildrenFlag) const {
return nullptr; return nullptr;
} }
void ShadowRoot::SetSlotting(ShadowRootSlotting slotting) {
slotting_ = static_cast<unsigned short>(slotting);
}
String ShadowRoot::InnerHTMLAsString() const { String ShadowRoot::InnerHTMLAsString() const {
return CreateMarkup(this, kChildrenOnly); return CreateMarkup(this, kChildrenOnly);
} }
......
...@@ -158,9 +158,7 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope { ...@@ -158,9 +158,7 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
void SetDelegatesFocus(bool flag) { delegates_focus_ = flag; } void SetDelegatesFocus(bool flag) { delegates_focus_ = flag; }
bool delegatesFocus() const { return delegates_focus_; } bool delegatesFocus() const { return delegates_focus_; }
void SetSlotting(ShadowRootSlotting slotting) { void SetSlotting(ShadowRootSlotting slotting);
slotting_ = static_cast<unsigned short>(slotting);
}
bool IsManualSlotting() { bool IsManualSlotting() {
return slotting_ == return slotting_ ==
static_cast<unsigned short>(ShadowRootSlotting::kManual); static_cast<unsigned short>(ShadowRootSlotting::kManual);
......
...@@ -241,7 +241,16 @@ void SlotAssignment::RecalcAssignment() { ...@@ -241,7 +241,16 @@ void SlotAssignment::RecalcAssignment() {
HTMLSlotElement* slot = nullptr; HTMLSlotElement* slot = nullptr;
if (!is_user_agent) { if (!is_user_agent) {
slot = FindSlotByName(child.SlotName()); if (owner_->IsManualSlotting()) {
for (auto candidate : Slots()) {
if (candidate->ContainsInAssignedNodesCandidates(child)) {
slot = candidate;
break;
}
}
} else {
slot = FindSlotByName(child.SlotName());
}
} else { } else {
if (user_agent_custom_assign_slot && ShouldAssignToCustomSlot(child)) { if (user_agent_custom_assign_slot && ShouldAssignToCustomSlot(child)) {
slot = user_agent_custom_assign_slot; slot = user_agent_custom_assign_slot;
......
...@@ -189,6 +189,18 @@ const HeapVector<Member<Element>> HTMLSlotElement::AssignedElementsForBinding( ...@@ -189,6 +189,18 @@ const HeapVector<Member<Element>> HTMLSlotElement::AssignedElementsForBinding(
return elements; return elements;
} }
void HTMLSlotElement::assign(HeapVector<Member<Node>> nodes) {
ContainingShadowRoot()->GetSlotAssignment().SetNeedsAssignmentRecalc();
assigned_nodes_candidates_.clear();
for (Member<Node> child : nodes) {
assigned_nodes_candidates_.insert(child);
}
}
bool HTMLSlotElement::ContainsInAssignedNodesCandidates(Node& host_child) {
return assigned_nodes_candidates_.Contains(&host_child);
}
const HeapVector<Member<Node>>& HTMLSlotElement::GetDistributedNodes() { const HeapVector<Member<Node>>& HTMLSlotElement::GetDistributedNodes() {
DCHECK(!RuntimeEnabledFeatures::IncrementalShadowDOMEnabled()); DCHECK(!RuntimeEnabledFeatures::IncrementalShadowDOMEnabled());
DCHECK(!NeedsDistributionRecalc()); DCHECK(!NeedsDistributionRecalc());
...@@ -691,6 +703,7 @@ void HTMLSlotElement::Trace(blink::Visitor* visitor) { ...@@ -691,6 +703,7 @@ void HTMLSlotElement::Trace(blink::Visitor* visitor) {
visitor->Trace(distributed_nodes_); visitor->Trace(distributed_nodes_);
visitor->Trace(old_distributed_nodes_); visitor->Trace(old_distributed_nodes_);
visitor->Trace(distributed_indices_); visitor->Trace(distributed_indices_);
visitor->Trace(assigned_nodes_candidates_);
HTMLElement::Trace(visitor); HTMLElement::Trace(visitor);
} }
......
...@@ -53,6 +53,9 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement { ...@@ -53,6 +53,9 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
const HeapVector<Member<Element>> AssignedElementsForBinding( const HeapVector<Member<Element>> AssignedElementsForBinding(
const AssignedNodesOptions&); const AssignedNodesOptions&);
void assign(HeapVector<Member<Node>> nodes);
bool ContainsInAssignedNodesCandidates(Node&);
const HeapVector<Member<Node>> FlattenedAssignedNodes(); const HeapVector<Member<Node>> FlattenedAssignedNodes();
Node* FirstAssignedNode() const { Node* FirstAssignedNode() const {
...@@ -161,6 +164,8 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement { ...@@ -161,6 +164,8 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
HeapVector<Member<Node>> assigned_nodes_; HeapVector<Member<Node>> assigned_nodes_;
bool slotchange_event_enqueued_ = false; bool slotchange_event_enqueued_ = false;
HeapHashSet<Member<Node>> assigned_nodes_candidates_;
// For IncrementalShadowDOM // For IncrementalShadowDOM
HeapVector<Member<Node>> flat_tree_children_; HeapVector<Member<Node>> flat_tree_children_;
......
...@@ -30,4 +30,5 @@ interface HTMLSlotElement : HTMLElement { ...@@ -30,4 +30,5 @@ interface HTMLSlotElement : HTMLElement {
[CEReactions, Reflect] attribute DOMString name; [CEReactions, Reflect] attribute DOMString name;
[ImplementedAs=AssignedNodesForBinding] sequence<Node> assignedNodes(optional AssignedNodesOptions options); [ImplementedAs=AssignedNodesForBinding] sequence<Node> assignedNodes(optional AssignedNodesOptions options);
[ImplementedAs=AssignedElementsForBinding] sequence<Elements> assignedElements(optional AssignedNodesOptions options); [ImplementedAs=AssignedElementsForBinding] sequence<Elements> assignedElements(optional AssignedNodesOptions options);
[RuntimeEnabled=ManualSlotting] void assign(sequence<Node> nodes);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment