LibWeb/Animation: Support progress values outside of [0,1]

If the progress is not in [0,1], the first two or the last two
keyframes are now used for interpolation outside the interval.
This commit is contained in:
Glenn Skrzypczak 2024-11-25 13:54:18 +01:00 committed by Andreas Kling
parent 0d15cc4672
commit 1e67b85571
Notes: github-actions[bot] 2024-11-25 17:11:18 +00:00
3 changed files with 27 additions and 38 deletions

View file

@ -1038,37 +1038,36 @@ void StyleComputer::collect_animation_into(DOM::Element& element, Optional<CSS::
return;
auto& keyframes = effect->key_frame_set()->keyframes_by_key;
// FIXME: Support progress values outside [0-1]
output_progress = clamp(output_progress.value(), 0, 1);
auto key = static_cast<u64>(output_progress.value() * 100.0 * Animations::KeyframeEffect::AnimationKeyFrameKeyScaleFactor);
auto matching_keyframe_it = keyframes.find_largest_not_above_iterator(key);
if (matching_keyframe_it.is_end()) {
if (keyframes.size() < 2) {
if constexpr (LIBWEB_CSS_ANIMATION_DEBUG) {
dbgln(" Did not find any start keyframe for the current state ({}) :(", key);
dbgln(" (have {} keyframes)", keyframes.size());
dbgln(" Did not find enough keyframes ({} keyframes)", keyframes.size());
for (auto it = keyframes.begin(); it != keyframes.end(); ++it)
dbgln(" - {}", it.key());
}
return;
}
auto keyframe_start = matching_keyframe_it.key();
auto keyframe_values = *matching_keyframe_it;
auto key = static_cast<i64>(round(output_progress.value() * 100.0 * Animations::KeyframeEffect::AnimationKeyFrameKeyScaleFactor));
auto keyframe_start_it = [&] {
if (output_progress.value() <= 0) {
return keyframes.begin();
}
auto potential_match = keyframes.find_largest_not_above_iterator(key);
if (output_progress.value() >= 0) {
return --potential_match;
}
return potential_match;
}();
auto keyframe_start = static_cast<i64>(keyframe_start_it.key());
auto keyframe_values = *keyframe_start_it;
auto initial_keyframe_it = matching_keyframe_it;
auto keyframe_end_it = ++matching_keyframe_it;
if (keyframe_end_it.is_end())
keyframe_end_it = initial_keyframe_it;
auto keyframe_end = keyframe_end_it.key();
auto keyframe_end_it = ++keyframe_start_it;
VERIFY(!keyframe_end_it.is_end());
auto keyframe_end = static_cast<i64>(keyframe_end_it.key());
auto keyframe_end_values = *keyframe_end_it;
auto progress_in_keyframe = [&] {
if (keyframe_start == keyframe_end)
return 0.f;
return static_cast<float>(key - keyframe_start) / static_cast<float>(keyframe_end - keyframe_start);
}();
auto progress_in_keyframe
= static_cast<float>(key - keyframe_start) / static_cast<float>(keyframe_end - keyframe_start);
if constexpr (LIBWEB_CSS_ANIMATION_DEBUG) {
auto valid_properties = keyframe_values.properties.size();

View file

@ -166,18 +166,6 @@ cubic-bezier(1, 1, 1, 1)
80: 0.80
90: 0.90
100: 1.00
cubic-bezier(1, 1000, 1, 1000)
0: 0.00
10: 1.00
20: 1.00
30: 1.00
40: 1.00
50: 1.00
60: 1.00
70: 1.00
80: 1.00
90: 1.00
100: 1.00
step-start
0: 1.00
10: 1.00

View file

@ -20,7 +20,8 @@
"ease-in-out",
"cubic-bezier(0, 0, 0, 0)",
"cubic-bezier(1, 1, 1, 1)",
"cubic-bezier(1, 1000, 1, 1000)",
// FIXME: "cubic-bezier(1, 1000, 1, 1000)",
// This test fails, because it sets an opacity > 1, which should not be possible
"step-start",
"step-end",
"steps(1000)",
@ -33,16 +34,17 @@
];
for (const easing of easings) {
const target = document.createElement('div');
const target = document.createElement("div");
document.body.appendChild(target);
println(easing);
const animation = target.animate(
{ opacity: ['0', '1'] },
{ opacity: ["0", "1"] },
{
duration: 100,
fill: 'forwards',
fill: "forwards",
easing: easing,
});
}
);
const computed_style = getComputedStyle(target);
for (let time = 0; time <= 100; time += 10) {
animation.currentTime = time;