aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_thread.rs
diff options
context:
space:
mode:
authoryvt <i@yvt.jp>2022-10-28 01:31:19 +0900
committerMartin Robinson <mrobinson@igalia.com>2023-02-10 14:44:27 +0100
commiteffd5a3107081d6efb2bf6e50a67bbb0b282f82a (patch)
tree8e56c61e98c04bb0fa0e3ffcbe5ad6d3d4d98bdd /components/script/script_thread.rs
parentaf1b0b0f14d951b8e712b71a220e308d7b2f0c2e (diff)
downloadservo-effd5a3107081d6efb2bf6e50a67bbb0b282f82a.tar.gz
servo-effd5a3107081d6efb2bf6e50a67bbb0b282f82a.zip
fix(script): request animation ticks if `Animations::pending_events` is not empty
Fixes the test case `/_mozilla/css/css-transition-cancel-event .html`, which was failing under a specific circumstance. The observed sequence of events during the failing test run looks like this: 1. Transitions start in `div1` and `div2`. 2. `div1` generates a `transitionend` event. 3. The `transitionend` event handler removes `div2` from DOM, cancelling its ongoing transition. 4. `div2` is supposed to generate a `transitioncancel` event in a timely manner, which it does not. The test fails as a result. What is going on here? Here's a possible explaination: 1. During one invocation of `ScriptThread::handle_msgs`... 2. In step 2, `ScriptThread::update_animations_send_events` -> `Document ::update_for_new_timeline_value` detects the completion of the transition, and in response, pends the `transitionend` event. 3. In step 3, `ScriptThread::update_animations_send_events` -> `Animations::send_pending_events` calls the `transitionend` handler. 4. The `transitionend` event handler removes `div2`, thereby cancelling its ongoing transition and triggering a reflow. 5. Reflow takes place. During this, `Animations::do_post_reflow_update` -> `Animations::handle_canceled_animations` pends the `transitioncancel` event (precursor to step 4). 6. Having discovering that there was no running animation, `Animations:: do_post_reflow_update` calls `self.update_running_animation_presence (_, false)`, which sends `AnimationState::NoAnimationsPresent`. 7. The invocation of `ScriptThread::handle_msgs` ends, and another starts. It blocks waiting for events. 8. Meanwhile, the compositor receives `AnimationState:: NoAnimationsPresent` and stops further generation of animation ticks. 9. With no events to wake it up, the script thread is stuck waiting despite having the pending `transitioncancel` event (step 4). The HTML specification [says][1] that "an event loop must continually run [...] as long as it exists" and does not say it can block if there is nothing to do. Blocking is merely optimization in a user agent implementation. Pending animation-related events must be processed every time a "rendering opportunity" arises unless the user agent has a reason to believe that it "would have no visible effect". Skipping the processing of animation-related events would have visible effect if such events are indeed present. The correct implementation in Servo, therefore, would be to request more animation ticks so that such events are processed in a subsequent tick. [1]: https://html.spec.whatwg.org/multipage/#event-loop-processing-model
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r--components/script/script_thread.rs2
1 files changed, 1 insertions, 1 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index a82edd61cc3..b417f453cdf 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1709,7 +1709,7 @@ impl ScriptThread {
}
for (_, document) in self.documents.borrow().iter() {
- document.animations().send_pending_events();
+ document.animations().send_pending_events(document.window());
}
}