Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 28 Aug 2012 13:23:42 -0400
changeset 105717 b22fb91ad7e207e91bfd63ecf18410d17ee356b3
parent 105716 539643ca53ec94b6d520c5ee5bc9ccfa63dbec7b (current diff)
parent 105674 271ca35d7645edcd3df21e350e044c4e00cce171 (diff)
child 105718 44cfdb8eba09def2914ce7e5c1486b5d09a94509
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
milestone18.0a1
Merge m-c to inbound.
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -385,38 +385,45 @@ void nsMutationReceiver::NodeWillBeDestr
 
 // Observer
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
 
 DOMCI_DATA(MutationObserver, nsDOMMutationObserver)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MutationObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationObserver)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationObserver)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
   for (int32_t i = 0; i < tmp->mReceivers.Count(); ++i) {
     tmp->mReceivers[i]->Disconnect(false);
   }
   tmp->mReceivers.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingMutations)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCallback)
   // No need to handle mTransientReceivers
   NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mReceivers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingMutations)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCallback)
   // No need to handle mTransientReceivers
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
--- a/content/base/src/nsDOMMutationObserver.h
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -17,16 +17,17 @@
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "nsIVariant.h"
 #include "nsContentList.h"
 #include "mozilla/dom/Element.h"
 #include "nsClassHashtable.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMMutationEvent.h"
+#include "nsWrapperCache.h"
 
 class nsDOMMutationObserver;
 
 class nsDOMMutationRecord : public nsIDOMMutationRecord
 {
 public:
   nsDOMMutationRecord(const nsAString& aType) : mType(aType)
   {
@@ -284,32 +285,61 @@ public:
     AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
                         nsIDOMMutationEvent::MODIFICATION);
   }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)
 
 class nsDOMMutationObserver : public nsIDOMMutationObserver,
-                              public nsIJSNativeInitializer
+                              public nsIJSNativeInitializer,
+                              public nsWrapperCache
 {
 public:
   nsDOMMutationObserver() : mWaitingForRun(false), mId(++sCount)
   {
     mTransientReceivers.Init();
   }
   virtual ~nsDOMMutationObserver();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMMutationObserver,
-                                           nsIDOMMutationObserver)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMMutationObserver,
+                                                         nsIDOMMutationObserver)
   NS_DECL_NSIDOMMUTATIONOBSERVER
 
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                         uint32_t argc, jsval* argv);
 
+  void GetParentObject(nsIScriptGlobalObject** aParentObject)
+  {
+    if (mOwner) {
+      CallQueryInterface(mOwner, aParentObject);
+    } else {
+      *aParentObject = nullptr;
+    }
+  }
+
+  static nsDOMMutationObserver* FromSupports(nsISupports* aSupports)
+  {
+    nsIDOMMutationObserver* mutationObserver =
+      static_cast<nsIDOMMutationObserver*>(aSupports);
+#ifdef DEBUG
+    {
+      nsCOMPtr<nsIDOMMutationObserver> mutationObserver_qi =
+        do_QueryInterface(aSupports);
+
+      // If this assertion fires the QI implementation for the object in
+      // question doesn't use the nsIDOMMutationObserver pointer as the
+      // nsISupports pointer. That must be fixed, or we'll crash...
+      NS_ASSERTION(mutationObserver_qi == mutationObserver, "Uh, fix QI!");
+    }
+#endif
+
+    return static_cast<nsDOMMutationObserver*>(mutationObserver);
+  }
+
   void HandleMutation();
 
   // static methods
   static void HandleMutations()
   {
     if (sScheduledMutationObservers) {
       HandleMutationsInternal();
     }
--- a/content/base/test/test_mutationobservers.html
+++ b/content/base/test/test_mutationobservers.html
@@ -518,40 +518,61 @@ function testTakeRecords() {
   div.removeAttribute("foo");
   takenRecords = m.takeRecords();
   div.setAttribute("foo", "bar");
   div.innerHTML = s;
   div.removeAttribute("foo");
 }
 
 function testTakeRecords() {
+  function mutationListener(e) {
+    ++mutationEventCount;
+    is(e.attrChange, MutationEvent.ADDITION, "unexpected change");
+  }
+
   m = new M(function(records, observer) {
       is(records.length, 2, "Should have got 2 records");
       is(records[0].type, "attributes", "Should have got attributes");
       is(records[0].attributeName, "foo", "");
       is(records[0].oldValue, null, "");
       is(records[1].type, "attributes", "Should have got attributes");
       is(records[1].attributeName, "foo", "");
       is(records[1].oldValue, "bar", "");
       observer.disconnect();
-      then();
+      div.removeEventListener("DOMAttrModified", mutationListener);
+      then(testExpandos);
       m = null;
     });
   m.observe(div, { attributes: true, attributeOldValue: true });
   var mutationEventCount = 0;
-  div.addEventListener("DOMAttrModified",
-                       function(e) {
-                         ++mutationEventCount;
-                         is(e.attrChange, MutationEvent.ADDITION, "unexpected change");
-                       });
+  div.addEventListener("DOMAttrModified", mutationListener);
   div.setAttribute("foo", "bar");
   div.setAttribute("foo", "bar");
   is(mutationEventCount, 1, "Should have got only one mutation event!");
 }
 
+function testExpandos() {
+  var m2 = new M(function(records, observer) {
+    is(observer.expandoProperty, true);
+    observer.disconnect();
+    then();
+  });
+  m2.expandoProperty = true;
+  m2.observe(div, { attributes: true });
+  m2 = null;
+  if (SpecialPowers) {
+    // Run GC several times to see if the expando property disappears.
+    SpecialPowers.gc();
+    SpecialPowers.gc();
+    SpecialPowers.gc();
+    SpecialPowers.gc();
+  }
+  div.setAttribute("foo", "bar2");
+}
+
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 <div id="log">
 </div>
 </body>
 </html>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1650,18 +1650,19 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MediaQueryList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(MutationObserver, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(MutationObserver, nsDOMMutationObserverSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(MutationRecord, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_CLASSINFO_DATA(MozWifiStatusChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozWifiConnectionInfoEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -7986,16 +7987,47 @@ nsEventTargetSH::AddProperty(nsIXPConnec
 void
 nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
 {
   nsDOMEventTargetHelper *target =
     nsDOMEventTargetHelper::FromSupports(aNative);
   nsContentUtils::PreserveWrapper(aNative, target);
 }
 
+// MutationObserver helper
+
+NS_IMETHODIMP
+nsDOMMutationObserverSH::PreCreate(nsISupports* aNativeObj, JSContext* aCx,
+                                   JSObject* aGlobalObj, JSObject** aParentObj)
+{
+  nsDOMMutationObserver* mutationObserver =
+    nsDOMMutationObserver::FromSupports(aNativeObj);
+  nsCOMPtr<nsIScriptGlobalObject> native_parent;
+  mutationObserver->GetParentObject(getter_AddRefs(native_parent));
+  *aParentObj = native_parent ? native_parent->GetGlobalJSObject() : aGlobalObj;
+  return *aParentObj ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsDOMMutationObserverSH::AddProperty(nsIXPConnectWrappedNative* aWrapper,
+                                     JSContext* aCx, JSObject* aObj, jsid aId,
+                                     jsval* aVp, bool* aRetVal)
+{
+  nsDOMMutationObserverSH::PreserveWrapper(GetNative(aWrapper, aObj));
+  return NS_OK;
+}
+
+void
+nsDOMMutationObserverSH::PreserveWrapper(nsISupports* aNative)
+{
+  nsDOMMutationObserver* mutationObserver =
+    nsDOMMutationObserver::FromSupports(aNative);
+  nsContentUtils::PreserveWrapper(aNative, mutationObserver);
+}
+
 // IDBEventTarget helper
 
 NS_IMETHODIMP
 IDBEventTargetSH::PreCreate(nsISupports *aNativeObj, JSContext *aCx,
                             JSObject *aGlobalObj, JSObject **aParentObj)
 {
   IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNativeObj);
   JSObject *parent = target->GetParentObject();
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -334,16 +334,40 @@ public:
   virtual void PreserveWrapper(nsISupports *aNative);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsEventTargetSH(aData);
   }
 };
 
+class nsDOMMutationObserverSH : public nsDOMGenericSH
+{
+protected:
+  nsDOMMutationObserverSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
+  {
+  }
+
+  virtual ~nsDOMMutationObserverSH()
+  {
+  }
+public:
+  NS_IMETHOD PreCreate(nsISupports* aNativeObj, JSContext* aCx,
+                       JSObject* aGlobalObj, JSObject** aParentObj);
+  NS_IMETHOD AddProperty(nsIXPConnectWrappedNative* aWrapper, JSContext* aCx,
+                         JSObject* aObj, jsid aId, jsval* aVp, bool* aRetval);
+
+  virtual void PreserveWrapper(nsISupports* aNative);
+
+  static nsIClassInfo* doCreate(nsDOMClassInfoData* aData)
+  {
+    return new nsDOMMutationObserverSH(aData);
+  }
+};
+
 // Window scriptable helper
 
 class nsWindowSH : public nsDOMGenericSH
 {
 protected:
   nsWindowSH(nsDOMClassInfoData *aData) : nsDOMGenericSH(aData)
   {
   }