mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: linear(...)
easing: Implement right-continuous behaviour on discontinuities
Differential Revision: https://phabricator.services.mozilla.com/D152078
This commit is contained in:
parent
2a1e89468a
commit
c296356a8c
1 changed files with 18 additions and 15 deletions
|
@ -75,16 +75,24 @@ impl PiecewiseLinearFunction {
|
||||||
next: PiecewiseLinearFunctionEntry,
|
next: PiecewiseLinearFunctionEntry,
|
||||||
asymptote: &PiecewiseLinearFunctionEntry,
|
asymptote: &PiecewiseLinearFunctionEntry,
|
||||||
) -> ValueType {
|
) -> ValueType {
|
||||||
// Line is vertical, or the two points are identical. Avoid infinite slope by pretending
|
// Short circuit if the x is on prev or next.
|
||||||
// the line is flat.
|
// `next` point is preferred as per spec.
|
||||||
|
if x.approx_eq(&next.x) {
|
||||||
|
return next.y;
|
||||||
|
}
|
||||||
|
if x.approx_eq(&prev.x) {
|
||||||
|
return prev.y;
|
||||||
|
}
|
||||||
|
// Avoid division by zero.
|
||||||
if prev.x.approx_eq(&next.x) {
|
if prev.x.approx_eq(&next.x) {
|
||||||
return asymptote.y;
|
return next.y;
|
||||||
}
|
}
|
||||||
let slope = (next.y - prev.y) / (next.x - prev.x);
|
let slope = (next.y - prev.y) / (next.x - prev.x);
|
||||||
return slope * (x - asymptote.x) + asymptote.y;
|
return slope * (x - asymptote.x) + asymptote.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the y value of the piecewise linear function given the x value.
|
/// Get the y value of the piecewise linear function given the x value, as per
|
||||||
|
/// https://drafts.csswg.org/css-easing-2/#linear-easing-function-output
|
||||||
pub fn at(&self, x: ValueType) -> ValueType {
|
pub fn at(&self, x: ValueType) -> ValueType {
|
||||||
if !x.is_finite() {
|
if !x.is_finite() {
|
||||||
return if x > 0.0 { 1.0 } else { 0.0 };
|
return if x > 0.0 { 1.0 } else { 0.0 };
|
||||||
|
@ -108,24 +116,19 @@ impl PiecewiseLinearFunction {
|
||||||
}
|
}
|
||||||
let mut rev_iter = self.entries.iter().rev();
|
let mut rev_iter = self.entries.iter().rev();
|
||||||
let last = rev_iter.next().unwrap();
|
let last = rev_iter.next().unwrap();
|
||||||
if x > last.x {
|
if x >= last.x {
|
||||||
let second_last = rev_iter.next().unwrap();
|
let second_last = rev_iter.next().unwrap();
|
||||||
return Self::interpolate(x, *second_last, *last, last);
|
return Self::interpolate(x, *second_last, *last, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we know the input sits within the domain explicitly defined by our function.
|
// Now we know the input sits within the domain explicitly defined by our function.
|
||||||
for (prev, next) in self.entries.iter().tuple_windows() {
|
for (point_b, point_a) in self.entries.iter().rev().tuple_windows() {
|
||||||
if x > next.x {
|
// Need to let point A be the _last_ point where its x is less than the input x,
|
||||||
|
// hence the reverse traversal.
|
||||||
|
if x < point_a.x {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Prefer left hand side value
|
return Self::interpolate(x, *point_a, *point_b, point_a);
|
||||||
if x.approx_eq(&prev.x) {
|
|
||||||
return prev.y;
|
|
||||||
}
|
|
||||||
if x.approx_eq(&next.x) {
|
|
||||||
return next.y;
|
|
||||||
}
|
|
||||||
return Self::interpolate(x, *prev, *next, prev);
|
|
||||||
}
|
}
|
||||||
unreachable!("Input is supposed to be within the entries' min & max!");
|
unreachable!("Input is supposed to be within the entries' min & max!");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue