Changeset 98659 in webkit
- Timestamp:
- Oct 27, 2011 4:38:09 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r98658 r98659 1 2011-10-27 Rafael Weinstein <rafaelw@chromium.org> 2 3 [MutationObservers] Implement subtree observation of transiently disconnected nodes 4 https://bugs.webkit.org/show_bug.cgi?id=70788 5 6 Reviewed by Ryosuke Niwa. 7 8 Added tests which assert that nodes can be detached from a subtree where observation is registered 9 and still be observed -- until the end of the current "microtask". 10 11 * fast/mutation/observe-subtree-expected.txt: 12 * fast/mutation/observe-subtree.html: 13 1 14 2011-10-27 Filip Pizlo <fpizlo@apple.com> 2 15 -
trunk/LayoutTests/fast/mutation/observe-subtree-expected.txt
r98163 r98659 34 34 PASS mutations[0].attributeNamespace is null 35 35 36 Testing that transiently detached nodes are still observed via subtree. 37 ...both changes should be received. Change detached subDiv again. 38 PASS mutations.length is 2 39 PASS mutations[0].type is "attributes" 40 PASS mutations[0].target is subDiv 41 PASS mutations[0].attributeName is "foo" 42 PASS mutations[1].type is "attributes" 43 PASS mutations[1].target is subDiv 44 PASS mutations[1].attributeName is "test" 45 ...transient subtree observation was stopped after delivery, so subDiv change should not be received. Reattach and change again. 46 PASS mutations is null 47 ...reattached subtree should now be observable. Try detaching and re-observing. 48 PASS mutations.length is 1 49 PASS mutations[0].type is "attributes" 50 PASS mutations[0].target is subDiv 51 PASS mutations[0].attributeName is "foo" 52 ...The change made before re-observing should be received, but not the one after. 53 PASS mutations.length is 1 54 PASS mutations[0].type is "characterData" 55 PASS mutations[0].target is subDiv.firstChild 56 57 Testing correct behavior of transient observation with complex movement . 58 ...All changes should be received except for setting the "d" attribute on subDiv3 before it was reachable from div. 59 PASS mutations.length is 6 60 PASS mutations[0].type is "attributes" 61 PASS mutations[0].target is subDiv 62 PASS mutations[0].attributeName is "a" 63 PASS mutations[1].type is "attributes" 64 PASS mutations[1].target is subDiv2 65 PASS mutations[1].attributeName is "b" 66 PASS mutations[2].type is "characterData" 67 PASS mutations[2].target is text 68 PASS mutations[3].type is "attributes" 69 PASS mutations[3].target is subDiv2 70 PASS mutations[3].attributeName is "e" 71 PASS mutations[4].type is "attributes" 72 PASS mutations[4].target is subDiv3 73 PASS mutations[4].attributeName is "f" 74 PASS mutations[5].type is "attributes" 75 PASS mutations[5].target is subDiv2 76 PASS mutations[5].attributeName is "g" 77 36 78 PASS successfullyParsed is true 37 79 -
trunk/LayoutTests/fast/mutation/observe-subtree.html
r98407 r98659 16 16 var mutations2; 17 17 var div; 18 var subDiv ;18 var subDiv, subDiv2, subDiv3, text; 19 19 var calls; 20 20 … … 136 136 start(); 137 137 } 138 var tests = [testBasic, testMultipleObservers, testMultipleObservations]; 138 139 function testTransientDetachedBasic() { 140 var observer; 141 142 function start() { 143 debug('Testing that transiently detached nodes are still observed via subtree.'); 144 145 mutations = null; 146 div = document.createElement('div'); 147 subDiv = div.appendChild(document.createElement('div')); 148 subDiv.innerHTML = 'hello, world'; 149 observer = new WebKitMutationObserver(function(mutations) { 150 window.mutations = mutations; 151 }); 152 153 observer.observe(div, {attributes: true, characterData: true, subtree: true}); 154 subDiv.setAttribute('foo', 'bar'); 155 div.removeChild(subDiv); 156 subDiv.setAttribute('test', 'test'); 157 setTimeout(checkDeliveredAndChangeAgain, 0); 158 } 159 160 function checkDeliveredAndChangeAgain() { 161 debug('...both changes should be received. Change detached subDiv again.'); 162 163 shouldBe('mutations.length', '2'); 164 shouldBe('mutations[0].type', '"attributes"'); 165 shouldBe('mutations[0].target', 'subDiv'); 166 shouldBe('mutations[0].attributeName', '"foo"'); 167 shouldBe('mutations[1].type', '"attributes"'); 168 shouldBe('mutations[1].target', 'subDiv'); 169 shouldBe('mutations[1].attributeName', '"test"'); 170 171 mutations = null; 172 subDiv.setAttribute('foo', 'baz'); 173 174 setTimeout(checkNotDeliveredAndReattach); 175 } 176 177 function checkNotDeliveredAndReattach() { 178 debug('...transient subtree observation was stopped after delivery, so subDiv change should not be received. Reattach and change again.'); 179 180 shouldBe('mutations', 'null'); 181 182 mutations = null 183 div.appendChild(subDiv); 184 subDiv.setAttribute('foo', 'bat'); 185 186 setTimeout(checkDeliveredAndReobserve); 187 } 188 189 function checkDeliveredAndReobserve() { 190 debug('...reattached subtree should now be observable. Try detaching and re-observing.'); 191 192 shouldBe('mutations.length', '1'); 193 shouldBe('mutations[0].type', '"attributes"'); 194 shouldBe('mutations[0].target', 'subDiv'); 195 shouldBe('mutations[0].attributeName', '"foo"'); 196 197 mutations = null; 198 div.removeChild(subDiv); 199 subDiv.firstChild.textContent = 'badbye'; 200 observer.observe(div, {attributes: true, characterData: true, subtree: true}); 201 subDiv.setAttribute('foo', 'boo'); 202 203 setTimeout(finish); 204 } 205 206 207 function finish() { 208 debug('...The change made before re-observing should be received, but not the one after.'); 209 210 shouldBe('mutations.length', '1'); 211 shouldBe('mutations[0].type', '"characterData"'); 212 shouldBe('mutations[0].target', 'subDiv.firstChild'); 213 214 observer.disconnect(); 215 debug(''); 216 runNextTest(); 217 } 218 start(); 219 } 220 221 function testTransientDetachedDetailed() { 222 var observer; 223 224 function start() { 225 debug('Testing correct behavior of transient observation with complex movement .'); 226 227 mutations = null; 228 div = document.createElement('div'); 229 subDiv = div.appendChild(document.createElement('div')); 230 subDiv2 = subDiv.appendChild(document.createElement('div')); 231 subDiv2.innerHTML = 'hello, world'; 232 subDiv3 = document.createElement('div'); 233 234 observer = new WebKitMutationObserver(function(mutations) { 235 window.mutations = mutations; 236 }); 237 238 observer.observe(div, {attributes: true, characterData: true, subtree: true}); 239 div.removeChild(subDiv); 240 subDiv.removeChild(subDiv2); 241 text = subDiv2.removeChild(subDiv2.firstChild); 242 243 subDiv.setAttribute('a', 'a'); 244 subDiv2.setAttribute('b', 'b'); 245 text.textContent = 'c'; 246 subDiv3.appendChild(subDiv2); 247 subDiv3.setAttribute('d', 'd'); 248 subDiv2.setAttribute('e', 'e'); 249 div.appendChild(subDiv3); 250 subDiv3.setAttribute('f', 'f'); 251 subDiv2.setAttribute('g', 'g'); 252 253 setTimeout(finish, 0); 254 } 255 256 function finish() { 257 debug('...All changes should be received except for setting the "d" attribute on subDiv3 before it was reachable from div.'); 258 259 shouldBe('mutations.length', '6'); 260 shouldBe('mutations[0].type', '"attributes"'); 261 shouldBe('mutations[0].target', 'subDiv'); 262 shouldBe('mutations[0].attributeName', '"a"'); 263 264 shouldBe('mutations[1].type', '"attributes"'); 265 shouldBe('mutations[1].target', 'subDiv2'); 266 shouldBe('mutations[1].attributeName', '"b"'); 267 268 shouldBe('mutations[2].type', '"characterData"'); 269 shouldBe('mutations[2].target', 'text'); 270 271 shouldBe('mutations[3].type', '"attributes"'); 272 shouldBe('mutations[3].target', 'subDiv2'); 273 shouldBe('mutations[3].attributeName', '"e"'); 274 275 shouldBe('mutations[4].type', '"attributes"'); 276 shouldBe('mutations[4].target', 'subDiv3'); 277 shouldBe('mutations[4].attributeName', '"f"'); 278 279 shouldBe('mutations[5].type', '"attributes"'); 280 shouldBe('mutations[5].target', 'subDiv2'); 281 shouldBe('mutations[5].attributeName', '"g"'); 282 283 observer.disconnect(); 284 debug(''); 285 runNextTest(); 286 } 287 start(); 288 } 289 290 var tests = [testBasic, testMultipleObservers, testMultipleObservations, testTransientDetachedBasic, testTransientDetachedDetailed]; 139 291 var testIndex = 0; 140 292 -
trunk/Source/WebCore/ChangeLog
r98657 r98659 1 2011-10-27 Rafael Weinstein <rafaelw@chromium.org> 2 3 [MutationObservers] Implement subtree observation of transiently disconnected nodes 4 https://bugs.webkit.org/show_bug.cgi?id=70788 5 6 Reviewed by Ryosuke Niwa. 7 8 This patch adds support for observing all descendant nodes reachable from a subtree 9 observation until delivery of mutations -- even if they become detached. We do this by 10 introducing a "transient registration" which can exist for a short time along side 11 normal registrations on Node. Transient registrations have a reference to the node 12 which "owns" the subtree observation registration (the "registrationNode"). Transient 13 registrations are cleared immediately before mutations are delivered to an observer, 14 or when the observer re-observes at the registrationNode, in-effect resetting the 15 observation. 16 17 New tests added to fast/mutation/observe-subtree.html. 18 19 * dom/CharacterData.cpp: 20 (WebCore::CharacterData::dispatchModifiedEvent): 21 * dom/ChildListMutationScope.cpp: 22 (WebCore::MutationAccumulationRouter::ChildListMutationAccumulator::ChildListMutationAccumulator): 23 (WebCore::MutationAccumulationRouter::ChildListMutationAccumulator::enqueueMutationRecord): 24 (WebCore::MutationAccumulationRouter::MutationAccumulationRouter::incrementScopingLevel): 25 * dom/ContainerNode.cpp: 26 (WebCore::dispatchChildRemovalEvents): 27 * dom/Element.cpp: 28 (WebCore::enqueueAttributesMutationRecord): 29 * dom/Node.cpp: 30 (WebCore::addMatchingObservers): 31 (WebCore::Node::getRegisteredMutationObserversOfType): 32 (WebCore::Node::registerMutationObserver): 33 (WebCore::Node::unregisterMutationObserver): 34 (WebCore::Node::notifySubtreeObserversOfDisconnection): 35 * dom/Node.h: 36 * dom/NodeRareData.h: 37 (WebCore::MutationObserverEntry::MutationObserverEntry): 38 (WebCore::MutationObserverEntry::operator==): 39 * dom/WebKitMutationObserver.cpp: 40 (WebCore::WebKitMutationObserver::observe): 41 (WebCore::unregisterTransientEntries): 42 (WebCore::WebKitMutationObserver::disconnect): 43 (WebCore::WebKitMutationObserver::observedNodeDestructed): 44 (WebCore::WebKitMutationObserver::observedSubtreeWillDisconnect): 45 (WebCore::WebKitMutationObserver::clearTransientEntries): 46 (WebCore::WebKitMutationObserver::deliver): 47 * dom/WebKitMutationObserver.h: 48 1 49 2011-10-27 Pratik Solanki <psolanki@apple.com> 2 50 -
trunk/Source/WebCore/dom/CharacterData.cpp
r98262 r98659 194 194 { 195 195 #if ENABLE(MUTATION_OBSERVERS) 196 Vector<WebKitMutationObserver*> observers;196 HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; 197 197 getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::CharacterData); 198 198 if (!observers.isEmpty()) { 199 199 RefPtr<MutationRecord> mutation = MutationRecord::createCharacterData(this); 200 for ( size_t i = 0; i < observers.size(); ++i)201 observers[i]->enqueueMutationRecord(mutation);200 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) 201 iter->first->enqueueMutationRecord(mutation); 202 202 } 203 203 #endif -
trunk/Source/WebCore/dom/ChildListMutationScope.cpp
r98262 r98659 54 54 WTF_MAKE_NONCOPYABLE(ChildListMutationAccumulator); 55 55 public: 56 ChildListMutationAccumulator(PassRefPtr<Node>, Vector<WebKitMutationObserver*>&);56 ChildListMutationAccumulator(PassRefPtr<Node>, HashMap<WebKitMutationObserver*, MutationObserverOptions>&); 57 57 ~ChildListMutationAccumulator(); 58 58 … … 74 74 RefPtr<Node> m_lastAdded; 75 75 76 Vector<WebKitMutationObserver*> m_observers;76 HashMap<WebKitMutationObserver*, MutationObserverOptions> m_observers; 77 77 }; 78 78 … … 101 101 }; 102 102 103 ChildListMutationAccumulator::ChildListMutationAccumulator(PassRefPtr<Node> target, Vector<WebKitMutationObserver*>& observers)103 ChildListMutationAccumulator::ChildListMutationAccumulator(PassRefPtr<Node> target, HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers) 104 104 : m_target(target) 105 105 { … … 170 170 m_target, StaticNodeList::adopt(m_addedNodes), StaticNodeList::adopt(m_removedNodes), m_previousSibling, m_nextSibling); 171 171 172 for ( size_t i = 0; i < m_observers.size(); ++i)173 m_observers[i]->enqueueMutationRecord(mutation);172 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = m_observers.begin(); iter != m_observers.end(); ++iter) 173 iter->first->enqueueMutationRecord(mutation); 174 174 175 175 clear(); … … 245 245 } 246 246 247 Vector<WebKitMutationObserver*> observers;247 HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; 248 248 target->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::ChildList); 249 249 if (observers.isEmpty()) -
trunk/Source/WebCore/dom/ContainerNode.cpp
r98121 r98659 1145 1145 ChildListMutationScope mutation(c->parentNode()); 1146 1146 mutation.willRemoveChild(c); 1147 c->notifyMutationObserversNodeWillDetach(); 1147 1148 } 1148 1149 #endif -
trunk/Source/WebCore/dom/Element.cpp
r98492 r98659 620 620 static void enqueueAttributesMutationRecord(Element* element, const QualifiedName& name) 621 621 { 622 Vector<WebKitMutationObserver*> observers;622 HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; 623 623 element->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::Attributes); 624 624 if (observers.isEmpty()) … … 626 626 627 627 RefPtr<MutationRecord> mutation = MutationRecord::createAttributes(element, name); 628 for ( size_t i = 0; i < observers.size(); ++i)629 observers[i]->enqueueMutationRecord(mutation);628 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) 629 iter->first->enqueueMutationRecord(mutation); 630 630 } 631 631 #endif -
trunk/Source/WebCore/dom/Node.cpp
r98388 r98659 550 550 551 551 #if ENABLE(MUTATION_OBSERVERS) 552 Vector<MutationObserverEntry>* observerEntries = mutationObserverEntries(); 553 if (observerEntries) { 554 for (size_t i = 0; i < observerEntries->size(); ++i) 555 observerEntries->at(i).observer->observedNodeDestructed(this); 552 if (Vector<MutationObserverRegistration>* registry = mutationObserverRegistry()) { 553 for (size_t i = 0; i < registry->size(); ++i) 554 registry->at(i).observer->observedNodeDestructed(this); 556 555 } 557 556 #endif … … 2699 2698 2700 2699 #if ENABLE(MUTATION_OBSERVERS) 2701 Vector<MutationObserver Entry>* Node::mutationObserverEntries()2702 { 2703 return hasRareData() ? rareData()->mutationObserver Entries() : 0;2704 } 2705 2706 static void addMatchingObservers(Hash Set<WebKitMutationObserver*>& observerSet, Vector<MutationObserverEntry>* observerEntries, MutationObserverOptions options)2707 { 2708 if (! observerEntries)2709 return; 2710 2711 const size_t size = observerEntries->size();2700 Vector<MutationObserverRegistration>* Node::mutationObserverRegistry() 2701 { 2702 return hasRareData() ? rareData()->mutationObserverRegistry() : 0; 2703 } 2704 2705 static void addMatchingObservers(HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers, Vector<MutationObserverRegistration>* registry, MutationObserverOptions options) 2706 { 2707 if (!registry) 2708 return; 2709 2710 const size_t size = registry->size(); 2712 2711 for (size_t i = 0; i < size; ++i) { 2713 MutationObserverEntry& entry = observerEntries->at(i); 2714 if (entry.hasAllOptions(options)) 2715 observerSet.add(entry.observer.get()); 2716 } 2717 } 2718 2719 void Node::getRegisteredMutationObserversOfType(Vector<WebKitMutationObserver*>& observers, WebKitMutationObserver::MutationType type) 2720 { 2721 HashSet<WebKitMutationObserver*> observerSet; 2722 addMatchingObservers(observerSet, mutationObserverEntries(), type); 2712 MutationObserverRegistration& entry = registry->at(i); 2713 2714 if (!entry.hasAllOptions(options)) 2715 continue; 2716 2717 pair<HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator, bool> result = observers.add(entry.observer.get(), entry.options); 2718 if (!result.second) 2719 result.first->second |= entry.options; 2720 } 2721 } 2722 2723 void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers, WebKitMutationObserver::MutationType type) 2724 { 2725 addMatchingObservers(observers, mutationObserverRegistry(), type); 2723 2726 for (Node* node = parentNode(); node; node = node->parentNode()) 2724 addMatchingObservers(observerSet, node->mutationObserverEntries(), type | WebKitMutationObserver::Subtree); 2725 2726 // FIXME: this method should output a HashSet instead of a Vector. 2727 if (!observerSet.isEmpty()) 2728 copyToVector(observerSet, observers); 2729 } 2730 2731 Node::MutationRegistrationResult Node::registerMutationObserver(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options) 2732 { 2733 Vector<MutationObserverEntry>* observerEntries = ensureRareData()->ensureMutationObserverEntries(); 2734 MutationObserverEntry entry(observer, options); 2735 2736 size_t index = observerEntries->find(entry); 2727 addMatchingObservers(observers, node->mutationObserverRegistry(), type | WebKitMutationObserver::Subtree); 2728 } 2729 2730 Node::MutationRegistrationResult Node::registerMutationObserver(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options, Node* registrationNode) 2731 { 2732 Vector<MutationObserverRegistration>* registry = ensureRareData()->ensureMutationObserverRegistry(); 2733 MutationObserverRegistration registration(observer, options, registrationNode); 2734 2735 size_t index = registry->find(registration); 2737 2736 if (index == notFound) { 2738 observerEntries->append(entry);2737 registry->append(registration); 2739 2738 return MutationObserverRegistered; 2740 2739 } 2741 2740 2742 (*observerEntries)[index].options = entry.options;2741 registry->at(index).options = registration.options; 2743 2742 return MutationRegistrationOptionsReset; 2744 2743 } 2745 2744 2746 void Node::unregisterMutationObserver(PassRefPtr<WebKitMutationObserver> observer )2747 { 2748 Vector<MutationObserver Entry>* observerEntries = mutationObserverEntries();2749 ASSERT( observerEntries);2750 if (! observerEntries)2751 return; 2752 2753 MutationObserver Entry entry(observer, 0);2754 size_t index = observerEntries->find(entry);2745 void Node::unregisterMutationObserver(PassRefPtr<WebKitMutationObserver> observer, Node* registrationNode) 2746 { 2747 Vector<MutationObserverRegistration>* registry = mutationObserverRegistry(); 2748 ASSERT(registry); 2749 if (!registry) 2750 return; 2751 2752 MutationObserverRegistration registration(observer, 0, registrationNode); 2753 size_t index = registry->find(registration); 2755 2754 ASSERT(index != notFound); 2756 2755 if (index == notFound) 2757 2756 return; 2758 2757 2759 observerEntries->remove(index); 2758 registry->remove(index); 2759 } 2760 2761 void Node::notifyMutationObserversNodeWillDetach() 2762 { 2763 for (Node* node = parentNode(); node; node = node->parentNode()) { 2764 Vector<MutationObserverRegistration>* registry = node->mutationObserverRegistry(); 2765 if (!registry) 2766 continue; 2767 2768 const size_t size = registry->size(); 2769 for (size_t i = 0; i < size; ++i) { 2770 MutationObserverRegistration& registration = registry->at(i); 2771 if (!registration.hasAllOptions(WebKitMutationObserver::Subtree)) 2772 continue; 2773 2774 Node* registrationNode = registration.registrationNode; 2775 if (!registrationNode) 2776 registrationNode = node; 2777 registration.observer->willDetachNodeInObservedSubtree(registrationNode, registration.options, this); 2778 } 2779 } 2760 2780 } 2761 2781 #endif // ENABLE(MUTATION_OBSERVERS) -
trunk/Source/WebCore/dom/Node.h
r98402 r98659 82 82 class TreeScope; 83 83 84 struct MutationObserver Entry;84 struct MutationObserverRegistration; 85 85 86 86 typedef int ExceptionCode; … … 591 591 592 592 #if ENABLE(MUTATION_OBSERVERS) 593 void getRegisteredMutationObserversOfType( Vector<WebKitMutationObserver*>&, WebKitMutationObserver::MutationType);593 void getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationObserverOptions>&, WebKitMutationObserver::MutationType); 594 594 595 595 enum MutationRegistrationResult { … … 597 597 MutationRegistrationOptionsReset 598 598 }; 599 MutationRegistrationResult registerMutationObserver(PassRefPtr<WebKitMutationObserver>, MutationObserverOptions); 600 601 void unregisterMutationObserver(PassRefPtr<WebKitMutationObserver>); 599 MutationRegistrationResult registerMutationObserver(PassRefPtr<WebKitMutationObserver>, MutationObserverOptions, Node* registrationNode = 0); 600 601 void unregisterMutationObserver(PassRefPtr<WebKitMutationObserver>, Node* registrationNode = 0); 602 603 void notifyMutationObserversNodeWillDetach(); 602 604 #endif // ENABLE(MUTATION_OBSERVERS) 603 605 … … 726 728 727 729 #if ENABLE(MUTATION_OBSERVERS) 728 Vector<MutationObserver Entry>* mutationObserverEntries();730 Vector<MutationObserverRegistration>* mutationObserverRegistry(); 729 731 #endif 730 732 -
trunk/Source/WebCore/dom/NodeRareData.h
r98163 r98659 90 90 91 91 #if ENABLE(MUTATION_OBSERVERS) 92 struct MutationObserver Entry{93 MutationObserver Entry(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options)92 struct MutationObserverRegistration { 93 MutationObserverRegistration(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options, Node* node) 94 94 : observer(observer) 95 95 , options(options) 96 { 97 } 98 99 bool operator==(const MutationObserverEntry& other) const 100 { 101 return observer == other.observer; 96 , registrationNode(node) 97 { 98 } 99 100 bool operator==(const MutationObserverRegistration& other) const 101 { 102 return observer == other.observer && registrationNode == other.registrationNode; 102 103 } 103 104 … … 109 110 RefPtr<WebKitMutationObserver> observer; 110 111 MutationObserverOptions options; 112 113 // registrationNode will be 0 if the registration is non-transient. I.e. The registrationNode is the Node in whose 114 // registry it exists. 115 // Note that this doesn't need to be a RefPtr because the observer will be holding a RefPtr to the same node at 116 // least for the lifetime of this Registration in its m_transientObservedNodes map. 117 Node* registrationNode; 111 118 }; 112 119 #endif // ENABLE(MUTATION_OBSERVERS) … … 162 169 163 170 #if ENABLE(MUTATION_OBSERVERS) 164 Vector<MutationObserver Entry>* mutationObserverEntries() { return m_mutationObservers.get(); }165 Vector<MutationObserver Entry>* ensureMutationObserverEntries()166 { 167 if (!m_mutationObserver s)168 m_mutationObserver s = adoptPtr(new Vector<MutationObserverEntry>);169 return m_mutationObserver s.get();171 Vector<MutationObserverRegistration>* mutationObserverRegistry() { return m_mutationObserverRegistry.get(); } 172 Vector<MutationObserverRegistration>* ensureMutationObserverRegistry() 173 { 174 if (!m_mutationObserverRegistry) 175 m_mutationObserverRegistry = adoptPtr(new Vector<MutationObserverRegistration>); 176 return m_mutationObserverRegistry.get(); 170 177 } 171 178 #endif … … 189 196 190 197 #if ENABLE(MUTATION_OBSERVERS) 191 OwnPtr<Vector<MutationObserver Entry> > m_mutationObservers;198 OwnPtr<Vector<MutationObserverRegistration> > m_mutationObserverRegistry; 192 199 #endif 193 200 }; -
trunk/Source/WebCore/dom/WebKitMutationObserver.cpp
r98121 r98659 54 54 WebKitMutationObserver::~WebKitMutationObserver() 55 55 { 56 clearAllTransientObservations(); 57 } 58 59 static inline void clearTransientObservationsForRegistration(WebKitMutationObserver* observer, Node* registrationNode, PassOwnPtr<NodeHashSet> transientNodes) 60 { 61 for (NodeHashSet::iterator iter = transientNodes->begin(); iter != transientNodes->end(); ++iter) 62 (*iter)->unregisterMutationObserver(observer, registrationNode); 56 63 } 57 64 … … 60 67 // FIXME: More options composition work needs to be done here, e.g., validation. 61 68 62 if (node->registerMutationObserver(this, options) == Node::MutationObserverRegistered) 69 if (node->registerMutationObserver(this, options) == Node::MutationObserverRegistered) { 63 70 m_observedNodes.append(node); 71 return; 72 } 73 74 HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.find(node); 75 if (iter == m_transientObservedNodes.end()) 76 return; 77 78 clearTransientObservationsForRegistration(this, node, adoptPtr(iter->second)); 79 m_transientObservedNodes.remove(iter); 64 80 } 65 81 … … 70 86 71 87 m_observedNodes.clear(); 88 clearAllTransientObservations(); 72 89 } 73 90 74 91 void WebKitMutationObserver::observedNodeDestructed(Node* node) 75 92 { 93 ASSERT(!m_transientObservedNodes.contains(node)); 94 76 95 size_t index = m_observedNodes.find(node); 77 96 ASSERT(index != notFound); … … 96 115 } 97 116 117 void WebKitMutationObserver::willDetachNodeInObservedSubtree(PassRefPtr<Node> prpRegistrationNode, MutationObserverOptions options, PassRefPtr<Node> prpDetachingNode) 118 { 119 RefPtr<Node> registrationNode = prpRegistrationNode; 120 RefPtr<Node> detachingNode = prpDetachingNode; 121 122 detachingNode->registerMutationObserver(this, options, registrationNode.get()); 123 HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.find(registrationNode); 124 if (iter != m_transientObservedNodes.end()) { 125 iter->second->add(detachingNode); 126 return; 127 } 128 129 OwnPtr<NodeHashSet> set = adoptPtr(new NodeHashSet()); 130 set->add(detachingNode); 131 m_transientObservedNodes.set(registrationNode, set.leakPtr()); 132 } 133 134 void WebKitMutationObserver::clearAllTransientObservations() 135 { 136 for (HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.begin(); iter != m_transientObservedNodes.end(); ++iter) 137 clearTransientObservationsForRegistration(this, iter->first.get(), adoptPtr(iter->second)); 138 139 m_transientObservedNodes.clear(); 140 } 141 98 142 void WebKitMutationObserver::deliver() 99 143 { 100 144 MutationRecordArray records; 101 145 records.swap(m_records); 146 clearAllTransientObservations(); 102 147 m_callback->handleEvent(&records, this); 103 148 } -
trunk/Source/WebCore/dom/WebKitMutationObserver.h
r97714 r98659 34 34 #if ENABLE(MUTATION_OBSERVERS) 35 35 36 #include <wtf/HashMap.h> 37 #include <wtf/HashSet.h> 36 38 #include <wtf/PassOwnPtr.h> 37 39 #include <wtf/RefCounted.h> … … 46 48 47 49 typedef unsigned char MutationObserverOptions; 50 typedef HashSet<RefPtr<Node> > NodeHashSet; 48 51 49 52 class WebKitMutationObserver : public RefCounted<WebKitMutationObserver> { … … 69 72 void observe(Node*, MutationObserverOptions); 70 73 void disconnect(); 74 void willDetachNodeInObservedSubtree(PassRefPtr<Node> registrationNode, MutationObserverOptions, PassRefPtr<Node> detachingNode); 71 75 void observedNodeDestructed(Node*); 72 76 void enqueueMutationRecord(PassRefPtr<MutationRecord>); … … 75 79 WebKitMutationObserver(PassRefPtr<MutationCallback>); 76 80 81 void clearAllTransientObservations(); 77 82 void deliver(); 78 83 … … 80 85 Vector<RefPtr<MutationRecord> > m_records; 81 86 Vector<Node*> m_observedNodes; // NodeRareData has a RefPtr to this, so use a weak pointer to avoid a cycle. 87 88 // FIXME: Change this to be OwnPtr<NodeHashSet> when OwnPtr supports being contained as map values. 89 HashMap<RefPtr<Node>, NodeHashSet*> m_transientObservedNodes; 82 90 }; 83 91
Note: See TracChangeset
for help on using the changeset viewer.