Bug 1279403 - Part 1: Force to apply corresponding change hint if there is no corresponding layer to generate display item even if animation's segment is transform:none or 100% opacity. r=birtles

To create a stacking context for animations on transform:none segment,
we need to set NS_FRAME_MAY_BE_TRANSFORMED.  The fix is comming in part 2.

Note that in case of animations which has properties preventing running on
the compositor, e.g., width or height, corresponding layer is not created
at all, but even in such cases, we normally set valid change hint for such
animations in each tick, i.e. restyles in each tick. For example:

div.animate([{ opacity: 1, width: '100px' }, { opacity: 0, width: '200px' }], 1000);

This animation causes restyles in every ticks without this patch, this patch
does not affect such animations at all. The only animations which will be
affected by this patch are animations which has opacity/transform but
did not have those properies. e.g,  setting transform by setKeyframes or
changing target element from other target which prevents running on the
compositor, etc.

MozReview-Commit-ID: 78fYqyX8uDX

--HG--
extra : rebase_source : c4a6ef244f26f3d808fd2c6a5f80c1a15478ae31
This commit is contained in:
Hiroyuki Ikezoe 2016-07-11 08:27:02 +09:00
Родитель ecdc48365b
Коммит 685a35fbc5
6 изменённых файлов: 148 добавлений и 0 удалений

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

@ -470,5 +470,50 @@ promise_test(function(t) {
}, 'animation with fill:backwards in delay phase is running on the ' +
' main-thread while it is in delay phase');
promise_test(function(t) {
var div = addDiv(t);
var animation = div.animate([{ opacity: 1, offset: 0 },
{ opacity: 1, offset: 0.99 },
{ opacity: 0, offset: 1 }], 100 * MS_PER_SEC);
var another = addDiv(t);
return animation.ready.then(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Opacity animation on a 100% opacity keyframe reports ' +
'that it is running on the compositor from the begining');
animation.effect.target = another;
return waitForFrame();
}).then(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Opacity animation on a 100% opacity keyframe keeps ' +
'running on the compositor after changing the target ' +
'element');
});
}, '100% opacity animations with keeps running on the ' +
'compositor after changing the target element');
promise_test(function(t) {
var div = addDiv(t);
var animation = div.animate({ color: ['red', 'black'] }, 100 * MS_PER_SEC);
return animation.ready.then(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Color animation reports that it is not running on the ' +
'compositor');
animation.effect.setKeyframes([{ opacity: 1, offset: 0 },
{ opacity: 1, offset: 0.99 },
{ opacity: 0, offset: 1 }]);
return waitForFrame();
}).then(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'100% opacity animation set by using setKeyframes reports ' +
'that it is running on the compositor');
});
}, '100% opacity animation set up by converting an existing animation with ' +
'cannot be run on the compositor, is running on the compositor');
</script>
</body>

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

@ -2754,6 +2754,24 @@ ElementRestyler::AddLayerChangesForAnimation()
}
hint |= layerInfo.mChangeHint;
}
// We consider it's the first paint for the frame if we have an animation
// for the property but have no layer.
// Note that in case of animations which has properties preventing running
// on the compositor, e.g., width or height, corresponding layer is not
// created at all, but even in such cases, we normally set valid change
// hint for such animations in each tick, i.e. restyles in each tick. As
// a result, we usually do restyles for such animations in every tick on
// the main-thread. The only animations which will be affected by this
// explicit change hint are animations that have opacity/transform but did
// not have those properies just before. e.g, setting transform by
// setKeyframes or changing target element from other target which prevents
// running on the compositor, etc.
if (!layer &&
nsLayoutUtils::HasRelevantAnimationOfProperty(mFrame,
layerInfo.mProperty)) {
hint |= layerInfo.mChangeHint;
}
}
if (hint) {
mChangeList->AppendChange(mFrame, mContent, hint);

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

@ -1,3 +1,5 @@
test-pref(dom.animations-api.core.enabled,true) == 1246046-1.html green-box.html
test-pref(dom.animations-api.core.enabled,true) == 1267937-1.html 1267937-ref.html
test-pref(dom.animations-api.core.enabled,true) == stacking-context-transform-none-animation-before-appending-element.html stacking-context-animation-ref.html
test-pref(dom.animations-api.core.enabled,true) == stacking-context-opacity-changing-keyframe.html stacking-context-animation-ref.html
test-pref(dom.animations-api.core.enabled,true) == stacking-context-opacity-changing-target.html stacking-context-animation-changing-target-ref.html

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

@ -0,0 +1,24 @@
<!DOCTYPE html>
<title>Reference of testcases for bug 1279403</title>
<style>
span {
height: 100px;
width: 100px;
background: green;
position: fixed;
top: 50px;
}
div {
height: 100px;
width: 100px;
background: blue;
}
#first {
}
#second {
position: fixed;
}
</style>
<span></span>
<div id="first"></div>
<div id="second"></div>

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

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html class="reftest-wait reftest-no-flush">
<title>Changing keyframes to opacity frames creates a stacking context</title>
<style>
span {
height: 100px;
width: 100px;
position: fixed;
background: green;
top: 50px;
}
#test {
width: 100px; height: 100px;
background: blue;
}
</style>
<span></span>
<div id="test"></div>
<script>
var anim = document.getElementById("test")
.animate({ }, { duration: 100000 });
anim.ready.then(function() {
anim.effect.setKeyframes({ opacity: [1, 1] });
requestAnimationFrame(function() {
document.documentElement.classList.remove("reftest-wait");
});
});
</script>

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

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html class="reftest-wait reftest-no-flush">
<title>
Opacity animation creates a stacking context when changing its target
</title>
<style>
span {
height: 100px;
width: 100px;
position: fixed;
background: green;
top: 50px;
}
div {
width: 100px; height: 100px;
background: blue;
}
</style>
<span></span>
<div id="test"></div>
<div id="another"></div>
<script>
var anim = document.getElementById("test")
.animate({ opacity: [1, 1] }, { duration: 100000 });
anim.ready.then(function() {
anim.effect.target = document.getElementById("another");
requestAnimationFrame(function() {
document.documentElement.classList.remove("reftest-wait");
});
});
</script>