Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: third_party/WebKit/Source/core/html/HTMLSlotElement.cpp

Issue 1899653002: Support slotchange event (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
index 156689e76873104ff6fec7eaa50a98d24490e829..b968766a96d3fec8e657a75e850a683ac118f06d 100644
--- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -32,8 +32,10 @@
#include "bindings/core/v8/Microtask.h"
#include "core/HTMLNames.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/StyleChangeReason.h"
+#include "core/dom/StyleEngine.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
#include "core/events/Event.h"
@@ -46,6 +48,8 @@ using namespace HTMLNames;
inline HTMLSlotElement::HTMLSlotElement(Document& document)
: HTMLElement(slotTag, document)
, m_distributionState(DistributionDone)
+ , m_assignmentState(AssignmentDone)
+ , m_slotchangeEventAdded(false)
{
setHasCustomStyleCallbacks();
}
@@ -86,7 +90,7 @@ const HeapVector<Member<Node>>& HTMLSlotElement::getDistributedNodes()
void HTMLSlotElement::appendAssignedNode(Node& node)
{
- ASSERT(m_distributionState == DistributionOnGoing);
+ ASSERT(m_assignmentState == AssignmentOnGoing);
m_assignedNodes.append(&node);
}
@@ -98,6 +102,12 @@ void HTMLSlotElement::appendDistributedNode(Node& node)
m_distributedIndices.set(&node, size);
}
+void HTMLSlotElement::appendFallbackNode(Node& node)
+{
+ ASSERT(m_assignmentState == AssignmentOnGoing);
+ m_fallbackNodes.append(&node);
+}
+
void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other)
{
ASSERT(m_distributionState == DistributionOnGoing);
@@ -107,19 +117,27 @@ void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other)
m_distributedIndices.set(node.get(), index++);
}
+void HTMLSlotElement::willUpdateAssignment()
+{
+ ASSERT(m_assignmentState != AssignmentOnGoing);
+ m_assignmentState = AssignmentOnGoing;
+ m_oldAssignedNodes.swap(m_assignedNodes);
+ m_assignedNodes.clear();
+}
+
void HTMLSlotElement::willUpdateDistribution()
{
ASSERT(m_distributionState != DistributionOnGoing);
m_distributionState = DistributionOnGoing;
- m_assignedNodes.clear();
m_oldDistributedNodes.swap(m_distributedNodes);
m_distributedNodes.clear();
m_distributedIndices.clear();
}
-bool HTMLSlotElement::hasSlotChangeEventListener()
+void HTMLSlotElement::willUpdateFallback()
{
- return eventTargetData() && eventTargetData()->eventListenerMap.find(EventTypeNames::slotchange);
+ m_oldFallbackNodes.swap(m_fallbackNodes);
+ m_fallbackNodes.clear();
}
void HTMLSlotElement::dispatchSlotChangeEvent()
@@ -127,6 +145,7 @@ void HTMLSlotElement::dispatchSlotChangeEvent()
Event* event = Event::create(EventTypeNames::slotchange);
event->setTarget(this);
dispatchScopedEvent(event);
+ m_slotchangeEventAdded = false;
}
Node* HTMLSlotElement::distributedNodeNextTo(const Node& node) const
@@ -179,6 +198,7 @@ void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicSt
if (name == nameAttr) {
if (ShadowRoot* root = containingShadowRoot())
root->owner()->willAffectSelector();
+ document().updateAssignment();
}
HTMLElement::attributeChanged(name, oldValue, newValue, reason);
}
@@ -187,8 +207,11 @@ void HTMLSlotElement::childrenChanged(const ChildrenChange& change)
{
HTMLElement::childrenChanged(change);
if (ShadowRoot* root = containingShadowRoot()) {
- if (ElementShadow* rootOwner = root->owner())
+ if (ElementShadow* rootOwner = root->owner()) {
rootOwner->setNeedsDistributionRecalc();
+ if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCascadeV1)
+ document().updateAssignment();
+ }
}
}
@@ -206,6 +229,8 @@ Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode*
// clear the distribution when inserted again to avoid cycles.
clearDistribution();
+ if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCascadeV1)
+ document().updateAssignment();
return InsertionDone;
}
@@ -224,7 +249,9 @@ void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint)
if (root == insertionPoint->treeScope().rootNode())
root->didRemoveSlot();
-
+ if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCascadeV1) {
+ document().updateAssignment();
+ }
HTMLElement::removedFrom(insertionPoint);
}
@@ -237,9 +264,9 @@ void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change)
node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::PropagateInheritChangeToDistributedNodes));
}
-void HTMLSlotElement::updateDistributedNodesWithFallback()
+void HTMLSlotElement::updateFallbackNodes()
{
- if (!m_distributedNodes.isEmpty())
+ if (!m_fallbackNodes.isEmpty())
return;
for (auto& child : NodeTraversal::childrenOf(*this)) {
if (!child.isSlotAssignable())
@@ -247,13 +274,30 @@ void HTMLSlotElement::updateDistributedNodesWithFallback()
// Insertion points are not supported as slots fallback
if (isActiveInsertionPoint(child))
continue;
- if (isHTMLSlotElement(child))
- appendDistributedNodesFrom(toHTMLSlotElement(child));
+ appendFallbackNode(child);
+ }
+}
+
+void HTMLSlotElement::updateDistributedNodesWithFallback()
+{
+ if (!m_distributedNodes.isEmpty())
+ return;
+ for (auto node : m_fallbackNodes) {
+ if (isHTMLSlotElement(node))
+ appendDistributedNodesFrom(*toHTMLSlotElement(node));
else
- appendDistributedNode(child);
+ appendDistributedNode(*node);
}
}
+bool HTMLSlotElement::assignmentChanged()
+{
+ ASSERT(m_assignmentState != AssignmentOnGoing);
+ if (m_assignmentState == AssignmentDone)
+ m_assignmentState = m_oldAssignedNodes == m_assignedNodes ? AssignmentUnchanged : AssignmentChanged;
+ return m_assignmentState == AssignmentChanged;
+}
+
bool HTMLSlotElement::distributionChanged()
{
ASSERT(m_distributionState != DistributionOnGoing);
@@ -262,6 +306,19 @@ bool HTMLSlotElement::distributionChanged()
return m_distributionState == DistributionChanged;
}
+bool HTMLSlotElement::fallbackChanged()
+{
+ return m_oldFallbackNodes == m_fallbackNodes;
+}
+
+void HTMLSlotElement::didUpdateAssignment()
+{
+ ASSERT(m_assignmentState == AssignmentOnGoing);
+ m_assignmentState = AssignmentDone;
+ if ((assignmentChanged() || fallbackChanged()) && !m_slotchangeEventAdded)
+ fireSlotChangeEvent();
+}
+
void HTMLSlotElement::didUpdateDistribution()
{
ASSERT(m_distributionState == DistributionOnGoing);
@@ -272,9 +329,28 @@ void HTMLSlotElement::didUpdateDistribution()
if (!shadow->needsDistributionRecalc() && distributionChanged())
shadow->setNeedsDistributionRecalc();
}
- if (hasSlotChangeEventListener() && distributionChanged()) {
- // TODO(hayato): Do not enqueue a slotchange event for the same slot twice in the microtask queue
- Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChangeEvent, this));
+}
+
+void HTMLSlotElement::fireSlotChangeEvent()
+{
+ ASSERT(!m_slotchangeEventAdded);
+ Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChangeEvent, this));
+ m_slotchangeEventAdded = true;
+
+ Element* shadowHost = isShadowHost(parentElement()) ? parentElement() : nullptr;
+ ShadowRoot* shadowRoot = shadowRootIfV1();
+ if (shadowHost && shadowRoot) {
+ // If this slot is assigned to another slot, fire slot change event of that slot too.
+ const AtomicString& assignedSlot = normalizeSlotName(fastGetAttribute(HTMLNames::slotAttr));
+ if (assignedSlot != emptyAtom) {
+ const HeapVector<Member<HTMLSlotElement>>& slots = shadowRoot->descendantSlots();
+ for (Member<HTMLSlotElement> slot : slots) {
+ if (slot->name() == assignedSlot && !slot->hasSlotChangeEventInMicrotask()) {
+ slot->fireSlotChangeEvent();
+ break;
+ }
+ }
+ }
}
}
@@ -293,8 +369,11 @@ DEFINE_TRACE(HTMLSlotElement)
{
visitor->trace(m_assignedNodes);
visitor->trace(m_distributedNodes);
+ visitor->trace(m_fallbackNodes);
visitor->trace(m_distributedIndices);
+ visitor->trace(m_oldAssignedNodes);
visitor->trace(m_oldDistributedNodes);
+ visitor->trace(m_oldFallbackNodes);
HTMLElement::trace(visitor);
}

Powered by Google App Engine
This is Rietveld 408576698