/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// If assignedNodes is empty, use children of slot as fallback content. if (assignedNodes.IsEmpty()) { for (nsIContent* child = aSlot->GetFirstChild(); child;
child = child->GetNextSibling()) { if (!child->IsSlotable()) { continue;
}
// no-op if the input nodes and the assigned nodes are identical // This also works if the two 'assign' calls are like // > slot.assign(node1, node2); // > slot.assign(node1, node2, node1, node2); if (!mAssignedNodes.IsEmpty() && aNodes.Length() >= mAssignedNodes.Length()) {
nsTHashMap<nsPtrHashKey<nsIContent>, size_t> nodeIndexMap; for (size_t i = 0; i < aNodes.Length(); ++i) {
nsIContent* content; if (aNodes[i].IsElement()) {
content = aNodes[i].GetAsElement();
} else {
content = aNodes[i].GetAsText();
}
MOZ_ASSERT(content); // We only care about the first index this content appears // in the array
nodeIndexMap.LookupOrInsert(content, i);
}
if (nodeIndexMap.Count() == mAssignedNodes.Length()) { bool isIdentical = true; for (size_t i = 0; i < mAssignedNodes.Length(); ++i) {
size_t indexInInputNodes; if (!nodeIndexMap.Get(mAssignedNodes[i]->AsContent(),
&indexInInputNodes) ||
indexInInputNodes != i) {
isIdentical = false; break;
}
} if (isIdentical) { return;
}
}
}
// 1. For each node of this's manually assigned nodes, set node's manual slot // assignment to null. for (nsINode* node : mManuallyAssignedNodes) {
MOZ_ASSERT(node->AsContent()->GetManualSlotAssignment() == this);
node->AsContent()->SetManualSlotAssignment(nullptr);
}
// 2. Let nodesSet be a new ordered set.
mManuallyAssignedNodes.Clear();
// An optimization to keep track which slots need to enqueue // slotchange event, such that they can be enqueued later in // tree order.
nsTHashSet<RefPtr<HTMLSlotElement>> changedSlots;
// Clear out existing assigned nodes if (mInManualShadowRoot) { if (!mAssignedNodes.IsEmpty()) {
changedSlots.EnsureInserted(this); if (root) {
root->InvalidateStyleAndLayoutOnSubtree(this);
}
ClearAssignedNodes();
}
MOZ_ASSERT(content); // XXXsmaug Should we have a helper for // https://infra.spec.whatwg.org/#ordered-set? if (content->GetManualSlotAssignment() != this) { if (HTMLSlotElement* oldSlot = content->GetAssignedSlot()) { if (changedSlots.EnsureInserted(oldSlot)) { if (root) {
MOZ_ASSERT(oldSlot->GetContainingShadow() == root);
root->InvalidateStyleAndLayoutOnSubtree(oldSlot);
}
}
}
if (changedSlots.EnsureInserted(this)) { if (root) {
root->InvalidateStyleAndLayoutOnSubtree(this);
}
} // 3.1 (HTML Spec) If content's manual slot assignment refers to a slot, // then remove node from that slot's manually assigned nodes. 3.2 (HTML // Spec) Set content's manual slot assignment to this. if (HTMLSlotElement* oldSlot = content->GetManualSlotAssignment()) {
oldSlot->RemoveManuallyAssignedNode(*content);
}
content->SetManualSlotAssignment(this);
mManuallyAssignedNodes.AppendElement(content);
if (root && host && content->GetParent() == host) { // Equivalent to 4.2.2.4.3 (DOM Spec) `Set slot's assigned nodes to // slottables`
root->MaybeReassignContent(*content);
}
}
}
// The `assign slottables` step is completed already at this point, // however we haven't fired the `slotchange` event yet because this // needs to be done in tree order. if (root) { for (nsIContent* child = root->GetFirstChild(); child;
child = child->GetNextNode()) { if (HTMLSlotElement* slot = HTMLSlotElement::FromNode(child)) { if (changedSlots.EnsureRemoved(slot)) {
slot->EnqueueSlotChangeEvent();
}
}
}
MOZ_ASSERT(changedSlots.IsEmpty());
}
}
void HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsIContent& aNode) {
MOZ_ASSERT(!aNode.GetAssignedSlot(), "Losing track of a slot");
mAssignedNodes.InsertElementAt(aIndex, &aNode);
aNode.SetAssignedSlot(this);
RecalculateHasSlottedState();
SlotAssignedNodeAdded(this, aNode);
}
void HTMLSlotElement::AppendAssignedNode(nsIContent& aNode) {
MOZ_ASSERT(!aNode.GetAssignedSlot(), "Losing track of a slot");
mAssignedNodes.AppendElement(&aNode);
aNode.SetAssignedSlot(this);
RecalculateHasSlottedState();
SlotAssignedNodeAdded(this, aNode);
}
void HTMLSlotElement::RecalculateHasSlottedState() { bool hasSlotted = false; // Find the first node that makes this a slotted element. for (const RefPtr<nsINode>& assignedNode : mAssignedNodes) { if (auto* slot = HTMLSlotElement::FromNode(assignedNode)) { if (slot->IsInShadowTree() &&
!slot->State().HasState(ElementState::HAS_SLOTTED)) { continue;
}
}
hasSlotted = true; break;
} if (State().HasState(ElementState::HAS_SLOTTED) != hasSlotted) {
SetStates(ElementState::HAS_SLOTTED, hasSlotted); // If slot is a slotted node itself, the assigned slot needs to // RecalculateHasSlottedState: if (auto* slot = GetAssignedSlot()) {
slot->RecalculateHasSlottedState();
}
}
}
void HTMLSlotElement::RemoveAssignedNode(nsIContent& aNode) { // This one runs from unlinking, so we can't guarantee that the slot pointer // hasn't been cleared.
MOZ_ASSERT(!aNode.GetAssignedSlot() || aNode.GetAssignedSlot() == this, "How exactly?");
mAssignedNodes.RemoveElement(&aNode);
aNode.SetAssignedSlot(nullptr);
void HTMLSlotElement::EnqueueSlotChangeEvent() { if (mInSignalSlotList) { return;
}
// FIXME(bug 1459704): Need to figure out how to deal with microtasks posted // during shutdown. if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { return;
}
DocGroup* docGroup = OwnerDoc()->GetDocGroup(); if (!docGroup) { return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.