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/HashSet.h" 44 #include "wtf/MainThread.h" 45 #include "wtf/Vector.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(PassRefPtr<MutationCallback> callback) 59 { 60 ASSERT(isMainThread()); 61 return adoptRef(new MutationObserver(callback)); 62 } 63 64 MutationObserver::MutationObserver(PassRefPtr<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 } 75 76 bool MutationObserver::validateOptions(MutationObserverOptions options) 77 { 78 return (options & (Attributes | CharacterData | ChildList)) 79 && ((options & Attributes) || !(options & AttributeOldValue)) 80 && ((options & Attributes) || !(options & AttributeFilter)) 81 && ((options & CharacterData) || !(options & CharacterDataOldValue)); 82 } 83 84 void MutationObserver::observe(Node* node, const Dictionary& optionsDictionary, ExceptionState& es) 85 { 86 if (!node) { 87 es.throwDOMException(NotFoundError); 88 return; 89 } 90 91 static const struct { 92 const char* name; 93 MutationObserverOptions value; 94 } booleanOptions[] = { 95 { "childList", ChildList }, 96 { "attributes", Attributes }, 97 { "characterData", CharacterData }, 98 { "subtree", Subtree }, 99 { "attributeOldValue", AttributeOldValue }, 100 { "characterDataOldValue", CharacterDataOldValue } 101 }; 102 MutationObserverOptions options = 0; 103 for (unsigned i = 0; i < sizeof(booleanOptions) / sizeof(booleanOptions[0]); ++i) { 104 bool value = false; 105 if (optionsDictionary.get(booleanOptions[i].name, value) && value) 106 options |= booleanOptions[i].value; 107 } 108 109 HashSet<AtomicString> attributeFilter; 110 if (optionsDictionary.get("attributeFilter", attributeFilter)) 111 options |= AttributeFilter; 112 113 if (!validateOptions(options)) { 114 es.throwDOMException(SyntaxError); 115 return; 116 } 117 118 node->registerMutationObserver(this, options, attributeFilter); 119 } 120 121 Vector<RefPtr<MutationRecord> > MutationObserver::takeRecords() 122 { 123 Vector<RefPtr<MutationRecord> > records; 124 records.swap(m_records); 125 return records; 126 } 127 128 void MutationObserver::disconnect() 129 { 130 m_records.clear(); 131 HashSet<MutationObserverRegistration*> registrations(m_registrations); 132 for (HashSet<MutationObserverRegistration*>::iterator iter = registrations.begin(); iter != registrations.end(); ++iter) 133 (*iter)->unregister(); 134 } 135 136 void MutationObserver::observationStarted(MutationObserverRegistration* registration) 137 { 138 ASSERT(!m_registrations.contains(registration)); 139 m_registrations.add(registration); 140 } 141 142 void MutationObserver::observationEnded(MutationObserverRegistration* registration) 143 { 144 ASSERT(m_registrations.contains(registration)); 145 m_registrations.remove(registration); 146 } 147 148 typedef HashSet<RefPtr<MutationObserver> > MutationObserverSet; 149 150 static MutationObserverSet& activeMutationObservers() 151 { 152 DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ()); 153 return activeObservers; 154 } 155 156 static MutationObserverSet& suspendedMutationObservers() 157 { 158 DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, ()); 159 return suspendedObservers; 160 } 161 162 void MutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation) 163 { 164 ASSERT(isMainThread()); 165 m_records.append(mutation); 166 activeMutationObservers().add(this); 167 } 168 169 void MutationObserver::setHasTransientRegistration() 170 { 171 ASSERT(isMainThread()); 172 activeMutationObservers().add(this); 173 } 174 175 HashSet<Node*> MutationObserver::getObservedNodes() const 176 { 177 HashSet<Node*> observedNodes; 178 for (HashSet<MutationObserverRegistration*>::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) 179 (*iter)->addRegistrationNodesToSet(observedNodes); 180 return observedNodes; 181 } 182 183 bool MutationObserver::canDeliver() 184 { 185 return !m_callback->scriptExecutionContext()->activeDOMObjectsAreSuspended(); 186 } 187 188 void MutationObserver::deliver() 189 { 190 ASSERT(canDeliver()); 191 192 // Calling clearTransientRegistrations() can modify m_registrations, so it's necessary 193 // to make a copy of the transient registrations before operating on them. 194 Vector<MutationObserverRegistration*, 1> transientRegistrations; 195 for (HashSet<MutationObserverRegistration*>::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) { 196 if ((*iter)->hasTransientRegistrations()) 197 transientRegistrations.append(*iter); 198 } 199 for (size_t i = 0; i < transientRegistrations.size(); ++i) 200 transientRegistrations[i]->clearTransientRegistrations(); 201 202 if (m_records.isEmpty()) 203 return; 204 205 Vector<RefPtr<MutationRecord> > records; 206 records.swap(m_records); 207 208 m_callback->call(records, this); 209 } 210 211 void MutationObserver::deliverAllMutations() 212 { 213 ASSERT(isMainThread()); 214 static bool deliveryInProgress = false; 215 if (deliveryInProgress) 216 return; 217 deliveryInProgress = true; 218 219 if (!suspendedMutationObservers().isEmpty()) { 220 Vector<RefPtr<MutationObserver> > suspended; 221 copyToVector(suspendedMutationObservers(), suspended); 222 for (size_t i = 0; i < suspended.size(); ++i) { 223 if (!suspended[i]->canDeliver()) 224 continue; 225 226 suspendedMutationObservers().remove(suspended[i]); 227 activeMutationObservers().add(suspended[i]); 228 } 229 } 230 231 while (!activeMutationObservers().isEmpty()) { 232 Vector<RefPtr<MutationObserver> > observers; 233 copyToVector(activeMutationObservers(), observers); 234 activeMutationObservers().clear(); 235 std::sort(observers.begin(), observers.end(), ObserverLessThan()); 236 for (size_t i = 0; i < observers.size(); ++i) { 237 if (observers[i]->canDeliver()) 238 observers[i]->deliver(); 239 else 240 suspendedMutationObservers().add(observers[i]); 241 } 242 } 243 244 deliveryInProgress = false; 245 } 246 247 } // namespace WebCore 248