Bug 1416450 - Ensure IntersectionObservers are deleted when adopting elements. r=mrbkap, a=gchang
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sun, 19 Nov 2017 16:22:54 +0200
changeset 444807 59d1822ef42e424b36850209345b678926f994e6
parent 444806 df6d0aff01790273b36dae1cf0835e5d4d168eac
child 444808 8297b7a3b50cdff3cf8eef7ff6698d253f146ab7
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, gchang
bugs1416450
milestone58.0
Bug 1416450 - Ensure IntersectionObservers are deleted when adopting elements. r=mrbkap, a=gchang
dom/base/Element.cpp
dom/base/nsNodeUtils.cpp
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -4301,29 +4301,43 @@ Element::ClearDataset()
   slots->mDataset = nullptr;
 }
 
 enum nsPreviousIntersectionThreshold {
   eUninitialized = -2,
   eNonIntersecting = -1
 };
 
+static void
+IntersectionObserverPropertyDtor(void* aObject, nsAtom* aPropertyName,
+                                 void* aPropertyValue, void* aData)
+{
+  Element* element = static_cast<Element*>(aObject);
+  IntersectionObserverList* observers =
+    static_cast<IntersectionObserverList*>(aPropertyValue);
+  for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
+    DOMIntersectionObserver* observer = iter.Key();
+    observer->UnlinkElement(*element);
+  }
+  delete observers;
+}
+
 void
 Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
 {
   IntersectionObserverList* observers =
     static_cast<IntersectionObserverList*>(
       GetProperty(nsGkAtoms::intersectionobserverlist)
     );
 
   if (!observers) {
     observers = new IntersectionObserverList();
     observers->Put(aObserver, eUninitialized);
     SetProperty(nsGkAtoms::intersectionobserverlist, observers,
-                nsINode::DeleteProperty<IntersectionObserverList>);
+                IntersectionObserverPropertyDtor, true);
     return;
   }
 
   observers->LookupForAdd(aObserver).OrInsert([]() {
     // If element is being observed, value can be:
     //   -2:   Makes sure next calculated threshold always differs, leading to a
     //         notification task being scheduled.
     //   -1:   Non-intersecting.
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -300,22 +300,16 @@ nsNodeUtils::LastRelease(nsINode* aNode)
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // Delete all properties before tearing down the document. Some of the
     // properties are bound to nsINode objects and the destructor functions of
     // the properties may want to use the owner document of the nsINode.
     static_cast<nsIDocument*>(aNode)->DeleteAllProperties();
   }
   else {
     if (aNode->HasProperties()) {
-      if (aNode->IsElement()) {
-        Element* elem = aNode->AsElement();
-        elem->UnlinkIntersectionObservers();
-        elem->DeleteProperty(nsGkAtoms::intersectionobserverlist);
-      }
-
       // Strong reference to the document so that deleting properties can't
       // delete the document.
       nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
       document->DeleteAllPropertiesFor(aNode);
     }
 
     // I wonder whether it's faster to do the HasFlag check first....
     if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&