diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 3d46090ac1bd..263dadc12b12 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2107,6 +2107,9 @@ ScrollFrameHelper::~ScrollFrameHelper() if (mScrollEvent) { mScrollEvent->Revoke(); } + if (mScrollEndEvent) { + mScrollEndEvent->Revoke(); + } } /* @@ -2186,7 +2189,7 @@ ScrollFrameHelper::CompleteAsyncScroll(const nsRect &aRange, nsAtom* aOrigin) // We are done scrolling, set our destination to wherever we actually ended // up scrolling to. mDestination = GetScrollPosition(); - FireScrollEndEvent(); + PostScrollEndEvent(); } bool @@ -4422,10 +4425,25 @@ ScrollFrameHelper::FireScrollPortEvent() mOuter->PresContext(), &event); } +void +ScrollFrameHelper::PostScrollEndEvent() +{ + if (mScrollEndEvent) { + return; + } + + // The ScrollEndEvent constructor registers itself with the refresh driver. + mScrollEndEvent = new ScrollEndEvent(this); +} + void ScrollFrameHelper::FireScrollEndEvent() { MOZ_ASSERT(mOuter->GetContent()); + MOZ_ASSERT(mScrollEndEvent); + mScrollEndEvent->Revoke(); + mScrollEndEvent = nullptr; + nsContentUtils::DispatchEventOnlyToChrome(mOuter->GetContent()->OwnerDoc(), mOuter->GetContent(), NS_LITERAL_STRING("scrollend"), @@ -4821,6 +4839,22 @@ ScrollFrameHelper::ScrollEvent::Run() return NS_OK; } +ScrollFrameHelper::ScrollEndEvent::ScrollEndEvent(ScrollFrameHelper* aHelper) + : Runnable("ScrollFrameHelper::ScrollEndEvent") + , mHelper(aHelper) +{ + mHelper->mOuter->PresContext()->RefreshDriver()->PostScrollEvent(this); +} + +NS_IMETHODIMP +ScrollFrameHelper::ScrollEndEvent::Run() +{ + if (mHelper) { + mHelper->FireScrollEndEvent(); + } + return NS_OK; +} + void ScrollFrameHelper::FireScrollEvent() { diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 3af6e77a8727..37d5cc889128 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -69,6 +69,7 @@ public: nsTArray& aElements); void AppendAnonymousContentTo(nsTArray& aElements, uint32_t aFilter); nsresult FireScrollPortEvent(); + void PostScrollEndEvent(); void FireScrollEndEvent(); void PostOverflowEvent(); using PostDestroyData = nsIFrame::PostDestroyData; @@ -131,6 +132,15 @@ public: ScrollFrameHelper* mHelper; }; + class ScrollEndEvent : public Runnable { + public: + NS_DECL_NSIRUNNABLE + explicit ScrollEndEvent(ScrollFrameHelper* aHelper); + void Revoke() { mHelper = nullptr; } + private: + ScrollFrameHelper* mHelper; + }; + class AsyncScrollPortEvent : public Runnable { public: NS_DECL_NSIRUNNABLE @@ -402,7 +412,7 @@ public: void SetTransformingByAPZ(bool aTransforming) { if (mTransformingByAPZ && !aTransforming) { - FireScrollEndEvent(); + PostScrollEndEvent(); } mTransformingByAPZ = aTransforming; if (!mozilla::css::TextOverflow::HasClippedOverflow(mOuter)) { @@ -495,6 +505,7 @@ public: nsCOMPtr mResizerContent; RefPtr mScrollEvent; + RefPtr mScrollEndEvent; nsRevocableEventPtr mAsyncScrollPortEvent; nsRevocableEventPtr mScrolledAreaEvent; nsIFrame* mHScrollbarBox;