Bug 1390039 - Part 2: Use DirectionVector as an alias of euclid::Vector3D<f32>.
Therefore, we can reuse the methods of Vector3D, instead of implementing
similar ones.
MozReview-Commit-ID: BNqjiPyhMxB
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -1136,17 +1136,17 @@ impl ToAnimatedZero for TransformOperati
ty.to_animated_zero()?,
tz.to_animated_zero()?,
))
},
TransformOperation::Scale(..) => {
Ok(TransformOperation::Scale(1.0, 1.0, 1.0))
},
TransformOperation::Rotate(x, y, z, a) => {
- let (x, y, z, _) = DirectionVector::get_normalized_vector_and_angle(x, y, z, a);
+ let (x, y, z, _) = TransformList::get_normalized_vector_and_angle(x, y, z, a);
Ok(TransformOperation::Rotate(x, y, z, Angle::zero()))
},
TransformOperation::Perspective(..) |
TransformOperation::AccumulateMatrix { .. } |
TransformOperation::InterpolateMatrix { .. } => {
// Perspective: We convert a perspective function into an equivalent
// ComputedMatrix, and then decompose/interpolate/recompose these matrices.
// AccumulateMatrix/InterpolateMatrix: We do interpolation on
@@ -1214,19 +1214,19 @@ impl Animate for TransformOperation {
animate_multiplicative_factor(*fz, *tz, procedure)?,
))
},
(
&TransformOperation::Rotate(fx, fy, fz, fa),
&TransformOperation::Rotate(tx, ty, tz, ta),
) => {
let (fx, fy, fz, fa) =
- DirectionVector::get_normalized_vector_and_angle(fx, fy, fz, fa);
+ TransformList::get_normalized_vector_and_angle(fx, fy, fz, fa);
let (tx, ty, tz, ta) =
- DirectionVector::get_normalized_vector_and_angle(tx, ty, tz, ta);
+ TransformList::get_normalized_vector_and_angle(tx, ty, tz, ta);
if (fx, fy, fz) == (tx, ty, tz) {
let ia = fa.animate(&ta, procedure)?;
Ok(TransformOperation::Rotate(fx, fy, fz, ia))
} else {
let matrix_f = rotate_to_matrix(fx, fy, fz, fa);
let matrix_t = rotate_to_matrix(tx, ty, tz, ta);
Ok(TransformOperation::Matrix(
matrix_f.animate(&matrix_t, procedure)?,
@@ -1633,30 +1633,30 @@ pub struct MatrixDecomposed3D {
/// The quaternion used to represent the rotation.
pub quaternion: Quaternion,
}
impl Quaternion {
/// Return a quaternion from a unit direction vector and angle (unit: radian).
#[inline]
fn from_direction_and_angle(vector: &DirectionVector, angle: f64) -> Self {
- debug_assert!((vector.length() - 1.).abs() < 0.0001f64,
- "Only accept an unit direction vector to create a quaternion");
+ debug_assert!((vector.length() - 1.).abs() < 0.0001,
+ "Only accept an unit direction vector to create a quaternion");
// Reference:
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
//
// if the direction axis is (x, y, z) = xi + yj + zk,
// and the angle is |theta|, this formula can be done using
// an extension of Euler's formula:
// q = cos(theta/2) + (xi + yj + zk)(sin(theta/2))
// = cos(theta/2) +
// x*sin(theta/2)i + y*sin(theta/2)j + z*sin(theta/2)k
- Quaternion(vector.0.x * (angle / 2.).sin(),
- vector.0.y * (angle / 2.).sin(),
- vector.0.z * (angle / 2.).sin(),
+ Quaternion(vector.x as f64 * (angle / 2.).sin(),
+ vector.y as f64 * (angle / 2.).sin(),
+ vector.z as f64 * (angle / 2.).sin(),
(angle / 2.).cos())
}
/// Calculate the dot product.
#[inline]
fn dot(&self, other: &Self) -> f64 {
self.0 * other.0 + self.1 * other.1 + self.2 * other.2 + self.3 * other.3
}
@@ -2333,19 +2333,19 @@ impl ComputeSquaredDistance for Transfor
fz.compute_squared_distance(&tz)?,
)
},
(
&TransformOperation::Rotate(fx, fy, fz, fa),
&TransformOperation::Rotate(tx, ty, tz, ta),
) => {
let (fx, fy, fz, angle1) =
- DirectionVector::get_normalized_vector_and_angle(fx, fy, fz, fa);
+ TransformList::get_normalized_vector_and_angle(fx, fy, fz, fa);
let (tx, ty, tz, angle2) =
- DirectionVector::get_normalized_vector_and_angle(tx, ty, tz, ta);
+ TransformList::get_normalized_vector_and_angle(tx, ty, tz, ta);
if (fx, fy, fz) == (tx, ty, tz) {
angle1.compute_squared_distance(&angle2)
} else {
let v1 = DirectionVector::new(fx, fy, fz);
let v2 = DirectionVector::new(tx, ty, tz);
let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
q1.compute_squared_distance(&q2)
--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -1,89 +1,46 @@
/* 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/. */
//! Computed types for CSS values that are related to transformations.
use app_units::Au;
-use euclid::{Point3D, Radians, Rect, Transform3D};
+use euclid::{Radians, Rect, Transform3D, Vector3D};
use properties::longhands::transform::computed_value::{ComputedOperation, ComputedMatrix};
use properties::longhands::transform::computed_value::T as TransformList;
use std::f32;
use super::CSSFloat;
use values::computed::{Angle, Length, LengthOrPercentage, Number, Percentage};
use values::generics::transform::TimingFunction as GenericTimingFunction;
use values::generics::transform::TransformOrigin as GenericTransformOrigin;
/// The computed value of a CSS `<transform-origin>`
pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPercentage, Length>;
/// A computed timing function.
pub type TimingFunction = GenericTimingFunction<u32, Number>;
+/// A vector to represent the direction vector (rotate axis) for Rotate3D.
+pub type DirectionVector = Vector3D<CSSFloat>;
+
impl TransformOrigin {
/// Returns the initial computed value for `transform-origin`.
#[inline]
pub fn initial_value() -> Self {
Self::new(
LengthOrPercentage::Percentage(Percentage(0.5)),
LengthOrPercentage::Percentage(Percentage(0.5)),
Length::from_px(0),
)
}
}
-/// A wrapper of Point3D to represent the direction vector (rotate axis) for Rotate3D.
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct DirectionVector(pub Point3D<f64>);
-
-impl DirectionVector {
- /// Create a DirectionVector.
- #[inline]
- pub fn new(x: f32, y: f32, z: f32) -> Self {
- DirectionVector(Point3D::new(x as f64, y as f64, z as f64))
- }
-
- /// Return the normalized direction vector.
- #[inline]
- pub fn normalize(&mut self) -> bool {
- let len = self.length();
- if len > 0. {
- self.0.x = self.0.x / len;
- self.0.y = self.0.y / len;
- self.0.z = self.0.z / len;
- true
- } else {
- false
- }
- }
-
- /// Get the length of this vector.
- #[inline]
- pub fn length(&self) -> f64 {
- self.0.to_array().iter().fold(0f64, |sum, v| sum + v * v).sqrt()
- }
-
- /// Return the normalized direction vector and its angle.
- // A direction vector that cannot be normalized, such as [0,0,0], will cause the
- // rotation to not be applied. i.e. Use an identity matrix or rotate3d(0, 0, 1, 0).
- pub fn get_normalized_vector_and_angle(x: f32, y: f32, z: f32, angle: Angle)
- -> (f32, f32, f32, Angle) {
- let mut vector = DirectionVector::new(x, y, z);
- if vector.normalize() {
- (vector.0.x as f32, vector.0.y as f32, vector.0.z as f32, angle)
- } else {
- (0., 0., 1., Angle::zero())
- }
- }
-}
-
impl From<ComputedMatrix> for Transform3D<CSSFloat> {
#[inline]
fn from(m: ComputedMatrix) -> Self {
Transform3D::row_major(
m.m11, m.m12, m.m13, m.m14,
m.m21, m.m22, m.m23, m.m24,
m.m31, m.m32, m.m33, m.m34,
m.m41, m.m42, m.m43, m.m44)
@@ -118,22 +75,19 @@ impl TransformList {
LengthOrPercentage::Percentage(_) => 0.,
LengthOrPercentage::Calc(calc) => calc.length().to_f32_px(),
}
};
for operation in list {
let matrix = match *operation {
ComputedOperation::Rotate(ax, ay, az, theta) => {
- // https://www.w3.org/TR/css-transforms-1/#funcdef-rotate3d
- // A direction vector that cannot be normalized, such as [0, 0, 0], will cause
- // the rotation to not be applied, so we use identity matrix in this case.
let theta = Angle::from_radians(2.0f32 * f32::consts::PI - theta.radians());
let (ax, ay, az, theta) =
- DirectionVector::get_normalized_vector_and_angle(ax, ay, az, theta);
+ Self::get_normalized_vector_and_angle(ax, ay, az, theta);
Transform3D::create_rotation(ax, ay, az, Radians::new(theta.radians()))
}
ComputedOperation::Perspective(d) => {
let d = d.to_f32_px();
if d > 0. {
Transform3D::create_perspective(d)
} else {
Transform3D::identity()
@@ -180,9 +134,26 @@ impl TransformList {
}
};
transform = transform.pre_mul(&matrix);
}
Some(transform)
}
+
+ /// Return the normalized direction vector and its angle for Rotate3D.
+ pub fn get_normalized_vector_and_angle(x: f32, y: f32, z: f32, angle: Angle)
+ -> (f32, f32, f32, Angle) {
+ use euclid::approxeq::ApproxEq;
+ use euclid::num::Zero;
+ let vector = DirectionVector::new(x, y, z);
+ if vector.square_length().approx_eq(&f32::zero()) {
+ // https://www.w3.org/TR/css-transforms-1/#funcdef-rotate3d
+ // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the
+ // rotation to not be applied, so we use identity matrix (i.e. rotate3d(0, 0, 1, 0)).
+ (0., 0., 1., Angle::zero())
+ } else {
+ let vector = vector.normalize();
+ (vector.x, vector.y, vector.z, angle)
+ }
+ }
}