1 | /* |
2 | * Copyright (C) 2011 Google 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 are |
6 | * met: |
7 | * |
8 | * * Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * * Redistributions in binary form must reproduce the above |
11 | * copyright notice, this list of conditions and the following disclaimer |
12 | * in the documentation and/or other materials provided with the |
13 | * distribution. |
14 | * * Neither the name of Google Inc. nor the names of its |
15 | * contributors may be used to endorse or promote products derived from |
16 | * this software without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | #include "config.h" |
32 | #include "MutationRecord.h" |
33 | |
34 | #include "CharacterData.h" |
35 | #include "JSNode.h" |
36 | #include "StaticNodeList.h" |
37 | #include <wtf/NeverDestroyed.h> |
38 | #include <wtf/StdLibExtras.h> |
39 | |
40 | namespace WebCore { |
41 | |
42 | namespace { |
43 | |
44 | static void visitNodeList(JSC::SlotVisitor& visitor, NodeList& nodeList) |
45 | { |
46 | ASSERT(!nodeList.isLiveNodeList()); |
47 | unsigned length = nodeList.length(); |
48 | for (unsigned i = 0; i < length; ++i) |
49 | visitor.addOpaqueRoot(root(nodeList.item(i))); |
50 | } |
51 | |
52 | class ChildListRecord final : public MutationRecord { |
53 | public: |
54 | ChildListRecord(ContainerNode& target, Ref<NodeList>&& added, Ref<NodeList>&& removed, RefPtr<Node>&& previousSibling, RefPtr<Node>&& nextSibling) |
55 | : m_target(target) |
56 | , m_addedNodes(WTFMove(added)) |
57 | , m_removedNodes(WTFMove(removed)) |
58 | , m_previousSibling(WTFMove(previousSibling)) |
59 | , m_nextSibling(WTFMove(nextSibling)) |
60 | { |
61 | } |
62 | |
63 | private: |
64 | const AtomicString& type() override; |
65 | Node* target() override { return m_target.ptr(); } |
66 | NodeList* addedNodes() override { return m_addedNodes.get(); } |
67 | NodeList* removedNodes() override { return m_removedNodes.get(); } |
68 | Node* previousSibling() override { return m_previousSibling.get(); } |
69 | Node* nextSibling() override { return m_nextSibling.get(); } |
70 | |
71 | void visitNodesConcurrently(JSC::SlotVisitor& visitor) const final |
72 | { |
73 | visitor.addOpaqueRoot(root(m_target.ptr())); |
74 | if (m_addedNodes) |
75 | visitNodeList(visitor, *m_addedNodes); |
76 | if (m_removedNodes) |
77 | visitNodeList(visitor, *m_removedNodes); |
78 | } |
79 | |
80 | Ref<ContainerNode> m_target; |
81 | RefPtr<NodeList> m_addedNodes; |
82 | RefPtr<NodeList> m_removedNodes; |
83 | RefPtr<Node> m_previousSibling; |
84 | RefPtr<Node> m_nextSibling; |
85 | }; |
86 | |
87 | class RecordWithEmptyNodeLists : public MutationRecord { |
88 | public: |
89 | RecordWithEmptyNodeLists(Node& target, const String& oldValue) |
90 | : m_target(target) |
91 | , m_oldValue(oldValue) |
92 | { |
93 | } |
94 | |
95 | private: |
96 | Node* target() override { return m_target.ptr(); } |
97 | String oldValue() override { return m_oldValue; } |
98 | NodeList* addedNodes() override { return lazilyInitializeEmptyNodeList(m_addedNodes); } |
99 | NodeList* removedNodes() override { return lazilyInitializeEmptyNodeList(m_removedNodes); } |
100 | |
101 | static NodeList* lazilyInitializeEmptyNodeList(RefPtr<NodeList>& nodeList) |
102 | { |
103 | if (!nodeList) |
104 | nodeList = StaticNodeList::create(); |
105 | return nodeList.get(); |
106 | } |
107 | |
108 | void visitNodesConcurrently(JSC::SlotVisitor& visitor) const final |
109 | { |
110 | visitor.addOpaqueRoot(root(m_target.ptr())); |
111 | } |
112 | |
113 | Ref<Node> m_target; |
114 | String m_oldValue; |
115 | RefPtr<NodeList> m_addedNodes; |
116 | RefPtr<NodeList> m_removedNodes; |
117 | }; |
118 | |
119 | class AttributesRecord final : public RecordWithEmptyNodeLists { |
120 | public: |
121 | AttributesRecord(Element& target, const QualifiedName& name, const AtomicString& oldValue) |
122 | : RecordWithEmptyNodeLists(target, oldValue) |
123 | , m_attributeName(name.localName()) |
124 | , m_attributeNamespace(name.namespaceURI()) |
125 | { |
126 | } |
127 | |
128 | private: |
129 | const AtomicString& type() override; |
130 | const AtomicString& attributeName() override { return m_attributeName; } |
131 | const AtomicString& attributeNamespace() override { return m_attributeNamespace; } |
132 | |
133 | AtomicString m_attributeName; |
134 | AtomicString m_attributeNamespace; |
135 | }; |
136 | |
137 | class CharacterDataRecord : public RecordWithEmptyNodeLists { |
138 | public: |
139 | CharacterDataRecord(CharacterData& target, const String& oldValue) |
140 | : RecordWithEmptyNodeLists(target, oldValue) |
141 | { |
142 | } |
143 | |
144 | private: |
145 | const AtomicString& type() override; |
146 | }; |
147 | |
148 | class MutationRecordWithNullOldValue final : public MutationRecord { |
149 | public: |
150 | MutationRecordWithNullOldValue(MutationRecord& record) |
151 | : m_record(record) |
152 | { |
153 | } |
154 | |
155 | private: |
156 | const AtomicString& type() override { return m_record->type(); } |
157 | Node* target() override { return m_record->target(); } |
158 | NodeList* addedNodes() override { return m_record->addedNodes(); } |
159 | NodeList* removedNodes() override { return m_record->removedNodes(); } |
160 | Node* previousSibling() override { return m_record->previousSibling(); } |
161 | Node* nextSibling() override { return m_record->nextSibling(); } |
162 | const AtomicString& attributeName() override { return m_record->attributeName(); } |
163 | const AtomicString& attributeNamespace() override { return m_record->attributeNamespace(); } |
164 | |
165 | String oldValue() override { return String(); } |
166 | |
167 | void visitNodesConcurrently(JSC::SlotVisitor& visitor) const final |
168 | { |
169 | m_record->visitNodesConcurrently(visitor); |
170 | } |
171 | |
172 | Ref<MutationRecord> m_record; |
173 | }; |
174 | |
175 | const AtomicString& ChildListRecord::type() |
176 | { |
177 | static NeverDestroyed<AtomicString> childList("childList" , AtomicString::ConstructFromLiteral); |
178 | return childList; |
179 | } |
180 | |
181 | const AtomicString& AttributesRecord::type() |
182 | { |
183 | static NeverDestroyed<AtomicString> attributes("attributes" , AtomicString::ConstructFromLiteral); |
184 | return attributes; |
185 | } |
186 | |
187 | const AtomicString& CharacterDataRecord::type() |
188 | { |
189 | static NeverDestroyed<AtomicString> characterData("characterData" , AtomicString::ConstructFromLiteral); |
190 | return characterData; |
191 | } |
192 | |
193 | } // namespace |
194 | |
195 | Ref<MutationRecord> MutationRecord::createChildList(ContainerNode& target, Ref<NodeList>&& added, Ref<NodeList>&& removed, RefPtr<Node>&& previousSibling, RefPtr<Node>&& nextSibling) |
196 | { |
197 | return adoptRef(static_cast<MutationRecord&>(*new ChildListRecord(target, WTFMove(added), WTFMove(removed), WTFMove(previousSibling), WTFMove(nextSibling)))); |
198 | } |
199 | |
200 | Ref<MutationRecord> MutationRecord::createAttributes(Element& target, const QualifiedName& name, const AtomicString& oldValue) |
201 | { |
202 | return adoptRef(static_cast<MutationRecord&>(*new AttributesRecord(target, name, oldValue))); |
203 | } |
204 | |
205 | Ref<MutationRecord> MutationRecord::createCharacterData(CharacterData& target, const String& oldValue) |
206 | { |
207 | return adoptRef(static_cast<MutationRecord&>(*new CharacterDataRecord(target, oldValue))); |
208 | } |
209 | |
210 | Ref<MutationRecord> MutationRecord::createWithNullOldValue(MutationRecord& record) |
211 | { |
212 | return adoptRef(static_cast<MutationRecord&>(*new MutationRecordWithNullOldValue(record))); |
213 | } |
214 | |
215 | MutationRecord::~MutationRecord() = default; |
216 | |
217 | } // namespace WebCore |
218 | |