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