mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 09:49:14 +00:00
Bug 1775351: Part 2: linear(...)
easing: Simplify piecewise linear implementation given parsing simplification. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D150163
This commit is contained in:
parent
9b9505a23c
commit
bdcfb83f13
@ -26,7 +26,7 @@ pub struct PiecewiseLinearFunction {
|
||||
}
|
||||
|
||||
/// Parameters to define one linear stop.
|
||||
pub type PiecewiseLinearFunctionBuildParameters = (CSSFloat, Option<CSSFloat>, Option<CSSFloat>);
|
||||
pub type PiecewiseLinearFunctionBuildParameters = (CSSFloat, Option<CSSFloat>);
|
||||
|
||||
impl PiecewiseLinearFunction {
|
||||
/// Interpolate y value given x and two points. The linear function will be rooted at the asymptote.
|
||||
@ -97,8 +97,8 @@ impl PiecewiseLinearFunction {
|
||||
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);
|
||||
for (y, x_start) in iter {
|
||||
builder = builder.push(y, x_start);
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
@ -161,11 +161,8 @@ impl PiecewiseLinearFunctionBuilder {
|
||||
/// the x value is calculated later. If the end x value is specified, a flat segment
|
||||
/// is generated. If start x value is not specified but end x is, it is treated as
|
||||
/// start x.
|
||||
pub fn push(mut self, y: CSSFloat, x_start: Option<CSSFloat>, x_end: Option<CSSFloat>) -> Self {
|
||||
pub fn push(mut self, y: CSSFloat, x_start: Option<CSSFloat>) -> Self {
|
||||
self.create_entry(y, x_start);
|
||||
if x_end.is_some() {
|
||||
self.create_entry(y, x_end.map(|x| x));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ impl ComputedLinearStop {
|
||||
(
|
||||
x.output,
|
||||
x.input.into_rust().map(|x| x.0),
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ fn linear_keyword_equivalent_out_of_bounds() {
|
||||
|
||||
fn get_const_function() -> PiecewiseLinearFunction {
|
||||
PiecewiseLinearFunctionBuilder::new()
|
||||
.push(CONST_VALUE as f32, None, None)
|
||||
.push(CONST_VALUE as f32, None)
|
||||
.build()
|
||||
}
|
||||
|
||||
@ -49,12 +49,12 @@ fn const_function_out_of_bounds() {
|
||||
#[test]
|
||||
fn implied_input_spacing() {
|
||||
let explicit_spacing = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
let implied_spacing = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
assert!(implied_spacing
|
||||
.at(0.)
|
||||
@ -70,9 +70,9 @@ fn implied_input_spacing() {
|
||||
#[test]
|
||||
fn interpolation() {
|
||||
let interpolate = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(0.7, None, None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(0.7, None)
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
assert!(interpolate.at(0.1).approx_eq(&0.14));
|
||||
assert!(interpolate.at(0.25).approx_eq(&0.35));
|
||||
@ -85,14 +85,14 @@ fn interpolation() {
|
||||
#[test]
|
||||
fn implied_multiple_input_spacing() {
|
||||
let multiple_implied = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(0.8, None, None)
|
||||
.push(0.6, None, None)
|
||||
.push(0.4, None, None)
|
||||
.push(0.5, Some(0.4), None)
|
||||
.push(0.1, None, None)
|
||||
.push(0.9, None, None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(0.8, None)
|
||||
.push(0.6, None)
|
||||
.push(0.4, None)
|
||||
.push(0.5, Some(0.4))
|
||||
.push(0.1, None)
|
||||
.push(0.9, None)
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
assert!(multiple_implied.at(0.1).approx_eq(&0.8));
|
||||
assert!(multiple_implied.at(0.2).approx_eq(&0.6));
|
||||
@ -106,8 +106,8 @@ fn implied_multiple_input_spacing() {
|
||||
#[test]
|
||||
fn nonzero_edge_values() {
|
||||
let nonzero_edges = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.1, Some(0.0), None)
|
||||
.push(0.7, Some(1.0), None)
|
||||
.push(0.1, Some(0.0))
|
||||
.push(0.7, Some(1.0))
|
||||
.build();
|
||||
assert!(nonzero_edges.at(0.).approx_eq(&0.1));
|
||||
assert!(nonzero_edges.at(0.5).approx_eq(&0.4));
|
||||
@ -118,9 +118,9 @@ fn nonzero_edge_values() {
|
||||
fn out_of_bounds_extrapolate() {
|
||||
// General case: extrapolate from the edges' slope
|
||||
let oob_extend = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(0.7, None, None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(0.7, None)
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
assert!(oob_extend.at(-0.25).approx_eq(&-0.35));
|
||||
assert!(oob_extend.at(1.25).approx_eq(&1.15));
|
||||
@ -130,11 +130,11 @@ fn out_of_bounds_extrapolate() {
|
||||
fn out_of_bounds_flat() {
|
||||
// Repeated endpoints: flat extrapolation out-of-bounds
|
||||
let oob_flat = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.7, None, None)
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.7, None)
|
||||
.push(1.0, Some(1.0))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(oob_flat
|
||||
.at(0.0)
|
||||
@ -145,9 +145,10 @@ fn out_of_bounds_flat() {
|
||||
#[test]
|
||||
fn flat_region() {
|
||||
let flat = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.5, Some(0.25), Some(0.7))
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.5, Some(0.25))
|
||||
.push(0.5, Some(0.7))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(flat.at(0.125).approx_eq(&0.25));
|
||||
assert!(flat.at(0.5).approx_eq(&0.5));
|
||||
@ -157,9 +158,10 @@ fn flat_region() {
|
||||
#[test]
|
||||
fn step() {
|
||||
let step = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.0, Some(0.5), None)
|
||||
.push(1.0, Some(0.5), Some(1.0))
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.0, Some(0.5))
|
||||
.push(1.0, Some(0.5))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(step.at(0.25).approx_eq(&0.0));
|
||||
// At the discontinuity, take the left hand side value
|
||||
@ -170,10 +172,12 @@ fn step() {
|
||||
#[test]
|
||||
fn step_multiple_conflicting() {
|
||||
let step = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.0, Some(0.5), None)
|
||||
.push(0.75, Some(0.5), Some(0.5))
|
||||
.push(1.0, Some(0.5), Some(1.0))
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.0, Some(0.5))
|
||||
.push(0.75, Some(0.5))
|
||||
.push(0.75, Some(0.5))
|
||||
.push(1.0, Some(0.5))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(step.at(0.25).approx_eq(&0.0));
|
||||
assert!(step.at(0.5).approx_eq(&0.0));
|
||||
@ -183,10 +187,10 @@ fn step_multiple_conflicting() {
|
||||
#[test]
|
||||
fn always_monotonic() {
|
||||
let monotonic = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.3, Some(0.5), None)
|
||||
.push(0.4, Some(0.4), None)
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.3, Some(0.5))
|
||||
.push(0.4, Some(0.4))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(monotonic.at(0.25).approx_eq(&0.15));
|
||||
// A discontinuity at x = 0.5 from y = 0.3 to 0.4
|
||||
@ -197,10 +201,11 @@ fn always_monotonic() {
|
||||
#[test]
|
||||
fn always_monotonic_flat() {
|
||||
let monotonic = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.2, Some(0.2), None)
|
||||
.push(0.4, Some(0.1), Some(0.15))
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.2, Some(0.2))
|
||||
.push(0.4, Some(0.1))
|
||||
.push(0.4, Some(0.15))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(monotonic.at(0.2).approx_eq(&0.2));
|
||||
// A discontinuity at x = 0.2 from y = 0.2 to 0.4
|
||||
@ -210,10 +215,11 @@ fn always_monotonic_flat() {
|
||||
#[test]
|
||||
fn always_monotonic_flat_backwards() {
|
||||
let monotonic = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.2, Some(0.2), None)
|
||||
.push(0.3, Some(0.3), Some(0.2))
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.2, Some(0.2))
|
||||
.push(0.3, Some(0.3))
|
||||
.push(0.3, Some(0.2))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(monotonic.at(0.2).approx_eq(&0.2));
|
||||
assert!(monotonic.at(0.3).approx_eq(&0.3));
|
||||
@ -223,8 +229,8 @@ fn always_monotonic_flat_backwards() {
|
||||
#[test]
|
||||
fn input_out_of_bounds() {
|
||||
let oob = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(-0.5), None)
|
||||
.push(1.0, Some(1.5), None)
|
||||
.push(0.0, Some(-0.5))
|
||||
.push(1.0, Some(1.5))
|
||||
.build();
|
||||
assert!(oob.at(-0.5).approx_eq(&0.0));
|
||||
assert!(oob.at(0.0).approx_eq(&0.25));
|
||||
@ -236,14 +242,14 @@ fn input_out_of_bounds() {
|
||||
#[test]
|
||||
fn invalid_builder_input() {
|
||||
let built_from_invalid = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(f32::NEG_INFINITY), None)
|
||||
.push(0.7, Some(f32::NAN), None)
|
||||
.push(1.0, Some(f32::INFINITY), None)
|
||||
.push(0.0, Some(f32::NEG_INFINITY))
|
||||
.push(0.7, Some(f32::NAN))
|
||||
.push(1.0, Some(f32::INFINITY))
|
||||
.build();
|
||||
let equivalent = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(0.7, None, None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(0.7, None)
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
|
||||
assert!(built_from_invalid.at(0.0).approx_eq(&equivalent.at(0.0)));
|
||||
@ -256,8 +262,8 @@ fn invalid_builder_input() {
|
||||
#[test]
|
||||
fn input_domain_not_complete() {
|
||||
let not_covered = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.2, Some(0.2), None)
|
||||
.push(0.8, Some(0.8), None)
|
||||
.push(0.2, Some(0.2))
|
||||
.push(0.8, Some(0.8))
|
||||
.build();
|
||||
assert!(not_covered.at(0.0).approx_eq(&0.0));
|
||||
assert!(not_covered.at(0.5).approx_eq(&0.5));
|
||||
@ -267,20 +273,20 @@ fn input_domain_not_complete() {
|
||||
#[test]
|
||||
fn input_second_negative() {
|
||||
let function = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, None, None)
|
||||
.push(0.0, Some(-0.1), None)
|
||||
.push(0.3, Some(-0.05), None)
|
||||
.push(0.5, None, None)
|
||||
.push(0.2, Some(0.6), None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, None)
|
||||
.push(0.0, Some(-0.1))
|
||||
.push(0.3, Some(-0.05))
|
||||
.push(0.5, None)
|
||||
.push(0.2, Some(0.6))
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
let equivalent = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(0.3, Some(0.0), None)
|
||||
.push(0.5, Some(0.3), None)
|
||||
.push(0.2, Some(0.6), None)
|
||||
.push(1.0, Some(1.0), None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.0, Some(0.0))
|
||||
.push(0.3, Some(0.0))
|
||||
.push(0.5, Some(0.3))
|
||||
.push(0.2, Some(0.6))
|
||||
.push(1.0, Some(1.0))
|
||||
.build();
|
||||
assert!(function.at(-0.1).approx_eq(&equivalent.at(-0.1)));
|
||||
assert!(function.at(0.0).approx_eq(&equivalent.at(0.0)));
|
||||
@ -292,9 +298,9 @@ fn input_second_negative() {
|
||||
#[test]
|
||||
fn input_second_last_above_1() {
|
||||
let function = PiecewiseLinearFunctionBuilder::new()
|
||||
.push(0.0, Some(0.0), None)
|
||||
.push(1.0, Some(2.0), None)
|
||||
.push(1.0, None, None)
|
||||
.push(0.0, Some(0.0))
|
||||
.push(1.0, Some(2.0))
|
||||
.push(1.0, None)
|
||||
.build();
|
||||
assert!(function.at(-0.5).approx_eq(&-0.25));
|
||||
assert!(function.at(0.0).approx_eq(&0.0));
|
||||
|
Loading…
x
Reference in New Issue
Block a user