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.
This commit is contained in:
Emilio Cobos Álvarez 2016-06-20 17:30:43 +02:00
parent c16c5acade
commit bc970596d6
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 77 additions and 27 deletions

View file

@ -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<ConstellationMsg>,
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<ConstellationMsg>,
*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<OpaqueNode, Vec<Animation>>) {
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)
}
}

View file

@ -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)
});
}

View file

@ -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<Impl: SelectorImplExt>(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<Damage, Impl>(context: &SharedStyleContext<Imp
damage: Option<&mut Damage>)
where Impl: SelectorImplExt,
Damage: TRestyleDamage<ConcreteComputedValues = Impl::ComputedValues> {
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);
}