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#pragma once
27
28#include "RenderTreeUpdater.h"
29#include "ShadowRoot.h"
30#include <wtf/HashMap.h>
31#include <wtf/HashSet.h>
32#include <wtf/Vector.h>
33#include <wtf/WeakPtr.h>
34#include <wtf/text/AtomString.h>
35#include <wtf/text/AtomStringHash.h>
36
37namespace WebCore {
38
39class Element;
40class HTMLSlotElement;
41class Node;
42
43class SlotAssignment {
44 WTF_MAKE_NONCOPYABLE(SlotAssignment); WTF_MAKE_FAST_ALLOCATED;
45public:
46 SlotAssignment();
47 virtual ~SlotAssignment();
48
49 static const AtomString& defaultSlotName() { return emptyAtom(); }
50
51 HTMLSlotElement* findAssignedSlot(const Node&, ShadowRoot&);
52
53 void renameSlotElement(HTMLSlotElement&, const AtomString& oldName, const AtomString& newName, ShadowRoot&);
54 void addSlotElementByName(const AtomString&, HTMLSlotElement&, ShadowRoot&);
55 void removeSlotElementByName(const AtomString&, HTMLSlotElement&, ContainerNode* oldParentOfRemovedTreeForRemoval, ShadowRoot&);
56 void slotFallbackDidChange(HTMLSlotElement&, ShadowRoot&);
57 void resolveSlotsBeforeNodeInsertionOrRemoval(ShadowRoot&);
58 void willRemoveAllChildren(ShadowRoot&);
59
60 void didChangeSlot(const AtomString&, ShadowRoot&);
61 void enqueueSlotChangeEvent(const AtomString&, ShadowRoot&);
62
63 const Vector<Node*>* assignedNodesForSlot(const HTMLSlotElement&, ShadowRoot&);
64
65 virtual void hostChildElementDidChange(const Element&, ShadowRoot&);
66
67private:
68 struct Slot {
69 WTF_MAKE_FAST_ALLOCATED;
70 public:
71 Slot() { }
72
73 bool hasSlotElements() { return !!elementCount; }
74 bool hasDuplicatedSlotElements() { return elementCount > 1; }
75 bool shouldResolveSlotElement() { return !element && elementCount; }
76
77 WeakPtr<HTMLSlotElement> element;
78 WeakPtr<HTMLSlotElement> oldElement;
79 unsigned elementCount { 0 };
80 bool seenFirstElement { false };
81 Vector<Node*> assignedNodes;
82 };
83
84 bool hasAssignedNodes(ShadowRoot&, Slot&);
85 enum class SlotMutationType { Insertion, Removal };
86 void resolveSlotsAfterSlotMutation(ShadowRoot&, SlotMutationType, ContainerNode* oldParentOfRemovedTree = nullptr);
87
88 virtual const AtomString& slotNameForHostChild(const Node&) const;
89
90 HTMLSlotElement* findFirstSlotElement(Slot&, ShadowRoot&);
91 void resolveAllSlotElements(ShadowRoot&);
92
93 void assignSlots(ShadowRoot&);
94 void assignToSlot(Node& child, const AtomString& slotName);
95
96 HashMap<AtomString, std::unique_ptr<Slot>> m_slots;
97
98#ifndef NDEBUG
99 HashSet<HTMLSlotElement*> m_slotElementsForConsistencyCheck;
100#endif
101
102 bool m_needsToResolveSlotElements { false };
103 bool m_slotAssignmentsIsValid { false };
104 bool m_willBeRemovingAllChildren { false };
105 unsigned m_slotMutationVersion { 0 };
106 unsigned m_slotResolutionVersion { 0 };
107};
108
109inline void ShadowRoot::resolveSlotsBeforeNodeInsertionOrRemoval()
110{
111 if (UNLIKELY(shouldFireSlotchangeEvent() && m_slotAssignment))
112 m_slotAssignment->resolveSlotsBeforeNodeInsertionOrRemoval(*this);
113}
114
115inline void ShadowRoot::willRemoveAllChildren(ContainerNode&)
116{
117 if (UNLIKELY(shouldFireSlotchangeEvent() && m_slotAssignment))
118 m_slotAssignment->willRemoveAllChildren(*this);
119}
120
121inline void ShadowRoot::didRemoveAllChildrenOfShadowHost()
122{
123 if (m_slotAssignment) // FIXME: This is incorrect when there were no elements or text nodes removed.
124 m_slotAssignment->didChangeSlot(nullAtom(), *this);
125}
126
127inline void ShadowRoot::didChangeDefaultSlot()
128{
129 if (m_slotAssignment)
130 m_slotAssignment->didChangeSlot(nullAtom(), *this);
131}
132
133inline void ShadowRoot::hostChildElementDidChange(const Element& childElement)
134{
135 if (m_slotAssignment)
136 m_slotAssignment->hostChildElementDidChange(childElement, *this);
137}
138
139inline void ShadowRoot::hostChildElementDidChangeSlotAttribute(Element& element, const AtomString& oldValue, const AtomString& newValue)
140{
141 if (!m_slotAssignment)
142 return;
143 m_slotAssignment->didChangeSlot(oldValue, *this);
144 m_slotAssignment->didChangeSlot(newValue, *this);
145 RenderTreeUpdater::tearDownRenderers(element);
146}
147
148} // namespace WebCore
149