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. // Previous scale due to the CSS transform property.
Maybe<gfxSize> mPreviousTransformScale; 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 // Number of restyle operations detected
uint8_t mRestyleCounts[ACTIVITY_COUNT]; uint8_t mRestyleCounts[ACTIVITY_COUNT];
bool mContentActive; bool mContentActive;
@ -109,12 +116,20 @@ public:
LayerActivityTracker() LayerActivityTracker()
: nsExpirationTracker<LayerActivity,4>(GENERATION_MS, : nsExpirationTracker<LayerActivity,4>(GENERATION_MS,
"LayerActivityTracker") "LayerActivityTracker")
, mDestroying(false)
{} {}
~LayerActivityTracker() { ~LayerActivityTracker() {
mDestroying = true;
AgeAllGenerations(); AgeAllGenerations();
} }
virtual void NotifyExpired(LayerActivity* aObject); virtual void NotifyExpired(LayerActivity* aObject);
public:
nsWeakFrame mCurrentScrollHandlerFrame;
private:
bool mDestroying;
}; };
static LayerActivityTracker* gLayerActivityTracker = nullptr; static LayerActivityTracker* gLayerActivityTracker = nullptr;
@ -133,6 +148,13 @@ NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DeleteValue<LayerActivity>)
void void
LayerActivityTracker::NotifyExpired(LayerActivity* aObject) 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); RemoveObject(aObject);
nsIFrame* f = aObject->mFrame; nsIFrame* f = aObject->mFrame;
@ -294,6 +316,27 @@ ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
mutationCount = 0xFF; 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 static bool
IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext) IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
{ {
@ -310,10 +353,14 @@ IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame, ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
nsCSSProperty aProperty) nsCSSProperty aProperty)
{ {
if (!IsPresContextInScriptAnimationCallback(aFrame->PresContext())) { if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
return; NotifyAnimated(aFrame, aProperty);
}
if (gLayerActivityTracker &&
gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) {
NotifyAnimatedFromScrollHandler(aFrame, aProperty,
gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
} }
NotifyAnimated(aFrame, aProperty);
} }
/* static */ bool /* static */ bool
@ -322,6 +369,29 @@ ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSProperty aProper
return IsStyleAnimated(nullptr, aFrame, aProperty); 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 /* static */ bool
ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder, ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsCSSProperty aProperty) nsIFrame* aFrame, nsCSSProperty aProperty)
@ -340,7 +410,11 @@ ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
LayerActivity* layerActivity = GetLayerActivity(aFrame); LayerActivity* layerActivity = GetLayerActivity(aFrame);
if (layerActivity) { 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; return true;
} }
} }
@ -458,6 +532,15 @@ ActiveLayerTracker::IsContentActive(nsIFrame* aFrame)
return layerActivity && layerActivity->mContentActive; return layerActivity && layerActivity->mContentActive;
} }
/* static */ void
ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame* aFrame)
{
if (!gLayerActivityTracker) {
gLayerActivityTracker = new LayerActivityTracker();
}
gLayerActivityTracker->mCurrentScrollHandlerFrame = aFrame;
}
/* static */ void /* static */ void
ActiveLayerTracker::Shutdown() ActiveLayerTracker::Shutdown()
{ {

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

@ -49,6 +49,12 @@ public:
* Any such marking will time out after a short period. * Any such marking will time out after a short period.
*/ */
static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty); 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 * Notify that a property in the inline style rule of aFrame's element
* has been modified. * has been modified.
@ -107,6 +113,13 @@ public:
* Return true if this frame's content is still marked as active. * Return true if this frame's content is still marked as active.
*/ */
static bool IsContentActive(nsIFrame* aFrame); 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 } // namespace mozilla

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

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

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

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