blob: f2ffbcea3d577552d04956a26e50d01edf250c2d [file] [log] [blame]
<!DOCTYPE html>
<body>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<style>
div {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: black;
}
</style>
<script>
const createDiv = test => {
const div = document.createElement("div");
test.add_cleanup(() => div.remove());
return document.body.appendChild(div);
}
const animationReadyToAnimateAccelerated = async animation => {
await animation.ready;
await new Promise(requestAnimationFrame);
await new Promise(requestAnimationFrame);
await new Promise(requestAnimationFrame);
}
const duration = 1000 * 1000; // 1000s.
promise_test(async test => {
const target = createDiv(test);
const animation = target.animate(
{ transform: "translateX(100px)" },
{ composite: "add", duration }
);
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Setting 'composite' to 'add' should prevent acceleration");
promise_test(async test => {
const target = createDiv(test);
const animation = target.animate(
[{ offset: 1, composite: "add", transform: "translateX(100px)" }],
{ duration }
);
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Setting 'composite' to 'add' on a keyframe should prevent acceleration");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
// First add a replace animation that could be accelerated by itself.
animations.push(target.animate(
{ transform: "translateX(100px)" },
{ duration }
));
// Then, add a composing animation that prevents the whole stack to be accelerated.
animations.push(target.animate(
{ transform: "translateY(100px)" },
{ composite: "add", duration }
));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Setting 'composite' to 'add' on an animation further up the stack should prevent lower animations in the stack from being accelerated");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
// First add a composing animation that cannot be run accelerated on its own.
animations.push(target.animate(
{ transform: "translateX(100px)" },
{ composite: "add", duration }
));
// Then, add a replace animation that should be accelerated since it completely obliterates
// the previous composing animation.
animations.push(target.animate(
{ transform: ["none", "translateY(100px)"] },
{ duration }
));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Setting 'composite' to 'add' on an animation lower down the stack should allow replace animations further up the stack to be accelerated");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
// First add a composing animation that cannot be run accelerated on its own.
animations.push(target.animate(
{ transform: "translateX(100px)" },
{ composite: "add", duration }
));
// Then, add a replace animation that should be accelerated except it can't because
// it contains an implicit keyframe derived from the output of the previous animation.
animations.push(target.animate(
{ transform: "translateX(100px)" },
{ duration }
));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Setting 'composite' to 'add' on an animation lower down the stack should prevent replace animations with an implicity keyframe further up the stack to be accelerated");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
// First add a composing animation that cannot be run accelerated on its own.
animations.push(target.animate(
{ marginLeft: "100px" },
{ composite: "add", duration }
));
// Then, add a replace animation with an implicit keyframes that can be accelerated
// since there are no other composing animations below it in the stack that target
// that property.
animations.push(target.animate(
{ transform: "translateX(100px)" },
{ duration }
));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
}, "Setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated should allow replace animations with implicit keyframes further up the stack to be accelerated");
// The following tests check the dynamic interruption and/or start of accelerated animations
// after changes made to other effects in the stack.
promise_test(async test => {
const target = createDiv(test);
const animation = target.animate({ transform: "translateX(100px)" }, duration);
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
// Setting the effect composition to "add" means that the animation should
// no longer be accelerated.
animation.effect.composite = "add";
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
// Resetting the effect composition to "replace" means that the animation
// should be accelerated again.
animation.effect.composite = "replace";
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
}, "Dynamically setting 'composite' on an effect should toggle acceleration");
promise_test(async test => {
const keyframes = composite => [{ offset: 1, composite, transform: "translateX(100px)" }];
const target = createDiv(test);
const animation = target.animate(keyframes("replace"), duration);
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
// Setting the keyframe composition to "add" means that the animation should
// no longer be accelerated.
animation.effect.setKeyframes(keyframes("add"));
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
// Resetting the keyframe composition to "replace" means that the animation
// should be accelerated again.
animation.effect.setKeyframes(keyframes("replace"));
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
}, "Dynamically setting 'composite' on a keyframe should toggle acceleration");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
animations.push(target.animate({ transform: "translateX(100px)" }, duration));
animations.push(target.animate({ transform: "translateY(100px)" }, duration));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2, "Step 1");
// Make the second animation a composing animation. This will prevent the first animation
// from running accelerated as well.
animations[1].effect.composite = "add";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0, "Step 2");
// Reset to the original state.
animations[1].effect.composite = "replace";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2, "Step 3");
}, "Dynamically setting 'composite' to 'add' on an animation further up the stack should toggle acceleration on lower animations in the stack");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
animations.push(target.animate({ transform: "translateX(100px)" }, duration));
animations.push(target.animate({ transform: ["none", "translateY(100px)"] }, duration));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2);
// Make the first animation a composing animation. This will prevent the other animation from running accelerated.
animations[0].effect.composite = "add";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
// Reset to the original state.
animations[0].effect.composite = "replace";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2);
}, "Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration but always allow replace animations further up the stack to be accelerated");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
animations.push(target.animate({ transform: "translateX(100px)" }, duration));
animations.push(target.animate({ transform: "translateX(100px)" }, duration));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2);
// Make the first animation a composing animation. This will prevent both animations
// from running accelerated since the second animation uses the first animation as
// input due to using an implicit 0% keyframe.
animations[0].effect.composite = "add";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
// Reset to the original state.
animations[0].effect.composite = "replace";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 2);
}, "Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration on replace animations with an implicity keyframe further up the stack");
promise_test(async test => {
const target = createDiv(test);
const animations = [];
animations.push(target.animate({ marginLeft: "100px" }, duration));
animations.push(target.animate({ transform: "translateX(100px)" }, duration));
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
// Make the first animation a composing animation. This should not prevent the other animation from running accelerated.
animations[0].effect.composite = "add";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
// Reset to the original state.
animations[0].effect.composite = "replace";
await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation)));
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
}, "Dynamically setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated shouldn't prevent acceleration of animations with implicit keyframes further up the stack to be accelerated");
promise_test(async test => {
const target = createDiv(test);
const animation = target.animate({ transform: "translateX(100px)" }, duration);
await animationReadyToAnimateAccelerated(animation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);
const composingAnimation = target.animate(
{ transform: "translateY(100px)" },
{ composite: "add", duration }
);
await animationReadyToAnimateAccelerated(composingAnimation);
assert_equals(internals.acceleratedAnimationsForElement(target).length, 0);
}, "Adding a composing effect on top of an existing replace effect should prevent both effects from running accelerated");
</script>
</body>