diff --git a/components/style/animation.rs b/components/style/animation.rs index 1df3dc08cca..fa5888ffeeb 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -88,16 +88,16 @@ impl PropertyAnimation { /// The output of the timing function given the progress ration of this animation. fn timing_function_output(&self, progress: f64) -> f64 { let epsilon = 1. / (200. * self.duration); - match self.timing_function { + match &self.timing_function { GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => { - Bezier::new(x1, y1, x2, y2).solve(progress, epsilon) + Bezier::new(*x1, *y1, *x2, *y2).solve(progress, epsilon) }, GenericTimingFunction::Steps(steps, pos) => { - let mut current_step = (progress * (steps as f64)).floor() as i32; + let mut current_step = (progress * (*steps as f64)).floor() as i32; - if pos == StepPosition::Start || - pos == StepPosition::JumpStart || - pos == StepPosition::JumpBoth + if *pos == StepPosition::Start || + *pos == StepPosition::JumpStart || + *pos == StepPosition::JumpBoth { current_step = current_step + 1; } @@ -113,12 +113,12 @@ impl PropertyAnimation { } let jumps = match pos { - StepPosition::JumpBoth => steps + 1, - StepPosition::JumpNone => steps - 1, + StepPosition::JumpBoth => *steps + 1, + StepPosition::JumpNone => *steps - 1, StepPosition::JumpStart | StepPosition::JumpEnd | StepPosition::Start | - StepPosition::End => steps, + StepPosition::End => *steps, }; if progress <= 1.0 && current_step > jumps { @@ -127,6 +127,10 @@ impl PropertyAnimation { (current_step as f64) / (jumps as f64) }, + GenericTimingFunction::LinearFunction(_elements) => { + // TODO(dshin): To be implemented (bug 1764126) + progress + }, GenericTimingFunction::Keyword(keyword) => { let bezier = match keyword { TimingKeyword::Linear => return progress, @@ -360,9 +364,10 @@ impl ComputedKeyframe { let mut computed_steps: Vec = Vec::with_capacity(intermediate_steps.len()); for (step_index, step) in intermediate_steps.into_iter().enumerate() { let start_percentage = step.start_percentage; - let timing_function = step.timing_function.unwrap_or(default_timing_function); let properties_changed_in_step = step.declarations.longhands().clone(); + let step_timing_function = step.timing_function.clone(); let step_style = step.resolve_style(element, context, base_style, resolver); + let timing_function = step_timing_function.unwrap_or_else(|| default_timing_function.clone()); let values = { // If a value is not set in a property declaration we use the value from @@ -741,7 +746,7 @@ impl Animation { let animation = PropertyAnimation { from: from.clone(), to: to.clone(), - timing_function: prev_keyframe.timing_function, + timing_function: prev_keyframe.timing_function.clone(), duration: duration_between_keyframes as f64, }; diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 0edfbf84451..9588d0e6147 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1046,7 +1046,7 @@ fn static_assert() { for (ours, others) in iter { % if member: - ours.m${gecko_ffi_name}.${member} = others.m${gecko_ffi_name}.${member}; + ours.m${gecko_ffi_name}.${member} = others.m${gecko_ffi_name}.${member}.clone(); % else: ours.m${gecko_ffi_name} = others.m${gecko_ffi_name}.clone(); % endif @@ -1111,7 +1111,7 @@ fn static_assert() { ${impl_copy_animation_or_transition_value(type, 'timing_function', "TimingFunction", "mTiming")} pub fn ${type}_timing_function_at(&self, index: usize) -> longhands::${type}_timing_function::computed_value::SingleComputedValue { - self.gecko.m${type.capitalize()}s[index].mTimingFunction.mTiming + self.gecko.m${type.capitalize()}s[index].mTimingFunction.mTiming.clone() } diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index e84339a3371..9f3ec6295d7 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -331,7 +331,7 @@ impl KeyframesStep { match *declaration { PropertyDeclaration::AnimationTimingFunction(ref value) => { // Use the first value. - Some(value.0[0]) + Some(value.0[0].clone()) }, PropertyDeclaration::CSSWideKeyword(..) => None, PropertyDeclaration::WithVariables(..) => None, diff --git a/components/style/values/computed/easing.rs b/components/style/values/computed/easing.rs index 877810de6d6..3db7261e2ea 100644 --- a/components/style/values/computed/easing.rs +++ b/components/style/values/computed/easing.rs @@ -4,11 +4,14 @@ //! Computed types for CSS Easing functions. -use crate::values::computed::{Integer, Number}; +use crate::values::computed::{Integer, Number, Percentage}; use crate::values::generics::easing; /// A computed timing function. -pub type ComputedTimingFunction = easing::TimingFunction; +pub type ComputedTimingFunction = easing::TimingFunction; /// An alias of the computed timing function. pub type TimingFunction = ComputedTimingFunction; + +/// A computed linear easing entry. +pub type ComputedLinearStop = easing::LinearStop; diff --git a/components/style/values/generics/easing.rs b/components/style/values/generics/easing.rs index 02c8d348547..12e42f3c9d4 100644 --- a/components/style/values/generics/easing.rs +++ b/components/style/values/generics/easing.rs @@ -6,8 +6,9 @@ //! https://drafts.csswg.org/css-easing/#timing-functions use crate::parser::ParserContext; +use crate::values::generics::Optional; -/// A generic easing function. +/// An entry for linear easing function. #[derive( Clone, Copy, @@ -20,9 +21,33 @@ use crate::parser::ParserContext; ToResolvedValue, ToShmem, )] +#[repr(C)] +pub struct LinearStop { + /// Output of the function at the given point. + pub output: Number, + /// Playback progress at which this output starts. + #[css(skip_if = "Optional::is_none")] + pub input_start: Optional, + /// Playback progress at which this output ends. + #[css(skip_if = "Optional::is_none")] + pub input_end: Optional, +} + +/// A generic easing function. +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] #[value_info(ty = "TIMING_FUNCTION")] #[repr(u8, C)] -pub enum TimingFunction { +pub enum TimingFunction { /// `linear | ease | ease-in | ease-out | ease-in-out` Keyword(TimingKeyword), /// `cubic-bezier(, , , )` @@ -39,6 +64,11 @@ pub enum TimingFunction { #[css(comma, function)] #[value_info(other_values = "step-start,step-end")] Steps(Integer, #[css(skip_if = "is_end")] StepPosition), + /// linear([]#) + /// = && ? + /// = {1, 2} + #[css(comma, function = "linear")] + LinearFunction(#[css(iterable)] crate::OwnedSlice>), } #[allow(missing_docs)] @@ -110,7 +140,7 @@ fn is_end(position: &StepPosition) -> bool { *position == StepPosition::JumpEnd || *position == StepPosition::End } -impl TimingFunction { +impl TimingFunction { /// `ease` #[inline] pub fn ease() -> Self { diff --git a/components/style/values/specified/easing.rs b/components/style/values/specified/easing.rs index 26b921ebdc4..e05783cba2f 100644 --- a/components/style/values/specified/easing.rs +++ b/components/style/values/specified/easing.rs @@ -3,18 +3,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Specified types for CSS Easing functions. - use crate::parser::{Parse, ParserContext}; +use crate::values::computed::easing::ComputedLinearStop; use crate::values::computed::easing::TimingFunction as ComputedTimingFunction; +use crate::values::computed::Percentage as ComputedPercentage; use crate::values::generics::easing::TimingFunction as GenericTimingFunction; use crate::values::generics::easing::{StepPosition, TimingKeyword}; -use crate::values::specified::{Integer, Number}; +use crate::values::specified::{Integer, Number, Percentage}; use cssparser::Parser; use selectors::parser::SelectorParseErrorKind; +use std::iter::FromIterator; use style_traits::{ParseError, StyleParseErrorKind}; /// A specified timing function. -pub type TimingFunction = GenericTimingFunction; +pub type TimingFunction = GenericTimingFunction; impl Parse for TimingFunction { fn parse<'i, 't>( @@ -88,9 +90,9 @@ impl Parse for TimingFunction { impl TimingFunction { /// Generate the ComputedTimingFunction without Context. pub fn to_computed_value_without_context(&self) -> ComputedTimingFunction { - match *self { + match &self { GenericTimingFunction::Steps(steps, pos) => { - GenericTimingFunction::Steps(steps.value(), pos) + GenericTimingFunction::Steps(steps.value(), *pos) }, GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => { GenericTimingFunction::CubicBezier { @@ -100,7 +102,23 @@ impl TimingFunction { y2: y2.get(), } }, - GenericTimingFunction::Keyword(keyword) => GenericTimingFunction::Keyword(keyword), + GenericTimingFunction::Keyword(keyword) => GenericTimingFunction::Keyword(*keyword), + GenericTimingFunction::LinearFunction(steps) => { + let iter = steps.iter().map(|e| ComputedLinearStop { + output: e.output.get(), + input_start: e + .input_start + .into_rust() + .map(|x| ComputedPercentage(x.get())) + .into(), + input_end: e + .input_end + .into_rust() + .map(|x| ComputedPercentage(x.get())) + .into(), + }); + GenericTimingFunction::LinearFunction(crate::OwnedSlice::from_iter(iter)) + }, } } }