Diff
Modified: trunk/LayoutTests/ChangeLog (99592 => 99593)
--- trunk/LayoutTests/ChangeLog 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/LayoutTests/ChangeLog 2011-11-08 18:29:54 UTC (rev 99593)
@@ -1,3 +1,16 @@
+2011-11-08 Adam Klein <[email protected]>
+
+ Only walk up the tree in search of MutationObservers if one has been added
+ https://bugs.webkit.org/show_bug.cgi?id=71499
+
+ Reviewed by Ojan Vafai.
+
+ Created a basic test showing that MutationObservers
+ are preserved when a Node switches documents.
+
+ * fast/mutation/cross-document-expected.txt: Added.
+ * fast/mutation/cross-document.html: Added.
+
2011-11-08 Ojan Vafai <[email protected]>
Move regressions from V8 roll to from the downstream expectations file.
Added: trunk/LayoutTests/fast/mutation/cross-document-expected.txt (0 => 99593)
--- trunk/LayoutTests/fast/mutation/cross-document-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/mutation/cross-document-expected.txt 2011-11-08 18:29:54 UTC (rev 99593)
@@ -0,0 +1,23 @@
+Test that MutationObservers move correctly across documents
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing basic aspects of cross-document observation.
+PASS mutations.length is 1
+PASS mutations[0].type is "attributes"
+PASS mutations[0].target is div
+PASS mutations[0].attributeName is "id"
+PASS mutations[0].attributeNamespace is null
+
+Testing that subtree observation works after node is moved.
+PASS mutations.length is 1
+PASS mutations[0].type is "attributes"
+PASS mutations[0].target is subDiv
+PASS mutations[0].attributeName is "id"
+PASS mutations[0].attributeNamespace is null
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/mutation/cross-document.html (0 => 99593)
--- trunk/LayoutTests/fast/mutation/cross-document.html (rev 0)
+++ trunk/LayoutTests/fast/mutation/cross-document.html 2011-11-08 18:29:54 UTC (rev 99593)
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+
+window.jsTestIsAsync = true;
+var mutations;
+var div, subDiv;
+
+function testBasic() {
+ var observer;
+
+ function start() {
+ debug('Testing basic aspects of cross-document observation.');
+
+ mutations = null;
+ div = document.createElement('div');
+ observer = new WebKitMutationObserver(function(mutations) {
+ window.mutations = mutations;
+ });
+
+ observer.observe(div, {attributes: true});
+ var newDoc = document.implementation.createDocument('', '', null);
+ newDoc.appendChild(div);
+ div.id = 'foo';
+ setTimeout(finish, 0);
+ }
+
+ function finish() {
+ shouldBe('mutations.length', '1');
+ shouldBe('mutations[0].type', '"attributes"');
+ shouldBe('mutations[0].target', 'div');
+ shouldBe('mutations[0].attributeName', '"id"');
+ shouldBe('mutations[0].attributeNamespace', 'null');
+ observer.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+function testSubtree() {
+ var observer;
+
+ function start() {
+ debug('Testing that subtree observation works after node is moved.');
+
+ mutations = null;
+ div = document.createElement('div');
+ subDiv = div.appendChild(document.createElement('div'));
+ observer = new WebKitMutationObserver(function(mutations) {
+ window.mutations = mutations;
+ });
+
+ observer.observe(div, {attributes: true, subtree: true});
+ var newDoc = document.implementation.createDocument('', '', null);
+ newDoc.appendChild(div);
+ subDiv.id = 'foo';
+ setTimeout(finish, 0);
+ }
+
+ function finish() {
+ shouldBe('mutations.length', '1');
+ shouldBe('mutations[0].type', '"attributes"');
+ shouldBe('mutations[0].target', 'subDiv');
+ shouldBe('mutations[0].attributeName', '"id"');
+ shouldBe('mutations[0].attributeNamespace', 'null');
+ observer.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+var tests = [testBasic, testSubtree];
+var testIndex = 0;
+
+function runNextTest() {
+ if (testIndex < tests.length)
+ tests[testIndex++]();
+ else
+ finishJSTest();
+}
+
+description('Test that MutationObservers move correctly across documents');
+
+if (!window.WebKitMutationObserver)
+ testFailed('This test requires ENABLE(MUTATION_OBSERVERS)');
+else
+ runNextTest();
+
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (99592 => 99593)
--- trunk/Source/WebCore/ChangeLog 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/ChangeLog 2011-11-08 18:29:54 UTC (rev 99593)
@@ -1,3 +1,40 @@
+2011-11-08 Adam Klein <[email protected]>
+
+ Only walk up the tree in search of MutationObservers if one has been added
+ https://bugs.webkit.org/show_bug.cgi?id=71499
+
+ Reviewed by Ojan Vafai.
+
+ Analogous to m_listenerTypes, added an m_subtreeMutationObserverTypes field
+ to Document that keeps track of which observer types have been added.
+ This allows us to avoid doing any extra work if MutationObservers are
+ not attached to a document.
+
+ This could be improved upon to keep a count of each type, as removing
+ an observer currently has no effect on m_subtreeMutationObserverTypes.
+ But that would require a more complex implementation: one counter per
+ mutation type. And it would be easier to get wrong: if the counter
+ gets out of sync with the actual state of the DOM, we could start
+ dropping mutation notifications.
+
+ Test: fast/mutation/cross-document.html
+
+ * dom/Document.h:
+ (WebCore::Document::hasSubtreeMutationObserverOfType):
+ (WebCore::Document::hasSubtreeMutationObserver):
+ (WebCore::Document::addSubtreeMutationObserverTypes):
+ * dom/MutationObserverRegistration.h:
+ (WebCore::MutationObserverRegistration::isSubtree):
+ (WebCore::MutationObserverRegistration::deliveryOptions):
+ (WebCore::MutationObserverRegistration::mutationTypes):
+ * dom/Node.cpp:
+ (WebCore::Node::didMoveToNewOwnerDocument): Update mutationObserverTypes when a Node is moved to a new document.
+ (WebCore::Node::getRegisteredMutationObserversOfType): Exit early if it's known that no observers of |type| are registered.
+ (WebCore::Node::notifyMutationObserversNodeWillDetach): Exit early if it's known no subtree observers of any type are registered.
+ * dom/WebKitMutationObserver.cpp:
+ (WebCore::WebKitMutationObserver::observe): Update mutationObserverTypes when an observation occurs.
+ * dom/WebKitMutationObserver.h: Add WebKitMutationObserver::AllMutationTypes to enum
+
2011-11-08 Andreas Kling <[email protected]>
Devirtualize CSSValue.
Modified: trunk/Source/WebCore/dom/Document.cpp (99592 => 99593)
--- trunk/Source/WebCore/dom/Document.cpp 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/Document.cpp 2011-11-08 18:29:54 UTC (rev 99593)
@@ -360,6 +360,9 @@
, m_compatibilityMode(NoQuirksMode)
, m_compatibilityModeLocked(false)
, m_domTreeVersion(++s_globalTreeVersion)
+#if ENABLE(MUTATION_OBSERVERS)
+ , m_subtreeMutationObserverTypes(0)
+#endif
, m_styleSheets(StyleSheetList::create(this))
, m_readyState(Complete)
, m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
Modified: trunk/Source/WebCore/dom/Document.h (99592 => 99593)
--- trunk/Source/WebCore/dom/Document.h 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/Document.h 2011-11-08 18:29:54 UTC (rev 99593)
@@ -46,6 +46,7 @@
#include "Timer.h"
#include "TreeScope.h"
#include "ViewportArguments.h"
+#include "WebKitMutationObserver.h"
#include <wtf/Deque.h>
#include <wtf/FixedArray.h>
#include <wtf/OwnPtr.h>
@@ -776,6 +777,15 @@
void addListenerType(ListenerType listenerType) { m_listenerTypes = m_listenerTypes | listenerType; }
void addListenerTypeIfNeeded(const AtomicString& eventType);
+#if ENABLE(MUTATION_OBSERVERS)
+ bool hasSubtreeMutationObserverOfType(WebKitMutationObserver::MutationType type) const
+ {
+ return m_subtreeMutationObserverTypes & type;
+ }
+ bool hasSubtreeMutationObserver() const { return m_subtreeMutationObserverTypes; }
+ void addSubtreeMutationObserverTypes(MutationObserverOptions types) { m_subtreeMutationObserverTypes |= types; }
+#endif
+
CSSStyleDeclaration* getOverrideStyle(Element*, const String& pseudoElt);
int nodeAbsIndex(Node*);
@@ -1238,6 +1248,10 @@
unsigned short m_listenerTypes;
+#if ENABLE(MUTATION_OBSERVERS)
+ MutationObserverOptions m_subtreeMutationObserverTypes;
+#endif
+
RefPtr<StyleSheetList> m_styleSheets; // All of the stylesheets that are currently in effect for our media type and stylesheet set.
typedef ListHashSet<Node*, 32> StyleSheetCandidateListHashSet;
Modified: trunk/Source/WebCore/dom/MutationObserverRegistration.h (99592 => 99593)
--- trunk/Source/WebCore/dom/MutationObserverRegistration.h 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/MutationObserverRegistration.h 2011-11-08 18:29:54 UTC (rev 99593)
@@ -53,9 +53,11 @@
void unregister();
bool shouldReceiveMutationFrom(Node*, WebKitMutationObserver::MutationType);
+ bool isSubtree() const { return m_options & WebKitMutationObserver::Subtree; }
WebKitMutationObserver* observer() { return m_observer.get(); }
- MutationRecordDeliveryOptions deliveryOptions() { return m_options & (WebKitMutationObserver::AttributeOldValue | WebKitMutationObserver::CharacterDataOldValue); }
+ MutationRecordDeliveryOptions deliveryOptions() const { return m_options & (WebKitMutationObserver::AttributeOldValue | WebKitMutationObserver::CharacterDataOldValue); }
+ MutationObserverOptions mutationTypes() const { return m_options & WebKitMutationObserver::AllMutationTypes; }
private:
MutationObserverRegistration(PassRefPtr<WebKitMutationObserver>, Node*);
Modified: trunk/Source/WebCore/dom/Node.cpp (99592 => 99593)
--- trunk/Source/WebCore/dom/Node.cpp 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/Node.cpp 2011-11-08 18:29:54 UTC (rev 99593)
@@ -2544,6 +2544,24 @@
{
ASSERT(!didMoveToNewOwnerDocumentWasCalled);
setDidMoveToNewOwnerDocumentWasCalled(true);
+
+ // FIXME: Event listener types for this node should be set on the new owner document here.
+
+#if ENABLE(MUTATION_OBSERVERS)
+ if (Vector<OwnPtr<MutationObserverRegistration> >* registry = mutationObserverRegistry()) {
+ for (size_t i = 0; i < registry->size(); ++i) {
+ if (registry->at(i)->isSubtree())
+ document()->addSubtreeMutationObserverTypes(registry->at(i)->mutationTypes());
+ }
+ }
+
+ if (HashSet<MutationObserverRegistration*>* transientRegistry = transientMutationObserverRegistry()) {
+ for (HashSet<MutationObserverRegistration*>::iterator iter = transientRegistry->begin(); iter != transientRegistry->end(); ++iter) {
+ if ((*iter)->isSubtree())
+ document()->addSubtreeMutationObserverTypes((*iter)->mutationTypes());
+ }
+ }
+#endif
}
#if ENABLE(SVG)
@@ -2734,7 +2752,12 @@
void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, WebKitMutationObserver::MutationType type)
{
- for (Node* node = this; node; node = node->parentNode())
+ collectMatchingObserversForMutation(observers, this, type);
+
+ if (!document()->hasSubtreeMutationObserverOfType(type))
+ return;
+
+ for (Node* node = parentNode(); node; node = node->parentNode())
collectMatchingObserversForMutation(observers, node, type);
}
@@ -2785,6 +2808,9 @@
void Node::notifyMutationObserversNodeWillDetach()
{
+ if (!document()->hasSubtreeMutationObserver())
+ return;
+
for (Node* node = parentNode(); node; node = node->parentNode()) {
if (Vector<OwnPtr<MutationObserverRegistration> >* registry = node->mutationObserverRegistry()) {
const size_t size = registry->size();
Modified: trunk/Source/WebCore/dom/WebKitMutationObserver.cpp (99592 => 99593)
--- trunk/Source/WebCore/dom/WebKitMutationObserver.cpp 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/WebKitMutationObserver.cpp 2011-11-08 18:29:54 UTC (rev 99593)
@@ -34,6 +34,7 @@
#include "WebKitMutationObserver.h"
+#include "Document.h"
#include "MutationCallback.h"
#include "MutationObserverRegistration.h"
#include "MutationRecord.h"
@@ -61,6 +62,9 @@
{
MutationObserverRegistration* registration = node->registerMutationObserver(this);
registration->resetObservation(options);
+
+ if (registration->isSubtree())
+ node->document()->addSubtreeMutationObserverTypes(registration->mutationTypes());
}
void WebKitMutationObserver::disconnect()
Modified: trunk/Source/WebCore/dom/WebKitMutationObserver.h (99592 => 99593)
--- trunk/Source/WebCore/dom/WebKitMutationObserver.h 2011-11-08 18:27:07 UTC (rev 99592)
+++ trunk/Source/WebCore/dom/WebKitMutationObserver.h 2011-11-08 18:29:54 UTC (rev 99593)
@@ -55,7 +55,9 @@
enum MutationType {
ChildList = 1 << 0,
Attributes = 1 << 1,
- CharacterData = 1 << 2
+ CharacterData = 1 << 2,
+
+ AllMutationTypes = ChildList | Attributes | CharacterData
};
enum ObservationFlags {