| 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..331437363377ec23e6146f20400e17cbe95f9bb0 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
|
| @@ -177,8 +196,11 @@ void HTMLSlotElement::detach(const AttachContext& context)
|
| void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
|
| {
|
| if (name == nameAttr) {
|
| - if (ShadowRoot* root = containingShadowRoot())
|
| + if (ShadowRoot* root = containingShadowRoot()) {
|
| root->owner()->willAffectSelector();
|
| + if (root->isV1() && oldValue != newValue)
|
| + root->assignV1();
|
| + }
|
| }
|
| HTMLElement::attributeChanged(name, oldValue, newValue, reason);
|
| }
|
| @@ -187,15 +209,19 @@ 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 (m_assignedNodes.isEmpty() && root->isV1())
|
| + root->assignV1();
|
| }
|
| }
|
|
|
| Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode* insertionPoint)
|
| {
|
| HTMLElement::insertedInto(insertionPoint);
|
| - if (ShadowRoot* root = containingShadowRoot()) {
|
| + ShadowRoot* root = containingShadowRoot();
|
| + if (root) {
|
| if (ElementShadow* rootOwner = root->owner())
|
| rootOwner->setNeedsDistributionRecalc();
|
| if (root == insertionPoint->treeScope().rootNode())
|
| @@ -206,6 +232,9 @@ Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode*
|
| // clear the distribution when inserted again to avoid cycles.
|
| clearDistribution();
|
|
|
| + if (root && root->isV1())
|
| + root->assignV1();
|
| +
|
| return InsertionDone;
|
| }
|
|
|
| @@ -222,9 +251,14 @@ void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint)
|
| // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
|
| clearDistribution();
|
|
|
| - if (root == insertionPoint->treeScope().rootNode())
|
| + ContainerNode& rootNode = insertionPoint->treeScope().rootNode();
|
| + if (root == &rootNode)
|
| root->didRemoveSlot();
|
| + else if (rootNode.isShadowRoot() && toShadowRoot(rootNode).isV1())
|
| + toShadowRoot(rootNode).assignV1();
|
|
|
| + if (root && root->isV1())
|
| + root->assignV1();
|
| HTMLElement::removedFrom(insertionPoint);
|
| }
|
|
|
| @@ -237,9 +271,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 +281,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 +313,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 +336,21 @@ 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;
|
| + // If this slot is assigned to another slot, fire slot change event of that slot too.
|
| + if (shadowHost && shadowHost->shadowRootIfV1()) {
|
| + if (HTMLSlotElement* assigned = assignedSlot()) {
|
| + if (!assigned->m_slotchangeEventAdded)
|
| + assigned->fireSlotChangeEvent();
|
| + }
|
| }
|
| }
|
|
|
| @@ -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);
|
| }
|
|
|
|
|