Bug 1416450, ensure IntersectionObservers are deleted when adopting elements, r=mrbkap
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sun, 19 Nov 2017 16:22:54 +0200
changeset 392610 ef82504a2782
parent 392609 ba1f15d69399
child 392611 ab7aa50cd1af
push id97484
push useropettay@mozilla.com
push date2017-11-19 14:43 +0000
treeherdermozilla-inbound@ef82504a2782 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1416450
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1416450, ensure IntersectionObservers are deleted when adopting elements, r=mrbkap
dom/base/Element.cpp
dom/base/nsNodeUtils.cpp
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -4329,29 +4329,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) &&