Rewrite IntersectionObserver list handling to be more robust.

Tag #935.
This commit is contained in:
wolfbeast 2019-01-18 19:09:30 +01:00 committed by Roy Tam
commit dc2cf8544d
3 changed files with 40 additions and 8 deletions

View file

@ -162,6 +162,11 @@ DOMIntersectionObserver::Observe(Element& aTarget)
void
DOMIntersectionObserver::Unobserve(Element& aTarget)
{
if (!mObservationTargets.Contains(&aTarget)) {
// You're not on the list, buddy!
return;
}
if (mObservationTargets.Length() == 1) {
Disconnect();
return;
@ -188,7 +193,7 @@ DOMIntersectionObserver::Connect()
}
mConnected = true;
if(mDocument) {
if (mDocument) {
mDocument->AddIntersectionObserver(this);
}
}
@ -293,12 +298,25 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) {
presContext = rootFrame->PresContext()->GetParentPresContext();
rootFrame = presContext->PresShell()->GetRootScrollFrame();
// Walk up the tree
presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
}
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
rootRect = scrollFrame->GetScrollPortRect();
// If we end up with a null root frame for some reason, we'll proceed
// with an empty root intersection rect.
if (scrollFrame) {
rootRect = scrollFrame->GetScrollPortRect();
}
}
}
}

View file

@ -109,7 +109,9 @@ protected:
class DOMIntersectionObserver final : public nsISupports,
public nsWrapperCache
{
virtual ~DOMIntersectionObserver() { }
virtual ~DOMIntersectionObserver() {
Disconnect();
}
public:
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,

View file

@ -12313,6 +12313,10 @@ nsDocument::RemoveIntersectionObserver(DOMIntersectionObserver* aObserver)
void
nsDocument::UpdateIntersectionObservations()
{
if (mIntersectionObservers.IsEmpty()) {
return;
}
DOMHighResTimeStamp time = 0;
if (nsPIDOMWindowInner* window = GetInnerWindow()) {
Performance* perf = window->GetPerformance();
@ -12320,9 +12324,15 @@ nsDocument::UpdateIntersectionObservations()
time = perf->Now();
}
}
nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count());
for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Get()->GetKey();
observer->Update(this, time);
observers.AppendElement(observer);
}
for (const auto& observer : observers) {
if (observer) {
observer->Update(this, time);
}
}
}
@ -12335,7 +12345,7 @@ nsDocument::ScheduleIntersectionObserverNotification()
nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this,
&nsDocument::NotifyIntersectionObservers);
NS_DispatchToCurrentThread(notification);
NS_DispatchToCurrentThread(notification.forget());
}
void
@ -12347,7 +12357,9 @@ nsDocument::NotifyIntersectionObservers()
observers.AppendElement(observer);
}
for (const auto& observer : observers) {
observer->Notify();
if (observer) {
observer->Notify();
}
}
}