Skip to content

Commit

Permalink
Part 3: Do normalization for NormalizedTiming().
Browse files Browse the repository at this point in the history
This implements the normalization of the specified time, defined in
[web-animations-2]:
https://drafts.csswg.org/web-animations-2/#normalize-specified-timing.
However, it is possible to update this, based on the spec issue:
w3c/csswg-drafts#4862.

For now, we just do normalization for delay, end delay, and
iteration duration based on the end time. And make sure the end time is
equal to the timeline duration.

Differential Revision: https://phabricator.services.mozilla.com/D149685

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1775327
gecko-commit: 71bbfaecf629a3d73c72600d35c0ac2965516d60
gecko-reviewers: firefox-animation-reviewers, birtles
  • Loading branch information
BorisChiou authored and moz-wptsync-bot committed Jul 11, 2022
1 parent 8c410d7 commit 63da5b9
Showing 1 changed file with 235 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<!DOCTYPE html>
<title>The various animation longhands with progress based animations</title>
<link rel="help" src="https://drafts.csswg.org/css-animations-2">
<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/4862">
<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/6674">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@keyframes anim {
from { translate: 0px; }
to { translate: 100px; }
}
#container {
width: 300px;
height: 300px;
overflow: scroll;
}
#target {
width: 100px;
height: 100px;
translate: none;
}
</style>
<body>
<div id="log"></div>
<script>
"use strict";

const createTargetAndScroller = function(t) {
let container = document.createElement('div');
container.id = 'container';
let target = document.createElement('div');
target.id = 'target';
let content = document.createElement('div');
content.style.blockSize = '100%';

// The height of target is 100px and the content is 100%, so the scroll range
// is [0, 100].

// <div id='container'>
// <div id='target'></div>
// <div style='block-size: 100%;'></div>
// </div>
document.body.appendChild(container);
container.appendChild(target);
container.appendChild(content);

if (t && typeof t.add_cleanup === 'function') {
t.add_cleanup(() => {
content.remove();
target.remove();
container.remove();
});
}

return [target, container];
};

// ------------------------------
// Test animation-duration
// ------------------------------

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '25px');
}, 'animation-duration');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '0s linear anim scroll(nearest)';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '100px');
}, 'animation-duration: 0s');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = 'infinite linear anim scroll(nearest)';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '100px');
}, 'animation-duration: infinite');


// ------------------------------
// Test animation-iteration-count
// ------------------------------

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '25px');

// Let animation become 50% in the 1st iteration.
target.style.animationIterationCount = '2';
assert_equals(getComputedStyle(target).translate, '50px');

// Let animation become 0% in the 2nd iteration.
target.style.animationIterationCount = '4';
assert_equals(getComputedStyle(target).translate, '0px');
}, 'animation-iteration-count');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationIterationCount = '0';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '0px');
}, 'animation-iteration-count: 0');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationIterationCount = 'infinite';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '100px');
}, 'animation-iteration-count: infinite');


// ------------------------------
// Test animation-direction
// ------------------------------

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';

scroller.scrollTop = 25 // [0, 100].
assert_equals(getComputedStyle(target).translate, '25px');
}, 'animation-direction: normal');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationDirection = 'reverse';

scroller.scrollTop = 25; // 25% in the reversing direction.
assert_equals(getComputedStyle(target).translate, '75px');
}, 'animation-direction: reverse');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationIterationCount = '2';
target.style.animationDirection = 'alternate';

scroller.scrollTop = 10; // 20% in the 1st iteration.
assert_equals(getComputedStyle(target).translate, '20px');

scroller.scrollTop = 60; // 20% in the 2nd iteration (reversing direction).
assert_equals(getComputedStyle(target).translate, '80px');
}, 'animation-direction: alternate');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationIterationCount = '2';
target.style.animationDirection = 'alternate-reverse';

scroller.scrollTop = 10; // 20% in the 1st iteration (reversing direction).
assert_equals(getComputedStyle(target).translate, '80px');

scroller.scrollTop = 60; // 20% in the 2nd iteration.
assert_equals(getComputedStyle(target).translate, '20px');
}, 'animation-direction: alternate-reverse');


// ------------------------------
// Test animation-delay
// ------------------------------

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';

scroller.scrollTop = 25; // [0, 100].
assert_equals(getComputedStyle(target).translate, '25px');

// (start delay: 10s) (duration: 10s)
// before active
// |--------------------|--------------------|
// 0px 50px 100px (The scroller)
// 0% 100% (The iteration progress)

// Let animation be in before phase.
target.style.animationDelay = '10s';
assert_equals(getComputedStyle(target).translate, 'none');

scroller.scrollTop = 50; // The animation enters active phase.
assert_equals(getComputedStyle(target).translate, '0px');

scroller.scrollTop = 75; // The ieration progress is 50%.
assert_equals(getComputedStyle(target).translate, '50px');
}, 'animation-delay with a positive value');

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';

// active
// |--------------------|
// 0px 100px (The scroller)
// 50% 100% (The iteration progress)

scroller.scrollTop = 20; // [0, 100].
target.style.animationDelay = '-5s';
assert_equals(getComputedStyle(target).translate, '60px');
}, 'animation-delay with a negative value');


// ------------------------------
// Test animation-fill-mode
// ------------------------------

test(t => {
let [target, scroller] = createTargetAndScroller(t);
target.style.animation = '10s linear anim scroll(nearest)';
target.style.animationDelay = '10s';

scroller.scrollTop = 25;
assert_equals(getComputedStyle(target).translate, 'none');

target.style.animationFillMode = 'backwards';
assert_equals(getComputedStyle(target).translate, '0px');
}, 'animation-fill-mode');

</script>
</body>

0 comments on commit 63da5b9

Please sign in to comment.