Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DOMWindowUtils test with animation</title>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script src="/tests/dom/animation/test/testcommon.js"></script>
</head>
<body>
<script type="application/javascript">
const SimpleTest = window.opener.SimpleTest;
const utils = SpecialPowers.getDOMWindowUtils(window);
const next = window.opener.next;
const is = window.opener.is;
const ok = window.opener.ok;
function addStyle(rules) {
const extraStyle = document.createElement("style");
document.head.appendChild(extraStyle);
rules.forEach(rule => {
extraStyle.sheet.insertRule(rule, extraStyle.sheet.cssRules.length);
});
}
function deleteStyle() {
document.head.querySelector("style").remove();
}
let propertyIndex = 0;
function test_getUnanimatedComputedStyle() {
const name = `--property-${++propertyIndex}`;
CSS.registerProperty({
name,
syntax: "<length>",
initialValue: "2px",
inherits: false,
});
[
{
property: "opacity",
keyframes: [1, 0],
expectedInitialStyle: "1",
expectedDuringTransitionStyle: "0",
isDiscrete: false,
},
{
property: name,
keyframes: ["1px", "10px"],
expectedInitialStyle: "2px",
expectedDuringTransitionStyle: "2px",
isDiscrete: true,
},
{
property: "clear",
keyframes: ["left", "inline-end"],
expectedInitialStyle: "none",
expectedDuringTransitionStyle: "inline-end",
isDiscrete: true,
},
].forEach(testcase => {
const { property, keyframes, expectedInitialStyle,
expectedDuringTransitionStyle, isDiscrete } = testcase;
[null, "unset", "initial", "inherit"].forEach(initialStyle => {
const scriptAnimation = target => {
return target.animate({ [property]: keyframes }, 1000);
}
checkUnanimatedComputedStyle(property, initialStyle, null,
expectedInitialStyle, expectedInitialStyle,
scriptAnimation, "script animation");
const cssAnimationStyle = `@keyframes cssanimation {`
+ ` from { ${property}: ${ keyframes[0] }; }`
+ ` to { ${property}: ${ keyframes[1] }; } }`;
addStyle([cssAnimationStyle]);
const cssAnimation = target => {
target.style.animation = "cssanimation 1s";
return target.getAnimations()[0];
}
checkUnanimatedComputedStyle(property, initialStyle, null,
expectedInitialStyle, expectedInitialStyle,
cssAnimation, "CSS Animations");
deleteStyle();
// We don't support discrete animations for CSS Transitions yet.
if (!isDiscrete) {
const cssTransition = target => {
target.style[property] = keyframes[0];
target.style.transition =
`${ property } 1s`;
window.getComputedStyle(target)[property];
target.style[property] = keyframes[1];
return target.getAnimations()[0];
}
checkUnanimatedComputedStyle(property, initialStyle, null,
expectedInitialStyle,
expectedDuringTransitionStyle,
cssTransition, "CSS Transitions");
}
addStyle([cssAnimationStyle,
".pseudo::before { content: '' }",
".animation::before { animation: cssanimation 1s }"]);
const pseudoAnimation = target => {
target.classList.add("animation");
return target.getAnimations({ subtree: true })[0];
}
checkUnanimatedComputedStyle(property, initialStyle, "::before",
expectedInitialStyle, expectedInitialStyle,
pseudoAnimation, "Animation at pseudo");
deleteStyle();
});
});
const div = document.createElement("div");
document.body.appendChild(div);
SimpleTest.doesThrow(
() => utils.getUnanimatedComputedStyle(div, null, "background", utils.FLUSH_NONE),
"NS_ERROR_INVALID_ARG",
"Shorthand property should throw");
SimpleTest.doesThrow(
() => utils.getUnanimatedComputedStyle(div, null, "invalid", utils.FLUSH_NONE),
"NS_ERROR_INVALID_ARG",
"Invalid property should throw");
SimpleTest.doesThrow(
() => utils.getUnanimatedComputedStyle(null, null, "opacity", utils.FLUSH_NONE),
"NS_ERROR_INVALID_ARG",
"Null element should throw");
SimpleTest.doesThrow(
() => utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_LAYOUT),
"NS_ERROR_INVALID_ARG",
"FLUSH_LAYOUT option should throw");
SimpleTest.doesThrow(
() => utils.getUnanimatedComputedStyle(div, "::before", "opacity", utils.FLUSH_NONE),
"NS_ERROR_FAILURE",
"Non-existent pseudo should throw");
// Flush styles since getUnanimatedComputedStyle flushes pending styles even
// with FLUSH_NONE option if the element hasn't yet styled.
getComputedStyle(div).opacity;
div.style.opacity = "0";
is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_NONE),
"1",
"getUnanimatedComputedStyle with FLUSH_NONE should not flush pending styles");
is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_STYLE),
"0",
"getUnanimatedComputedStyle with FLUSH_STYLE should flush pending styles");
div.remove();
test_needsFlushWithThrottledAnimations();
}
function checkUnanimatedComputedStyle(property, initialStyle, pseudoType,
expectedBeforeAnimation,
expectedDuringAnimation,
animate, animationType) {
const div = document.createElement("div");
document.body.appendChild(div);
if (initialStyle) {
div.style[property] = initialStyle;
}
if (pseudoType) {
div.classList.add("pseudo");
}
is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE),
expectedBeforeAnimation,
`'${ property }' property with '${ initialStyle }' style `
+ `should be '${ expectedBeforeAnimation }' `
+ `before animating by ${ animationType }`);
const animation = animate(div);
animation.currentTime = 500;
is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE),
expectedDuringAnimation,
`'${ property }' property with '${ initialStyle }' style `
+ `should be '${ expectedDuringAnimation }' `
+ `even while animating by ${ animationType }`);
div.remove();
}
function test_needsFlushWithThrottledAnimations() {
const div = document.createElement("div");
div.style = "width: 100px; height: 100px; background-color: blue;";
document.body.appendChild(div);
const animation = div.animate({ opacity: [ 0, 1 ] },
{ duration: 100000, iterations: Infinity });
waitForAnimationReadyToRestyle(animation).then(() => {
ok(SpecialPowers.wrap(animation).isRunningOnCompositor,
"Opacity animation should run on the compositor");
// before flusing layout.
//ok(utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE),
// "needsFlush should return true if there is an animation on the compositor");
// Flush layout.
document.documentElement.getBoundingClientRect();
ok(!utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE),
"needsFlush should return false after flushing layout");
div.remove();
next();
window.close();
});
}
window.addEventListener("load", test_getUnanimatedComputedStyle);
</script>
</body>
</html>