mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
layout: Implement CSS transitions per CSS-TRANSITIONS § 2.
Transition events are not yet supported, and the only animatable properties are `top`, `right`, `bottom`, and `left`. However, all other features of transitions are supported. There are no automated tests at present because I'm not sure how best to test it, but three manual tests are included.
This commit is contained in:
parent
c1cc31b9d6
commit
66dd8c8a6c
31 changed files with 1603 additions and 224 deletions
116
components/util/bezier.rs
Normal file
116
components/util/bezier.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Parametric Bézier curves.
|
||||
//!
|
||||
//! This is based on `WebCore/platform/graphics/UnitBezier.h` in WebKit.
|
||||
|
||||
use geom::point::Point2D;
|
||||
use std::num::Float;
|
||||
|
||||
const NEWTON_METHOD_ITERATIONS: u8 = 8;
|
||||
|
||||
pub struct Bezier {
|
||||
ax: f64,
|
||||
bx: f64,
|
||||
cx: f64,
|
||||
ay: f64,
|
||||
by: f64,
|
||||
cy: f64,
|
||||
}
|
||||
|
||||
impl Bezier {
|
||||
#[inline]
|
||||
pub fn new(p1: Point2D<f64>, p2: Point2D<f64>) -> Bezier {
|
||||
let cx = 3.0 * p1.x;
|
||||
let bx = 3.0 * (p2.x - p1.x) - cx;
|
||||
|
||||
let cy = 3.0 * p1.y;
|
||||
let by = 3.0 * (p2.y - p1.y) - cy;
|
||||
|
||||
Bezier {
|
||||
ax: 1.0 - cx - bx,
|
||||
bx: bx,
|
||||
cx: cx,
|
||||
ay: 1.0 - cy - by,
|
||||
by: by,
|
||||
cy: cy,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_curve_x(&self, t: f64) -> f64 {
|
||||
// ax * t^3 + bx * t^2 + cx * t
|
||||
((self.ax * t + self.bx) * t + self.cx) * t
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_curve_y(&self, t: f64) -> f64 {
|
||||
((self.ay * t + self.by) * t + self.cy) * t
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_curve_derivative_x(&self, t: f64) -> f64 {
|
||||
(3.0 * self.ax * t + 2.0 * self.bx) * t + self.cx
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn solve_curve_x(&self, x: f64, epsilon: f64) -> f64 {
|
||||
// Fast path: Use Newton's method.
|
||||
let mut t = x;
|
||||
for _ in range(0, NEWTON_METHOD_ITERATIONS) {
|
||||
let x2 = self.sample_curve_x(t);
|
||||
if x2.approx_eq(x, epsilon) {
|
||||
return t
|
||||
}
|
||||
let dx = self.sample_curve_derivative_x(t);
|
||||
if dx.approx_eq(0.0, 1e-6) {
|
||||
break
|
||||
}
|
||||
t -= (x2 - x) / dx;
|
||||
}
|
||||
|
||||
// Slow path: Use bisection.
|
||||
let (mut lo, mut hi, mut t) = (0.0, 1.0, x);
|
||||
|
||||
if t < lo {
|
||||
return lo
|
||||
}
|
||||
if t > hi {
|
||||
return hi
|
||||
}
|
||||
|
||||
while lo < hi {
|
||||
let x2 = self.sample_curve_x(t);
|
||||
if x2.approx_eq(x, epsilon) {
|
||||
return t
|
||||
}
|
||||
if x > x2 {
|
||||
lo = t
|
||||
} else {
|
||||
hi = t
|
||||
}
|
||||
t = (hi - lo) / 2.0 + lo
|
||||
}
|
||||
|
||||
t
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn solve(&self, x: f64, epsilon: f64) -> f64 {
|
||||
self.sample_curve_y(self.solve_curve_x(x, epsilon))
|
||||
}
|
||||
}
|
||||
|
||||
trait ApproxEq {
|
||||
fn approx_eq(self, value: Self, epsilon: Self) -> bool;
|
||||
}
|
||||
|
||||
impl ApproxEq for f64 {
|
||||
#[inline]
|
||||
fn approx_eq(self, value: f64, epsilon: f64) -> bool {
|
||||
(self - value).abs() < epsilon
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ pub use selectors::smallvec;
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod bezier;
|
||||
pub mod cache;
|
||||
pub mod cursor;
|
||||
pub mod debug_utils;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue