Revise lifetime management of IntersectionObservers.

Tag #249
This commit is contained in:
wolfbeast 2018-12-22 02:15:50 +01:00 • committed by Roy Tam
commit 42d9f2ffb3
8 changed files with 46 additions and 26 deletions

View file

@ -43,16 +43,18 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries) NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries)
tmp->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries)
@ -185,10 +187,11 @@ DOMIntersectionObserver::Connect()
if (mConnected) { if (mConnected) {
return; return;
} }
mConnected = true;
nsIDocument* document = mOwner->GetExtantDoc(); mConnected = true;
document->AddIntersectionObserver(this); if(mDocument) {
mDocument->AddIntersectionObserver(this);
}
} }
void void
@ -202,11 +205,8 @@ DOMIntersectionObserver::Disconnect()
target->UnregisterIntersectionObserver(this); target->UnregisterIntersectionObserver(this);
} }
mObservationTargets.Clear(); mObservationTargets.Clear();
if (mOwner) { if (mDocument) {
nsIDocument* document = mOwner->GetExtantDoc(); mDocument->RemoveIntersectionObserver(this);
if (document) {
document->RemoveIntersectionObserver(this);
}
} }
mConnected = false; mConnected = false;
} }

View file

@ -106,7 +106,10 @@ class DOMIntersectionObserver final : public nsISupports,
public: public:
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner, DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
mozilla::dom::IntersectionCallback& aCb) mozilla::dom::IntersectionCallback& aCb)
: mOwner(aOwner), mCallback(&aCb), mConnected(false) : mOwner(aOwner)
, mDocument(mOwner->GetExtantDoc())
, mCallback(&aCb)
, mConnected(false)
{ {
} }
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -164,6 +167,7 @@ protected:
double aIntersectionRatio); double aIntersectionRatio);
nsCOMPtr<nsPIDOMWindowInner> mOwner; nsCOMPtr<nsPIDOMWindowInner> mOwner;
RefPtr<nsIDocument> mDocument;
RefPtr<mozilla::dom::IntersectionCallback> mCallback; RefPtr<mozilla::dom::IntersectionCallback> mCallback;
RefPtr<Element> mRoot; RefPtr<Element> mRoot;
nsCSSRect mRootMargin; nsCSSRect mRootMargin;

View file

@ -3947,7 +3947,7 @@ Element::ClearDataset()
slots->mDataset = nullptr; slots->mDataset = nullptr;
} }
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
Element::RegisteredIntersectionObservers() Element::RegisteredIntersectionObservers()
{ {
nsDOMSlots* slots = DOMSlots(); nsDOMSlots* slots = DOMSlots();
@ -3962,7 +3962,7 @@ enum nsPreviousIntersectionThreshold {
void void
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{ {
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers(); RegisteredIntersectionObservers();
if (observers->Contains(aObserver)) { if (observers->Contains(aObserver)) {
return; return;
@ -3979,7 +3979,7 @@ Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
void void
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver) Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{ {
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers(); RegisteredIntersectionObservers();
observers->Remove(aObserver); observers->Remove(aObserver);
} }
@ -3987,7 +3987,7 @@ Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
bool bool
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold) Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
{ {
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers(); RegisteredIntersectionObservers();
if (!observers->Contains(aObserver)) { if (!observers->Contains(aObserver)) {
return false; return false;

View file

@ -1382,7 +1382,8 @@ protected:
nsDOMTokenList* GetTokenList(nsIAtom* aAtom, nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr); const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* RegisteredIntersectionObservers(); nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
RegisteredIntersectionObservers();
private: private:
/** /**

View file

@ -585,6 +585,12 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
mCustomElementData->mCallbackQueue[i]->Traverse(cb); mCustomElementData->mCallbackQueue[i]->Traverse(cb);
} }
} }
for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mRegisteredIntersectionObservers[i]");
cb.NoteXPCOMChild(observer);
}
} }
void void

View file

@ -354,7 +354,8 @@ public:
/** /**
* Registered Intersection Observers on the element. * Registered Intersection Observers on the element.
*/ */
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers; nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
mRegisteredIntersectionObservers;
}; };
protected: protected:

View file

@ -1736,8 +1736,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntersectionObservers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks)
for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) { for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
@ -12375,15 +12373,15 @@ nsDocument::ReportUseCounters()
void void
nsDocument::AddIntersectionObserver(DOMIntersectionObserver* aObserver) nsDocument::AddIntersectionObserver(DOMIntersectionObserver* aObserver)
{ {
NS_ASSERTION(mIntersectionObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex, MOZ_ASSERT(!mIntersectionObservers.Contains(aObserver),
"Intersection observer already in the list"); "Intersection observer already in the list");
mIntersectionObservers.AppendElement(aObserver); mIntersectionObservers.PutEntry(aObserver);
} }
void void
nsDocument::RemoveIntersectionObserver(DOMIntersectionObserver* aObserver) nsDocument::RemoveIntersectionObserver(DOMIntersectionObserver* aObserver)
{ {
mIntersectionObservers.RemoveElement(aObserver); mIntersectionObservers.RemoveEntry(aObserver);
} }
void void
@ -12396,7 +12394,8 @@ nsDocument::UpdateIntersectionObservations()
time = perf->Now(); time = perf->Now();
} }
} }
for (const auto& observer : mIntersectionObservers) { for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Get()->GetKey();
observer->Update(this, time); observer->Update(this, time);
} }
} }
@ -12404,6 +12403,10 @@ nsDocument::UpdateIntersectionObservations()
void void
nsDocument::ScheduleIntersectionObserverNotification() nsDocument::ScheduleIntersectionObserverNotification()
{ {
if (mIntersectionObservers.IsEmpty()) {
return;
}
nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this, nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this,
&nsDocument::NotifyIntersectionObservers); &nsDocument::NotifyIntersectionObservers);
NS_DispatchToCurrentThread(notification); NS_DispatchToCurrentThread(notification);
@ -12412,7 +12415,11 @@ nsDocument::ScheduleIntersectionObserverNotification()
void void
nsDocument::NotifyIntersectionObservers() nsDocument::NotifyIntersectionObservers()
{ {
nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers); nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count());
for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Get()->GetKey();
observers.AppendElement(observer);
}
for (const auto& observer : observers) { for (const auto& observer : observers) {
observer->Notify(); observer->Notify();
} }

View file

@ -1341,8 +1341,9 @@ protected:
// Array of observers // Array of observers
nsTObserverArray<nsIDocumentObserver*> mObservers; nsTObserverArray<nsIDocumentObserver*> mObservers;
// Array of intersection observers // Hashtable of intersection observers
nsTArray<RefPtr<mozilla::dom::DOMIntersectionObserver>> mIntersectionObservers; nsTHashtable<nsPtrHashKey<mozilla::dom::DOMIntersectionObserver>>
mIntersectionObservers;
// Tracker for animations that are waiting to start. // Tracker for animations that are waiting to start.
// nullptr until GetOrCreatePendingAnimationTracker is called. // nullptr until GetOrCreatePendingAnimationTracker is called.