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 void
DOMIntersectionObserver::Unobserve(Element& aTarget) DOMIntersectionObserver::Unobserve(Element& aTarget)
{ {
if (!mObservationTargets.Contains(&aTarget)) {
// You're not on the list, buddy!
return;
}
if (mObservationTargets.Length() == 1) { if (mObservationTargets.Length() == 1) {
Disconnect(); Disconnect();
return; return;
@ -188,7 +193,7 @@ DOMIntersectionObserver::Connect()
} }
mConnected = true; mConnected = true;
if(mDocument) { if (mDocument) {
mDocument->AddIntersectionObserver(this); mDocument->AddIntersectionObserver(this);
} }
} }
@ -293,15 +298,28 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
if (rootFrame) { if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext(); nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) { while (!presContext->IsRootContentDocument()) {
presContext = rootFrame->PresContext()->GetParentPresContext(); // Walk up the tree
rootFrame = presContext->PresShell()->GetRootScrollFrame(); presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
} }
root = rootFrame->GetContent()->AsElement(); root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame); nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
// 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(); rootRect = scrollFrame->GetScrollPortRect();
} }
} }
} }
}
nsMargin rootMargin; nsMargin rootMargin;
NS_FOR_CSS_SIDES(side) { NS_FOR_CSS_SIDES(side) {

View file

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

View file

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