From bc970596d6f49cff387ecce401094bf417797ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 20 Jun 2016 17:30:43 +0200 Subject: [PATCH] layout: Make animations work... more or less. There's some maths I've done wrong, but it DOES animate some things, though they're only triggered past the first restyle, and we probably have some duplications where the animations arrive to layout. Anyway, got to go. --- components/layout/animation.rs | 66 +++++++++++++++++++++------------ components/layout_thread/lib.rs | 3 +- components/style/animation.rs | 35 +++++++++++++++-- 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/components/layout/animation.rs b/components/layout/animation.rs index b8e5bed96d4..42a71206522 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -4,6 +4,7 @@ //! CSS transitions and animations. +use context::SharedLayoutContext; use flow::{self, Flow}; use gfx::display_list::OpaqueNode; use ipc_channel::ipc::IpcSender; @@ -13,7 +14,7 @@ use script_traits::{AnimationState, LayoutMsg as ConstellationMsg}; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::sync::mpsc::Receiver; -use style::animation::{Animation, update_style_for_animation}; +use style::animation::{Animation, KeyframesAnimationState, KeyframesIterationState, update_style_for_animation}; use time; /// Processes any new animations that were discovered after style recalculation. @@ -39,15 +40,33 @@ pub fn update_animation_state(constellation_chan: &IpcSender, let mut keys_to_remove = vec![]; for (key, running_animations) in running_animations.iter_mut() { let mut animations_still_running = vec![]; - for running_animation in running_animations.drain(..) { - if now < running_animation.end_time { + for mut running_animation in running_animations.drain(..) { + let still_running = match running_animation { + Animation::Transition(_, started_at, ref frame) => { + now < started_at + frame.duration + } + Animation::Keyframes(_, _, ref mut state) => { + // This animation is still running, or we need to keep + // iterating. + now < state.started_at + state.duration || + match state.iteration_state { + KeyframesIterationState::Finite(ref mut current, ref max) => { + *current += 1; + *current < *max + } + KeyframesIterationState::Infinite => { + state.started_at += state.duration; + true + } + } + } + }; + + if still_running { animations_still_running.push(running_animation); continue - } else if running_animation.state.pending_iterations > 0 { - // if the animation should run again, just tick it... - let duration = running_animation.end_time - running_animation.start_time; - running_animation.start_time += duration; } + expired_animations.entry(*key) .or_insert_with(Vec::new) .push(running_animation); @@ -59,40 +78,41 @@ pub fn update_animation_state(constellation_chan: &IpcSender, *running_animations = animations_still_running } } + for key in keys_to_remove { running_animations.remove(&key).unwrap(); } // Add new running animations. for new_running_animation in new_running_animations { - match running_animations.entry(new_running_animation.node) { - Entry::Vacant(entry) => { - entry.insert(vec![new_running_animation]); - } - Entry::Occupied(mut entry) => entry.get_mut().push(new_running_animation), - } + running_animations.entry(*new_running_animation.node()) + .or_insert_with(Vec::new) + .push(new_running_animation); } - let animation_state; - if running_animations.is_empty() { - animation_state = AnimationState::NoAnimationsPresent; + let animation_state = if running_animations.is_empty() { + AnimationState::NoAnimationsPresent } else { - animation_state = AnimationState::AnimationsPresent; - } + AnimationState::AnimationsPresent + }; constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state)) .unwrap(); } /// Recalculates style for a set of animations. This does *not* run with the DOM lock held. -pub fn recalc_style_for_animations(flow: &mut Flow, +pub fn recalc_style_for_animations(context: &SharedLayoutContext, + flow: &mut Flow, animations: &mut HashMap>) { let mut damage = RestyleDamage::empty(); flow.mutate_fragments(&mut |fragment| { - if let Some(ref animations) = animations.get_mut(&fragment.node) { - for mut animation in *animations { + if let Some(ref mut animations) = animations.get_mut(&fragment.node) { + for ref mut animation in animations.iter_mut() { if !animation.is_paused() { - update_style_for_animation(animation, &mut fragment.style, Some(&mut damage)); + update_style_for_animation(&context.style_context, + animation, + &mut fragment.style, + Some(&mut damage)); animation.increment_keyframe_if_applicable(); } } @@ -102,6 +122,6 @@ pub fn recalc_style_for_animations(flow: &mut Flow, let base = flow::mut_base(flow); base.restyle_damage.insert(damage); for kid in base.children.iter_mut() { - recalc_style_for_animations(kid, animations) + recalc_style_for_animations(context, kid, animations) } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 67e21ab744b..b37d35e905a 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1307,7 +1307,8 @@ impl LayoutThread { self.profiler_metadata(), self.time_profiler_chan.clone(), || { - animation::recalc_style_for_animations(flow_ref::deref_mut(&mut root_flow), + animation::recalc_style_for_animations(&layout_context, + flow_ref::deref_mut(&mut root_flow), &mut animations) }); } diff --git a/components/style/animation.rs b/components/style/animation.rs index 83c7fffc1e2..a0375b380ad 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -61,7 +61,30 @@ pub enum Animation { Keyframes(OpaqueNode, Atom, KeyframesAnimationState), } -/// A keyframes animation previously sent to layout. +impl Animation { + pub fn node(&self) -> &OpaqueNode { + match *self { + Animation::Transition(ref node, _, _) => node, + Animation::Keyframes(ref node, _, _) => node, + } + } + + pub fn is_paused(&self) -> bool { + match *self { + Animation::Transition(..) => false, + Animation::Keyframes(_, _, ref state) => state.paused, + } + } + + pub fn increment_keyframe_if_applicable(&mut self) { + if let Animation::Keyframes(_, _, ref mut state) = *self { + if let KeyframesIterationState::Finite(ref mut iterations, _) = state.iteration_state { + *iterations += 1; + } + } + } +} + /// A single animation frame of a single property. #[derive(Debug, Clone)] @@ -255,7 +278,8 @@ pub fn maybe_start_animations(context: &SharedStyleContex continue } - if let Some(ref animation) = context.stylist.animations().get(&name) { + if context.stylist.animations().get(&name).is_some() { + debug!("maybe_start_animations: animation {} found", name); let delay = box_style.animation_delay.0.get_mod(i).seconds(); let animation_start = time::precise_time_s() + delay as f64; let duration = box_style.animation_duration.0.get_mod(i).seconds(); @@ -307,9 +331,11 @@ pub fn update_style_for_animation(context: &SharedStyleContext) where Impl: SelectorImplExt, Damage: TRestyleDamage { + debug!("update_style_for_animation: entering"); let now = time::precise_time_s(); match *animation { Animation::Transition(_, start_time, ref frame) => { + debug!("update_style_for_animation: transition found"); let mut new_style = (*style).clone(); let updated_style = update_style_for_animation_frame(&mut new_style, now, start_time, @@ -323,6 +349,7 @@ where Impl: SelectorImplExt, } } Animation::Keyframes(_, ref name, ref state) => { + debug!("update_style_for_animation: animation found {:?}", name); debug_assert!(!state.paused); let duration = state.duration; let started_at = state.started_at; @@ -369,8 +396,8 @@ where Impl: SelectorImplExt, for i in 1..animation.steps.len() { if total_progress as f32 <= animation.steps[i].start_percentage.0 { // We might have found our current keyframe. - target_keyframe = Some(&animation.steps[i]); last_keyframe = target_keyframe; + target_keyframe = Some(&animation.steps[i]); } } @@ -414,6 +441,7 @@ where Impl: SelectorImplExt, let mut style_changed = false; for transition_property in &animation.properties_changed { + debug!("update_style_for_animation: scanning prop {:?} for animation {}", transition_property, name); if let Some(property_animation) = PropertyAnimation::from_transition_property(*transition_property, timing_function, Time(relative_duration as f32), @@ -426,6 +454,7 @@ where Impl: SelectorImplExt, } if style_changed { + debug!("update_style_for_animation: got style change in animation {:?}", name); if let Some(damage) = damage { *damage = *damage | Damage::compute(Some(style), &new_style); }