mirror of
https://github.com/servo/servo.git
synced 2025-06-25 17:44:33 +01:00
compositor: Always send an animating tick when a pipeline starts animating (#37507)
Instead of taking into account whether the entire WebView starts animating, always send an animation tick when a pipeline moves from the "not animating" to "animating" state. It could be that the WebView was animating, but not painting if the animation was not producing display lists. In that case, the required tick would never come, because it is sent after a repaint. Testing: Added a new WPT test. Fixes: #37458. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
ded753f01b
commit
56e901d0c2
4 changed files with 112 additions and 10 deletions
|
@ -279,13 +279,14 @@ impl WebViewRenderer {
|
|||
}
|
||||
|
||||
/// Sets or unsets the animations-running flag for the given pipeline. Returns
|
||||
/// true if the [`WebViewRenderer`]'s overall animating state changed.
|
||||
/// true if the pipeline has started animating.
|
||||
pub(crate) fn change_pipeline_running_animations_state(
|
||||
&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
animation_state: AnimationState,
|
||||
) -> bool {
|
||||
let pipeline_details = self.ensure_pipeline_details(pipeline_id);
|
||||
let was_animating = pipeline_details.animating();
|
||||
match animation_state {
|
||||
AnimationState::AnimationsPresent => {
|
||||
pipeline_details.animations_running = true;
|
||||
|
@ -300,23 +301,38 @@ impl WebViewRenderer {
|
|||
pipeline_details.animation_callbacks_running = false;
|
||||
},
|
||||
}
|
||||
self.update_animation_state()
|
||||
let started_animating = !was_animating && pipeline_details.animating();
|
||||
|
||||
self.update_animation_state();
|
||||
|
||||
// It's important that an animation tick is triggered even if the
|
||||
// WebViewRenderer's overall animation state hasn't changed. It's possible that
|
||||
// the WebView was animating, but not producing new display lists. In that case,
|
||||
// no repaint will happen and thus no repaint will trigger the next animation tick.
|
||||
started_animating
|
||||
}
|
||||
|
||||
/// Sets or unsets the throttled flag for the given pipeline. Returns
|
||||
/// true if the [`WebViewRenderer`]'s overall animating state changed.
|
||||
/// true if the pipeline has started animating.
|
||||
pub(crate) fn set_throttled(&mut self, pipeline_id: PipelineId, throttled: bool) -> bool {
|
||||
self.ensure_pipeline_details(pipeline_id).throttled = throttled;
|
||||
let pipeline_details = self.ensure_pipeline_details(pipeline_id);
|
||||
let was_animating = pipeline_details.animating();
|
||||
pipeline_details.throttled = throttled;
|
||||
let started_animating = !was_animating && pipeline_details.animating();
|
||||
|
||||
// Throttling a pipeline can cause it to be taken into the "not-animating" state.
|
||||
self.update_animation_state()
|
||||
self.update_animation_state();
|
||||
|
||||
// It's important that an animation tick is triggered even if the
|
||||
// WebViewRenderer's overall animation state hasn't changed. It's possible that
|
||||
// the WebView was animating, but not producing new display lists. In that case,
|
||||
// no repaint will happen and thus no repaint will trigger the next animation tick.
|
||||
started_animating
|
||||
}
|
||||
|
||||
pub(crate) fn update_animation_state(&mut self) -> bool {
|
||||
let animating = self.pipelines.values().any(PipelineDetails::animating);
|
||||
let old_animating = std::mem::replace(&mut self.animating, animating);
|
||||
self.webview.set_animating(self.animating);
|
||||
old_animating != self.animating
|
||||
fn update_animation_state(&mut self) {
|
||||
self.animating = self.pipelines.values().any(PipelineDetails::animating);
|
||||
self.webview.set_animating(self.animating());
|
||||
}
|
||||
|
||||
/// On a Window refresh tick (e.g. vsync)
|
||||
|
|
11
tests/wpt/meta/MANIFEST.json
vendored
11
tests/wpt/meta/MANIFEST.json
vendored
|
@ -454483,6 +454483,10 @@
|
|||
"59843ae54b64f6ce4f7e616d4be491c911ea84cf",
|
||||
[]
|
||||
],
|
||||
"transition-in-iframe-001-iframe.html": [
|
||||
"b7214bd378bd60b2729bc276bd775a389fd4ebcb",
|
||||
[]
|
||||
],
|
||||
"two.gif": [
|
||||
"01435c80209d533dc2164ac48279574c7ba4615e",
|
||||
[]
|
||||
|
@ -614633,6 +614637,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"transition-in-iframe-001.html": [
|
||||
"2e5e64de2308aa0c1f176c1d047cd178cac5d3ed",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"transition-property-001.html": [
|
||||
"47a1417070f0c2e7b8171259d9c4f63c44e96bcc",
|
||||
[
|
||||
|
|
21
tests/wpt/tests/css/css-transitions/support/transition-in-iframe-001-iframe.html
vendored
Normal file
21
tests/wpt/tests/css/css-transitions/support/transition-in-iframe-001-iframe.html
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<style>
|
||||
html {
|
||||
background: red;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.addEventListener("message", () => {
|
||||
document.documentElement.style.background = "green";
|
||||
});
|
||||
document.documentElement.addEventListener(
|
||||
"transitionend", () => {
|
||||
window.parent.postMessage("complete", "*");
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
54
tests/wpt/tests/css/css-transitions/transition-in-iframe-001.html
vendored
Normal file
54
tests/wpt/tests/css/css-transitions/transition-in-iframe-001.html
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<title>Transitions: Transition in <iframe> on page with empty rAF finishes</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
|
||||
<link rel="author" href="mailto:mrobinson@igalia.com">
|
||||
<link rel="author" href="mailto:obrufau@igalia.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/common/rendering-utils.js"></script>
|
||||
|
||||
<style>
|
||||
#iframe {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let rAFId = null;
|
||||
function triggerNeverEndingUselessRAF() {
|
||||
rAFId = requestAnimationFrame(triggerNeverEndingUselessRAF);
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
await waitForAtLeastOneFrame();
|
||||
await waitForAtLeastOneFrame();
|
||||
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.id = "iframe";
|
||||
iframe.src = "support/transition-in-iframe-001-iframe.html"
|
||||
iframe.sandbox = "allow-scripts";
|
||||
|
||||
iframe.addEventListener("load", async () => {
|
||||
await waitForAtLeastOneFrame();
|
||||
await waitForAtLeastOneFrame();
|
||||
iframe.contentWindow.postMessage("loaded", "*");
|
||||
});
|
||||
|
||||
triggerNeverEndingUselessRAF();
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
await new Promise(resolve => {
|
||||
window.addEventListener("message", () => {
|
||||
cancelAnimationFrame(rAFId);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue