Skip to content

Fix CSS step timing functions jump-both, jump-start, start at timestamp 0; Early return when possible#342

Open
yezhizhen wants to merge 4 commits intomainfrom
fix-quantization
Open

Fix CSS step timing functions jump-both, jump-start, start at timestamp 0; Early return when possible#342
yezhizhen wants to merge 4 commits intomainfrom
fix-quantization

Conversation

@yezhizhen
Copy link
Copy Markdown
Member

@yezhizhen yezhizhen commented Mar 23, 2026

Make early return happen earlier:

  1. total_progress ≥ 1.0 and total_progress < 0 now handled immediately. Also make it direction aware.
  2. At timestamp 0, for normal direction, non‑jump step functions (jump‑end, jump‑none, end) now return the start‑keyframe value early, instead of proceeding to interpolation.
  3. Zero-interval: we exit early to avoid division‑by‑zero in percentage_between_keyframes

Try
Servo PR: servo/servo#43594

@yezhizhen yezhizhen changed the title (To be updated) Fix quantization (To be updated) Fix step quantization Mar 23, 2026
.iter()
.rev()
.position(|step| total_progress as f32 <= 1. - step.start_percentage)
.position(|step| (total_progress as f32) <= 1. - step.start_percentage)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be < too?

Copy link
Copy Markdown
Member Author

@yezhizhen yezhizhen Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we shouldn't. Otherwise for reversed direction at timestamp 0, we jump while we shouldn't for jump-start, jump-both, start.

But there's more severe problem I've been trying to fix based on horrible test results..

// At progress 0, we need to handle step functions specially
// for "jump-both, jump-start, start" step functions.
if total_progress == 0.0 {
if let TimingFunction::Steps(_steps, pos) = &prev_keyframe.timing_function {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to think this seems the wrong place to handle timing functions. Shouldn't it be handled in calculate_step_output()?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is handled there. But previously never get the chance to reach there (L723) due to early return.

The test result looks decent.

There's only one failure case that I hope to check tomorrow.

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed to Oriol. Btw I also find PropertyAnimation below weird, as it's resolving the timing function for every property. I imagine a better process would be:

  1. Use timing_function.calculate_output() to resolve the progress to a resolved_progress, which is number in [0, 1]
  2. Use prev_keyframe if resolved_progress is 0; Use next_keyframe is resolved_progress is 1
  3. Otherwise, calculate a linear interpolation between the two keyframes at resolved_progress

In this way we don't need handle special handling of any timing function here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be handled in calculate_step_output()?

fn calculate_step_output() is shared with Firefox. But Firefox doesn't have the problem we have here :/
This PR only changes Servo specific code.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
@yezhizhen yezhizhen requested a review from xiaochengh March 24, 2026 05:16
@yezhizhen yezhizhen changed the title (To be updated) Fix step quantization Fix CSS step timing functions jump-both, jump-start, start at timestamp 0 Mar 24, 2026
@yezhizhen yezhizhen changed the title Fix CSS step timing functions jump-both, jump-start, start at timestamp 0 Fix CSS step timing functions jump-both, jump-start, start at timestamp 0 Mar 24, 2026
@yezhizhen yezhizhen changed the title Fix CSS step timing functions jump-both, jump-start, start at timestamp 0 Fix CSS step timing functions jump-both, jump-start, start at timestamp 0; Early return when possible Mar 24, 2026
Copy link
Copy Markdown
Member Author

@yezhizhen yezhizhen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also made early return happen earlier in various cases, instead of proceed to interpolation.

See "Make early return happen earlier" in description.

@yezhizhen yezhizhen marked this pull request as ready for review March 24, 2026 05:31
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Some(index) => &self.computed_steps[index],
None => return,
None => {
debug_assert!(false, "next_keyframe_index should always be Some");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because:

  1. We always have steps at 0% and 100%
    debug_assert!(intermediate_steps.first().unwrap().start_percentage == 0.);
    debug_assert!(intermediate_steps.last().unwrap().start_percentage == 1.);
  2. This always exists for total_progress in [0,1), no matter reverse or normal.

Comment on lines +691 to +692
// Detect zero interval. Prevent division by zero from percentage_between_keyframes.
if Some(prev_keyframe_index) == next_keyframe_index {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The % between two keyframes should never be zero, because if it was then IntermediateComputedKeyframe::generate_from_keyframes should have coalesced those two frames.

If you're seeing two keyframes with the same % then I suspect the bug is in that function and not here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a bug of that function, but the result of index computation.

For example, reverse direction at total_progress == 0.0 can trigger the equality.

Signed-off-by: Euclid Ye <euclid.ye@huawei.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants