Bug 1201330 - Keep scroll handler induced layer activity active until the scroll frame becomes inactive. r=roc

--HG--
extra : commitid : K9ntCNQz1Fx
extra : rebase_source : ed8a567f22626d7074bbc58eb5e61baa251fe2c3
This commit is contained in:
Markus Stange 2015-10-30 16:28:53 +01:00
Родитель d4830adc3d
Коммит ef4655be32
4 изменённых файлов: 110 добавлений и 4 удалений

Просмотреть файл

@ -97,6 +97,13 @@ public:
// Previous scale due to the CSS transform property.
Maybe<gfxSize> mPreviousTransformScale;
// The scroll frame during for which we most recently received a call to
// NotifyAnimatedFromScrollHandler.
nsWeakFrame mAnimatingScrollHandlerFrame;
// The set of activities that were triggered during
// mAnimatingScrollHandlerFrame's scroll event handler.
EnumSet<ActivityIndex> mScrollHandlerInducedActivity;
// Number of restyle operations detected
uint8_t mRestyleCounts[ACTIVITY_COUNT];
bool mContentActive;
@ -109,12 +116,20 @@ public:
LayerActivityTracker()
: nsExpirationTracker<LayerActivity,4>(GENERATION_MS,
"LayerActivityTracker")
, mDestroying(false)
{}
~LayerActivityTracker() {
mDestroying = true;
AgeAllGenerations();
}
virtual void NotifyExpired(LayerActivity* aObject);
public:
nsWeakFrame mCurrentScrollHandlerFrame;
private:
bool mDestroying;
};
static LayerActivityTracker* gLayerActivityTracker = nullptr;
@ -133,6 +148,13 @@ NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DeleteValue<LayerActivity>)
void
LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
{
if (!mDestroying && aObject->mAnimatingScrollHandlerFrame.IsAlive()) {
// Reset the restyle counts, but let the layer activity survive.
PodArrayZero(aObject->mRestyleCounts);
MarkUsed(aObject);
return;
}
RemoveObject(aObject);
nsIFrame* f = aObject->mFrame;
@ -294,6 +316,27 @@ ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
mutationCount = 0xFF;
}
/* static */ void
ActiveLayerTracker::NotifyAnimatedFromScrollHandler(nsIFrame* aFrame, nsCSSProperty aProperty,
nsIFrame* aScrollFrame)
{
if (aFrame->PresContext() != aScrollFrame->PresContext()) {
// Don't allow cross-document dependencies.
return;
}
LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
LayerActivity::ActivityIndex activityIndex = LayerActivity::GetActivityIndexForProperty(aProperty);
if (layerActivity->mAnimatingScrollHandlerFrame.GetFrame() != aScrollFrame) {
// Discard any activity of a different scroll frame. We only track the
// most recent scroll handler induced activity.
layerActivity->mScrollHandlerInducedActivity.clear();
layerActivity->mAnimatingScrollHandlerFrame = aScrollFrame;
}
layerActivity->mScrollHandlerInducedActivity += activityIndex;
}
static bool
IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
{
@ -310,11 +353,15 @@ IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
nsCSSProperty aProperty)
{
if (!IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
return;
}
if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
NotifyAnimated(aFrame, aProperty);
}
if (gLayerActivityTracker &&
gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) {
NotifyAnimatedFromScrollHandler(aFrame, aProperty,
gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
}
}
/* static */ bool
ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
@ -322,6 +369,29 @@ ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSProperty aProper
return IsStyleAnimated(nullptr, aFrame, aProperty);
}
static bool
CheckScrollInducedActivity(LayerActivity* aLayerActivity,
LayerActivity::ActivityIndex aActivityIndex,
nsDisplayListBuilder* aBuilder)
{
if (!aLayerActivity->mScrollHandlerInducedActivity.contains(aActivityIndex) ||
!aLayerActivity->mAnimatingScrollHandlerFrame.IsAlive()) {
return false;
}
nsIScrollableFrame* scrollFrame =
do_QueryFrame(aLayerActivity->mAnimatingScrollHandlerFrame.GetFrame());
if (scrollFrame && (!aBuilder || scrollFrame->IsScrollingActive(aBuilder))) {
return true;
}
// The scroll frame has been destroyed or has become inactive. Clear it from
// the layer activity so that it can expire.
aLayerActivity->mAnimatingScrollHandlerFrame = nullptr;
aLayerActivity->mScrollHandlerInducedActivity.clear();
return false;
}
/* static */ bool
ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsCSSProperty aProperty)
@ -340,7 +410,11 @@ ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
LayerActivity* layerActivity = GetLayerActivity(aFrame);
if (layerActivity) {
if (layerActivity->RestyleCountForProperty(aProperty) >= 2) {
LayerActivity::ActivityIndex activityIndex = LayerActivity::GetActivityIndexForProperty(aProperty);
if (layerActivity->mRestyleCounts[activityIndex] >= 2) {
return true;
}
if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
return true;
}
}
@ -458,6 +532,15 @@ ActiveLayerTracker::IsContentActive(nsIFrame* aFrame)
return layerActivity && layerActivity->mContentActive;
}
/* static */ void
ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame* aFrame)
{
if (!gLayerActivityTracker) {
gLayerActivityTracker = new LayerActivityTracker();
}
gLayerActivityTracker->mCurrentScrollHandlerFrame = aFrame;
}
/* static */ void
ActiveLayerTracker::Shutdown()
{

Просмотреть файл

@ -49,6 +49,12 @@ public:
* Any such marking will time out after a short period.
*/
static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
/**
* Notify aFrame as being known to have an animation of aProperty through an
* inline style modification during aScrollFrame's scroll event handler.
*/
static void NotifyAnimatedFromScrollHandler(nsIFrame* aFrame, nsCSSProperty aProperty,
nsIFrame* aScrollFrame);
/**
* Notify that a property in the inline style rule of aFrame's element
* has been modified.
@ -107,6 +113,13 @@ public:
* Return true if this frame's content is still marked as active.
*/
static bool IsContentActive(nsIFrame* aFrame);
/**
* Called before and after a scroll event handler is executed, with the
* scrollframe or nullptr, respectively. This acts as a hint to treat
* inline style changes during the handler differently.
*/
static void SetCurrentScrollHandlerFrame(nsIFrame* aFrame);
};
} // namespace mozilla

Просмотреть файл

@ -4206,6 +4206,7 @@ ScrollFrameHelper::FireScrollEvent()
{
mScrollEvent.Forget();
ActiveLayerTracker::SetCurrentScrollHandlerFrame(mOuter);
WidgetGUIEvent event(true, eScroll, nullptr);
nsEventStatus status = nsEventStatus_eIgnore;
nsIContent* content = mOuter->GetContent();
@ -4223,6 +4224,7 @@ ScrollFrameHelper::FireScrollEvent()
event.mFlags.mBubbles = false;
EventDispatcher::Dispatch(content, prescontext, &event, nullptr, &status);
}
ActiveLayerTracker::SetCurrentScrollHandlerFrame(nullptr);
}
void

Просмотреть файл

@ -127,6 +127,14 @@ public:
return result;
}
/**
* Clear
*/
void clear()
{
mBitField = 0;
}
/**
* Intersection
*/