зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d4830adc3d
Коммит
ef4655be32
|
@ -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,10 +353,14 @@ 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());
|
||||
}
|
||||
NotifyAnimated(aFrame, aProperty);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -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
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче