Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / dom / MutationObserver.cpp
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
33 #include "MutationObserver.h"
34
35 #include "Dictionary.h"
36 #include "Document.h"
37 #include "ExceptionCode.h"
38 #include "Microtasks.h"
39 #include "MutationCallback.h"
40 #include "MutationObserverRegistration.h"
41 #include "MutationRecord.h"
42 #include <algorithm>
43 #include <wtf/MainThread.h>
44
45 namespace WebCore {
46
47 static unsigned s_observerPriority = 0;
48
49 Ref<MutationObserver> MutationObserver::create(PassRefPtr<MutationCallback> callback)
50 {
51     ASSERT(isMainThread());
52     return adoptRef(*new MutationObserver(callback));
53 }
54
55 MutationObserver::MutationObserver(PassRefPtr<MutationCallback> callback)
56     : m_callback(callback)
57     , m_priority(s_observerPriority++)
58 {
59 }
60
61 MutationObserver::~MutationObserver()
62 {
63     ASSERT(m_registrations.isEmpty());
64 }
65
66 bool MutationObserver::validateOptions(MutationObserverOptions options)
67 {
68     return (options & (Attributes | CharacterData | ChildList))
69         && ((options & Attributes) || !(options & AttributeOldValue))
70         && ((options & Attributes) || !(options & AttributeFilter))
71         && ((options & CharacterData) || !(options & CharacterDataOldValue));
72 }
73
74 void MutationObserver::observe(Node* node, const Dictionary& optionsDictionary, ExceptionCode& ec)
75 {
76     if (!node) {
77         ec = NOT_FOUND_ERR;
78         return;
79     }
80
81     static const struct {
82         const char* name;
83         MutationObserverOptions value;
84     } booleanOptions[] = {
85         { "childList", ChildList },
86         { "subtree", Subtree },
87         { "attributeOldValue", AttributeOldValue },
88         { "characterDataOldValue", CharacterDataOldValue }
89     };
90     MutationObserverOptions options = 0;
91     bool value = false;
92     for (auto& booleanOption : booleanOptions) {
93         if (optionsDictionary.get(booleanOption.name, value) && value)
94             options |= booleanOption.value;
95     }
96
97     HashSet<AtomicString> attributeFilter;
98     if (optionsDictionary.get("attributeFilter", attributeFilter))
99         options |= AttributeFilter;
100
101     bool attributesOptionIsSet = optionsDictionary.get("attributes", value);
102     if ((attributesOptionIsSet && value) || (!attributesOptionIsSet && (options & (AttributeFilter | AttributeOldValue))))
103         options |= Attributes;
104
105     bool characterDataOptionIsSet = optionsDictionary.get("characterData", value);
106     if ((characterDataOptionIsSet && value) || (!characterDataOptionIsSet && (options & CharacterDataOldValue)))
107         options |= CharacterData;
108
109     if (!validateOptions(options)) {
110         ec = SYNTAX_ERR;
111         return;
112     }
113
114     node->registerMutationObserver(this, options, attributeFilter);
115 }
116
117 Vector<RefPtr<MutationRecord>> MutationObserver::takeRecords()
118 {
119     Vector<RefPtr<MutationRecord>> records;
120     records.swap(m_records);
121     return records;
122 }
123
124 void MutationObserver::disconnect()
125 {
126     m_records.clear();
127     HashSet<MutationObserverRegistration*> registrations(m_registrations);
128     for (auto* registration : registrations)
129         MutationObserverRegistration::unregisterAndDelete(registration);
130 }
131
132 void MutationObserver::observationStarted(MutationObserverRegistration* registration)
133 {
134     ASSERT(!m_registrations.contains(registration));
135     m_registrations.add(registration);
136 }
137
138 void MutationObserver::observationEnded(MutationObserverRegistration* registration)
139 {
140     ASSERT(m_registrations.contains(registration));
141     m_registrations.remove(registration);
142 }
143
144 typedef HashSet<RefPtr<MutationObserver>> MutationObserverSet;
145
146 static MutationObserverSet& activeMutationObservers()
147 {
148     DEPRECATED_DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ());
149     return activeObservers;
150 }
151
152 static MutationObserverSet& suspendedMutationObservers()
153 {
154     DEPRECATED_DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, ());
155     return suspendedObservers;
156 }
157
158 static bool mutationObserverCompoundMicrotaskQueuedFlag;
159
160 class MutationObserverMicrotask : public Microtask {
161 public:
162     MutationObserverMicrotask()
163     {
164     }
165
166     virtual ~MutationObserverMicrotask()
167     {
168     }
169
170 private:    
171     virtual Result run()
172     {
173         mutationObserverCompoundMicrotaskQueuedFlag = false;
174
175         MutationObserver::deliverAllMutations();
176
177         return Result::Done;
178     }
179 };
180
181 static void queueMutationObserverCompoundMicrotask()
182 {
183     if (mutationObserverCompoundMicrotaskQueuedFlag)
184         return;
185     mutationObserverCompoundMicrotaskQueuedFlag = true;
186
187     auto microtask = std::make_unique<MutationObserverMicrotask>();
188     MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask));
189 }
190
191 void MutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation)
192 {
193     ASSERT(isMainThread());
194     m_records.append(mutation);
195     activeMutationObservers().add(this);
196
197     queueMutationObserverCompoundMicrotask();
198 }
199
200 void MutationObserver::setHasTransientRegistration()
201 {
202     ASSERT(isMainThread());
203     activeMutationObservers().add(this);
204
205     queueMutationObserverCompoundMicrotask();
206 }
207
208 HashSet<Node*> MutationObserver::getObservedNodes() const
209 {
210     HashSet<Node*> observedNodes;
211     for (auto* registration : m_registrations)
212         registration->addRegistrationNodesToSet(observedNodes);
213     return observedNodes;
214 }
215
216 bool MutationObserver::canDeliver()
217 {
218     return !m_callback->scriptExecutionContext()->activeDOMObjectsAreSuspended();
219 }
220
221 void MutationObserver::deliver()
222 {
223     ASSERT(canDeliver());
224
225     // Calling clearTransientRegistrations() can modify m_registrations, so it's necessary
226     // to make a copy of the transient registrations before operating on them.
227     Vector<MutationObserverRegistration*, 1> transientRegistrations;
228     for (auto* registration : m_registrations) {
229         if (registration->hasTransientRegistrations())
230             transientRegistrations.append(registration);
231     }
232     for (auto& registration : transientRegistrations)
233         registration->clearTransientRegistrations();
234
235     if (m_records.isEmpty())
236         return;
237
238     Vector<RefPtr<MutationRecord>> records;
239     records.swap(m_records);
240
241     m_callback->call(records, this);
242 }
243
244 void MutationObserver::deliverAllMutations()
245 {
246     ASSERT(isMainThread());
247     static bool deliveryInProgress = false;
248     if (deliveryInProgress)
249         return;
250     deliveryInProgress = true;
251
252     if (!suspendedMutationObservers().isEmpty()) {
253         Vector<RefPtr<MutationObserver>> suspended;
254         copyToVector(suspendedMutationObservers(), suspended);
255         for (auto& observer : suspended) {
256             if (!observer->canDeliver())
257                 continue;
258
259             suspendedMutationObservers().remove(observer);
260             activeMutationObservers().add(observer);
261         }
262     }
263
264     while (!activeMutationObservers().isEmpty()) {
265         Vector<RefPtr<MutationObserver>> observers;
266         copyToVector(activeMutationObservers(), observers);
267         activeMutationObservers().clear();
268         std::sort(observers.begin(), observers.end(), [](const RefPtr<MutationObserver>& lhs, const RefPtr<MutationObserver>& rhs) {
269             return lhs->m_priority < rhs->m_priority;
270         });
271
272         for (auto& observer : observers) {
273             if (observer->canDeliver())
274                 observer->deliver();
275             else
276                 suspendedMutationObservers().add(observer);
277         }
278     }
279
280     deliveryInProgress = false;
281 }
282
283 } // namespace WebCore