Element* SlotScopedTraversal::next(const Element& current) { // current.assignedSlot returns a slot only when current is assigned explicitly // If current is assigned to a slot, return a descendant of current, which is in the assigned scope of the same slot as current. HTMLSlotElement* slot = current.assignedSlot(); Element* nearestAncestorAssignedToSlot = SlotScopedTraversal::nearestAncestorAssignedToSlot(current); if (slot) { if (Element* next = ElementTraversal::next(current, ¤t)) return next; } else { // If current is in assigned scope, find an assigned ancestor. ASSERT(nearestAncestorAssignedToSlot); if (Element* next = ElementTraversal::next(current, nearestAncestorAssignedToSlot)) return next; slot = nearestAncestorAssignedToSlot->assignedSlot(); ASSERT(slot); } HeapVector<Member<Node>> assignedNodes = slot->getAssignedNodes(); size_t currentIndex = assignedNodes.find(*nearestAncestorAssignedToSlot); ASSERT(currentIndex != kNotFound); for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) { if (assignedNodes[currentIndex]->isElementNode()) return toElement(assignedNodes[currentIndex]); } return nullptr; }
Node* FlatTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, TraversalDirection direction) { HTMLSlotElement* slot = finalDestinationSlotFor(node); if (!slot) return nullptr; if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForward ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) return siblingInDistributedNodes; return traverseSiblings(*slot, direction); }
void SlotAssignment::assign(Node& hostChild, HTMLSlotElement& slot) { m_assignment.add(&hostChild, &slot); slot.appendAssignedNode(hostChild); if (isHTMLSlotElement(hostChild)) slot.appendDistributedNodes(toHTMLSlotElement(hostChild).getDistributedNodes()); else slot.appendDistributedNode(hostChild); }
static HTMLSlotElement* finalDestinationSlotFor(const Node& node) { HTMLSlotElement* slot = node.assignedSlot(); if (!slot) return nullptr; for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assignedSlot()) { slot = next; } return slot; }
static bool wasInShadowTreeBeforeInserted(HTMLSlotElement& slot, ContainerNode& insertionPoint) { ShadowRoot* root1 = slot.containingShadowRoot(); ShadowRoot* root2 = insertionPoint.containingShadowRoot(); if (root1 && root2 && root1 == root2) return false; return root1; }
static void flattenAssignedNodes(Vector<Node*>& nodes, const HTMLSlotElement& slot) { auto* assignedNodes = slot.assignedNodes(); if (!assignedNodes) { for (Node* child = slot.firstChild(); child; child = child->nextSibling()) { if (is<HTMLSlotElement>(*child)) flattenAssignedNodes(nodes, downcast<HTMLSlotElement>(*child)); else if (is<Text>(*child) || is<Element>(*child)) nodes.append(child); } return; } for (Node* node : *assignedNodes) { if (is<HTMLSlotElement>(*node)) flattenAssignedNodes(nodes, downcast<HTMLSlotElement>(*node)); else nodes.append(node); } }
void SlotAssignment::didChangeSlot(const AtomicString& slotAttrValue, ShadowRoot& shadowRoot) { auto& slotName = slotNameFromAttributeValue(slotAttrValue); auto it = m_slots.find(slotName); if (it == m_slots.end()) return; HTMLSlotElement* slotElement = findFirstSlotElement(*it->value, shadowRoot); if (!slotElement) return; shadowRoot.host()->invalidateStyleAndRenderersForSubtree(); m_slotAssignmentsIsValid = false; if (shadowRoot.mode() == ShadowRootMode::UserAgent) return; slotElement->enqueueSlotChangeEvent(); }
void StyleInvalidator::invalidateSlotDistributedElements(HTMLSlotElement& slot, const RecursionData& recursionData) const { for (auto& distributedNode : slot.getDistributedNodes()) { if (distributedNode->needsStyleRecalc()) continue; if (!distributedNode->isElementNode()) continue; if (recursionData.matchesCurrentInvalidationSetsAsSlotted(toElement(*distributedNode))) distributedNode->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); } }
Element* SlotScopedTraversal::next(const Element& current) { Element* nearestInclusiveAncestorAssignedToSlot = SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(current); DCHECK(nearestInclusiveAncestorAssignedToSlot); // Search within children of an element which is assigned to a slot. if (Element* next = nextSkippingChildrenOfShadowHost( current, *nearestInclusiveAncestorAssignedToSlot)) return next; // Seek to the next element assigned to the same slot. HTMLSlotElement* slot = nearestInclusiveAncestorAssignedToSlot->assignedSlot(); DCHECK(slot); const HeapVector<Member<Node>>& assignedNodes = slot->assignedNodes(); size_t currentIndex = assignedNodes.find(*nearestInclusiveAncestorAssignedToSlot); DCHECK_NE(currentIndex, kNotFound); for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) { if (assignedNodes[currentIndex]->isElementNode()) return toElement(assignedNodes[currentIndex]); } return nullptr; }