Changeset 97659 in webkit
- Timestamp:
- Oct 17, 2011 3:31:25 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r97657 r97659 1 2011-10-17 Rafael Weinstein <rafaelw@chromium.org> 2 3 [MutationObservers] Implement WebKitMutationObserver.observe for attributes 4 https://bugs.webkit.org/show_bug.cgi?id=68956 5 6 Reviewed by Ryosuke Niwa. 7 8 * fast/mutation/observe-attributes-expected.txt: Added. 9 * fast/mutation/observe-attributes.html: Added. 10 1 11 2011-10-17 Dirk Pranke <dpranke@chromium.org> 2 12 -
trunk/Source/WebCore/ChangeLog
r97658 r97659 1 2011-10-17 Rafael Weinstein <rafaelw@chromium.org> 2 3 [MutationObservers] Implement WebKitMutationObserver.observe for attributes 4 https://bugs.webkit.org/show_bug.cgi?id=68956 5 6 Reviewed by Ryosuke Niwa. 7 8 Test: fast/mutation/observe-attributes.html 9 10 This adds an initial implementation for registering mutation observers on nodes, 11 delivering mutation records at the end of the outer-most script invokation and 12 observing mutations to element attributes. 13 14 Note that the outer-most script invokation only works in V8. 15 16 Note also that support for observing changes to the style attribute when updated 17 via the style property is not implemented here. 18 19 * bindings/v8/V8Proxy.cpp: 20 (WebCore::V8Proxy::didLeaveScriptContext): 21 * dom/Element.cpp: 22 (WebCore::enqueueAttributesMutationRecord): 23 (WebCore::Element::setAttribute): 24 * dom/MutationRecord.cpp: 25 (WebCore::MutationRecord::createAttributes): 26 * dom/MutationRecord.h: 27 * dom/MutationRecord.idl: 28 * dom/Node.cpp: 29 (WebCore::Node::clearRareData): 30 (WebCore::Node::mutationObserverData): 31 (WebCore::Node::ensureMutationObserverData): 32 (WebCore::Node::registeredMutationObserversOfType): 33 (WebCore::Node::registerMutationObserver): 34 (WebCore::Node::deregisterMutationObserver): 35 * dom/Node.h: 36 * dom/NodeRareData.h: 37 (WebCore::MutationObserverRegistration::MutationObserverRegistration): 38 (WebCore::MutationObserverRegistration::operator==): 39 (WebCore::MutationObserverData::MutationObserverData): 40 (WebCore::MutationObserverData::~MutationObserverData): 41 (WebCore::NodeRareData::mutationObserverData): 42 (WebCore::NodeRareData::ensureMutationObserverData): 43 * dom/WebKitMutationObserver.cpp: 44 (WebCore::WebKitMutationObserver::observe): 45 (WebCore::WebKitMutationObserver::disconnect): 46 (WebCore::WebKitMutationObserver::wasDeregistered): 47 (WebCore::activeMutationObservers): 48 (WebCore::WebKitMutationObserver::enqueueMutationRecord): 49 (WebCore::WebKitMutationObserver::deliverAllMutations): 50 (WebCore::WebKitMutationObserver::deliver): 51 * dom/WebKitMutationObserver.h: 52 1 53 2011-10-17 Andreas Kling <kling@webkit.org> 2 54 -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r97637 r97659 5467 5467 C6F0900A14327B6100685849 /* MutationCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900114327B6100685849 /* MutationCallback.h */; }; 5468 5468 C6F0900E14327B6100685849 /* WebKitMutationObserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6F0900514327B6100685849 /* WebKitMutationObserver.cpp */; }; 5469 C6F0900F14327B6100685849 /* WebKitMutationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900614327B6100685849 /* WebKitMutationObserver.h */; };5469 C6F0900F14327B6100685849 /* WebKitMutationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900614327B6100685849 /* WebKitMutationObserver.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5470 5470 C6F0901114327B6100685849 /* MutationObserverOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900814327B6100685849 /* MutationObserverOptions.h */; }; 5471 5471 C6F0902814327D4F00685849 /* JSMutationCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6F0902014327D4F00685849 /* JSMutationCallback.cpp */; }; -
trunk/Source/WebCore/bindings/v8/V8Proxy.cpp
r97280 r97659 66 66 #include "V8XMLHttpRequestException.h" 67 67 #include "V8XPathException.h" 68 #include "WebKitMutationObserver.h" 68 69 #include "WorkerContext.h" 69 70 #include "WorkerContextExecutionProxy.h" … … 621 622 if (page->group().hasLocalStorage()) 622 623 page->group().localStorage()->unlock(); 624 625 #if ENABLE(MUTATION_OBSERVERS) 626 WebCore::WebKitMutationObserver::deliverAllMutations(); 627 #endif 623 628 } 624 629 -
trunk/Source/WebCore/dom/Element.cpp
r97638 r97659 49 49 #include "HTMLParserIdioms.h" 50 50 #include "InspectorInstrumentation.h" 51 #include "MutationRecord.h" 51 52 #include "NodeList.h" 52 53 #include "NodeRenderStyle.h" … … 60 61 #include "Text.h" 61 62 #include "TextIterator.h" 63 #include "WebKitMutationObserver.h" 62 64 #include "WebKitAnimationList.h" 63 65 #include "XMLNames.h" … … 611 613 } 612 614 615 #if ENABLE(MUTATION_OBSERVERS) 616 static void enqueueAttributesMutationRecord(Element* element, const QualifiedName& name) 617 { 618 Vector<WebKitMutationObserver*> observers; 619 element->registeredMutationObserversOfType(observers, WebKitMutationObserver::Attributes); 620 if (observers.isEmpty()) 621 return; 622 623 RefPtr<MutationRecord> mutation = MutationRecord::createAttributes(element, name); 624 for (Vector<WebKitMutationObserver*>::iterator iter = observers.begin(); iter != observers.end(); ++iter) 625 (*iter)->enqueueMutationRecord(mutation); 626 } 627 #endif 628 613 629 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec) 614 630 { … … 630 646 631 647 document()->incDOMTreeVersion(); 648 649 #if ENABLE(MUTATION_OBSERVERS) 650 // The call to attributeChanged below may dispatch DOMSubtreeModified, so it's important to enqueue a MutationRecord now. 651 enqueueAttributesMutationRecord(this, attributeName); 652 #endif 632 653 633 654 if (isIdAttributeName(old ? old->name() : attributeName)) … … 663 684 // Allocate attribute map if necessary. 664 685 Attribute* old = attributes(false)->getAttributeItem(name); 686 687 #if ENABLE(MUTATION_OBSERVERS) 688 // The call to attributeChanged below may dispatch DOMSubtreeModified, so it's important to enqueue a MutationRecord now. 689 enqueueAttributesMutationRecord(this, name); 690 #endif 665 691 666 692 if (isIdAttributeName(name)) -
trunk/Source/WebCore/dom/MutationRecord.cpp
r96064 r97659 37 37 #include "Node.h" 38 38 #include "NodeList.h" 39 #include "QualifiedName.h" 39 40 #include <wtf/Assertions.h> 40 41 #include <wtf/StdLibExtras.h> … … 70 71 class AttributesRecord : public MutationRecord { 71 72 public: 72 AttributesRecord(PassRefPtr<Node> target, const AtomicString& attributeName, const AtomicString& attributeNamespace)73 AttributesRecord(PassRefPtr<Node> target, const QualifiedName& name) 73 74 : MutationRecord(target) 74 , m_attributeName( attributeName)75 , m_attributeNamespace( attributeNamespace)75 , m_attributeName(name.localName()) 76 , m_attributeNamespace(name.namespaceURI()) 76 77 { 77 78 } … … 80 81 virtual const AtomicString& type(); 81 82 virtual const AtomicString& attributeName() { return m_attributeName; } 82 virtual const AtomicString& attributeNamespace() { return m_attributeName ; }83 virtual const AtomicString& attributeNamespace() { return m_attributeNamespace; } 83 84 virtual String oldValue() { return m_oldValue; } 84 85 virtual void setOldValue(const String& value) { m_oldValue = value; } … … 129 130 } 130 131 131 PassRefPtr<MutationRecord> MutationRecord::createAttributes(PassRefPtr<Node> target, const AtomicString& attributeName, const AtomicString& attributeNamespace)132 PassRefPtr<MutationRecord> MutationRecord::createAttributes(PassRefPtr<Node> target, const QualifiedName& name) 132 133 { 133 return adoptRef(static_cast<MutationRecord*>(new AttributesRecord(target, attributeName, attributeNamespace)));134 return adoptRef(static_cast<MutationRecord*>(new AttributesRecord(target, name))); 134 135 } 135 136 -
trunk/Source/WebCore/dom/MutationRecord.h
r96064 r97659 43 43 class Node; 44 44 class NodeList; 45 class QualifiedName; 45 46 46 47 class MutationRecord : public RefCounted<MutationRecord> { 47 48 public: 48 49 static PassRefPtr<MutationRecord> createChildList(PassRefPtr<Node> target, PassRefPtr<NodeList> added, PassRefPtr<NodeList> removed, PassRefPtr<Node> previousSibling, PassRefPtr<Node> nextSibling); 49 static PassRefPtr<MutationRecord> createAttributes(PassRefPtr<Node> target, const AtomicString& attributeName, const AtomicString& attributeNamespace);50 static PassRefPtr<MutationRecord> createAttributes(PassRefPtr<Node> target, const QualifiedName&); 50 51 static PassRefPtr<MutationRecord> createCharacterData(PassRefPtr<Node> target); 51 52 -
trunk/Source/WebCore/dom/MutationRecord.idl
r96064 r97659 42 42 43 43 readonly attribute DOMString attributeName; 44 readonly attribute DOMString attributeNamespace;44 readonly attribute [ConvertNullStringTo=Null] DOMString attributeNamespace; 45 45 46 readonly attribute DOMString oldValue;46 readonly attribute [ConvertNullStringTo=Null] DOMString oldValue; 47 47 }; 48 48 } -
trunk/Source/WebCore/dom/Node.cpp
r97574 r97659 101 101 #include <wtf/RefCountedLeakCounter.h> 102 102 #include <wtf/UnusedParam.h> 103 #include <wtf/Vector.h> 103 104 #include <wtf/text/CString.h> 104 105 #include <wtf/text/StringBuilder.h> … … 547 548 treeScope()->removeNodeListCache(); 548 549 550 #if ENABLE(MUTATION_OBSERVERS) 551 Vector<MutationObserverEntry>* observerEnties = mutationObserverEntries(); 552 if (observerEnties) { 553 for (Vector<MutationObserverEntry>::iterator iter = observerEnties->begin(); iter != observerEnties->end(); ++iter) 554 iter->observer->observedNodeDestructed(this); 555 } 556 #endif 557 549 558 NodeRareData::NodeRareDataMap& dataMap = NodeRareData::rareDataMap(); 550 559 NodeRareData::NodeRareDataMap::iterator it = dataMap.find(this); … … 2674 2683 } 2675 2684 2685 #if ENABLE(MUTATION_OBSERVERS) 2686 Vector<MutationObserverEntry>* Node::mutationObserverEntries() 2687 { 2688 return hasRareData() ? rareData()->mutationObserverEntries() : 0; 2689 } 2690 2691 Vector<MutationObserverEntry>* Node::ensureMutationObserverEntries() 2692 { 2693 return ensureRareData()->ensureMutationObserverEntries(); 2694 } 2695 2696 void Node::registeredMutationObserversOfType(Vector<WebKitMutationObserver*>& observers, WebKitMutationObserver::MutationType type) 2697 { 2698 Vector<MutationObserverEntry>* observerEntries = mutationObserverEntries(); 2699 if (!observerEntries || observerEntries->isEmpty()) 2700 return; 2701 2702 for (Vector<MutationObserverEntry>::iterator iter = observerEntries->begin(); iter != observerEntries->end(); ++iter) { 2703 if (iter->matches(type)) 2704 observers.append(iter->observer.get()); 2705 } 2706 } 2707 2708 Node::MutationRegistrationResult Node::registerMutationObserver(PassRefPtr<WebKitMutationObserver> observer, unsigned char options) 2709 { 2710 Vector<MutationObserverEntry>* observerEntries = ensureMutationObserverEntries(); 2711 MutationObserverEntry entry(observer, options); 2712 2713 size_t index = observerEntries->find(entry); 2714 if (index == notFound) { 2715 observerEntries->append(entry); 2716 return MutationObserverRegistered; 2717 } 2718 2719 (*observerEntries)[index].options = entry.options; 2720 return MutationRegistrationOptionsReset; 2721 } 2722 2723 void Node::unregisterMutationObserver(PassRefPtr<WebKitMutationObserver> observer) 2724 { 2725 Vector<MutationObserverEntry>* observerEntries = mutationObserverEntries(); 2726 ASSERT(observerEntries); 2727 if (!observerEntries) 2728 return; 2729 2730 MutationObserverEntry entry(observer, 0); 2731 size_t index = observerEntries->find(entry); 2732 ASSERT(index != notFound); 2733 if (index == notFound) 2734 return; 2735 2736 observerEntries->remove(index); 2737 } 2738 #endif // ENABLE(MUTATION_OBSERVERS) 2739 2740 2676 2741 void Node::handleLocalEvents(Event* event) 2677 2742 { -
trunk/Source/WebCore/dom/Node.h
r97471 r97659 32 32 #include "ScriptWrappable.h" 33 33 #include "TreeShared.h" 34 #include "WebKitMutationObserver.h" 34 35 #include <wtf/Forward.h> 35 36 #include <wtf/ListHashSet.h> … … 59 60 class IntRect; 60 61 class KeyboardEvent; 62 class MutationObserverEntry; 61 63 class NSResolver; 62 64 class NamedNodeMap; … … 586 588 #endif 587 589 590 #if ENABLE(MUTATION_OBSERVERS) 591 Vector<MutationObserverEntry>* mutationObserverEntries(); 592 Vector<MutationObserverEntry>* ensureMutationObserverEntries(); 593 594 void registeredMutationObserversOfType(Vector<WebKitMutationObserver*>&, WebKitMutationObserver::MutationType); 595 596 // Returns true if the observer wasn't already registered on this node. 597 enum MutationRegistrationResult { 598 MutationObserverRegistered, 599 MutationRegistrationOptionsReset 600 }; 601 MutationRegistrationResult registerMutationObserver(PassRefPtr<WebKitMutationObserver>, unsigned char options); 602 603 void unregisterMutationObserver(PassRefPtr<WebKitMutationObserver>); 604 #endif // ENABLE(MUTATION_OBSERVERS) 605 588 606 private: 589 607 enum NodeFlags { -
trunk/Source/WebCore/dom/NodeRareData.h
r97471 r97659 33 33 #include "QualifiedName.h" 34 34 #include "TagNodeList.h" 35 #include "WebKitMutationObserver.h" 35 36 #include <wtf/HashSet.h> 36 37 #include <wtf/OwnPtr.h> … … 87 88 NodeListsNodeData() : m_labelsNodeListCache(0) {} 88 89 }; 89 90 91 #if ENABLE(MUTATION_OBSERVERS) 92 struct MutationObserverEntry { 93 MutationObserverEntry(PassRefPtr<WebKitMutationObserver> observer, unsigned char options) 94 : observer(observer) 95 , options(options) 96 { 97 } 98 99 bool operator==(const MutationObserverEntry& other) const 100 { 101 return observer == other.observer; 102 } 103 104 bool matches(unsigned char options) const 105 { 106 return this->options & options; 107 } 108 109 RefPtr<WebKitMutationObserver> observer; 110 unsigned char options; 111 }; 112 113 #endif // ENABLE(MUTATION_OBSERVERS) 114 90 115 class NodeRareData { 91 116 WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED; … … 137 162 } 138 163 164 #if ENABLE(MUTATION_OBSERVERS) 165 Vector<MutationObserverEntry>* mutationObserverEntries() { return m_mutationObservers.get(); } 166 Vector<MutationObserverEntry>* ensureMutationObserverEntries() 167 { 168 if (!m_mutationObservers) 169 m_mutationObservers = adoptPtr(new Vector<MutationObserverEntry>); 170 return m_mutationObservers.get(); 171 } 172 #endif 173 139 174 bool isFocused() const { return m_isFocused; } 140 175 void setFocused(bool focused) { m_isFocused = focused; } … … 153 188 bool m_isFocused : 1; 154 189 bool m_needsFocusAppearanceUpdateSoonAfterAttach : 1; 190 191 #if ENABLE(MUTATION_OBSERVERS) 192 OwnPtr<Vector<MutationObserverEntry> > m_mutationObservers; 193 #endif 155 194 }; 156 195 -
trunk/Source/WebCore/dom/WebKitMutationObserver.cpp
r97159 r97659 35 35 #include "WebKitMutationObserver.h" 36 36 37 #include "MutationObserverOptions.h" 37 38 #include "MutationCallback.h" 38 #include "NotImplemented.h" 39 #include "MutationRecord.h" 40 #include "Node.h" 41 #include <wtf/ListHashSet.h> 39 42 40 43 namespace WebCore { … … 54 57 } 55 58 56 void WebKitMutationObserver::observe(Node* , MutationObserverOptions*)59 void WebKitMutationObserver::observe(Node* node, MutationObserverOptions* options) 57 60 { 58 notImplemented(); 61 unsigned char optionFlags = 0; 62 63 // FIXME: Push composition of the optionFlags into the custom binding. 64 if (options->childList()) 65 optionFlags |= ChildList; 66 if (options->attributes()) 67 optionFlags |= Attributes; 68 if (options->characterData()) 69 optionFlags |= CharacterData; 70 // FIXME: More options composition work needs to be done here. 71 72 if (node->registerMutationObserver(this, optionFlags) == Node::MutationObserverRegistered) 73 m_observedNodes.append(node); 59 74 } 60 75 61 76 void WebKitMutationObserver::disconnect() 62 77 { 63 notImplemented(); 78 for (Vector<Node*>::iterator iter = m_observedNodes.begin(); iter != m_observedNodes.end(); ++iter) 79 (*iter)->unregisterMutationObserver(this); 80 81 m_observedNodes.clear(); 82 } 83 84 void WebKitMutationObserver::observedNodeDestructed(Node* node) 85 { 86 size_t index = m_observedNodes.find(node); 87 ASSERT(index != notFound); 88 if (index == notFound) 89 return; 90 91 m_observedNodes.remove(index); 92 } 93 94 typedef ListHashSet<RefPtr<WebKitMutationObserver> > MutationObserverSet; 95 96 static MutationObserverSet& activeMutationObservers() 97 { 98 DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ()); 99 return activeObservers; 100 } 101 102 void WebKitMutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation) 103 { 104 m_records.append(mutation); 105 activeMutationObservers().add(this); 106 } 107 108 void WebKitMutationObserver::deliver() 109 { 110 MutationRecordArray records; 111 records.swap(m_records); 112 m_callback->handleEvent(&records, this); 113 } 114 115 void WebKitMutationObserver::deliverAllMutations() 116 { 117 while (!activeMutationObservers().isEmpty()) { 118 MutationObserverSet::iterator iter = activeMutationObservers().begin(); 119 RefPtr<WebKitMutationObserver> observer = *iter; 120 activeMutationObservers().remove(iter); 121 observer->deliver(); 122 } 64 123 } 65 124 -
trunk/Source/WebCore/dom/WebKitMutationObserver.h
r97159 r97659 37 37 #include <wtf/RefCounted.h> 38 38 #include <wtf/RefPtr.h> 39 #include <wtf/Vector.h> 39 40 40 41 namespace WebCore { … … 42 43 class MutationCallback; 43 44 class MutationObserverOptions; 45 class MutationRecord; 44 46 class Node; 45 47 46 48 class WebKitMutationObserver : public RefCounted<WebKitMutationObserver> { 47 49 public: 50 enum MutationType { 51 ChildList = 1 << 0, 52 Attributes = 1 << 1, 53 CharacterData = 1 << 2 54 }; 55 56 enum OptionFlags { 57 Subtree = 1 << 3, 58 AttributeOldValue = 1 << 4, 59 CharacterDataOldValue = 1 << 5, 60 AttributeFilter = 1 << 6 61 }; 62 48 63 static PassRefPtr<WebKitMutationObserver> create(PassRefPtr<MutationCallback>); 64 static void deliverAllMutations(); 49 65 50 66 ~WebKitMutationObserver(); … … 52 68 void observe(Node*, MutationObserverOptions*); 53 69 void disconnect(); 70 void observedNodeDestructed(Node*); 71 void enqueueMutationRecord(PassRefPtr<MutationRecord>); 54 72 55 73 private: 56 74 WebKitMutationObserver(PassRefPtr<MutationCallback>); 57 75 76 void deliver(); 77 58 78 RefPtr<MutationCallback> m_callback; 79 Vector<RefPtr<MutationRecord> > m_records; 80 Vector<Node*> m_observedNodes; // NodeRareData has a RefPtr to this, so use a weak pointer to avoid a cycle. 59 81 }; 60 82
Note: See TracChangeset
for help on using the changeset viewer.