Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/dom/MutationObserver.h"
33
34 #include <algorithm>
35 #include "bindings/v8/Dictionary.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/ExceptionCode.h"
39 #include "core/dom/Microtask.h"
40 #include "core/dom/MutationCallback.h"
41 #include "core/dom/MutationObserverRegistration.h"
42 #include "core/dom/MutationRecord.h"
43 #include "core/dom/Node.h"
44 #include "core/inspector/InspectorInstrumentation.h"
45 #include "wtf/MainThread.h"
46
47 namespace WebCore {
48
49 static unsigned s_observerPriority = 0;
50
51 struct MutationObserver::ObserverLessThan {
52     bool operator()(const RefPtr<MutationObserver>& lhs, const RefPtr<MutationObserver>& rhs)
53     {
54         return lhs->m_priority < rhs->m_priority;
55     }
56 };
57
58 PassRefPtr<MutationObserver> MutationObserver::create(PassOwnPtr<MutationCallback> callback)
59 {
60     ASSERT(isMainThread());
61     return adoptRef(new MutationObserver(callback));
62 }
63
64 MutationObserver::MutationObserver(PassOwnPtr<MutationCallback> callback)
65     : m_callback(callback)
66     , m_priority(s_observerPriority++)
67 {
68     ScriptWrappable::init(this);
69 }
70
71 MutationObserver::~MutationObserver()
72 {
73     ASSERT(m_registrations.isEmpty());
74     if (!m_records.isEmpty())
75         InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this);
76 }
77
78 void MutationObserver::observe(Node* node, const Dictionary& optionsDictionary, ExceptionState& exceptionState)
79 {
80     if (!node) {
81         exceptionState.throwDOMException(NotFoundError, "The provided node was null.");
82         return;
83     }
84
85     MutationObserverOptions options = 0;
86
87     bool attributeOldValue = false;
88     bool attributeOldValuePresent = optionsDictionary.get("attributeOldValue", attributeOldValue);
89     if (attributeOldValue)
90         options |= AttributeOldValue;
91
92     HashSet<AtomicString> attributeFilter;
93     bool attributeFilterPresent = optionsDictionary.get("attributeFilter", attributeFilter);
94     if (attributeFilterPresent)
95         options |= AttributeFilter;
96
97     bool attributes = false;
98     bool attributesPresent = optionsDictionary.get("attributes", attributes);
99     if (attributes || (!attributesPresent && (attributeOldValuePresent || attributeFilterPresent)))
100         options |= Attributes;
101
102     bool characterDataOldValue = false;
103     bool characterDataOldValuePresent = optionsDictionary.get("characterDataOldValue", characterDataOldValue);
104     if (characterDataOldValue)
105         options |= CharacterDataOldValue;
106
107     bool characterData = false;
108     bool characterDataPresent = optionsDictionary.get("characterData", characterData);
109     if (characterData || (!characterDataPresent && characterDataOldValuePresent))
110         options |= CharacterData;
111
112     bool childListValue = false;
113     if (optionsDictionary.get("childList", childListValue) && childListValue)
114         options |= ChildList;
115
116     bool subtreeValue = false;
117     if (optionsDictionary.get("subtree", subtreeValue) && subtreeValue)
118         options |= Subtree;
119
120     if (!(options & Attributes)) {
121         if (options & AttributeOldValue) {
122             exceptionState.throwDOMException(TypeError, "The options object may only set 'attributeOldValue' to true when 'attributes' is true or not present.");
123             return;
124         }
125         if (options & AttributeFilter) {
126             exceptionState.throwDOMException(TypeError, "The options object may only set 'attributeFilter' when 'attributes' is true or not present.");
127             return;
128         }
129     }
130     if (!((options & CharacterData) || !(options & CharacterDataOldValue))) {
131         exceptionState.throwDOMException(TypeError, "The options object may only set 'characterDataOldValue' to true when 'characterData' is true or not present.");
132         return;
133     }
134
135     if (!(options & (Attributes | CharacterData | ChildList))) {
136         exceptionState.throwDOMException(TypeError, "The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.");
137         return;
138     }
139
140     node->registerMutationObserver(this, options, attributeFilter);
141 }
142
143 Vector<RefPtr<MutationRecord> > MutationObserver::takeRecords()
144 {
145     Vector<RefPtr<MutationRecord> > records;
146     records.swap(m_records);
147     InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this);
148     return records;
149 }
150
151 void MutationObserver::disconnect()
152 {
153     m_records.clear();
154     InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this);
155     HashSet<MutationObserverRegistration*> registrations(m_registrations);
156     for (HashSet<MutationObserverRegistration*>::iterator iter = registrations.begin(); iter != registrations.end(); ++iter)
157         (*iter)->unregister();
158 }
159
160 void MutationObserver::observationStarted(MutationObserverRegistration* registration)
161 {
162     ASSERT(!m_registrations.contains(registration));
163     m_registrations.add(registration);
164 }
165
166 void MutationObserver::observationEnded(MutationObserverRegistration* registration)
167 {
168     ASSERT(m_registrations.contains(registration));
169     m_registrations.remove(registration);
170 }
171
172 typedef HashSet<RefPtr<MutationObserver> > MutationObserverSet;
173
174 static MutationObserverSet& activeMutationObservers()
175 {
176     DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ());
177     return activeObservers;
178 }
179
180 static MutationObserverSet& suspendedMutationObservers()
181 {
182     DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, ());
183     return suspendedObservers;
184 }
185
186 static void activateObserver(PassRefPtr<MutationObserver> observer)
187 {
188     if (activeMutationObservers().isEmpty())
189         Microtask::enqueueMicrotask(&MutationObserver::deliverMutations);
190
191     activeMutationObservers().add(observer);
192 }
193
194 void MutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation)
195 {
196     ASSERT(isMainThread());
197     m_records.append(mutation);
198     activateObserver(this);
199     InspectorInstrumentation::didEnqueueMutationRecord(m_callback->executionContext(), this);
200 }
201
202 void MutationObserver::setHasTransientRegistration()
203 {
204     ASSERT(isMainThread());
205     activateObserver(this);
206 }
207
208 HashSet<Node*> MutationObserver::getObservedNodes() const
209 {
210     HashSet<Node*> observedNodes;
211     for (HashSet<MutationObserverRegistration*>::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter)
212         (*iter)->addRegistrationNodesToSet(observedNodes);
213     return observedNodes;
214 }
215
216 bool MutationObserver::canDeliver()
217 {
218     return !m_callback->executionContext()->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 (HashSet<MutationObserverRegistration*>::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) {
229         if ((*iter)->hasTransientRegistrations())
230             transientRegistrations.append(*iter);
231     }
232     for (size_t i = 0; i < transientRegistrations.size(); ++i)
233         transientRegistrations[i]->clearTransientRegistrations();
234
235     if (m_records.isEmpty())
236         return;
237
238     Vector<RefPtr<MutationRecord> > records;
239     records.swap(m_records);
240
241     InspectorInstrumentation::willDeliverMutationRecords(m_callback->executionContext(), this);
242     m_callback->call(records, this);
243     InspectorInstrumentation::didDeliverMutationRecords(m_callback->executionContext());
244 }
245
246 void MutationObserver::resumeSuspendedObservers()
247 {
248     ASSERT(isMainThread());
249     if (suspendedMutationObservers().isEmpty())
250         return;
251
252     Vector<RefPtr<MutationObserver> > suspended;
253     copyToVector(suspendedMutationObservers(), suspended);
254     for (size_t i = 0; i < suspended.size(); ++i) {
255         if (suspended[i]->canDeliver()) {
256             suspendedMutationObservers().remove(suspended[i]);
257             activateObserver(suspended[i]);
258         }
259     }
260 }
261
262 void MutationObserver::deliverMutations()
263 {
264     ASSERT(isMainThread());
265     Vector<RefPtr<MutationObserver> > observers;
266     copyToVector(activeMutationObservers(), observers);
267     activeMutationObservers().clear();
268     std::sort(observers.begin(), observers.end(), ObserverLessThan());
269     for (size_t i = 0; i < observers.size(); ++i) {
270         if (observers[i]->canDeliver())
271             observers[i]->deliver();
272         else
273             suspendedMutationObservers().add(observers[i]);
274     }
275 }
276
277 } // namespace WebCore