mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Hook up linear easing calculation for servo and expose it to C++
Differential Revision: https://phabricator.services.mozilla.com/D146838
This commit is contained in:
parent
6326a384a8
commit
b31be826c4
3 changed files with 64 additions and 11 deletions
|
@ -10,6 +10,7 @@
|
||||||
use crate::bezier::Bezier;
|
use crate::bezier::Bezier;
|
||||||
use crate::context::{CascadeInputs, SharedStyleContext};
|
use crate::context::{CascadeInputs, SharedStyleContext};
|
||||||
use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
|
use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
|
||||||
|
use crate::piecewise_linear::PiecewiseLinearFunction;
|
||||||
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
||||||
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
|
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
|
||||||
use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
|
use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
|
||||||
|
@ -26,6 +27,7 @@ use crate::style_resolver::StyleResolverForElement;
|
||||||
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
|
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
|
||||||
use crate::stylesheets::layer_rule::LayerOrder;
|
use crate::stylesheets::layer_rule::LayerOrder;
|
||||||
use crate::values::animated::{Animate, Procedure};
|
use crate::values::animated::{Animate, Procedure};
|
||||||
|
use crate::values::computed::easing::ComputedLinearStop;
|
||||||
use crate::values::computed::{Time, TimingFunction};
|
use crate::values::computed::{Time, TimingFunction};
|
||||||
use crate::values::generics::box_::AnimationIterationCount;
|
use crate::values::generics::box_::AnimationIterationCount;
|
||||||
use crate::values::generics::easing::{
|
use crate::values::generics::easing::{
|
||||||
|
@ -127,9 +129,16 @@ impl PropertyAnimation {
|
||||||
|
|
||||||
(current_step as f64) / (jumps as f64)
|
(current_step as f64) / (jumps as f64)
|
||||||
},
|
},
|
||||||
GenericTimingFunction::LinearFunction(_elements) => {
|
GenericTimingFunction::LinearFunction(elements) => {
|
||||||
// TODO(dshin): To be implemented (bug 1764126)
|
// TODO(dshin): For servo, which uses this code path, constructing the function
|
||||||
progress
|
// every time the animation advances seem... expensive.
|
||||||
|
PiecewiseLinearFunction::from_iter(
|
||||||
|
elements
|
||||||
|
.iter()
|
||||||
|
.map(ComputedLinearStop::to_piecewise_linear_build_parameters),
|
||||||
|
)
|
||||||
|
.at(progress as f32)
|
||||||
|
.into()
|
||||||
},
|
},
|
||||||
GenericTimingFunction::Keyword(keyword) => {
|
GenericTimingFunction::Keyword(keyword) => {
|
||||||
let bezier = match keyword {
|
let bezier = match keyword {
|
||||||
|
@ -367,7 +376,8 @@ impl ComputedKeyframe {
|
||||||
let properties_changed_in_step = step.declarations.longhands().clone();
|
let properties_changed_in_step = step.declarations.longhands().clone();
|
||||||
let step_timing_function = step.timing_function.clone();
|
let step_timing_function = step.timing_function.clone();
|
||||||
let step_style = step.resolve_style(element, context, base_style, resolver);
|
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 timing_function =
|
||||||
|
step_timing_function.unwrap_or_else(|| default_timing_function.clone());
|
||||||
|
|
||||||
let values = {
|
let values = {
|
||||||
// If a value is not set in a property declaration we use the value from
|
// If a value is not set in a property declaration we use the value from
|
||||||
|
|
|
@ -13,7 +13,7 @@ type ValueType = CSSFloat;
|
||||||
/// a single entry in a piecewise linear function.
|
/// a single entry in a piecewise linear function.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Entry {
|
struct PiecewiseLinearFunctionEntry {
|
||||||
x: ValueType,
|
x: ValueType,
|
||||||
y: ValueType,
|
y: ValueType,
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,20 @@ struct Entry {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PiecewiseLinearFunction {
|
pub struct PiecewiseLinearFunction {
|
||||||
entries: crate::OwnedSlice<Entry>,
|
entries: crate::OwnedSlice<PiecewiseLinearFunctionEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parameters to define one linear stop.
|
||||||
|
pub type PiecewiseLinearFunctionBuildParameters = (CSSFloat, Option<CSSFloat>, Option<CSSFloat>);
|
||||||
|
|
||||||
impl PiecewiseLinearFunction {
|
impl PiecewiseLinearFunction {
|
||||||
/// Interpolate y value given x and two points. The linear function will be rooted at the asymptote.
|
/// Interpolate y value given x and two points. The linear function will be rooted at the asymptote.
|
||||||
fn interpolate(x: ValueType, prev: Entry, next: Entry, asymptote: &Entry) -> ValueType {
|
fn interpolate(
|
||||||
|
x: ValueType,
|
||||||
|
prev: PiecewiseLinearFunctionEntry,
|
||||||
|
next: PiecewiseLinearFunctionEntry,
|
||||||
|
asymptote: &PiecewiseLinearFunctionEntry,
|
||||||
|
) -> ValueType {
|
||||||
// Line is vertical, or the two points are identical. Avoid infinite slope by pretending
|
// Line is vertical, or the two points are identical. Avoid infinite slope by pretending
|
||||||
// the line is flat.
|
// the line is flat.
|
||||||
if prev.x.approx_eq(&next.x) {
|
if prev.x.approx_eq(&next.x) {
|
||||||
|
@ -82,6 +90,18 @@ impl PiecewiseLinearFunction {
|
||||||
}
|
}
|
||||||
unreachable!("Input is supposed to be within the entries' min & max!");
|
unreachable!("Input is supposed to be within the entries' min & max!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create the piecewise linear function from an iterator that generates the parameter tuple.
|
||||||
|
pub fn from_iter<Iter>(iter: Iter) -> Self
|
||||||
|
where
|
||||||
|
Iter: Iterator<Item = PiecewiseLinearFunctionBuildParameters> + ExactSizeIterator,
|
||||||
|
{
|
||||||
|
let mut builder = PiecewiseLinearFunctionBuilder::with_capacity(iter.len());
|
||||||
|
for (y, x_start, x_end) in iter {
|
||||||
|
builder = builder.push(y, x_start, x_end);
|
||||||
|
}
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entry of a piecewise linear function while building, where the calculation of x value can be deferred.
|
/// Entry of a piecewise linear function while building, where the calculation of x value can be deferred.
|
||||||
|
@ -105,6 +125,15 @@ impl PiecewiseLinearFunctionBuilder {
|
||||||
PiecewiseLinearFunctionBuilder::default()
|
PiecewiseLinearFunctionBuilder::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a builder for a known amount of linear stop entries.
|
||||||
|
pub fn with_capacity(len: usize) -> Self {
|
||||||
|
PiecewiseLinearFunctionBuilder {
|
||||||
|
largest_x: None,
|
||||||
|
smallest_x: None,
|
||||||
|
entries: Vec::with_capacity(len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_entry(&mut self, y: ValueType, x: Option<ValueType>) {
|
fn create_entry(&mut self, y: ValueType, x: Option<ValueType>) {
|
||||||
let x = match x {
|
let x = match x {
|
||||||
Some(x) if x.is_finite() => x,
|
Some(x) if x.is_finite() => x,
|
||||||
|
@ -148,7 +177,7 @@ impl PiecewiseLinearFunctionBuilder {
|
||||||
if self.entries.len() == 1 {
|
if self.entries.len() == 1 {
|
||||||
// Don't bother resolving anything.
|
// Don't bother resolving anything.
|
||||||
return PiecewiseLinearFunction {
|
return PiecewiseLinearFunction {
|
||||||
entries: crate::OwnedSlice::from_slice(&[Entry {
|
entries: crate::OwnedSlice::from_slice(&[PiecewiseLinearFunctionEntry {
|
||||||
x: 0.,
|
x: 0.,
|
||||||
y: self.entries[0].y,
|
y: self.entries[0].y,
|
||||||
}]),
|
}]),
|
||||||
|
@ -173,7 +202,7 @@ impl PiecewiseLinearFunctionBuilder {
|
||||||
.get_or_insert(self.largest_x.filter(|x| x > &1.0).unwrap_or(1.0));
|
.get_or_insert(self.largest_x.filter(|x| x > &1.0).unwrap_or(1.0));
|
||||||
|
|
||||||
let mut result = Vec::with_capacity(self.entries.len());
|
let mut result = Vec::with_capacity(self.entries.len());
|
||||||
result.push(Entry {
|
result.push(PiecewiseLinearFunctionEntry {
|
||||||
x: self.entries[0].x.unwrap(),
|
x: self.entries[0].x.unwrap(),
|
||||||
y: self.entries[0].y,
|
y: self.entries[0].y,
|
||||||
});
|
});
|
||||||
|
@ -199,14 +228,14 @@ impl PiecewiseLinearFunctionBuilder {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(j, e)| {
|
.map(|(j, e)| {
|
||||||
debug_assert!(e.x.is_none(), "Expected an entry with x undefined!");
|
debug_assert!(e.x.is_none(), "Expected an entry with x undefined!");
|
||||||
Entry {
|
PiecewiseLinearFunctionEntry {
|
||||||
x: increment * (j + 1) as ValueType + start_x,
|
x: increment * (j + 1) as ValueType + start_x,
|
||||||
y: e.y,
|
y: e.y,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
result.push(Entry {
|
result.push(PiecewiseLinearFunctionEntry {
|
||||||
x: e.x.unwrap(),
|
x: e.x.unwrap(),
|
||||||
y: e.y,
|
y: e.y,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! Computed types for CSS Easing functions.
|
//! Computed types for CSS Easing functions.
|
||||||
|
|
||||||
|
use crate::piecewise_linear::PiecewiseLinearFunctionBuildParameters;
|
||||||
use crate::values::computed::{Integer, Number, Percentage};
|
use crate::values::computed::{Integer, Number, Percentage};
|
||||||
use crate::values::generics::easing;
|
use crate::values::generics::easing;
|
||||||
|
|
||||||
|
@ -15,3 +16,16 @@ pub type TimingFunction = ComputedTimingFunction;
|
||||||
|
|
||||||
/// A computed linear easing entry.
|
/// A computed linear easing entry.
|
||||||
pub type ComputedLinearStop = easing::LinearStop<Number, Percentage>;
|
pub type ComputedLinearStop = easing::LinearStop<Number, Percentage>;
|
||||||
|
|
||||||
|
impl ComputedLinearStop {
|
||||||
|
/// Convert this type to entries that can be used to build PiecewiseLinearFunction.
|
||||||
|
pub fn to_piecewise_linear_build_parameters(
|
||||||
|
x: &ComputedLinearStop,
|
||||||
|
) -> PiecewiseLinearFunctionBuildParameters {
|
||||||
|
(
|
||||||
|
x.output,
|
||||||
|
x.input_start.into_rust().map(|x| x.0),
|
||||||
|
x.input_end.into_rust().map(|x| x.0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue