diff options
author | bors-servo <servo-ops@mozilla.com> | 2020-04-01 15:19:15 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-01 15:19:15 -0400 |
commit | 516279e24f3d77e0050aeeed17ef24c9701edc1a (patch) | |
tree | f469887f1532704aaca28715b4d897cc3b69e9b6 | |
parent | af1ebe79efd799498010f196983a233aa5203d64 (diff) | |
parent | 2bb6ab4567802c3b77ee8a926ea55daf60ff441a (diff) | |
download | servo-516279e24f3d77e0050aeeed17ef24c9701edc1a.tar.gz servo-516279e24f3d77e0050aeeed17ef24c9701edc1a.zip |
Auto merge of #26074 - jdm:transition-fix, r=SimonSapin
Avoid infinitely looping CSS transitions.
This change addresses the long-standing issue of CSS transitions not ending appropriately. It does not fundamentally change the way we process transitions/animations.
---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #20379
- [x] There are tests for these changes
-rw-r--r-- | components/layout/animation.rs | 1 | ||||
-rw-r--r-- | components/style/animation.rs | 35 | ||||
-rw-r--r-- | components/style/matching.rs | 7 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta-layout-2020/css/transitionend_event.html.ini | 4 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/MANIFEST.json | 7 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/transitionend_event.html | 27 |
6 files changed, 61 insertions, 20 deletions
diff --git a/components/layout/animation.rs b/components/layout/animation.rs index 96e4801fa4e..8a99a75fc72 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -110,6 +110,7 @@ pub fn update_animation_state<E>( .unwrap(); } + debug!("expiring animation for {:?}", running_animation); expired_animations .entry(*key) .or_insert_with(Vec::new) diff --git a/components/style/animation.rs b/components/style/animation.rs index 7f96e55b18f..d98cc901b6a 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -425,6 +425,11 @@ pub fn start_transitions_if_applicable( // above. property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0); + debug!( + "checking {:?} for matching end value", + possibly_expired_animations + ); + // Per [1], don't trigger a new transition if the end state for that // transition is the same as that of a transition that's already // running on the same node. @@ -852,26 +857,18 @@ pub fn complete_expired_transitions( node: OpaqueNode, style: &mut Arc<ComputedValues>, context: &SharedStyleContext, -) -> bool { - let had_animations_to_expire; - { - let all_expired_animations = context.expired_animations.read(); - let animations_to_expire = all_expired_animations.get(&node); - had_animations_to_expire = animations_to_expire.is_some(); - if let Some(ref animations) = animations_to_expire { - for animation in *animations { - debug!("Updating expired animation {:?}", animation); - // TODO: support animation-fill-mode - if let Animation::Transition(_, _, ref frame) = *animation { - frame.property_animation.update(Arc::make_mut(style), 1.0); - } + expired_animations: &mut Vec<crate::animation::PropertyAnimation>, +) { + let mut all_expired_animations = context.expired_animations.write(); + if let Some(animations) = all_expired_animations.remove(&node) { + debug!("removing expired animations for {:?}", node); + for animation in animations { + debug!("Updating expired animation {:?}", animation); + // TODO: support animation-fill-mode + if let Animation::Transition(_, _, frame) = animation { + frame.property_animation.update(Arc::make_mut(style), 1.0); + expired_animations.push(frame.property_animation); } } } - - if had_animations_to_expire { - context.expired_animations.write().remove(&node); - } - - had_animations_to_expire } diff --git a/components/style/matching.rs b/components/style/matching.rs index 06e74810cfd..37843fca776 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -607,7 +607,12 @@ trait PrivateMatchMethods: TElement { // Finish any expired transitions. let this_opaque = self.as_node().opaque(); - animation::complete_expired_transitions(this_opaque, style, context); + animation::complete_expired_transitions( + this_opaque, + style, + context, + possibly_expired_animations, + ); // Merge any running animations into the current style, and cancel them. let had_running_animations = context diff --git a/tests/wpt/mozilla/meta-layout-2020/css/transitionend_event.html.ini b/tests/wpt/mozilla/meta-layout-2020/css/transitionend_event.html.ini new file mode 100644 index 00000000000..8832e8963d6 --- /dev/null +++ b/tests/wpt/mozilla/meta-layout-2020/css/transitionend_event.html.ini @@ -0,0 +1,4 @@ +[transitionend_event.html] + expected: TIMEOUT + [transitionend_event] + expected: TIMEOUT diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index ff18a615fa1..65282571142 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13031,6 +13031,13 @@ {} ] ], + "transitionend_event.html": [ + "71b88117a0280fbffcf3ab77105c0460317c66c8", + [ + null, + {} + ] + ], "white-space-pre-line-long-line.html": [ "bf0d0085fef0f1639637b2e652a7fb857cd51bf6", [ diff --git a/tests/wpt/mozilla/tests/css/transitionend_event.html b/tests/wpt/mozilla/tests/css/transitionend_event.html new file mode 100644 index 00000000000..71b88117a02 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/transitionend_event.html @@ -0,0 +1,27 @@ +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #test { + width: 10px; + height: 10px; + background: black; + transition: 1ms linear transform; + } + .transform { + transform:scale(1.2); + } +</style> +<div id="test" class="transform"></div> +<script> + async_test(function(t) { + let d = document.querySelector('div'); + // Verify that we only receive a single transitionend event once the transition is complete. + d.ontransitionend = t.step_func(() => { + d.ontransitionend = t.unreached_func(); + t.step_timeout(() => t.done(), 100); + }); + t.step_timeout(() => d.className = "", 10); + }); +</script> |