Add an argument indicating the type of insertion to Node::insertedInto
[WebKit-https.git] / Source / WebCore / html / HTMLSlotElement.cpp
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "HTMLSlotElement.h"
28
29 #include "Event.h"
30 #include "EventNames.h"
31 #include "HTMLNames.h"
32 #include "MutationObserver.h"
33 #include "ShadowRoot.h"
34 #include "Text.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 Ref<HTMLSlotElement> HTMLSlotElement::create(const QualifiedName& tagName, Document& document)
41 {
42     return adoptRef(*new HTMLSlotElement(tagName, document));
43 }
44
45 HTMLSlotElement::HTMLSlotElement(const QualifiedName& tagName, Document& document)
46     : HTMLElement(tagName, document)
47 {
48     ASSERT(hasTagName(slotTag));
49 }
50
51 HTMLSlotElement::InsertedIntoResult HTMLSlotElement::insertedInto(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
52 {
53     auto insertionResult = HTMLElement::insertedInto(insertionType, parentOfInsertedTree);
54     ASSERT_UNUSED(insertionResult, insertionResult == InsertedIntoResult::Done);
55
56     if (insertionType.treeScopeChanged && isInShadowTree()) {
57         if (auto shadowRoot = containingShadowRoot())
58             shadowRoot->addSlotElementByName(attributeWithoutSynchronization(nameAttr), *this);
59     }
60
61     return InsertedIntoResult::Done;
62 }
63
64 void HTMLSlotElement::removedFrom(ContainerNode& insertionPoint)
65 {
66     // ContainerNode::removeBetween always sets the removed child's tree scope to Document's but InShadowRoot flag is unset in Node::removedFrom.
67     // So if InShadowRoot flag is set but this element's tree scope is Document's, this element has just been removed from a shadow root.
68     if (insertionPoint.isInShadowTree() && isInShadowTree() && &treeScope() == &document()) {
69         auto* oldShadowRoot = insertionPoint.containingShadowRoot();
70         ASSERT(oldShadowRoot);
71         oldShadowRoot->removeSlotElementByName(attributeWithoutSynchronization(nameAttr), *this);
72     }
73
74     HTMLElement::removedFrom(insertionPoint);
75 }
76
77 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
78 {
79     HTMLElement::attributeChanged(name, oldValue, newValue, reason);
80
81     if (isInShadowTree() && name == nameAttr) {
82         if (auto* shadowRoot = containingShadowRoot()) {
83             shadowRoot->removeSlotElementByName(oldValue, *this);
84             shadowRoot->addSlotElementByName(newValue, *this);
85         }
86     }
87 }
88
89 const Vector<Node*>* HTMLSlotElement::assignedNodes() const
90 {
91     auto* shadowRoot = containingShadowRoot();
92     if (!shadowRoot)
93         return nullptr;
94
95     return shadowRoot->assignedNodesForSlot(*this);
96 }
97
98 static void flattenAssignedNodes(Vector<Node*>& nodes, const HTMLSlotElement& slot)
99 {
100     auto* assignedNodes = slot.assignedNodes();
101     if (!assignedNodes) {
102         for (Node* child = slot.firstChild(); child; child = child->nextSibling()) {
103             if (is<HTMLSlotElement>(*child))
104                 flattenAssignedNodes(nodes, downcast<HTMLSlotElement>(*child));
105             else if (is<Text>(*child) || is<Element>(*child))
106                 nodes.append(child);
107         }
108         return;
109     }
110     for (Node* node : *assignedNodes) {
111         if (is<HTMLSlotElement>(*node))
112             flattenAssignedNodes(nodes, downcast<HTMLSlotElement>(*node));
113         else
114             nodes.append(node);
115     }
116 }
117
118 Vector<Node*> HTMLSlotElement::assignedNodes(const AssignedNodesOptions& options) const
119 {
120     if (options.flatten) {
121         Vector<Node*> nodes;
122         flattenAssignedNodes(nodes, *this);
123         return nodes;
124     }
125     auto* assignedNodes = this->assignedNodes();
126     if (!assignedNodes)
127         return { };
128     return *assignedNodes;
129 }
130
131 void HTMLSlotElement::enqueueSlotChangeEvent()
132 {
133     // https://dom.spec.whatwg.org/#signal-a-slot-change
134     if (m_inSignalSlotList)
135         return;
136     m_inSignalSlotList = true;
137     MutationObserver::enqueueSlotChangeEvent(*this);
138 }
139
140 void HTMLSlotElement::dispatchSlotChangeEvent()
141 {
142     m_inSignalSlotList = false;
143
144     bool bubbles = true;
145     bool cancelable = false;
146     Ref<Event> event = Event::create(eventNames().slotchangeEvent, bubbles, cancelable);
147     event->setTarget(this);
148     dispatchEvent(event);
149 }
150
151 }
152