diff --git a/content/base/src/nsDOMMutationObserver.cpp b/content/base/src/nsDOMMutationObserver.cpp index 6ad99fcb8d89..e0602fa40d67 100644 --- a/content/base/src/nsDOMMutationObserver.cpp +++ b/content/base/src/nsDOMMutationObserver.cpp @@ -585,6 +585,36 @@ nsDOMMutationObserver::Disconnect() return NS_OK; } +NS_IMETHODIMP +nsDOMMutationObserver::TakeRecords(nsIVariant** aRetVal) +{ + *aRetVal = TakeRecords().get(); + return NS_OK; +} + +already_AddRefed +nsDOMMutationObserver::TakeRecords() +{ + nsCOMPtr mutations = + do_CreateInstance("@mozilla.org/variant;1"); + PRInt32 len = mPendingMutations.Count(); + if (len == 0) { + mutations->SetAsEmptyArray(); + } else { + nsTArray mods(len); + for (PRInt32 i = 0; i < len; ++i) { + mods.AppendElement(mPendingMutations[i]); + } + + mutations->SetAsArray(nsIDataType::VTYPE_INTERFACE, + &NS_GET_IID(nsIDOMMutationRecord), + mods.Length(), + const_cast( + static_cast(mods.Elements()))); + mPendingMutations.Clear(); + } + return mutations.forget(); +} NS_IMETHODIMP nsDOMMutationObserver::Initialize(nsISupports* aOwner, JSContext* cx, @@ -639,21 +669,8 @@ nsDOMMutationObserver::HandleMutation() mPendingMutations.Clear(); return; } - - PRInt32 len = mPendingMutations.Count(); - nsTArray mods(len); - for (PRInt32 i = 0; i < len; ++i) { - mods.AppendElement(mPendingMutations[i]); - } - - nsCOMPtr mutations = - do_CreateInstance("@mozilla.org/variant;1"); - mutations->SetAsArray(nsIDataType::VTYPE_INTERFACE, - &NS_GET_IID(nsIDOMMutationRecord), - mods.Length(), - const_cast( - static_cast(mods.Elements()))); - mPendingMutations.Clear(); + + nsCOMPtr mutations = TakeRecords(); nsAutoMicroTask mt; sCurrentObserver = this; // For 'this' handling. mCallback->HandleMutations(mutations, this); diff --git a/content/base/src/nsDOMMutationObserver.h b/content/base/src/nsDOMMutationObserver.h index 4c276b26981d..4bd78d02f538 100644 --- a/content/base/src/nsDOMMutationObserver.h +++ b/content/base/src/nsDOMMutationObserver.h @@ -320,6 +320,8 @@ protected: nsMutationReceiver* GetReceiverFor(nsINode* aNode, bool aMayCreate); void RemoveReceiver(nsMutationReceiver* aReceiver); + already_AddRefed TakeRecords(); + void GetAllSubtreeObserversFor(nsINode* aNode, nsTArray& aObservers); void ScheduleForRun(); diff --git a/content/base/test/test_mutationobservers.html b/content/base/test/test_mutationobservers.html index 1b8031455d24..8bf20e2a52ec 100644 --- a/content/base/test/test_mutationobservers.html +++ b/content/base/test/test_mutationobservers.html @@ -477,7 +477,45 @@ function testModalDialog() { div.innerHTML = "foo"; window.showModalDialog("mutationobserver_dialog.html"); ok(didHandleCallback, "Should have called the callback while showing modal dialog!"); - then(); + then(testTakeRecords); +} + +function testTakeRecords() { + var s = "12"; + div.innerHTML = s; + var takenRecords; + m = new M(function(records, observer) { + is(records.length, 3, "Should have got 3 records"); + + is(records[0].type, "attributes", "Should have got attributes"); + is(records[0].attributeName, "foo", ""); + is(records[1].type, "childList", "Should have got childList"); + is(records[1].removedNodes.length, 2, "Should have got removedNodes"); + is(records[1].addedNodes.length, 2, "Should have got addedNodes"); + is(records[2].type, "attributes", "Should have got attributes"); + is(records[2].attributeName, "foo", ""); + + is(records.length, takenRecords.length, "Should have had similar mutations"); + is(records[0].type, takenRecords[0].type, "Should have had similar mutations"); + is(records[1].type, takenRecords[1].type, "Should have had similar mutations"); + is(records[2].type, takenRecords[2].type, "Should have had similar mutations"); + + is(records[1].removedNodes.length, takenRecords[1].removedNodes.length, "Should have had similar mutations"); + is(records[1].addedNodes.length, takenRecords[1].addedNodes.length, "Should have had similar mutations"); + + is(m.takeRecords().length, 0, "Shouldn't have any records"); + observer.disconnect(); + then(); + m = null; + }); + m.observe(div, { childList: true, attributes: true }); + div.setAttribute("foo", "bar"); + div.innerHTML = s; + div.removeAttribute("foo"); + takenRecords = m.takeRecords(); + div.setAttribute("foo", "bar"); + div.innerHTML = s; + div.removeAttribute("foo"); } SimpleTest.waitForExplicitFinish(); diff --git a/dom/interfaces/core/nsIDOMMutationObserver.idl b/dom/interfaces/core/nsIDOMMutationObserver.idl index 5cf7401f8e30..238f2223537c 100644 --- a/dom/interfaces/core/nsIDOMMutationObserver.idl +++ b/dom/interfaces/core/nsIDOMMutationObserver.idl @@ -56,12 +56,13 @@ dictionary MutationObserverInit }; //[Constructor(in nsIMutationCallback aDoneCallback)] -[scriptable, builtinclass, uuid(daeba265-9aa7-45ab-8de2-b6b039c13ced)] +[scriptable, builtinclass, uuid(156e2ce4-e44a-45f3-92c2-e6611f391dae)] interface nsIDOMMozMutationObserver : nsISupports { [implicit_jscontext] void observe(in nsIDOMNode aTarget, in jsval aOptions); void disconnect(); + nsIVariant takeRecords(); }; [scriptable, function, uuid(fb539590-b088-4d07-96ff-2cefbc90a198)]