WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-70860-20111103165458.patch (text/plain), 52.57 KB, created by
Rafael Weinstein
on 2011-11-03 16:54:59 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Rafael Weinstein
Created:
2011-11-03 16:54:59 PDT
Size:
52.57 KB
patch
obsolete
>Subversion Revision: 99233 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 71c81a6575f9239c25232b58e900ef16b715b2ec..be1a959aa6bd934a1c770c29a36c5c7375c207a3 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,47 @@ >+2011-10-31 Rafael Weinstein <rafaelw@chromium.org> >+ >+ [MutationObservers] Support attributeFilter for attribute mutations >+ https://bugs.webkit.org/show_bug.cgi?id=70860 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch adds an attributeFilter to the MutationObserverRegistration and >+ adds support for only observing attributes whose name are in the provided >+ filter set (array of strings). >+ >+ This patch also refactors out MutationObserverRegistration into its own class >+ which is now referenced by Node rather than copied within containers. >+ >+ * bindings/js/JSWebKitMutationObserverCustom.cpp: >+ (WebCore::JSWebKitMutationObserver::observe): >+ * bindings/v8/OptionsObject.cpp: >+ (WebCore::OptionsObject::get): >+ * bindings/v8/OptionsObject.h: >+ * bindings/v8/custom/V8WebKitMutationObserverCustom.cpp: >+ (WebCore::V8WebKitMutationObserver::observeCallback): >+ * dom/CharacterData.cpp: >+ (WebCore::CharacterData::dispatchModifiedEvent): >+ * dom/ChildListMutationScope.cpp: >+ (WebCore::MutationAccumulationRouter::MutationAccumulationRouter::incrementScopingLevel): >+ * dom/Element.cpp: >+ (WebCore::enqueueAttributesMutationRecord): >+ * dom/Node.cpp: >+ (WebCore::addMatchingObservers): >+ (WebCore::Node::getRegisteredMutationObserversOfType): >+ (WebCore::Node::registerMutationObserver): >+ (WebCore::Node::unregisterMutationObserver): >+ (WebCore::Node::notifyMutationObserversNodeWillDetach): >+ * dom/Node.h: >+ * dom/NodeRareData.h: >+ (WebCore::MutationObserverRegistration::MutationObserverRegistration): >+ (WebCore::MutationObserverRegistration::shouldReceiveMutation): >+ (WebCore::MutationObserverRegistration::caseInsensitiveAttributeFilter): >+ (WebCore::MutationObserverRegistration::isSubtree): >+ * dom/WebKitMutationObserver.cpp: >+ (WebCore::WebKitMutationObserver::observe): >+ (WebCore::WebKitMutationObserver::willDetachNodeInObservedSubtree): >+ * dom/WebKitMutationObserver.h: >+ > 2011-11-03 Joshua Bell <jsbell@chromium.org> > > IndexedDB result of deleting a record should be true or false >diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi >index 05f213e62ffbaa973f6719a2b0e2d16e206be2c1..308413798ac803984d7b68df55e753182ed52e0f 100644 >--- a/Source/WebCore/WebCore.gypi >+++ b/Source/WebCore/WebCore.gypi >@@ -5257,6 +5257,8 @@ > 'dom/MutationCallback.h', > 'dom/MutationEvent.cpp', > 'dom/MutationEvent.h', >+ 'dom/MutationObserverRegistration.cpp', >+ 'dom/MutationObserverRegistration.h', > 'dom/MutationRecord.cpp', > 'dom/MutationRecord.h', > 'dom/NameNodeList.cpp', >diff --git a/Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp b/Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp >index cd613ff160e577723f35cf22e51b1d618b50c321..eacec1423b697ef43fe9e16014ad661a5144066d 100644 >--- a/Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp >+++ b/Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp >@@ -78,6 +78,7 @@ JSValue JSWebKitMutationObserver::observe(ExecState* exec) > > JSDictionary dictionary(exec, optionsObject); > MutationObserverOptions options = 0; >+ // FIXME: Add support for parsing of the attributeFilter option. > bool option; > if (dictionary.tryGetProperty("childList", option) && option) > options |= WebKitMutationObserver::ChildList; >diff --git a/Source/WebCore/bindings/v8/OptionsObject.cpp b/Source/WebCore/bindings/v8/OptionsObject.cpp >index acafa23b0877c57ca583eb1a593eecf512d3713a..e681ecf8d382706ed6b6b7e951ab8fa24439c295 100644 >--- a/Source/WebCore/bindings/v8/OptionsObject.cpp >+++ b/Source/WebCore/bindings/v8/OptionsObject.cpp >@@ -210,6 +210,25 @@ bool OptionsObject::get(const String& key, MessagePortArray& value) const > return getMessagePortArray(v8Value, value); > } > >+bool OptionsObject::get(const String& key, HashSet<AtomicString>& value) const >+{ >+ v8::Local<v8::Value> v8Value; >+ if (!getKey(key, v8Value)) >+ return false; >+ >+ // FIXME: Support array-like objects >+ if (!v8Value->IsArray()) >+ return false; >+ >+ v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value); >+ for (size_t i = 0; i < v8Array->Length(); ++i) { >+ v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i)); >+ value.add(v8ValueToWebCoreString(indexedValue)); >+ } >+ >+ return true; >+} >+ > bool OptionsObject::getWithUndefinedOrNullCheck(const String& key, String& value) const > { > v8::Local<v8::Value> v8Value; >diff --git a/Source/WebCore/bindings/v8/OptionsObject.h b/Source/WebCore/bindings/v8/OptionsObject.h >index cd4c2fd8eff97573936c68bb4001e4d2ae80547d..69c11b11272a3131b3790f018cc9652781f81b0e 100644 >--- a/Source/WebCore/bindings/v8/OptionsObject.h >+++ b/Source/WebCore/bindings/v8/OptionsObject.h >@@ -30,6 +30,8 @@ > #include "PlatformString.h" > #include "ScriptValue.h" > #include <v8.h> >+#include <wtf/HashSet.h> >+#include <wtf/text/AtomicString.h> > > namespace WebCore { > >@@ -57,6 +59,7 @@ public: > bool get(const String&, unsigned long long&) const; > bool get(const String&, RefPtr<DOMWindow>&) const; > bool get(const String&, MessagePortArray&) const; >+ bool get(const String&, HashSet<AtomicString>&) const; > > bool getWithUndefinedOrNullCheck(const String&, String&) const; > >diff --git a/Source/WebCore/bindings/v8/custom/V8WebKitMutationObserverCustom.cpp b/Source/WebCore/bindings/v8/custom/V8WebKitMutationObserverCustom.cpp >index ef53eaf27ef1053ce70eade9d4c773cb43c34874..8df1aa2ab5c45eb364e0e0f612fdd2b19f7a0150 100644 >--- a/Source/WebCore/bindings/v8/custom/V8WebKitMutationObserverCustom.cpp >+++ b/Source/WebCore/bindings/v8/custom/V8WebKitMutationObserverCustom.cpp >@@ -43,6 +43,10 @@ > #include "V8Node.h" > #include "V8Proxy.h" > #include "V8Utilities.h" >+#include "WebKitMutationObserver.h" >+ >+#include <wtf/HashSet.h> >+#include <wtf/text/AtomicString.h> > > namespace WebCore { > >@@ -89,11 +93,15 @@ v8::Handle<v8::Value> V8WebKitMutationObserver::observeCallback(const v8::Argume > > OptionsObject optionsObject(args[1]); > unsigned options = 0; >+ HashSet<AtomicString> attributeFilter; > bool option; > if (optionsObject.get("childList", option) && option) > options |= WebKitMutationObserver::ChildList; >- if (optionsObject.get("attributes", option) && option) >+ if (optionsObject.get("attributes", option) && option) { > options |= WebKitMutationObserver::Attributes; >+ if (optionsObject.get("attributeFilter", attributeFilter)) >+ options |= WebKitMutationObserver::AttributeFilter; >+ } > if (optionsObject.get("characterData", option) && option) > options |= WebKitMutationObserver::CharacterData; > if (optionsObject.get("subtree", option) && option) >@@ -103,7 +111,7 @@ v8::Handle<v8::Value> V8WebKitMutationObserver::observeCallback(const v8::Argume > if (optionsObject.get("characterDataOldValue", option) && option) > options |= WebKitMutationObserver::CharacterDataOldValue; > >- imp->observe(target, options); >+ imp->observe(target, options, attributeFilter); > return v8::Handle<v8::Value>(); > } > >diff --git a/Source/WebCore/dom/CharacterData.cpp b/Source/WebCore/dom/CharacterData.cpp >index 3a5fd6fedb09baf224c45b4e54465e965b48ca50..c11966f21654dd754159ef13ffb0dd5b99a57864 100644 >--- a/Source/WebCore/dom/CharacterData.cpp >+++ b/Source/WebCore/dom/CharacterData.cpp >@@ -205,7 +205,7 @@ static bool isOldValueRequested(const HashMap<WebKitMutationObserver*, MutationO > > static void enqueueCharacterDataMutationRecord(Node* node, const String& oldData) > { >- HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; >+ HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions> observers; > node->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::CharacterData); > if (observers.isEmpty()) > return; >diff --git a/Source/WebCore/dom/ChildListMutationScope.cpp b/Source/WebCore/dom/ChildListMutationScope.cpp >index 5dcbdcff30daa98cb901b7b6eea0e4d1698fe62b..509cec5b285ad5d968c012061497c6c3acc392c5 100644 >--- a/Source/WebCore/dom/ChildListMutationScope.cpp >+++ b/Source/WebCore/dom/ChildListMutationScope.cpp >@@ -41,6 +41,7 @@ > #include "StaticNodeList.h" > #include <wtf/HashMap.h> > #include <wtf/RefCounted.h> >+#include <wtf/text/AtomicString.h> > > namespace WebCore { > >@@ -244,7 +245,7 @@ void MutationAccumulationRouter::incrementScopingLevel(Node* target) > return; > } > >- HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; >+ HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions> observers; > target->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::ChildList); > if (observers.isEmpty()) > m_accumulations.set(target, 0); >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index 39cabd836a03597b59f44e20146dfec0d025ea90..e8fb63bd6df5e2b7332c4260bbe41aba66cd5fa2 100644 >--- a/Source/WebCore/dom/Element.cpp >+++ b/Source/WebCore/dom/Element.cpp >@@ -633,8 +633,8 @@ static inline bool isOldValueRequested(const HashMap<WebKitMutationObserver*, Mu > > static void enqueueAttributesMutationRecord(Element* element, const QualifiedName& name, const AtomicString& oldValue) > { >- HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; >- element->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::Attributes); >+ HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions> observers; >+ element->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::Attributes, name.localName()); > if (observers.isEmpty()) > return; > >diff --git a/Source/WebCore/dom/MutationObserverRegistration.cpp b/Source/WebCore/dom/MutationObserverRegistration.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..341ea27f5f9122441bddd1f36d14b25b89bd270f >--- /dev/null >+++ b/Source/WebCore/dom/MutationObserverRegistration.cpp >@@ -0,0 +1,140 @@ >+/* >+ * Copyright (C) 2011 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+ >+#if ENABLE(MUTATION_OBSERVERS) >+ >+#include "MutationObserverRegistration.h" >+ >+#include "Document.h" >+#include "Node.h" >+ >+namespace WebCore { >+ >+PassOwnPtr<MutationObserverRegistration> MutationObserverRegistration::create(PassRefPtr<WebKitMutationObserver> observer, Node* registrationNode) >+{ >+ return adoptPtr(new MutationObserverRegistration(observer, registrationNode)); >+} >+ >+MutationObserverRegistration::MutationObserverRegistration(PassRefPtr<WebKitMutationObserver> observer, Node* registrationNode) >+ : m_observer(observer) >+ , m_registrationNode(registrationNode) >+ , m_options(0) >+{ >+ m_observer->observationStarted(this); >+} >+ >+MutationObserverRegistration::~MutationObserverRegistration() >+{ >+ clearTransientRegistrations(); >+ m_observer->observationEnded(this); >+} >+ >+void MutationObserverRegistration::resetObservation(MutationObserverOptions options, const HashSet<AtomicString>& attributeFilter) >+{ >+ clearTransientRegistrations(); >+ >+ m_options = options; >+ m_attributeFilter = attributeFilter; >+ m_caseInsensitiveAttributeFilter.clear(); >+} >+ >+void MutationObserverRegistration::observedSubtreeNodeWillDetach(PassRefPtr<Node> node) >+{ >+ if (!(m_options & WebKitMutationObserver::Subtree)) >+ return; >+ >+ node->registerTransientMutationObserver(this); >+ >+ if (!m_transientRegistrationNodes) { >+ m_transientRegistrationNodes = adoptPtr(new NodeHashSet); >+ m_registrationNodeKeepAlive = m_registrationNode; // Balanced in clearTransientRegistrations. >+ } >+ m_transientRegistrationNodes->add(node); >+} >+ >+void MutationObserverRegistration::clearTransientRegistrations() >+{ >+ if (!m_transientRegistrationNodes) { >+ ASSERT(!m_registrationNodeKeepAlive); >+ return; >+ } >+ >+ ASSERT(m_registrationNodeKeepAlive); >+ for (NodeHashSet::iterator iter = m_transientRegistrationNodes->begin(); iter != m_transientRegistrationNodes->end(); ++iter) >+ (*iter)->unregisterTransientMutationObserver(this); >+ >+ m_transientRegistrationNodes.clear(); >+ m_registrationNodeKeepAlive = 0; // Balanced in observeSubtreeNodeWillDetach. >+} >+ >+void MutationObserverRegistration::unregister() >+{ >+ m_registrationNode->unregisterMutationObserver(this); // This call will cause this object to be deleted. >+} >+ >+bool MutationObserverRegistration::shouldReceiveMutationFrom(Node* node, WebKitMutationObserver::MutationType type, const AtomicString& attributeName) >+{ >+ if (!(m_options & type)) >+ return false; >+ >+ if (m_registrationNode != node && !(m_options & WebKitMutationObserver::Subtree)) >+ return false; >+ >+ if (type != WebKitMutationObserver::Attributes || !(m_options & WebKitMutationObserver::AttributeFilter)) >+ return true; >+ >+ if (m_attributeFilter.contains(attributeName)) >+ return true; >+ >+ if (node->document()->isHTMLDocument() && node->isHTMLElement()) >+ return caseInsensitiveAttributeFilter().contains(attributeName); >+ >+ return false; >+} >+ >+const HashSet<AtomicString>& MutationObserverRegistration::caseInsensitiveAttributeFilter() >+{ >+ if (!m_caseInsensitiveAttributeFilter) { >+ m_caseInsensitiveAttributeFilter = adoptPtr(new HashSet<AtomicString>()); >+ for (HashSet<AtomicString>::const_iterator iter = m_attributeFilter.begin(); iter != m_attributeFilter.end(); ++iter) { >+ AtomicString attributeNameLower = iter->lower(); >+ if ((*iter) != attributeNameLower) >+ m_caseInsensitiveAttributeFilter->add(attributeNameLower); >+ } >+ } >+ >+ return *m_caseInsensitiveAttributeFilter; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(MUTATION_OBSERVERS) >diff --git a/Source/WebCore/dom/MutationObserverRegistration.h b/Source/WebCore/dom/MutationObserverRegistration.h >new file mode 100644 >index 0000000000000000000000000000000000000000..f5d7926f31c4018efbf897bcc81c8e730db90279 >--- /dev/null >+++ b/Source/WebCore/dom/MutationObserverRegistration.h >@@ -0,0 +1,80 @@ >+/* >+ * Copyright (C) 2011 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef MutationObserverRegistration_h >+#define MutationObserverRegistration_h >+ >+#if ENABLE(MUTATION_OBSERVERS) >+ >+#include "WebKitMutationObserver.h" >+#include <wtf/HashSet.h> >+#include <wtf/text/AtomicString.h> >+#include <wtf/text/AtomicStringHash.h> >+ >+namespace WebCore { >+ >+class MutationObserverRegistration { >+public: >+ >+ static PassOwnPtr<MutationObserverRegistration> create(PassRefPtr<WebKitMutationObserver>, Node*); >+ >+ ~MutationObserverRegistration(); >+ >+ void resetObservation(MutationObserverOptions, const HashSet<AtomicString>& attributeFilter); >+ void observedSubtreeNodeWillDetach(PassRefPtr<Node>); >+ void clearTransientRegistrations(); >+ void unregister(); >+ >+ bool shouldReceiveMutationFrom(Node*, WebKitMutationObserver::MutationType, const AtomicString& attributeName); >+ >+ WebKitMutationObserver* observer() { return m_observer.get(); } >+ MutationRecordDeliveryOptions deliveryOptions() { return m_options & (WebKitMutationObserver::AttributeOldValue | WebKitMutationObserver::CharacterDataOldValue); } >+ >+private: >+ MutationObserverRegistration(PassRefPtr<WebKitMutationObserver>, Node*); >+ >+ const HashSet<AtomicString>& caseInsensitiveAttributeFilter(); >+ >+ RefPtr<WebKitMutationObserver> m_observer; >+ Node* m_registrationNode; // Back-pointer to the Node which owns this registration. >+ RefPtr<Node> m_registrationNodeKeepAlive; // This registration takes reference to its owning node while it has transient registrations. >+ typedef HashSet<RefPtr<Node> > NodeHashSet; >+ OwnPtr<NodeHashSet> m_transientRegistrationNodes; >+ >+ MutationObserverOptions m_options; >+ HashSet<AtomicString> m_attributeFilter; >+ OwnPtr<HashSet<AtomicString> >m_caseInsensitiveAttributeFilter; >+}; >+ >+} // namespace WebCore >+ >+#endif // ENABLE(MUTATION_OBSERVERS) >+ >+#endif // MutationObserverRegistration_h >diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp >index badd07b29c1387ecf2f79b46bfea45e39fbcc0a9..46b9a8e5c11b7fe1a53be26ad215b73c77959c48 100644 >--- a/Source/WebCore/dom/Node.cpp >+++ b/Source/WebCore/dom/Node.cpp >@@ -548,10 +548,7 @@ void Node::clearRareData() > treeScope()->removeNodeListCache(); > > #if ENABLE(MUTATION_OBSERVERS) >- if (Vector<MutationObserverRegistration>* registry = mutationObserverRegistry()) { >- for (size_t i = 0; i < registry->size(); ++i) >- registry->at(i).observer->observedNodeDestructed(this); >- } >+ ASSERT(!transientMutationObserverRegistry() || transientMutationObserverRegistry()->isEmpty()); > #endif > > NodeRareData::NodeRareDataMap& dataMap = NodeRareData::rareDataMap(); >@@ -2696,59 +2693,70 @@ EventTargetData* Node::ensureEventTargetData() > } > > #if ENABLE(MUTATION_OBSERVERS) >-Vector<MutationObserverRegistration>* Node::mutationObserverRegistry() >+Vector<OwnPtr<MutationObserverRegistration> >* Node::mutationObserverRegistry() > { > return hasRareData() ? rareData()->mutationObserverRegistry() : 0; > } > >-static void addMatchingObservers(HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers, Vector<MutationObserverRegistration>* registry, MutationObserverOptions options) >+HashSet<MutationObserverRegistration*>* Node::transientMutationObserverRegistry() > { >- if (!registry) >- return; >+ return hasRareData() ? rareData()->transientMutationObserverRegistry() : 0; >+} > >- const size_t size = registry->size(); >- for (size_t i = 0; i < size; ++i) { >- MutationObserverRegistration& entry = registry->at(i); >+static inline void addObserverToDeliverySet(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, WebKitMutationObserver* observer, MutationRecordDeliveryOptions deliveryOptions) >+{ >+ pair<HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>::iterator, bool> result = observers.add(observer, deliveryOptions); >+ if (!result.second) >+ result.first->second |= deliveryOptions; >+} > >- if (!entry.hasAllOptions(options)) >- continue; >+void Node::collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, Node* fromNode, WebKitMutationObserver::MutationType type, const AtomicString& attributeName) >+{ >+ if (Vector<OwnPtr<MutationObserverRegistration> >* registry = fromNode->mutationObserverRegistry()) { >+ const size_t size = registry->size(); >+ for (size_t i = 0; i < size; ++i) { >+ MutationObserverRegistration* registration = registry->at(i).get(); >+ if (registration->shouldReceiveMutationFrom(this, type, attributeName)) >+ addObserverToDeliverySet(observers, registration->observer(), registration->deliveryOptions()); >+ } >+ } > >- pair<HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator, bool> result = observers.add(entry.observer.get(), entry.options); >- if (!result.second) >- result.first->second |= entry.options; >+ if (HashSet<MutationObserverRegistration*>* transientRegistry = fromNode->transientMutationObserverRegistry()) { >+ for (HashSet<MutationObserverRegistration*>::iterator iter = transientRegistry->begin(); iter != transientRegistry->end(); ++iter) { >+ MutationObserverRegistration* registration = *iter; >+ if (registration->shouldReceiveMutationFrom(this, type, attributeName)) >+ addObserverToDeliverySet(observers, registration->observer(), registration->deliveryOptions()); >+ } > } > } > >-void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers, WebKitMutationObserver::MutationType type) >+void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, WebKitMutationObserver::MutationType type, const AtomicString& attributeName) > { >- addMatchingObservers(observers, mutationObserverRegistry(), type); >- for (Node* node = parentNode(); node; node = node->parentNode()) >- addMatchingObservers(observers, node->mutationObserverRegistry(), type | WebKitMutationObserver::Subtree); >+ for (Node* node = this; node; node = node->parentNode()) >+ collectMatchingObserversForMutation(observers, node, type, attributeName); > } > >-Node::MutationRegistrationResult Node::registerMutationObserver(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options, Node* registrationNode) >+MutationObserverRegistration* Node::registerMutationObserver(PassRefPtr<WebKitMutationObserver> observer) > { >- Vector<MutationObserverRegistration>* registry = ensureRareData()->ensureMutationObserverRegistry(); >- MutationObserverRegistration registration(observer, options, registrationNode); >- >- size_t index = registry->find(registration); >- if (index == notFound) { >- registry->append(registration); >- return MutationObserverRegistered; >+ Vector<OwnPtr<MutationObserverRegistration> >* registry = ensureRareData()->ensureMutationObserverRegistry(); >+ for (size_t i = 0; i < registry->size(); ++i) { >+ if (registry->at(i)->observer() == observer) >+ return registry->at(i).get(); > } > >- registry->at(index).options = registration.options; >- return MutationRegistrationOptionsReset; >+ OwnPtr<MutationObserverRegistration> registration = MutationObserverRegistration::create(observer, this); >+ MutationObserverRegistration* registrationPtr = registration.get(); >+ registry->append(registration.release()); >+ return registrationPtr; > } > >-void Node::unregisterMutationObserver(PassRefPtr<WebKitMutationObserver> observer, Node* registrationNode) >+void Node::unregisterMutationObserver(MutationObserverRegistration* registration) > { >- Vector<MutationObserverRegistration>* registry = mutationObserverRegistry(); >+ Vector<OwnPtr<MutationObserverRegistration> >* registry = mutationObserverRegistry(); > ASSERT(registry); > if (!registry) > return; > >- MutationObserverRegistration registration(observer, 0, registrationNode); > size_t index = registry->find(registration); > ASSERT(index != notFound); > if (index == notFound) >@@ -2757,23 +2765,34 @@ void Node::unregisterMutationObserver(PassRefPtr<WebKitMutationObserver> observe > registry->remove(index); > } > >+void Node::registerTransientMutationObserver(MutationObserverRegistration* registration) >+{ >+ ensureRareData()->ensureTransientMutationObserverRegistry()->add(registration); >+} >+ >+void Node::unregisterTransientMutationObserver(MutationObserverRegistration* registration) >+{ >+ HashSet<MutationObserverRegistration*>* transientRegistry = transientMutationObserverRegistry(); >+ ASSERT(transientRegistry); >+ if (!transientRegistry) >+ return; >+ >+ ASSERT(transientRegistry->contains(registration)); >+ transientRegistry->remove(registration); >+} >+ > void Node::notifyMutationObserversNodeWillDetach() > { > for (Node* node = parentNode(); node; node = node->parentNode()) { >- Vector<MutationObserverRegistration>* registry = node->mutationObserverRegistry(); >- if (!registry) >- continue; >- >- const size_t size = registry->size(); >- for (size_t i = 0; i < size; ++i) { >- MutationObserverRegistration& registration = registry->at(i); >- if (!registration.hasAllOptions(WebKitMutationObserver::Subtree)) >- continue; >+ if (Vector<OwnPtr<MutationObserverRegistration> >* registry = node->mutationObserverRegistry()) { >+ const size_t size = registry->size(); >+ for (size_t i = 0; i < size; ++i) >+ registry->at(i)->observedSubtreeNodeWillDetach(this); >+ } > >- Node* registrationNode = registration.registrationNode; >- if (!registrationNode) >- registrationNode = node; >- registration.observer->willDetachNodeInObservedSubtree(registrationNode, registration.options, this); >+ if (HashSet<MutationObserverRegistration*>* transientRegistry = node->transientMutationObserverRegistry()) { >+ for (HashSet<MutationObserverRegistration*>::iterator iter = transientRegistry->begin(); iter != transientRegistry->end(); ++iter) >+ (*iter)->observedSubtreeNodeWillDetach(this); > } > } > } >diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h >index c8a131970ccc30d55735042437ecac6510d9455d..6b66c81d049283eed63442596d78d83d35545b77 100644 >--- a/Source/WebCore/dom/Node.h >+++ b/Source/WebCore/dom/Node.h >@@ -34,6 +34,7 @@ > #include "WebKitMutationObserver.h" > #include <wtf/Forward.h> > #include <wtf/ListHashSet.h> >+#include <wtf/text/AtomicString.h> > > #if USE(JSC) > namespace JSC { >@@ -590,16 +591,11 @@ public: > #endif > > #if ENABLE(MUTATION_OBSERVERS) >- void getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationObserverOptions>&, WebKitMutationObserver::MutationType); >- >- enum MutationRegistrationResult { >- MutationObserverRegistered, >- MutationRegistrationOptionsReset >- }; >- MutationRegistrationResult registerMutationObserver(PassRefPtr<WebKitMutationObserver>, MutationObserverOptions, Node* registrationNode = 0); >- >- void unregisterMutationObserver(PassRefPtr<WebKitMutationObserver>, Node* registrationNode = 0); >- >+ void getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, WebKitMutationObserver::MutationType, const AtomicString& attributeName = nullAtom); >+ MutationObserverRegistration* registerMutationObserver(PassRefPtr<WebKitMutationObserver>); >+ void unregisterMutationObserver(MutationObserverRegistration*); >+ void registerTransientMutationObserver(MutationObserverRegistration*); >+ void unregisterTransientMutationObserver(MutationObserverRegistration*); > void notifyMutationObserversNodeWillDetach(); > #endif // ENABLE(MUTATION_OBSERVERS) > >@@ -727,7 +723,9 @@ private: > void trackForDebugging(); > > #if ENABLE(MUTATION_OBSERVERS) >- Vector<MutationObserverRegistration>* mutationObserverRegistry(); >+ Vector<OwnPtr<MutationObserverRegistration> >* mutationObserverRegistry(); >+ HashSet<MutationObserverRegistration*>* transientMutationObserverRegistry(); >+ void collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, Node* fromNode, WebKitMutationObserver::MutationType, const AtomicString& attributeName); > #endif > > mutable uint32_t m_nodeFlags; >diff --git a/Source/WebCore/dom/NodeRareData.h b/Source/WebCore/dom/NodeRareData.h >index ecbd55922f4290bbb38da310970f058a0b564f4c..0aa1d53b4723ea5e0eff2abeec641947d3f90f8b 100644 >--- a/Source/WebCore/dom/NodeRareData.h >+++ b/Source/WebCore/dom/NodeRareData.h >@@ -29,6 +29,7 @@ > #include "MicroDataItemList.h" > #endif > >+#include "MutationObserverRegistration.h" > #include "NameNodeList.h" > #include "QualifiedName.h" > #include "TagNodeList.h" >@@ -36,6 +37,7 @@ > #include <wtf/HashSet.h> > #include <wtf/OwnPtr.h> > #include <wtf/PassOwnPtr.h> >+#include <wtf/text/AtomicString.h> > #include <wtf/text/StringHash.h> > > namespace WebCore { >@@ -88,36 +90,6 @@ private: > NodeListsNodeData() : m_labelsNodeListCache(0) {} > }; > >-#if ENABLE(MUTATION_OBSERVERS) >-struct MutationObserverRegistration { >- MutationObserverRegistration(PassRefPtr<WebKitMutationObserver> observer, MutationObserverOptions options, Node* node) >- : observer(observer) >- , options(options) >- , registrationNode(node) >- { >- } >- >- bool operator==(const MutationObserverRegistration& other) const >- { >- return observer == other.observer && registrationNode == other.registrationNode; >- } >- >- bool hasAllOptions(MutationObserverOptions options) const >- { >- return (this->options & options) == options; >- } >- >- RefPtr<WebKitMutationObserver> observer; >- MutationObserverOptions options; >- >- // registrationNode will be 0 if the registration is non-transient. I.e. The registrationNode is the Node in whose >- // registry it exists. >- // Note that this doesn't need to be a RefPtr because the observer will be holding a RefPtr to the same node at >- // least for the lifetime of this Registration in its m_transientObservedNodes map. >- Node* registrationNode; >-}; >-#endif // ENABLE(MUTATION_OBSERVERS) >- > class NodeRareData { > WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED; > public: >@@ -168,13 +140,21 @@ public: > } > > #if ENABLE(MUTATION_OBSERVERS) >- Vector<MutationObserverRegistration>* mutationObserverRegistry() { return m_mutationObserverRegistry.get(); } >- Vector<MutationObserverRegistration>* ensureMutationObserverRegistry() >+ Vector<OwnPtr<MutationObserverRegistration> >* mutationObserverRegistry() { return m_mutationObserverRegistry.get(); } >+ Vector<OwnPtr<MutationObserverRegistration> >* ensureMutationObserverRegistry() > { > if (!m_mutationObserverRegistry) >- m_mutationObserverRegistry = adoptPtr(new Vector<MutationObserverRegistration>); >+ m_mutationObserverRegistry = adoptPtr(new Vector<OwnPtr<MutationObserverRegistration> >); > return m_mutationObserverRegistry.get(); > } >+ >+ HashSet<MutationObserverRegistration*>* transientMutationObserverRegistry() { return m_transientMutationObserverRegistry.get(); } >+ HashSet<MutationObserverRegistration*>* ensureTransientMutationObserverRegistry() >+ { >+ if (!m_transientMutationObserverRegistry) >+ m_transientMutationObserverRegistry = adoptPtr(new HashSet<MutationObserverRegistration*>); >+ return m_transientMutationObserverRegistry.get(); >+ } > #endif > > bool isFocused() const { return m_isFocused; } >@@ -195,7 +175,8 @@ private: > bool m_needsFocusAppearanceUpdateSoonAfterAttach : 1; > > #if ENABLE(MUTATION_OBSERVERS) >- OwnPtr<Vector<MutationObserverRegistration> > m_mutationObserverRegistry; >+ OwnPtr<Vector<OwnPtr<MutationObserverRegistration> > > m_mutationObserverRegistry; >+ OwnPtr<HashSet<MutationObserverRegistration*> > m_transientMutationObserverRegistry; > #endif > }; > >diff --git a/Source/WebCore/dom/WebKitMutationObserver.cpp b/Source/WebCore/dom/WebKitMutationObserver.cpp >index b66caa083ee99e4e5038bc46b1258c8b504560a9..5bb9aaa1bd6306097ea8da7d3015c4ba00dd824b 100644 >--- a/Source/WebCore/dom/WebKitMutationObserver.cpp >+++ b/Source/WebCore/dom/WebKitMutationObserver.cpp >@@ -35,6 +35,7 @@ > #include "WebKitMutationObserver.h" > > #include "MutationCallback.h" >+#include "MutationObserverRegistration.h" > #include "MutationRecord.h" > #include "Node.h" > #include <wtf/ListHashSet.h> >@@ -53,51 +54,32 @@ WebKitMutationObserver::WebKitMutationObserver(PassRefPtr<MutationCallback> call > > WebKitMutationObserver::~WebKitMutationObserver() > { >- clearAllTransientObservations(); >+ ASSERT(m_registrations.isEmpty()); > } > >-static inline void clearTransientObservationsForRegistration(WebKitMutationObserver* observer, Node* registrationNode, PassOwnPtr<NodeHashSet> transientNodes) >+void WebKitMutationObserver::observe(Node* node, MutationObserverOptions options, const HashSet<AtomicString>& attributeFilter) > { >- for (NodeHashSet::iterator iter = transientNodes->begin(); iter != transientNodes->end(); ++iter) >- (*iter)->unregisterMutationObserver(observer, registrationNode); >+ MutationObserverRegistration* registration = node->registerMutationObserver(this); >+ registration->resetObservation(options, attributeFilter); > } > >-void WebKitMutationObserver::observe(Node* node, MutationObserverOptions options) >+void WebKitMutationObserver::disconnect() > { >- // FIXME: More options composition work needs to be done here, e.g., validation. >- >- if (node->registerMutationObserver(this, options) == Node::MutationObserverRegistered) { >- m_observedNodes.append(node); >- return; >- } >- >- HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.find(node); >- if (iter == m_transientObservedNodes.end()) >- return; >- >- clearTransientObservationsForRegistration(this, node, adoptPtr(iter->second)); >- m_transientObservedNodes.remove(iter); >+ HashSet<MutationObserverRegistration*> registrations(m_registrations); >+ for (HashSet<MutationObserverRegistration*>::iterator iter = registrations.begin(); iter != registrations.end(); ++iter) >+ (*iter)->unregister(); > } > >-void WebKitMutationObserver::disconnect() >+void WebKitMutationObserver::observationStarted(MutationObserverRegistration* registration) > { >- for (size_t i = 0; i < m_observedNodes.size(); ++i) >- m_observedNodes[i]->unregisterMutationObserver(this); >- >- m_observedNodes.clear(); >- clearAllTransientObservations(); >+ ASSERT(!m_registrations.contains(registration)); >+ m_registrations.add(registration); > } > >-void WebKitMutationObserver::observedNodeDestructed(Node* node) >+void WebKitMutationObserver::observationEnded(MutationObserverRegistration* registration) > { >- ASSERT(!m_transientObservedNodes.contains(node)); >- >- size_t index = m_observedNodes.find(node); >- ASSERT(index != notFound); >- if (index == notFound) >- return; >- >- m_observedNodes.remove(index); >+ ASSERT(m_registrations.contains(registration)); >+ m_registrations.remove(registration); > } > > typedef ListHashSet<RefPtr<WebKitMutationObserver> > MutationObserverSet; >@@ -114,36 +96,14 @@ void WebKitMutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mu > activeMutationObservers().add(this); > } > >-void WebKitMutationObserver::willDetachNodeInObservedSubtree(PassRefPtr<Node> prpRegistrationNode, MutationObserverOptions options, PassRefPtr<Node> prpDetachingNode) >-{ >- RefPtr<Node> registrationNode = prpRegistrationNode; >- RefPtr<Node> detachingNode = prpDetachingNode; >- >- detachingNode->registerMutationObserver(this, options, registrationNode.get()); >- HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.find(registrationNode); >- if (iter != m_transientObservedNodes.end()) { >- iter->second->add(detachingNode); >- return; >- } >- >- OwnPtr<NodeHashSet> set = adoptPtr(new NodeHashSet()); >- set->add(detachingNode); >- m_transientObservedNodes.set(registrationNode, set.leakPtr()); >-} >- >-void WebKitMutationObserver::clearAllTransientObservations() >-{ >- for (HashMap<RefPtr<Node>, NodeHashSet*>::iterator iter = m_transientObservedNodes.begin(); iter != m_transientObservedNodes.end(); ++iter) >- clearTransientObservationsForRegistration(this, iter->first.get(), adoptPtr(iter->second)); >- >- m_transientObservedNodes.clear(); >-} >- > void WebKitMutationObserver::deliver() > { > MutationRecordArray records; > records.swap(m_records); >- clearAllTransientObservations(); >+ >+ for (HashSet<MutationObserverRegistration*>::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) >+ (*iter)->clearTransientRegistrations(); >+ > m_callback->handleEvent(&records, this); > } > >diff --git a/Source/WebCore/dom/WebKitMutationObserver.h b/Source/WebCore/dom/WebKitMutationObserver.h >index 753204c24794d4e382db02551ea5480354dc4a75..64ab07024db51392da40e7eb594bf1a8f922e4a7 100644 >--- a/Source/WebCore/dom/WebKitMutationObserver.h >+++ b/Source/WebCore/dom/WebKitMutationObserver.h >@@ -33,21 +33,22 @@ > > #if ENABLE(MUTATION_OBSERVERS) > >-#include <wtf/HashMap.h> > #include <wtf/HashSet.h> >-#include <wtf/PassOwnPtr.h> >+#include <wtf/PassRefPtr.h> > #include <wtf/RefCounted.h> > #include <wtf/RefPtr.h> >-#include <wtf/Vector.h> >+#include <wtf/text/AtomicString.h> >+#include <wtf/text/AtomicStringHash.h> > > namespace WebCore { > > class MutationCallback; >+class MutationObserverRegistration; > class MutationRecord; > class Node; > > typedef unsigned char MutationObserverOptions; >-typedef HashSet<RefPtr<Node> > NodeHashSet; >+typedef unsigned char MutationRecordDeliveryOptions; > > class WebKitMutationObserver : public RefCounted<WebKitMutationObserver> { > public: >@@ -57,11 +58,14 @@ public: > CharacterData = 1 << 2 > }; > >- enum OptionFlags { >+ enum ObservationFlags { > Subtree = 1 << 3, >- AttributeOldValue = 1 << 4, >- CharacterDataOldValue = 1 << 5, >- AttributeFilter = 1 << 6 >+ AttributeFilter = 1 << 4 >+ }; >+ >+ enum DeliveryFlags { >+ AttributeOldValue = 1 << 5, >+ CharacterDataOldValue = 1 << 6, > }; > > static PassRefPtr<WebKitMutationObserver> create(PassRefPtr<MutationCallback>); >@@ -69,24 +73,19 @@ public: > > ~WebKitMutationObserver(); > >- void observe(Node*, MutationObserverOptions); >+ void observe(Node*, MutationObserverOptions, const HashSet<AtomicString>& attributeFilter); > void disconnect(); >- void willDetachNodeInObservedSubtree(PassRefPtr<Node> registrationNode, MutationObserverOptions, PassRefPtr<Node> detachingNode); >- void observedNodeDestructed(Node*); >+ void observationStarted(MutationObserverRegistration*); >+ void observationEnded(MutationObserverRegistration*); > void enqueueMutationRecord(PassRefPtr<MutationRecord>); > > private: > WebKitMutationObserver(PassRefPtr<MutationCallback>); >- >- void clearAllTransientObservations(); > void deliver(); > > RefPtr<MutationCallback> m_callback; > Vector<RefPtr<MutationRecord> > m_records; >- Vector<Node*> m_observedNodes; // NodeRareData has a RefPtr to this, so use a weak pointer to avoid a cycle. >- >- // FIXME: Change this to be OwnPtr<NodeHashSet> when OwnPtr supports being contained as map values. >- HashMap<RefPtr<Node>, NodeHashSet*> m_transientObservedNodes; >+ HashSet<MutationObserverRegistration*> m_registrations; // Back-pointers to registrations which are holding references to this observer. > }; > > } >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 627762beb3e918efb3a953dbd07c25d5323a090e..5a55bd2e4aba995c1eb7d7c518dd176acfe53fc0 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,13 @@ >+2011-10-31 Rafael Weinstein <rafaelw@chromium.org> >+ >+ [MutationObservers] Support attributeFilter for attribute mutations >+ https://bugs.webkit.org/show_bug.cgi?id=70860 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * fast/mutation/observe-attributes-expected.txt: >+ * fast/mutation/observe-attributes.html: >+ > 2011-11-03 Tony Chang <tony@chromium.org> > > Mark tests as slow in chromium. >diff --git a/LayoutTests/fast/mutation/observe-attributes-expected.txt b/LayoutTests/fast/mutation/observe-attributes-expected.txt >index 9bb07e9530fa7540a990edb07c3ea47b605d35bc..679e90586a88da1f965dfb7656536db44deeedc1 100644 >--- a/LayoutTests/fast/mutation/observe-attributes-expected.txt >+++ b/LayoutTests/fast/mutation/observe-attributes-expected.txt >@@ -92,6 +92,66 @@ PASS mutations[1].type is "attributes" > PASS mutations[1].attributeName is "id" > PASS mutations[1].oldValue is "foo" > >+Testing that attributeFilter works as expected and ignores case with HTML elements. >+...only foo, bar & boom should be received. >+PASS mutations.length is 3 >+PASS mutations[0].type is "attributes" >+PASS mutations[0].attributeName is "foo" >+PASS mutations[0].attributeNamespace is null >+PASS mutations[1].type is "attributes" >+PASS mutations[1].attributeName is "bar" >+PASS mutations[1].attributeNamespace is null >+PASS mutations[2].type is "attributes" >+PASS mutations[2].attributeName is "boom" >+PASS mutations[2].attributeNamespace is null >+ >+Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options. >+...only foo, bar & bat should be received. >+PASS mutations.length is 3 >+PASS mutations[0].type is "attributes" >+PASS mutations[0].attributeName is "foo" >+PASS mutations[0].attributeNamespace is null >+PASS mutations[1].type is "attributes" >+PASS mutations[1].attributeName is "bar" >+PASS mutations[1].attributeNamespace is null >+PASS mutations[2].type is "attributes" >+PASS mutations[2].attributeName is "bat" >+PASS mutations[2].attributeNamespace is null >+...bar, bat & baz should all be received. >+PASS mutations.length is 3 >+PASS mutations[0].type is "attributes" >+PASS mutations[0].attributeName is "bar" >+PASS mutations[0].attributeNamespace is null >+PASS mutations[1].type is "attributes" >+PASS mutations[1].attributeName is "bat" >+PASS mutations[1].attributeNamespace is null >+PASS mutations[2].type is "attributes" >+PASS mutations[2].attributeName is "baz" >+PASS mutations[2].attributeNamespace is null >+ >+Testing that attributeFilter respects case with non-HTML elements. >+...pathLength should be received. >+PASS mutations.length is 1 >+PASS mutations[0].type is "attributes" >+PASS mutations[0].attributeName is "pathLength" >+PASS mutations[0].attributeNamespace is "http://www.w3.org/2000/svg" >+ >+Testing that attributeFilter respects case with non-HTML elements. >+...only ID, id, booM, pathLength should be received. >+PASS mutations.length is 4 >+PASS mutations[0].type is "attributes" >+PASS mutations[0].attributeName is "ID" >+PASS mutations[0].attributeNamespace is null >+PASS mutations[1].type is "attributes" >+PASS mutations[1].attributeName is "id" >+PASS mutations[1].attributeNamespace is null >+PASS mutations[2].type is "attributes" >+PASS mutations[2].attributeName is "booM" >+PASS mutations[2].attributeNamespace is null >+PASS mutations[3].type is "attributes" >+PASS mutations[3].attributeName is "pathLength" >+PASS mutations[3].attributeNamespace is "http://www.w3.org/2000/svg" >+ > PASS successfullyParsed is true > > TEST COMPLETE >diff --git a/LayoutTests/fast/mutation/observe-attributes.html b/LayoutTests/fast/mutation/observe-attributes.html >index 395af7984581bd6a5f821cbce155afa66bdf419c..af58b518b512b08e79da0de8de4675934500198e 100644 >--- a/LayoutTests/fast/mutation/observe-attributes.html >+++ b/LayoutTests/fast/mutation/observe-attributes.html >@@ -107,7 +107,7 @@ function testMultipleRegistration() { > > function start() { > debug('Testing that re-observing the same node with the same observer has the effect of resetting the options.'); >- >+ > calls = 0; > mutations = null; > div = document.createElement('div'); >@@ -435,6 +435,209 @@ function testIDLAttribute() { > start(); > } > >+function testAttributeFilter() { >+ var div, path; >+ var observer; >+ >+ function start() { >+ debug('Testing that attributeFilter works as expected and ignores case with HTML elements.'); >+ >+ mutations = null; >+ observer = new WebKitMutationObserver(function(m) { >+ mutations = m; >+ }); >+ >+ div = document.createElement('div'); >+ observer.observe(div, { attributes: true, attributeFilter: ['foo', 'bar', 'booM'] }); >+ div.setAttribute('foo', 'foo'); >+ div.setAttribute('bar', 'bar'); >+ div.setAttribute('baz', 'baz'); >+ div.setAttribute('BOOm', 'boom'); >+ >+ setTimeout(finish, 0); >+ } >+ >+ function finish() { >+ debug('...only foo, bar & boom should be received.'); >+ >+ shouldBe('mutations.length', '3'); >+ shouldBe('mutations[0].type', '"attributes"'); >+ shouldBe('mutations[0].attributeName', '"foo"'); >+ shouldBe('mutations[0].attributeNamespace', 'null'); >+ shouldBe('mutations[1].type', '"attributes"'); >+ shouldBe('mutations[1].attributeName', '"bar"'); >+ shouldBe('mutations[1].attributeNamespace', 'null'); >+ shouldBe('mutations[2].type', '"attributes"'); >+ shouldBe('mutations[2].attributeName', '"boom"'); >+ shouldBe('mutations[2].attributeNamespace', 'null'); >+ observer.disconnect(); >+ debug(''); >+ runNextTest(); >+ } >+ >+ start(); >+} >+ >+function testAttributeFilterSubtree() { >+ var div, div2, div3; >+ var observer; >+ >+ function start() { >+ debug('Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options.'); >+ >+ mutations = null; >+ observer = new WebKitMutationObserver(function(m) { >+ mutations = m; >+ }); >+ >+ div = document.createElement('div'); >+ div2 = div.appendChild(document.createElement('div')); >+ div3 = div2.appendChild(document.createElement('div')); >+ >+ observer.observe(div, { attributes: true, subtree: true, attributeFilter: ['foo', 'bar'] }); >+ observer.observe(div2, { attributes: true, subtree: true, attributeFilter: ['bar', 'bat'] }); >+ >+ div3.setAttribute('foo', 'foo'); >+ div3.setAttribute('bar', 'bar'); >+ div3.setAttribute('bat', 'bat'); >+ div3.setAttribute('baz', 'baz'); >+ >+ setTimeout(checkAndObserveAll, 0); >+ } >+ >+ function checkAndObserveAll() { >+ debug('...only foo, bar & bat should be received.'); >+ >+ shouldBe('mutations.length', '3'); >+ shouldBe('mutations[0].type', '"attributes"'); >+ shouldBe('mutations[0].attributeName', '"foo"'); >+ shouldBe('mutations[0].attributeNamespace', 'null'); >+ shouldBe('mutations[1].type', '"attributes"'); >+ shouldBe('mutations[1].attributeName', '"bar"'); >+ shouldBe('mutations[1].attributeNamespace', 'null'); >+ shouldBe('mutations[2].type', '"attributes"'); >+ shouldBe('mutations[2].attributeName', '"bat"'); >+ shouldBe('mutations[2].attributeNamespace', 'null'); >+ >+ observer.observe(div2, { attributes: true, subtree: true }); >+ div3.setAttribute('bar', 'bar'); >+ div3.setAttribute('bat', 'bat'); >+ div3.setAttribute('baz', 'baz'); >+ >+ setTimeout(finish, 0); >+ } >+ >+ function finish() { >+ debug('...bar, bat & baz should all be received.'); >+ >+ shouldBe('mutations.length', '3'); >+ shouldBe('mutations[0].type', '"attributes"'); >+ shouldBe('mutations[0].attributeName', '"bar"'); >+ shouldBe('mutations[0].attributeNamespace', 'null'); >+ shouldBe('mutations[1].type', '"attributes"'); >+ shouldBe('mutations[1].attributeName', '"bat"'); >+ shouldBe('mutations[1].attributeNamespace', 'null'); >+ shouldBe('mutations[2].type', '"attributes"'); >+ shouldBe('mutations[2].attributeName', '"baz"'); >+ shouldBe('mutations[2].attributeNamespace', 'null'); >+ >+ observer.disconnect(); >+ debug(''); >+ runNextTest(); >+ } >+ >+ start(); >+} >+ >+function testAttributeFilterNonHTMLElement() { >+ var path; >+ var observer; >+ >+ function start() { >+ debug('Testing that attributeFilter respects case with non-HTML elements.'); >+ >+ mutations = null; >+ observer = new WebKitMutationObserver(function(m) { >+ mutations = m; >+ }); >+ >+ path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); >+ observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] }); >+ path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200'); >+ path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200'); >+ >+ setTimeout(finish, 0); >+ } >+ >+ function finish() { >+ debug('...pathLength should be received.'); >+ >+ shouldBe('mutations.length', '1'); >+ shouldBe('mutations[0].type', '"attributes"'); >+ shouldBe('mutations[0].attributeName', '"pathLength"'); >+ shouldBe('mutations[0].attributeNamespace', '"http://www.w3.org/2000/svg"'); >+ observer.disconnect(); >+ debug(''); >+ runNextTest(); >+ } >+ >+ start(); >+} >+ >+function testAttributeFilterNonHTMLDocument() { >+ var svgDoc, div, path; >+ var observer; >+ >+ function start() { >+ debug('Testing that attributeFilter respects case with non-HTML elements.'); >+ >+ svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', 'svg'); >+ mutations = null; >+ observer = new WebKitMutationObserver(function(m) { >+ mutations = m; >+ }); >+ >+ div = svgDoc.createElement('div'); >+ observer.observe(div, { attributes: true, attributeFilter: ['ID', 'id', 'booM'] }); >+ div.setAttribute('ID', 'ID'); >+ div.setAttribute('id', 'id'); >+ div.setAttribute('baz', 'baz'); >+ div.setAttribute('booM', 'boom'); >+ div.setAttribute('BOOm', 'boom'); >+ >+ path = svgDoc.createElementNS('http://www.w3.org/2000/svg', 'path'); >+ observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] }); >+ path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200'); >+ path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200'); >+ >+ setTimeout(finish, 0); >+ } >+ >+ function finish() { >+ debug('...only ID, id, booM, pathLength should be received.'); >+ >+ shouldBe('mutations.length', '4'); >+ shouldBe('mutations[0].type', '"attributes"'); >+ shouldBe('mutations[0].attributeName', '"ID"'); >+ shouldBe('mutations[0].attributeNamespace', 'null'); >+ shouldBe('mutations[1].type', '"attributes"'); >+ shouldBe('mutations[1].attributeName', '"id"'); >+ shouldBe('mutations[1].attributeNamespace', 'null'); >+ shouldBe('mutations[2].type', '"attributes"'); >+ shouldBe('mutations[2].attributeName', '"booM"'); >+ shouldBe('mutations[2].attributeNamespace', 'null'); >+ shouldBe('mutations[3].type', '"attributes"'); >+ shouldBe('mutations[3].attributeName', '"pathLength"'); >+ shouldBe('mutations[3].attributeNamespace', '"http://www.w3.org/2000/svg"'); >+ >+ observer.disconnect(); >+ debug(''); >+ runNextTest(); >+ } >+ >+ start(); >+} >+ > var tests = [ > testBasic, > testWrongType, >@@ -446,7 +649,11 @@ var tests = [ > testOldValue, > testOldValueAsRequested, > testOldValueUnionMultipleObservations, >- testIDLAttribute >+ testIDLAttribute, >+ testAttributeFilter, >+ testAttributeFilterSubtree, >+ testAttributeFilterNonHTMLElement, >+ testAttributeFilterNonHTMLDocument > ]; > var testIndex = 0; >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 70860
:
112960
|
113083
|
113366
|
113582
|
113602
|
113748
|
114168