diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index e7d3899168ca..e211042091b4 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -425,6 +425,8 @@ AddAnimationsAndTransitionsToLayer(Layer* aLayer, nsDisplayListBuilder* aBuilder AddAnimationsForProperty(frame, aProperty, &anim, aLayer, data); + + pt->mIsRunningOnCompositor = true; } aLayer->SetAnimationGeneration(et->mAnimationGeneration); } diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 9ba8d9dc0977..2a4cdc4e45c8 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -990,8 +990,8 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) nsTArray events; TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); bool didThrottle = false; - // Trim transitions that have completed, and post restyle events for - // frames that are still transitioning. + // Trim transitions that have completed, post restyle events for frames that + // are still transitioning, and start transitions with delays. { PRCList *next = PR_LIST_HEAD(&mElementData); while (next != &mElementData) { @@ -1010,7 +1010,7 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) uint32_t i = et->mPropertyTransitions.Length(); NS_ABORT_IF_FALSE(i != 0, "empty transitions list?"); - bool transitionEnded = false; + bool transitionStartedOrEnded = false; do { --i; ElementPropertyTransition &pt = et->mPropertyTransitions[i]; @@ -1046,7 +1046,13 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) // from the almost-completed value to the final value. pt.SetRemovedSentinel(); et->UpdateAnimationGeneration(mPresContext); - transitionEnded = true; + transitionStartedOrEnded = true; + } else if (pt.mStartTime <= now && canThrottleTick && + !pt.mIsRunningOnCompositor) { + // Start a transition with a delay where we should start the + // transition proper. + et->UpdateAnimationGeneration(mPresContext); + transitionStartedOrEnded = true; } } while (i != 0); @@ -1056,7 +1062,7 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) et->mElementProperty == nsGkAtoms::transitionsOfBeforeProperty || et->mElementProperty == nsGkAtoms::transitionsOfAfterProperty, "Unexpected element property; might restyle too much"); - if (!canThrottleTick || transitionEnded) { + if (!canThrottleTick || transitionStartedOrEnded) { nsRestyleHint hint = et->mElementProperty == nsGkAtoms::transitionsProperty ? eRestyle_Self : eRestyle_Subtree; mPresContext->PresShell()->RestyleForAnimation(et->mElement, hint); diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 9ec9636157f4..05ee51baa54c 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -24,7 +24,9 @@ struct ElementDependentRuleProcessorData; struct ElementPropertyTransition { - ElementPropertyTransition() {} + ElementPropertyTransition() + : mIsRunningOnCompositor(false) + {} nsCSSProperty mProperty; nsStyleAnimation::Value mStartValue, mEndValue; @@ -50,6 +52,10 @@ struct ElementPropertyTransition // in again when the transition is back to 2px, the mReversePortion // for the third transition (from 0px/2px to 10px) will be 0.8. double mReversePortion; + // true when the transition is running on the compositor. In particular, + // mIsRunningOnCompositor will be false if the transition has a delay and we + // are not yet at mStartTime, so there is no animation on the layer. + bool mIsRunningOnCompositor; // Compute the portion of the *value* space that we should be through // at the given time. (The input to the transition timing function @@ -174,24 +180,24 @@ public: void FlushTransitions(FlushFlags aFlags); - // Performs a 'mini-flush' to make styles from throttled transitions - // up-to-date prior to processing an unrelated style change, so that - // any transitions triggered by that style change produce correct - // results. - // - // In more detail: when we're able to run animations on the - // compositor, we sometimes "throttle" these animations by skipping - // updating style data on the main thread. However, whenever we - // process a normal (non-animation) style change, any changes in - // computed style on elements that have transition-* properties set - // may need to trigger new transitions; this process requires knowing - // both the old and new values of the property. To do this correctly, - // we need to have an up-to-date *old* value of the property on the - // primary frame. So the purpose of the mini-flush is to update the - // style for all throttled transitions and animations to the current - // animation state without making any other updates, so that when we - // process the queued style updates we'll have correct old data to - // compare against. When we do this, we don't bother touching frames + // Performs a 'mini-flush' to make styles from throttled transitions + // up-to-date prior to processing an unrelated style change, so that + // any transitions triggered by that style change produce correct + // results. + // + // In more detail: when we're able to run animations on the + // compositor, we sometimes "throttle" these animations by skipping + // updating style data on the main thread. However, whenever we + // process a normal (non-animation) style change, any changes in + // computed style on elements that have transition-* properties set + // may need to trigger new transitions; this process requires knowing + // both the old and new values of the property. To do this correctly, + // we need to have an up-to-date *old* value of the property on the + // primary frame. So the purpose of the mini-flush is to update the + // style for all throttled transitions and animations to the current + // animation state without making any other updates, so that when we + // process the queued style updates we'll have correct old data to + // compare against. When we do this, we don't bother touching frames // other than primary frames. void UpdateAllThrottledStyles();