Bug 1322291 - Part 2: Make sure that the base style is set even if additive or accumulates animations are in the delay phase. r=birtles

Before this patch we skipped KeyframeEffectReadOnly::ComposeStyle() for
animations that are not in effect.
After this patch we call KeyframeEffectReadOnly::ComposeStyle() even if the
animation is not in-effect state in order to prepare the base style for
properties that can be run on the compositor because the in-effect animation
will be sent to the compositor and might be composed onto the base style on the
compositor after the animation gets out of its delay phase.

MozReview-Commit-ID: FuAZv4jqVMJ

--HG--
extra : rebase_source : 9ef2f078e5ee18735fb8cd3086f20774fe8b1fd0
This commit is contained in:
Hiroyuki Ikezoe 2016-12-21 13:52:21 +09:00
Родитель bb044df0ec
Коммит 603fea3c36
6 изменённых файлов: 105 добавлений и 4 удалений

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

@ -923,10 +923,6 @@ Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
return;
}
if (!IsInEffect()) {
return;
}
// In order to prevent flicker, there are a few cases where we want to use
// a different time for rendering that would otherwise be returned by
// GetCurrentTime. These are:

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

@ -387,6 +387,49 @@ KeyframeEffectReadOnly::CompositeValue(
aCompositeOperation);
}
void
KeyframeEffectReadOnly::EnsureBaseStylesForCompositor(
const nsCSSPropertyIDSet& aPropertiesToSkip)
{
if (!mTarget) {
return;
}
RefPtr<nsStyleContext> styleContext;
for (const AnimationProperty& property : mProperties) {
if (!nsCSSProps::PropHasFlags(property.mProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
continue;
}
if (aPropertiesToSkip.HasProperty(property.mProperty)) {
continue;
}
for (const AnimationPropertySegment& segment : property.mSegments) {
if (segment.mFromComposite == dom::CompositeOperation::Replace &&
segment.mToComposite == dom::CompositeOperation::Replace) {
continue;
}
if (!styleContext) {
styleContext = GetTargetStyleContext();
}
MOZ_RELEASE_ASSERT(styleContext);
Unused << EffectCompositor::GetBaseStyle(property.mProperty,
styleContext,
*mTarget->mElement,
mTarget->mPseudoType);
// Make this property as needing a base style so that we send the (now
// cached) base style to the compositor.
SetNeedsBaseStyle(property.mProperty);
break;
}
}
}
void
KeyframeEffectReadOnly::ComposeStyle(
RefPtr<AnimValuesStyleRule>& aStyleRule,
@ -406,6 +449,19 @@ KeyframeEffectReadOnly::ComposeStyle(
// If the progress is null, we don't have fill data for the current
// time so we shouldn't animate.
if (computedTiming.mProgress.IsNull()) {
// If we are not in-effect, this effect might still be sent to the
// compositor and later become in-effect (e.g. if it is in the delay phase).
// In that case, we might need the base style in order to perform
// additive/accumulative animation on the compositor.
// In case of properties that can be run on the compositor, we need the base
// styles for such properties because those animation will be sent to
// compositor while they are in delay phase so that we can composite this
// animation on the compositor once the animation is out of the delay phase
// on the compositor.
if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Before) {
EnsureBaseStylesForCompositor(aPropertiesToSkip);
}
return;
}

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

@ -427,6 +427,11 @@ protected:
// compositor.
void SetNeedsBaseStyle(nsCSSPropertyID aProperty);
// Ensure the base styles is available for any properties that can be run on
// the compositor and which are not includes in |aPropertiesToSkip|.
void EnsureBaseStylesForCompositor(
const nsCSSPropertyIDSet& aPropertiesToSkip);
Maybe<OwningAnimationTarget> mTarget;
KeyframeEffectParams mEffectOptions;

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

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="reftest-wait">
<script>
document.addEventListener("DOMContentLoaded", boom);
function boom(){
let o1 = (function(){
let e=document.createElement("frameset");
document.documentElement.appendChild(e);
return e;
})();
let a1 = o1.animate({ "transform": "rotate3d(22,73,26,374grad)" },
{ duration: 10, delay: 100 });
// We need to wait the end of the delay to ensure that the animation is
// composited on the compositor, but there is no event for script animation
// that fires after the delay phase finished. So we wait for finished promise
// instead.
a1.finished.then(function() {
document.documentElement.className = "";
});
}
</script>
</body>
</html>

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

@ -13,5 +13,6 @@ pref(dom.animations-api.core.enabled,true) load 1277272-1.html
pref(dom.animations-api.core.enabled,true) load 1290535-1.html
pref(dom.animations-api.core.enabled,true) load 1304886-1.html
pref(dom.animations-api.core.enabled,true) load 1322382-1.html
pref(dom.animations-api.core.enabled,true) load 1322291-1.html
pref(dom.animations-api.core.enabled,true) load 1323114-1.html
pref(dom.animations-api.core.enabled,true) load 1323114-2.html

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

@ -471,6 +471,25 @@ promise_test(t => {
'composed onto a underlying animation with fill:forwards during positive ' +
'endDelay');
promise_test(t => {
useTestRefreshMode(t);
var div = addDiv(t, { style: 'transform: translateX(100px)' });
div.animate({ transform: 'translateX(200px)' },
{ duration: 100 * MS_PER_SEC, delay: 50 * MS_PER_SEC });
return waitForPaintsFlushed().then(() => {
SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(100 * MS_PER_SEC);
var transform =
SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 150, 0)',
'Transform value for animation with positive delay should be composed ' +
'onto the base style');
});
}, 'Transform value for animation with no keyframe at offset 0 and with ' +
'positive delay');
done();
</script>
</body>