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 "bindings/core/v8/ExceptionState.h" 35 #include "core/dom/ExceptionCode.h" 36 #include "core/dom/Microtask.h" 37 #include "core/dom/MutationCallback.h" 38 #include "core/dom/MutationObserverInit.h" 39 #include "core/dom/MutationObserverRegistration.h" 40 #include "core/dom/MutationRecord.h" 41 #include "core/dom/Node.h" 42 #include "core/inspector/InspectorInstrumentation.h" 43 #include "wtf/MainThread.h" 44 #include <algorithm> 45 46 namespace blink { 47 48 static unsigned s_observerPriority = 0; 49 50 struct MutationObserver::ObserverLessThan { 51 bool operator()(const RefPtrWillBeMember<MutationObserver>& lhs, const RefPtrWillBeMember<MutationObserver>& rhs) 52 { 53 return lhs->m_priority < rhs->m_priority; 54 } 55 }; 56 57 PassRefPtrWillBeRawPtr<MutationObserver> MutationObserver::create(PassOwnPtr<MutationCallback> callback) 58 { 59 ASSERT(isMainThread()); 60 return adoptRefWillBeNoop(new MutationObserver(callback)); 61 } 62 63 MutationObserver::MutationObserver(PassOwnPtr<MutationCallback> callback) 64 : m_callback(callback) 65 , m_priority(s_observerPriority++) 66 { 67 } 68 69 MutationObserver::~MutationObserver() 70 { 71 #if !ENABLE(OILPAN) 72 ASSERT(m_registrations.isEmpty()); 73 #endif 74 if (!m_records.isEmpty()) 75 InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this); 76 } 77 78 void MutationObserver::observe(Node* node, const MutationObserverInit& observerInit, 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 if (observerInit.hasAttributeOldValue() && observerInit.attributeOldValue()) 88 options |= AttributeOldValue; 89 90 HashSet<AtomicString> attributeFilter; 91 if (observerInit.hasAttributeFilter()) { 92 const Vector<String>& sequence = observerInit.attributeFilter(); 93 for (unsigned i = 0; i < sequence.size(); ++i) 94 attributeFilter.add(AtomicString(sequence[i])); 95 options |= AttributeFilter; 96 } 97 98 bool attributes = observerInit.hasAttributes() && observerInit.attributes(); 99 if (attributes || (!observerInit.hasAttributes() && (observerInit.hasAttributeOldValue() || observerInit.hasAttributeFilter()))) 100 options |= Attributes; 101 102 if (observerInit.hasCharacterDataOldValue() && observerInit.characterDataOldValue()) 103 options |= CharacterDataOldValue; 104 105 bool characterData = observerInit.hasCharacterData() && observerInit.characterData(); 106 if (characterData || (!observerInit.hasCharacterData() && observerInit.hasCharacterDataOldValue())) 107 options |= CharacterData; 108 109 if (observerInit.childList()) 110 options |= ChildList; 111 112 if (observerInit.subtree()) 113 options |= Subtree; 114 115 if (!(options & Attributes)) { 116 if (options & AttributeOldValue) { 117 exceptionState.throwTypeError("The options object may only set 'attributeOldValue' to true when 'attributes' is true or not present."); 118 return; 119 } 120 if (options & AttributeFilter) { 121 exceptionState.throwTypeError("The options object may only set 'attributeFilter' when 'attributes' is true or not present."); 122 return; 123 } 124 } 125 if (!((options & CharacterData) || !(options & CharacterDataOldValue))) { 126 exceptionState.throwTypeError("The options object may only set 'characterDataOldValue' to true when 'characterData' is true or not present."); 127 return; 128 } 129 130 if (!(options & (Attributes | CharacterData | ChildList))) { 131 exceptionState.throwTypeError("The options object must set at least one of 'attributes', 'characterData', or 'childList' to true."); 132 return; 133 } 134 135 node->registerMutationObserver(*this, options, attributeFilter); 136 } 137 138 MutationRecordVector MutationObserver::takeRecords() 139 { 140 MutationRecordVector records; 141 records.swap(m_records); 142 InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this); 143 return records; 144 } 145 146 void MutationObserver::disconnect() 147 { 148 m_records.clear(); 149 InspectorInstrumentation::didClearAllMutationRecords(m_callback->executionContext(), this); 150 MutationObserverRegistrationSet registrations(m_registrations); 151 for (MutationObserverRegistrationSet::iterator iter = registrations.begin(); iter != registrations.end(); ++iter) 152 (*iter)->unregister(); 153 ASSERT(m_registrations.isEmpty()); 154 } 155 156 void MutationObserver::observationStarted(MutationObserverRegistration* registration) 157 { 158 ASSERT(!m_registrations.contains(registration)); 159 m_registrations.add(registration); 160 } 161 162 void MutationObserver::observationEnded(MutationObserverRegistration* registration) 163 { 164 ASSERT(m_registrations.contains(registration)); 165 m_registrations.remove(registration); 166 } 167 168 static MutationObserverSet& activeMutationObservers() 169 { 170 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<MutationObserverSet>, activeObservers, (adoptPtrWillBeNoop(new MutationObserverSet()))); 171 return *activeObservers; 172 } 173 174 static MutationObserverSet& suspendedMutationObservers() 175 { 176 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<MutationObserverSet>, suspendedObservers, (adoptPtrWillBeNoop(new MutationObserverSet()))); 177 return *suspendedObservers; 178 } 179 180 static void activateObserver(PassRefPtrWillBeRawPtr<MutationObserver> observer) 181 { 182 if (activeMutationObservers().isEmpty()) 183 Microtask::enqueueMicrotask(WTF::bind(&MutationObserver::deliverMutations)); 184 185 activeMutationObservers().add(observer); 186 } 187 188 void MutationObserver::enqueueMutationRecord(PassRefPtrWillBeRawPtr<MutationRecord> mutation) 189 { 190 ASSERT(isMainThread()); 191 m_records.append(mutation); 192 activateObserver(this); 193 InspectorInstrumentation::didEnqueueMutationRecord(m_callback->executionContext(), this); 194 } 195 196 void MutationObserver::setHasTransientRegistration() 197 { 198 ASSERT(isMainThread()); 199 activateObserver(this); 200 } 201 202 WillBeHeapHashSet<RawPtrWillBeMember<Node> > MutationObserver::getObservedNodes() const 203 { 204 WillBeHeapHashSet<RawPtrWillBeMember<Node> > observedNodes; 205 for (MutationObserverRegistrationSet::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) 206 (*iter)->addRegistrationNodesToSet(observedNodes); 207 return observedNodes; 208 } 209 210 bool MutationObserver::canDeliver() 211 { 212 return !m_callback->executionContext()->activeDOMObjectsAreSuspended(); 213 } 214 215 void MutationObserver::deliver() 216 { 217 ASSERT(canDeliver()); 218 219 // Calling clearTransientRegistrations() can modify m_registrations, so it's necessary 220 // to make a copy of the transient registrations before operating on them. 221 WillBeHeapVector<RawPtrWillBeMember<MutationObserverRegistration>, 1> transientRegistrations; 222 for (MutationObserverRegistrationSet::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) { 223 if ((*iter)->hasTransientRegistrations()) 224 transientRegistrations.append(*iter); 225 } 226 for (size_t i = 0; i < transientRegistrations.size(); ++i) 227 transientRegistrations[i]->clearTransientRegistrations(); 228 229 if (m_records.isEmpty()) 230 return; 231 232 MutationRecordVector records; 233 records.swap(m_records); 234 235 InspectorInstrumentation::willDeliverMutationRecords(m_callback->executionContext(), this); 236 m_callback->call(records, this); 237 InspectorInstrumentation::didDeliverMutationRecords(m_callback->executionContext()); 238 } 239 240 void MutationObserver::resumeSuspendedObservers() 241 { 242 ASSERT(isMainThread()); 243 if (suspendedMutationObservers().isEmpty()) 244 return; 245 246 MutationObserverVector suspended; 247 copyToVector(suspendedMutationObservers(), suspended); 248 for (size_t i = 0; i < suspended.size(); ++i) { 249 if (suspended[i]->canDeliver()) { 250 suspendedMutationObservers().remove(suspended[i]); 251 activateObserver(suspended[i]); 252 } 253 } 254 } 255 256 void MutationObserver::deliverMutations() 257 { 258 ASSERT(isMainThread()); 259 MutationObserverVector observers; 260 copyToVector(activeMutationObservers(), observers); 261 activeMutationObservers().clear(); 262 std::sort(observers.begin(), observers.end(), ObserverLessThan()); 263 for (size_t i = 0; i < observers.size(); ++i) { 264 if (observers[i]->canDeliver()) 265 observers[i]->deliver(); 266 else 267 suspendedMutationObservers().add(observers[i]); 268 } 269 } 270 271 void MutationObserver::trace(Visitor* visitor) 272 { 273 #if ENABLE(OILPAN) 274 visitor->trace(m_records); 275 visitor->trace(m_registrations); 276 #endif 277 } 278 279 } // namespace blink 280