Skip to content
Permalink
Browse files
Add rudimentary implementation of imperative slot API
https://bugs.webkit.org/show_bug.cgi?id=243772

Reviewed by Antti Koivisto.

Add a very basic implementation of imperative slot API.

NodeRareData now contains a back reference to the slot element to which the node is manually assigned.
Each slot element remembers which nodes were last manually assigned.

These two states are updated by ManualSlotAssignment.

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/html/dom/idlharness.https-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/shadow-dom/imperative-slot-api-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/shadow-dom/imperative-slot-api-slotchange-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/shadow-dom/imperative-slot-fallback-clear-expected.txt:
* LayoutTests/platform/gtk/imported/w3c/web-platform-tests/html/dom/idlharness.https-expected.txt:
* LayoutTests/platform/ios-wk2/imported/w3c/web-platform-tests/html/dom/idlharness.https-expected.txt:
* LayoutTests/platform/ipad/imported/w3c/web-platform-tests/html/dom/idlharness.https-expected.txt:
* LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/html/dom/idlharness.https-expected.txt:

* Source/WebCore/dom/Node.cpp:
(WebCore::stringForRareDataUseType):
(WebCore::Node::manuallyAssignedSlot const): Added.
(WebCore::Node::setManuallyAssignedSlot): Added.
* Source/WebCore/dom/Node.h:

* Source/WebCore/dom/NodeRareData.cpp:
* Source/WebCore/dom/NodeRareData.h:
(WebCore::NodeRareData::manuallyAssignedSlot): Added.
(WebCore::NodeRareData::setManuallyAssignedSlot): Added.
(WebCore::NodeRareData::useTypes const):

* Source/WebCore/dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::addSlotElementByName): Construct ManualSlotAssignment as needed.
(WebCore::ShadowRoot::slotManualAssignmentDidChange):
* Source/WebCore/dom/ShadowRoot.h:

* Source/WebCore/dom/SlotAssignment.cpp:
(WebCore::NamedSlotAssignment::slotManualAssignmentDidChange): Added. No-op.
(WebCore::ManualSlotAssignment::findAssignedSlot): Ditto.
(WebCore::effectiveAssignedNodes): Ditto.
(WebCore::ManualSlotAssignment::assignedNodesForSlot): Ditto.
(WebCore::ManualSlotAssignment::renameSlotElement): Added. No-op.
(WebCore::ManualSlotAssignment::addSlotElementByName): Ditto.
(WebCore::ManualSlotAssignment::removeSlotElementByName): Ditto.
(WebCore::ManualSlotAssignment::slotManualAssignmentDidChange): Added. This implements the main logic
for updating manually assigned nodes. First, we clear slot-back references in the previous assignment,
and destroy any renderer created for the previous assignment. Second, we go through the current assignment
and find any slot in the same shadow tree from which we're taking nodes away. Finally, we visit each
slot which got affected by this assignment in the tree order and enqueue slotchange events as needed.
(WebCore::ManualSlotAssignment::slotFallbackDidChange): Added.
(WebCore::ManualSlotAssignment::hostChildElementDidChange): Ditto.
(WebCore::ManualSlotAssignment::hostChildElementDidChangeSlotAttribute): Ditto.
(WebCore::ManualSlotAssignment::willRemoveAssignedNode): Ditto.
(WebCore::ManualSlotAssignment::didRemoveAllChildrenOfShadowHost): Ditto.
(WebCore::ManualSlotAssignment::didMutateTextNodesOfShadowHost): Ditto.
* Source/WebCore/dom/SlotAssignment.h:
(WebCore::ManualSlotAssignment): Added.
(WebCore::ManualSlotAssignment::Slot): Added.

* Source/WebCore/html/HTMLSlotElement.cpp:
(WebCore::HTMLSlotElement::assign): Added.
(WebCore::HTMLSlotElement::removeManuallyAssignedNode): Added.
* Source/WebCore/html/HTMLSlotElement.h:

* Source/WebCore/html/HTMLSlotElement.idl:

Canonical link: https://commits.webkit.org/253320@main
  • Loading branch information
rniwa committed Aug 11, 2022
1 parent 2c61b57 commit b3a5c931e34b75897600609a07df70e3dc0924cc
Show file tree
Hide file tree
Showing 20 changed files with 301 additions and 73 deletions.
@@ -535,9 +535,6 @@ fast/history/page-cache-active-fetch-response-blobReadAsBlob.html [ DumpJSConsol
fast/dom/navigator-detached-no-crash.html [ DumpJSConsoleLogInStdErr ]
webaudio/audioworket-out-of-memory.html [ DumpJSConsoleLogInStdErr ]

webkit.org/b/242376 imported/w3c/web-platform-tests/shadow-dom/imperative-slot-layout-invalidation-001.html [ ImageOnlyFailure ]
webkit.org/b/243460 imported/w3c/web-platform-tests/shadow-dom/slot-fallback-content-006.html [ ImageOnlyFailure ]

# Newly imported WPT tests that are timing out.
imported/w3c/web-platform-tests/clipboard-apis/feature-policy/clipboard-read/clipboard-read-disabled-by-feature-policy.tentative.https.sub.html [ Skip ]
imported/w3c/web-platform-tests/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-attribute-cross-origin-tentative.https.sub.html [ Skip ]
@@ -1,3 +1,7 @@
CONSOLE MESSAGE: [blocked] The page at https://localhost:9443/html/dom/idlharness.https.html was not allowed to display insecure content from http://invalid/.

CONSOLE MESSAGE: Not allowed to request resource
CONSOLE MESSAGE: EventSource cannot load http://invalid/ due to access control checks.
HTML IDL tests


@@ -3898,16 +3902,16 @@ PASS HTMLSlotElement interface: existence and properties of interface prototype
PASS HTMLSlotElement interface: attribute name
PASS HTMLSlotElement interface: operation assignedNodes(optional AssignedNodesOptions)
PASS HTMLSlotElement interface: operation assignedElements(optional AssignedNodesOptions)
FAIL HTMLSlotElement interface: operation assign((Element or Text)...) assert_own_property: interface prototype object missing non-static operation expected property "assign" missing
PASS HTMLSlotElement interface: operation assign((Element or Text)...)
PASS HTMLSlotElement must be primary interface of document.createElement("slot")
PASS Stringification of document.createElement("slot")
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedNodes(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedNodes(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedElements(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedElements(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
FAIL HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type assert_inherits: property "assign" not found in prototype chain
FAIL HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError assert_inherits: property "assign" not found in prototype chain
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type
PASS HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLCanvasElement interface: existence and properties of interface object
PASS HTMLCanvasElement interface object length
PASS HTMLCanvasElement interface object name
@@ -1,17 +1,17 @@

PASS attachShadow can take slotAssignment parameter.
FAIL slot.attach() should take variadic not sequence. tTree.s1.assign is not a function. (In 'tTree.s1.assign(c1,c2)', 'tTree.s1.assign' is undefined)
FAIL Imperative slot API can assign nodes in manual slot assignment. assert_equals: expected null but got Element node <slot id="s1"></slot>
FAIL Order of slottables is preserved in manual slot assignment. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c2, tTree.c3, tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Previously assigned slottable is moved to new slot when it's reassigned. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c2, tTree.c3, tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Order and assignment of nodes are preserved during multiple assignment in a row. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Assigning invalid nodes should be allowed. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c4, tTree.c2)', 'tTree.s1.assign' is undefined)
FAIL Moving a slot to a new host, the slot loses its previously assigned slottables. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3)', 'tTree.s1.assign' is undefined)
FAIL Moving a slot's tree order position within a shadow host has no impact on its assigned slottables. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3)', 'tTree.s1.assign' is undefined)
FAIL Appending slottable to different host, it loses slot assignment. It can be re-assigned within a new host. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3)', 'tTree.s1.assign' is undefined)
FAIL Previously assigned node should not be assigned if slot moved to a new shadow root. The node is re-assigned when moved back. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Assignment with the same node in parameters should be ignored, first one wins. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c1, tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Removing a slot from DOM resets its slottable's slot assignment. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3)', 'tTree.s1.assign' is undefined)
FAIL Nodes can be assigned even if slots or nodes aren't in the same tree. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2)', 'tTree.s1.assign' is undefined)
FAIL Removing a node from the document does not break manually assigned slot linkage. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2)', 'tTree.s1.assign' is undefined)
PASS slot.attach() should take variadic not sequence.
PASS Imperative slot API can assign nodes in manual slot assignment.
PASS Order of slottables is preserved in manual slot assignment.
PASS Previously assigned slottable is moved to new slot when it's reassigned.
PASS Order and assignment of nodes are preserved during multiple assignment in a row.
PASS Assigning invalid nodes should be allowed.
PASS Moving a slot to a new host, the slot loses its previously assigned slottables.
PASS Moving a slot's tree order position within a shadow host has no impact on its assigned slottables.
PASS Appending slottable to different host, it loses slot assignment. It can be re-assigned within a new host.
PASS Previously assigned node should not be assigned if slot moved to a new shadow root. The node is re-assigned when moved back.
PASS Assignment with the same node in parameters should be ignored, first one wins.
PASS Removing a slot from DOM resets its slottable's slot assignment.
FAIL Nodes can be assigned even if slots or nodes aren't in the same tree. assert_equals: expected Element node <slot id="s1"></slot> but got null
PASS Removing a node from the document does not break manually assigned slot linkage.

@@ -1,15 +1,17 @@

FAIL slotchange event must not fire synchronously. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL slotchange event should not fire when assignments do not change assignedNodes. tTree.s1.assign is not a function. (In 'tTree.s1.assign()', 'tTree.s1.assign' is undefined)
FAIL slotchange event should not fire when same node is assigned. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event when slot's assigned nodes changes. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event on previous slot and new slot when node is reassigned. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event on node assignment and when assigned node is removed. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event when order of assigned nodes changes. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1, tTree.c2)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event when assigned node is removed. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL Fire slotchange event when removing a slot from Shadows Root that changes its assigned nodes. tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)
FAIL No slotchange event when adding or removing an empty slot. assert_equals: expected 0 but got 1
FAIL No slotchange event when adding another slotable. assert_equals: expected 0 but got 1
FAIL Fire slotchange event when assign node to nested slot, ensure event bubbles ups. tTree.s3.assign is not a function. (In 'tTree.s3.assign(tTree.s1)', 'tTree.s3.assign' is undefined)
FAIL Signal a slot change should be done in tree order. promise_test: Unhandled rejection with value: object "TypeError: tTree.s1.assign is not a function. (In 'tTree.s1.assign(tTree.c1)', 'tTree.s1.assign' is undefined)"
Harness Error (TIMEOUT), message = null

PASS slotchange event must not fire synchronously.
PASS slotchange event should not fire when assignments do not change assignedNodes.
PASS slotchange event should not fire when same node is assigned.
PASS Fire slotchange event when slot's assigned nodes changes.
PASS Fire slotchange event on previous slot and new slot when node is reassigned.
PASS Fire slotchange event on node assignment and when assigned node is removed.
PASS Fire slotchange event when order of assigned nodes changes.
TIMEOUT Fire slotchange event when assigned node is removed. Test timed out
NOTRUN Fire slotchange event when removing a slot from Shadows Root that changes its assigned nodes.
PASS No slotchange event when adding or removing an empty slot.
PASS No slotchange event when adding another slotable.
PASS Fire slotchange event when assign node to nested slot, ensure event bubbles ups.
NOTRUN Signal a slot change should be done in tree order.

@@ -1,4 +1,4 @@

FAIL Text node fallback should be cleared in a subsequently layout slot.assign is not a function. (In 'slot.assign(host.firstChild)', 'slot.assign' is undefined)
FAIL Element fallback should be cleared in a subsequent layout slot.assign is not a function. (In 'slot.assign(host.firstChild)', 'slot.assign' is undefined)
PASS Text node fallback should be cleared in a subsequently layout
PASS Element fallback should be cleared in a subsequent layout

@@ -3898,16 +3898,16 @@ PASS HTMLSlotElement interface: existence and properties of interface prototype
PASS HTMLSlotElement interface: attribute name
PASS HTMLSlotElement interface: operation assignedNodes(optional AssignedNodesOptions)
PASS HTMLSlotElement interface: operation assignedElements(optional AssignedNodesOptions)
FAIL HTMLSlotElement interface: operation assign((Element or Text)...) assert_own_property: interface prototype object missing non-static operation expected property "assign" missing
PASS HTMLSlotElement interface: operation assign((Element or Text)...)
PASS HTMLSlotElement must be primary interface of document.createElement("slot")
PASS Stringification of document.createElement("slot")
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedNodes(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedNodes(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedElements(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedElements(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
FAIL HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type assert_inherits: property "assign" not found in prototype chain
FAIL HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError assert_inherits: property "assign" not found in prototype chain
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type
PASS HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLCanvasElement interface: existence and properties of interface object
PASS HTMLCanvasElement interface object length
PASS HTMLCanvasElement interface object name
@@ -5901,4 +5901,3 @@ PASS Document interface: documentWithHandlers must inherit property "oncut" with
PASS Document interface: documentWithHandlers must inherit property "onpaste" with the proper type
PASS Document interface: documentWithHandlers must inherit property "activeElement" with the proper type
PASS ShadowRoot interface: attribute activeElement

@@ -3888,16 +3888,16 @@ PASS HTMLSlotElement interface: existence and properties of interface prototype
PASS HTMLSlotElement interface: attribute name
PASS HTMLSlotElement interface: operation assignedNodes(optional AssignedNodesOptions)
PASS HTMLSlotElement interface: operation assignedElements(optional AssignedNodesOptions)
FAIL HTMLSlotElement interface: operation assign((Element or Text)...) assert_own_property: interface prototype object missing non-static operation expected property "assign" missing
PASS HTMLSlotElement interface: operation assign((Element or Text)...)
PASS HTMLSlotElement must be primary interface of document.createElement("slot")
PASS Stringification of document.createElement("slot")
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedNodes(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedNodes(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedElements(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedElements(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
FAIL HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type assert_inherits: property "assign" not found in prototype chain
FAIL HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError assert_inherits: property "assign" not found in prototype chain
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type
PASS HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLCanvasElement interface: existence and properties of interface object
PASS HTMLCanvasElement interface object length
PASS HTMLCanvasElement interface object name
@@ -5891,4 +5891,3 @@ PASS Document interface: documentWithHandlers must inherit property "oncut" with
PASS Document interface: documentWithHandlers must inherit property "onpaste" with the proper type
PASS Document interface: documentWithHandlers must inherit property "activeElement" with the proper type
PASS ShadowRoot interface: attribute activeElement

@@ -3874,16 +3874,16 @@ PASS HTMLSlotElement interface: existence and properties of interface prototype
PASS HTMLSlotElement interface: attribute name
PASS HTMLSlotElement interface: operation assignedNodes(optional AssignedNodesOptions)
PASS HTMLSlotElement interface: operation assignedElements(optional AssignedNodesOptions)
FAIL HTMLSlotElement interface: operation assign((Element or Text)...) assert_own_property: interface prototype object missing non-static operation expected property "assign" missing
PASS HTMLSlotElement interface: operation assign((Element or Text)...)
PASS HTMLSlotElement must be primary interface of document.createElement("slot")
PASS Stringification of document.createElement("slot")
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedNodes(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedNodes(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedElements(optional AssignedNodesOptions)" with the proper type
PASS HTMLSlotElement interface: calling assignedElements(optional AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError
FAIL HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type assert_inherits: property "assign" not found in prototype chain
FAIL HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError assert_inherits: property "assign" not found in prototype chain
PASS HTMLSlotElement interface: document.createElement("slot") must inherit property "assign((Element or Text)...)" with the proper type
PASS HTMLSlotElement interface: calling assign((Element or Text)...) on document.createElement("slot") with too few arguments must throw TypeError
PASS HTMLCanvasElement interface: existence and properties of interface object
PASS HTMLCanvasElement interface object length
PASS HTMLCanvasElement interface object name
@@ -5890,4 +5890,3 @@ PASS Document interface: documentWithHandlers must inherit property "oncut" with
PASS Document interface: documentWithHandlers must inherit property "onpaste" with the proper type
PASS Document interface: documentWithHandlers must inherit property "activeElement" with the proper type
PASS ShadowRoot interface: attribute activeElement

0 comments on commit b3a5c93

Please sign in to comment.