Bug 1209970 - Fire scroll events early in the refresh tick. r=mats

With APZ we want to be firing scroll events to content more consistently, so
we tie them to the refresh driver tick rather than firing them on paint or
haphazardly on the next spin of the event loop.

Patch by Markus Stange, test fixes by Kartikaya Gupta
This commit is contained in:
Markus Stange 2015-12-17 17:19:30 -05:00
parent c54c0c2c3b
commit b5fd872e8d
5 changed files with 32 additions and 17 deletions

View File

@ -16,6 +16,8 @@ const SCROLL2_X = Math.round(300 * (1 + Math.random()));
const SCROLL2_Y = Math.round(400 * (1 + Math.random()));
const SCROLL2_STR = SCROLL2_X + "," + SCROLL2_Y;
requestLongerTimeout(2);
/**
* This test ensures that we properly serialize and restore scroll positions
* for an average page without any frames.

View File

@ -4225,18 +4225,28 @@ void ScrollFrameHelper::CurPosAttributeChanged(nsIContent* aContent)
/* ============= Scroll events ========== */
NS_IMETHODIMP
ScrollFrameHelper::ScrollEvent::Run()
ScrollFrameHelper::ScrollEvent::ScrollEvent(ScrollFrameHelper* aHelper)
: mHelper(aHelper)
{
if (mHelper)
mHelper->FireScrollEvent();
return NS_OK;
mHelper->mOuter->PresContext()->RefreshDriver()->AddRefreshObserver(this, Flush_Style);
}
ScrollFrameHelper::ScrollEvent::~ScrollEvent()
{
mHelper->mOuter->PresContext()->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
}
void
ScrollFrameHelper::ScrollEvent::WillRefresh(mozilla::TimeStamp aTime)
{
mHelper->FireScrollEvent();
}
void
ScrollFrameHelper::FireScrollEvent()
{
mScrollEvent.Forget();
MOZ_ASSERT(mScrollEvent);
mScrollEvent = nullptr;
ActiveLayerTracker::SetCurrentScrollHandlerFrame(mOuter);
WidgetGUIEvent event(true, eScroll, nullptr);
@ -4263,14 +4273,11 @@ ScrollFrameHelper::FireScrollEvent()
void
ScrollFrameHelper::PostScrollEvent()
{
if (mScrollEvent.IsPending())
if (mScrollEvent)
return;
nsRootPresContext* rpc = mOuter->PresContext()->GetRootPresContext();
if (!rpc)
return;
// The ScrollEvent constructor registers itself with the refresh driver.
mScrollEvent = new ScrollEvent(this);
rpc->AddWillPaintObserver(mScrollEvent.get());
}
NS_IMETHODIMP

View File

@ -19,6 +19,7 @@
#include "nsIReflowCallback.h"
#include "nsBoxLayoutState.h"
#include "nsQueryFrame.h"
#include "nsRefreshDriver.h"
#include "nsExpirationTracker.h"
#include "TextOverflow.h"
#include "ScrollVelocityQueue.h"
@ -101,11 +102,13 @@ public:
bool IsSmoothScrollingEnabled();
class ScrollEvent : public nsRunnable {
class ScrollEvent : public nsARefreshObserver {
public:
NS_DECL_NSIRUNNABLE
explicit ScrollEvent(ScrollFrameHelper *helper) : mHelper(helper) {}
void Revoke() { mHelper = nullptr; }
NS_INLINE_DECL_REFCOUNTING(ScrollEvent, override)
explicit ScrollEvent(ScrollFrameHelper *helper);
void WillRefresh(mozilla::TimeStamp aTime) override;
protected:
virtual ~ScrollEvent();
private:
ScrollFrameHelper *mHelper;
};
@ -417,7 +420,7 @@ public:
nsCOMPtr<nsIContent> mScrollCornerContent;
nsCOMPtr<nsIContent> mResizerContent;
nsRevocableEventPtr<ScrollEvent> mScrollEvent;
RefPtr<ScrollEvent> mScrollEvent;
nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent;
nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent;
nsIFrame* mHScrollbarBox;

View File

@ -526,8 +526,10 @@ function sendWheelAndPaint(aTarget, aOffsetX, aOffsetY, aEvent, aCallback, aWind
setTimeout(function() {
utils.advanceTimeAndRefresh(1000);
if (!aCallback)
if (!aCallback) {
utils.advanceTimeAndRefresh(0);
return;
}
var waitForPaints = function () {
SpecialPowers.Services.obs.removeObserver(waitForPaints, "apz-repaints-flushed", false);

View File

@ -1034,6 +1034,7 @@ function initElements()
resetScrollPosition(gSubView1);
resetScrollPosition(gSubView2);
resetScrollPosition(gSubView3);
_getDOMWindowUtils(window).advanceTimeAndRefresh(0);
runNextTestStep();
}