Bug 742482 - Add support for MutationObserver.takeRecords(), r=sicking
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 11 Apr 2012 08:24:18 +0300
changeset 94628 e636439e342fa7e561d2f86e0730251566dc5732
parent 94627 4db1292be760c4ddc632dbf8f5d69d73840b9ce2
child 94693 63f78a93ae5c3b41876e77332acd9d9e2c600479
child 94832 6edf254d7e5b56ca7641a1d5b6a7e44192261816
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs742482
milestone14.0a1
first release with
nightly linux32
e636439e342f / 14.0a1 / 20120411030716 / files
nightly linux64
e636439e342f / 14.0a1 / 20120411030716 / files
nightly mac
e636439e342f / 14.0a1 / 20120411030716 / files
nightly win32
e636439e342f / 14.0a1 / 20120411030716 / files
nightly win64
e636439e342f / 14.0a1 / 20120411030716 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 742482 - Add support for MutationObserver.takeRecords(), r=sicking
content/base/src/nsDOMMutationObserver.cpp
content/base/src/nsDOMMutationObserver.h
content/base/test/test_mutationobservers.html
dom/interfaces/core/nsIDOMMutationObserver.idl
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -580,16 +580,46 @@ nsDOMMutationObserver::Disconnect()
     mReceivers[i]->Disconnect(false);
   }
   mReceivers.Clear();
   mCurrentMutations.Clear();
   mPendingMutations.Clear();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMMutationObserver::TakeRecords(nsIVariant** aRetVal)
+{
+  *aRetVal = TakeRecords().get();
+  return NS_OK;
+}
+
+already_AddRefed<nsIVariant>
+nsDOMMutationObserver::TakeRecords()
+{
+  nsCOMPtr<nsIWritableVariant> mutations =
+    do_CreateInstance("@mozilla.org/variant;1");
+  PRInt32 len = mPendingMutations.Count();
+  if (len == 0) {
+    mutations->SetAsEmptyArray();
+  } else {
+    nsTArray<nsIDOMMutationRecord*> 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<void*>(
+                            static_cast<const void*>(mods.Elements())));
+    mPendingMutations.Clear();
+  }
+  return mutations.forget();
+}
 
 NS_IMETHODIMP
 nsDOMMutationObserver::Initialize(nsISupports* aOwner, JSContext* cx,
                                   JSObject* obj, PRUint32 argc, jsval* argv)
 {
   mOwner = do_QueryInterface(aOwner);
   if (!mOwner) {
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
@@ -634,31 +664,18 @@ nsDOMMutationObserver::HandleMutation()
     return;
   }
   nsCxPusher pusher;
   nsCOMPtr<nsIDOMEventTarget> et = do_QueryInterface(mOwner);
   if (!mCallback || !pusher.Push(et)) {
     mPendingMutations.Clear();
     return;
   }
-  
-  PRInt32 len = mPendingMutations.Count();
-  nsTArray<nsIDOMMutationRecord*> mods(len);
-  for (PRInt32 i = 0; i < len; ++i) {
-    mods.AppendElement(mPendingMutations[i]);
-  }
-  
-  nsCOMPtr<nsIWritableVariant> mutations =
-    do_CreateInstance("@mozilla.org/variant;1");
-  mutations->SetAsArray(nsIDataType::VTYPE_INTERFACE,
-                        &NS_GET_IID(nsIDOMMutationRecord),
-                        mods.Length(),
-                        const_cast<void*>(
-                          static_cast<const void*>(mods.Elements())));
-  mPendingMutations.Clear();
+
+  nsCOMPtr<nsIVariant> mutations = TakeRecords();
   nsAutoMicroTask mt;
   sCurrentObserver = this; // For 'this' handling.
   mCallback->HandleMutations(mutations, this);
   sCurrentObserver = nsnull;
 }
 
 class AsyncMutationHandler : public nsRunnable
 {
--- a/content/base/src/nsDOMMutationObserver.h
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -315,16 +315,18 @@ public:
 
   static void Shutdown();
 protected:
   friend class nsMutationReceiver;
   friend class nsAutoMutationBatch;
   nsMutationReceiver* GetReceiverFor(nsINode* aNode, bool aMayCreate);
   void RemoveReceiver(nsMutationReceiver* aReceiver);
 
+  already_AddRefed<nsIVariant> TakeRecords();
+
   void GetAllSubtreeObserversFor(nsINode* aNode,
                                  nsTArray<nsMutationReceiver*>& aObservers);
   void ScheduleForRun();
   void RescheduleForRun();
 
   nsDOMMutationRecord* CurrentRecord(const nsAString& aType);
   bool HasCurrentRecord(const nsAString& aType);
 
--- a/content/base/test/test_mutationobservers.html
+++ b/content/base/test/test_mutationobservers.html
@@ -472,17 +472,55 @@ function testModalDialog() {
       observer.disconnect();
       m = null;
       didHandleCallback = true;
     });
   m.observe(div, { childList: true });
   div.innerHTML = "<span><span>foo</span></span>";
   window.showModalDialog("mutationobserver_dialog.html");
   ok(didHandleCallback, "Should have called the callback while showing modal dialog!");
-  then();
+  then(testTakeRecords);
+}
+
+function testTakeRecords() {
+  var s = "<span>1</span><span>2</span>";
+  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();
 
 </script>
 </pre>
 <div id="log">
 </div>
--- a/dom/interfaces/core/nsIDOMMutationObserver.idl
+++ b/dom/interfaces/core/nsIDOMMutationObserver.idl
@@ -51,21 +51,22 @@ dictionary MutationObserverInit
   boolean characterData;
   boolean subtree;
   boolean attributeOldValue;
   boolean characterDataOldValue;
   jsval   attributeFilter; // DOMString[]
 };
 
 //[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)]
 interface nsIMutationObserverCallback : nsISupports
 {
   void handleMutations(in nsIVariant aRecords, in nsIDOMMozMutationObserver aObserver);
 };