diff options
author | Delan Azabani <dazabani@igalia.com> | 2024-02-27 23:39:06 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-27 15:39:06 +0000 |
commit | faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch) | |
tree | 4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/values/generics/transform.rs | |
parent | b07505417e629bbb081be9683630f2d7a5f50544 (diff) | |
download | servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.tar.gz servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.zip |
Move Stylo to its own repo (#31350)
* Remove packages that were moved to external repo
* Add workspace dependencies pointing to 2023-06-14 branch
* Fix servo-tidy.toml errors
* Update commit to include #31346
* Update commit to include servo/stylo#2
* Move css-properties.json lookup to target/doc/stylo
* Remove dependency on vendored mako in favour of pypi dependency
This also removes etc/ci/generate_workflow.py, which has been unused
since at least 9e71bd6a7010d6e5723831696ae0ebe26b47682f.
* Add temporary code to debug Windows test failures
* Fix failures on Windows due to custom target dir
* Update commit to include servo/stylo#3
* Fix license in tests/unit/style/build.rs
* Document how to build with local Stylo in Cargo.toml
Diffstat (limited to 'components/style/values/generics/transform.rs')
-rw-r--r-- | components/style/values/generics/transform.rs | 886 |
1 files changed, 0 insertions, 886 deletions
diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs deleted file mode 100644 index f1fd062b1ee..00000000000 --- a/components/style/values/generics/transform.rs +++ /dev/null @@ -1,886 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -//! Generic types for CSS values that are related to transformations. - -use crate::values::computed::length::Length as ComputedLength; -use crate::values::computed::length::LengthPercentage as ComputedLengthPercentage; -use crate::values::specified::angle::Angle as SpecifiedAngle; -use crate::values::specified::length::Length as SpecifiedLength; -use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage; -use crate::values::{computed, CSSFloat}; -use crate::{Zero, ZeroNoPercent}; -use euclid; -use euclid::default::{Rect, Transform3D}; -use std::fmt::{self, Write}; -use style_traits::{CssWriter, ToCss}; - -/// A generic 2D transformation matrix. -#[allow(missing_docs)] -#[derive( - Clone, - Copy, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[css(comma, function = "matrix")] -#[repr(C)] -pub struct GenericMatrix<T> { - pub a: T, - pub b: T, - pub c: T, - pub d: T, - pub e: T, - pub f: T, -} - -pub use self::GenericMatrix as Matrix; - -#[allow(missing_docs)] -#[cfg_attr(rustfmt, rustfmt_skip)] -#[derive( - Clone, - Copy, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[css(comma, function = "matrix3d")] -#[repr(C)] -pub struct GenericMatrix3D<T> { - pub m11: T, pub m12: T, pub m13: T, pub m14: T, - pub m21: T, pub m22: T, pub m23: T, pub m24: T, - pub m31: T, pub m32: T, pub m33: T, pub m34: T, - pub m41: T, pub m42: T, pub m43: T, pub m44: T, -} - -pub use self::GenericMatrix3D as Matrix3D; - -#[cfg_attr(rustfmt, rustfmt_skip)] -impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> { - #[inline] - fn from(m: Matrix<T>) -> Self { - Transform3D::new( - m.a.into(), m.b.into(), 0.0, 0.0, - m.c.into(), m.d.into(), 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - m.e.into(), m.f.into(), 0.0, 1.0, - ) - } -} - -#[cfg_attr(rustfmt, rustfmt_skip)] -impl<T: Into<f64>> From<Matrix3D<T>> for Transform3D<f64> { - #[inline] - fn from(m: Matrix3D<T>) -> Self { - Transform3D::new( - m.m11.into(), m.m12.into(), m.m13.into(), m.m14.into(), - m.m21.into(), m.m22.into(), m.m23.into(), m.m24.into(), - m.m31.into(), m.m32.into(), m.m33.into(), m.m34.into(), - m.m41.into(), m.m42.into(), m.m43.into(), m.m44.into(), - ) - } -} - -/// A generic transform origin. -#[derive( - Animate, - Clone, - ComputeSquaredDistance, - Copy, - Debug, - MallocSizeOf, - PartialEq, - SpecifiedValueInfo, - ToAnimatedZero, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(C)] -pub struct GenericTransformOrigin<H, V, Depth> { - /// The horizontal origin. - pub horizontal: H, - /// The vertical origin. - pub vertical: V, - /// The depth. - pub depth: Depth, -} - -pub use self::GenericTransformOrigin as TransformOrigin; - -impl<H, V, D> TransformOrigin<H, V, D> { - /// Returns a new transform origin. - pub fn new(horizontal: H, vertical: V, depth: D) -> Self { - Self { - horizontal, - vertical, - depth, - } - } -} - -fn is_same<N: PartialEq>(x: &N, y: &N) -> bool { - x == y -} - -/// A value for the `perspective()` transform function, which is either a -/// non-negative `<length>` or `none`. -#[derive( - Clone, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(C, u8)] -pub enum GenericPerspectiveFunction<L> { - /// `none` - None, - /// A `<length>`. - Length(L), -} - -impl<L> GenericPerspectiveFunction<L> { - /// Returns `f32::INFINITY` or the result of a function on the length value. - pub fn infinity_or(&self, f: impl FnOnce(&L) -> f32) -> f32 { - match *self { - Self::None => f32::INFINITY, - Self::Length(ref l) => f(l), - } - } -} - -pub use self::GenericPerspectiveFunction as PerspectiveFunction; - -#[derive( - Clone, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(C, u8)] -/// A single operation in the list of a `transform` value -pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage> -where - Angle: Zero, - LengthPercentage: Zero + ZeroNoPercent, - Number: PartialEq, -{ - /// Represents a 2D 2x3 matrix. - Matrix(GenericMatrix<Number>), - /// Represents a 3D 4x4 matrix. - Matrix3D(GenericMatrix3D<Number>), - /// A 2D skew. - /// - /// If the second angle is not provided it is assumed zero. - /// - /// Syntax can be skew(angle) or skew(angle, angle) - #[css(comma, function)] - Skew(Angle, #[css(skip_if = "Zero::is_zero")] Angle), - /// skewX(angle) - #[css(function = "skewX")] - SkewX(Angle), - /// skewY(angle) - #[css(function = "skewY")] - SkewY(Angle), - /// translate(x, y) or translate(x) - #[css(comma, function)] - Translate( - LengthPercentage, - #[css(skip_if = "ZeroNoPercent::is_zero_no_percent")] LengthPercentage, - ), - /// translateX(x) - #[css(function = "translateX")] - TranslateX(LengthPercentage), - /// translateY(y) - #[css(function = "translateY")] - TranslateY(LengthPercentage), - /// translateZ(z) - #[css(function = "translateZ")] - TranslateZ(Length), - /// translate3d(x, y, z) - #[css(comma, function = "translate3d")] - Translate3D(LengthPercentage, LengthPercentage, Length), - /// A 2D scaling factor. - /// - /// Syntax can be scale(factor) or scale(factor, factor) - #[css(comma, function)] - Scale(Number, #[css(contextual_skip_if = "is_same")] Number), - /// scaleX(factor) - #[css(function = "scaleX")] - ScaleX(Number), - /// scaleY(factor) - #[css(function = "scaleY")] - ScaleY(Number), - /// scaleZ(factor) - #[css(function = "scaleZ")] - ScaleZ(Number), - /// scale3D(factorX, factorY, factorZ) - #[css(comma, function = "scale3d")] - Scale3D(Number, Number, Number), - /// Describes a 2D Rotation. - /// - /// In a 3D scene `rotate(angle)` is equivalent to `rotateZ(angle)`. - #[css(function)] - Rotate(Angle), - /// Rotation in 3D space around the x-axis. - #[css(function = "rotateX")] - RotateX(Angle), - /// Rotation in 3D space around the y-axis. - #[css(function = "rotateY")] - RotateY(Angle), - /// Rotation in 3D space around the z-axis. - #[css(function = "rotateZ")] - RotateZ(Angle), - /// Rotation in 3D space. - /// - /// Generalization of rotateX, rotateY and rotateZ. - #[css(comma, function = "rotate3d")] - Rotate3D(Number, Number, Number, Angle), - /// Specifies a perspective projection matrix. - /// - /// Part of CSS Transform Module Level 2 and defined at - /// [§ 13.1. 3D Transform Function](https://drafts.csswg.org/css-transforms-2/#funcdef-perspective). - /// - /// The value must be greater than or equal to zero. - #[css(function)] - Perspective(GenericPerspectiveFunction<Length>), - /// A intermediate type for interpolation of mismatched transform lists. - #[allow(missing_docs)] - #[css(comma, function = "interpolatematrix")] - InterpolateMatrix { - from_list: GenericTransform< - GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, - >, - to_list: GenericTransform< - GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, - >, - progress: computed::Percentage, - }, - /// A intermediate type for accumulation of mismatched transform lists. - #[allow(missing_docs)] - #[css(comma, function = "accumulatematrix")] - AccumulateMatrix { - from_list: GenericTransform< - GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, - >, - to_list: GenericTransform< - GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, - >, - count: Integer, - }, -} - -pub use self::GenericTransformOperation as TransformOperation; - -#[derive( - Clone, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(C)] -/// A value of the `transform` property -pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>); - -pub use self::GenericTransform as Transform; - -impl<Angle, Number, Length, Integer, LengthPercentage> - TransformOperation<Angle, Number, Length, Integer, LengthPercentage> -where - Angle: Zero, - LengthPercentage: Zero + ZeroNoPercent, - Number: PartialEq, -{ - /// Check if it is any rotate function. - pub fn is_rotate(&self) -> bool { - use self::TransformOperation::*; - matches!( - *self, - Rotate(..) | Rotate3D(..) | RotateX(..) | RotateY(..) | RotateZ(..) - ) - } - - /// Check if it is any translate function - pub fn is_translate(&self) -> bool { - use self::TransformOperation::*; - match *self { - Translate(..) | Translate3D(..) | TranslateX(..) | TranslateY(..) | TranslateZ(..) => { - true - }, - _ => false, - } - } - - /// Check if it is any scale function - pub fn is_scale(&self) -> bool { - use self::TransformOperation::*; - match *self { - Scale(..) | Scale3D(..) | ScaleX(..) | ScaleY(..) | ScaleZ(..) => true, - _ => false, - } - } -} - -/// Convert a length type into the absolute lengths. -pub trait ToAbsoluteLength { - /// Returns the absolute length as pixel value. - fn to_pixel_length(&self, containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()>; -} - -impl ToAbsoluteLength for SpecifiedLength { - // This returns Err(()) if there is any relative length or percentage. We use this when - // parsing a transform list of DOMMatrix because we want to return a DOM Exception - // if there is relative length. - #[inline] - fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> { - match *self { - SpecifiedLength::NoCalc(len) => len.to_computed_pixel_length_without_context(), - SpecifiedLength::Calc(ref calc) => calc.to_computed_pixel_length_without_context(), - } - } -} - -impl ToAbsoluteLength for SpecifiedLengthPercentage { - // This returns Err(()) if there is any relative length or percentage. We use this when - // parsing a transform list of DOMMatrix because we want to return a DOM Exception - // if there is relative length. - #[inline] - fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> { - use self::SpecifiedLengthPercentage::*; - match *self { - Length(len) => len.to_computed_pixel_length_without_context(), - Calc(ref calc) => calc.to_computed_pixel_length_without_context(), - Percentage(..) => Err(()), - } - } -} - -impl ToAbsoluteLength for ComputedLength { - #[inline] - fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> { - Ok(self.px()) - } -} - -impl ToAbsoluteLength for ComputedLengthPercentage { - #[inline] - fn to_pixel_length(&self, containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> { - Ok(self - .maybe_percentage_relative_to(containing_len) - .ok_or(())? - .px()) - } -} - -/// Support the conversion to a 3d matrix. -pub trait ToMatrix { - /// Check if it is a 3d transform function. - fn is_3d(&self) -> bool; - - /// Return the equivalent 3d matrix. - fn to_3d_matrix( - &self, - reference_box: Option<&Rect<ComputedLength>>, - ) -> Result<Transform3D<f64>, ()>; -} - -/// A little helper to deal with both specified and computed angles. -pub trait ToRadians { - /// Return the radians value as a 64-bit floating point value. - fn radians64(&self) -> f64; -} - -impl ToRadians for computed::angle::Angle { - #[inline] - fn radians64(&self) -> f64 { - computed::angle::Angle::radians64(self) - } -} - -impl ToRadians for SpecifiedAngle { - #[inline] - fn radians64(&self) -> f64 { - computed::angle::Angle::from_degrees(self.degrees()).radians64() - } -} - -impl<Angle, Number, Length, Integer, LoP> ToMatrix - for TransformOperation<Angle, Number, Length, Integer, LoP> -where - Angle: Zero + ToRadians + Copy, - Number: PartialEq + Copy + Into<f32> + Into<f64>, - Length: ToAbsoluteLength, - LoP: Zero + ToAbsoluteLength + ZeroNoPercent, -{ - #[inline] - fn is_3d(&self) -> bool { - use self::TransformOperation::*; - match *self { - Translate3D(..) | TranslateZ(..) | Rotate3D(..) | RotateX(..) | RotateY(..) | - RotateZ(..) | Scale3D(..) | ScaleZ(..) | Perspective(..) | Matrix3D(..) => true, - _ => false, - } - } - - /// If |reference_box| is None, we will drop the percent part from translate because - /// we cannot resolve it without the layout info, for computed TransformOperation. - /// However, for specified TransformOperation, we will return Err(()) if there is any relative - /// lengths because the only caller, DOMMatrix, doesn't accept relative lengths. - #[inline] - fn to_3d_matrix( - &self, - reference_box: Option<&Rect<ComputedLength>>, - ) -> Result<Transform3D<f64>, ()> { - use self::TransformOperation::*; - - let reference_width = reference_box.map(|v| v.size.width); - let reference_height = reference_box.map(|v| v.size.height); - let matrix = match *self { - Rotate3D(ax, ay, az, theta) => { - let theta = theta.radians64(); - let (ax, ay, az, theta) = - get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta); - Transform3D::rotation( - ax as f64, - ay as f64, - az as f64, - euclid::Angle::radians(theta), - ) - }, - RotateX(theta) => { - let theta = euclid::Angle::radians(theta.radians64()); - Transform3D::rotation(1., 0., 0., theta) - }, - RotateY(theta) => { - let theta = euclid::Angle::radians(theta.radians64()); - Transform3D::rotation(0., 1., 0., theta) - }, - RotateZ(theta) | Rotate(theta) => { - let theta = euclid::Angle::radians(theta.radians64()); - Transform3D::rotation(0., 0., 1., theta) - }, - Perspective(ref p) => { - let px = match p { - PerspectiveFunction::None => f32::INFINITY, - PerspectiveFunction::Length(ref p) => p.to_pixel_length(None)?, - }; - create_perspective_matrix(px).cast() - }, - Scale3D(sx, sy, sz) => Transform3D::scale(sx.into(), sy.into(), sz.into()), - Scale(sx, sy) => Transform3D::scale(sx.into(), sy.into(), 1.), - ScaleX(s) => Transform3D::scale(s.into(), 1., 1.), - ScaleY(s) => Transform3D::scale(1., s.into(), 1.), - ScaleZ(s) => Transform3D::scale(1., 1., s.into()), - Translate3D(ref tx, ref ty, ref tz) => { - let tx = tx.to_pixel_length(reference_width)? as f64; - let ty = ty.to_pixel_length(reference_height)? as f64; - Transform3D::translation(tx, ty, tz.to_pixel_length(None)? as f64) - }, - Translate(ref tx, ref ty) => { - let tx = tx.to_pixel_length(reference_width)? as f64; - let ty = ty.to_pixel_length(reference_height)? as f64; - Transform3D::translation(tx, ty, 0.) - }, - TranslateX(ref t) => { - let t = t.to_pixel_length(reference_width)? as f64; - Transform3D::translation(t, 0., 0.) - }, - TranslateY(ref t) => { - let t = t.to_pixel_length(reference_height)? as f64; - Transform3D::translation(0., t, 0.) - }, - TranslateZ(ref z) => Transform3D::translation(0., 0., z.to_pixel_length(None)? as f64), - Skew(theta_x, theta_y) => Transform3D::skew( - euclid::Angle::radians(theta_x.radians64()), - euclid::Angle::radians(theta_y.radians64()), - ), - SkewX(theta) => Transform3D::skew( - euclid::Angle::radians(theta.radians64()), - euclid::Angle::radians(0.), - ), - SkewY(theta) => Transform3D::skew( - euclid::Angle::radians(0.), - euclid::Angle::radians(theta.radians64()), - ), - Matrix3D(m) => m.into(), - Matrix(m) => m.into(), - InterpolateMatrix { .. } | AccumulateMatrix { .. } => { - // TODO: Convert InterpolateMatrix/AccumulateMatrix into a valid Transform3D by - // the reference box and do interpolation on these two Transform3D matrices. - // Both Gecko and Servo don't support this for computing distance, and Servo - // doesn't support animations on InterpolateMatrix/AccumulateMatrix, so - // return an identity matrix. - // Note: DOMMatrix doesn't go into this arm. - Transform3D::identity() - }, - }; - Ok(matrix) - } -} - -impl<T> Transform<T> { - /// `none` - pub fn none() -> Self { - Transform(Default::default()) - } -} - -impl<T: ToMatrix> Transform<T> { - /// Return the equivalent 3d matrix of this transform list. - /// - /// We return a pair: the first one is the transform matrix, and the second one - /// indicates if there is any 3d transform function in this transform list. - #[cfg_attr(rustfmt, rustfmt_skip)] - pub fn to_transform_3d_matrix( - &self, - reference_box: Option<&Rect<ComputedLength>> - ) -> Result<(Transform3D<CSSFloat>, bool), ()> { - Self::components_to_transform_3d_matrix(&self.0, reference_box) - } - - /// Converts a series of components to a 3d matrix. - #[cfg_attr(rustfmt, rustfmt_skip)] - pub fn components_to_transform_3d_matrix( - ops: &[T], - reference_box: Option<&Rect<ComputedLength>>, - ) -> Result<(Transform3D<CSSFloat>, bool), ()> { - let cast_3d_transform = |m: Transform3D<f64>| -> Transform3D<CSSFloat> { - use std::{f32, f64}; - let cast = |v: f64| v.min(f32::MAX as f64).max(f32::MIN as f64) as f32; - Transform3D::new( - cast(m.m11), cast(m.m12), cast(m.m13), cast(m.m14), - cast(m.m21), cast(m.m22), cast(m.m23), cast(m.m24), - cast(m.m31), cast(m.m32), cast(m.m33), cast(m.m34), - cast(m.m41), cast(m.m42), cast(m.m43), cast(m.m44), - ) - }; - - let (m, is_3d) = Self::components_to_transform_3d_matrix_f64(ops, reference_box)?; - Ok((cast_3d_transform(m), is_3d)) - } - - /// Same as Transform::to_transform_3d_matrix but a f64 version. - pub fn to_transform_3d_matrix_f64( - &self, - reference_box: Option<&Rect<ComputedLength>> - ) -> Result<(Transform3D<f64>, bool), ()> { - Self::components_to_transform_3d_matrix_f64(&self.0, reference_box) - } - - fn components_to_transform_3d_matrix_f64( - ops: &[T], - reference_box: Option<&Rect<ComputedLength>>, - ) -> Result<(Transform3D<f64>, bool), ()> { - // We intentionally use Transform3D<f64> during computation to avoid - // error propagation because using f32 to compute triangle functions - // (e.g. in rotation()) is not accurate enough. In Gecko, we also use - // "double" to compute the triangle functions. Therefore, let's use - // Transform3D<f64> during matrix computation and cast it into f32 in - // the end. - let mut transform = Transform3D::<f64>::identity(); - let mut contain_3d = false; - - for operation in ops { - let matrix = operation.to_3d_matrix(reference_box)?; - contain_3d = contain_3d || operation.is_3d(); - transform = matrix.then(&transform); - } - - Ok((transform, contain_3d)) - } -} - -/// Return the transform matrix from a perspective length. -#[inline] -pub fn create_perspective_matrix(d: CSSFloat) -> Transform3D<CSSFloat> { - if d.is_finite() { - Transform3D::perspective(d.max(1.)) - } else { - Transform3D::identity() - } -} - -/// Return the normalized direction vector and its angle for Rotate3D. -pub fn get_normalized_vector_and_angle<T: Zero>( - x: CSSFloat, - y: CSSFloat, - z: CSSFloat, - angle: T, -) -> (CSSFloat, CSSFloat, CSSFloat, T) { - use crate::values::computed::transform::DirectionVector; - use euclid::approxeq::ApproxEq; - 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., T::zero()) - } else { - let vector = vector.robust_normalize(); - (vector.x, vector.y, vector.z, angle) - } -} - -#[derive( - Clone, - Copy, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToAnimatedZero, - ToComputedValue, - ToResolvedValue, - ToShmem, -)] -#[repr(C, u8)] -/// A value of the `Rotate` property -/// -/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum GenericRotate<Number, Angle> { - /// 'none' - None, - /// '<angle>' - Rotate(Angle), - /// '<number>{3} <angle>' - Rotate3D(Number, Number, Number, Angle), -} - -pub use self::GenericRotate as Rotate; - -/// A trait to check if the current 3D vector is parallel to the DirectionVector. -/// This is especially for serialization on Rotate. -pub trait IsParallelTo { - /// Returns true if this is parallel to the vector. - fn is_parallel_to(&self, vector: &computed::transform::DirectionVector) -> bool; -} - -impl<Number, Angle> ToCss for Rotate<Number, Angle> -where - Number: Copy + ToCss + Zero, - Angle: ToCss, - (Number, Number, Number): IsParallelTo, -{ - fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result - where - W: fmt::Write, - { - use crate::values::computed::transform::DirectionVector; - match *self { - Rotate::None => dest.write_str("none"), - Rotate::Rotate(ref angle) => angle.to_css(dest), - Rotate::Rotate3D(x, y, z, ref angle) => { - // If the axis is parallel with the x or y axes, it must serialize as the - // appropriate keyword. If a rotation about the z axis (that is, in 2D) is - // specified, the property must serialize as just an <angle> - // - // https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization - let v = (x, y, z); - let axis = if x.is_zero() && y.is_zero() && z.is_zero() { - // The zero length vector is parallel to every other vector, so - // is_parallel_to() returns true for it. However, it is definitely different - // from x axis, y axis, or z axis, and it's meaningless to perform a rotation - // using that direction vector. So we *have* to serialize it using that same - // vector - we can't simplify to some theoretically parallel axis-aligned - // vector. - None - } else if v.is_parallel_to(&DirectionVector::new(1., 0., 0.)) { - Some("x ") - } else if v.is_parallel_to(&DirectionVector::new(0., 1., 0.)) { - Some("y ") - } else if v.is_parallel_to(&DirectionVector::new(0., 0., 1.)) { - // When we're parallel to the z-axis, we can just serialize the angle. - return angle.to_css(dest); - } else { - None - }; - match axis { - Some(a) => dest.write_str(a)?, - None => { - x.to_css(dest)?; - dest.write_char(' ')?; - y.to_css(dest)?; - dest.write_char(' ')?; - z.to_css(dest)?; - dest.write_char(' ')?; - }, - } - angle.to_css(dest) - }, - } - } -} - -#[derive( - Clone, - Copy, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToAnimatedZero, - ToComputedValue, - ToResolvedValue, - ToShmem, -)] -#[repr(C, u8)] -/// A value of the `Scale` property -/// -/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum GenericScale<Number> { - /// 'none' - None, - /// '<number>{1,3}' - Scale(Number, Number, Number), -} - -pub use self::GenericScale as Scale; - -impl<Number> ToCss for Scale<Number> -where - Number: ToCss + PartialEq + Copy, - f32: From<Number>, -{ - fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result - where - W: fmt::Write, - f32: From<Number>, - { - match *self { - Scale::None => dest.write_str("none"), - Scale::Scale(ref x, ref y, ref z) => { - x.to_css(dest)?; - - let is_3d = f32::from(*z) != 1.0; - if is_3d || x != y { - dest.write_char(' ')?; - y.to_css(dest)?; - } - - if is_3d { - dest.write_char(' ')?; - z.to_css(dest)?; - } - Ok(()) - }, - } - } -} - -#[inline] -fn y_axis_and_z_axis_are_zero<LengthPercentage: Zero + ZeroNoPercent, Length: Zero>( - _: &LengthPercentage, - y: &LengthPercentage, - z: &Length, -) -> bool { - y.is_zero_no_percent() && z.is_zero() -} - -#[derive( - Clone, - Debug, - Deserialize, - MallocSizeOf, - PartialEq, - Serialize, - SpecifiedValueInfo, - ToAnimatedZero, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(C, u8)] -/// A value of the `translate` property -/// -/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization: -/// -/// If a 2d translation is specified, the property must serialize with only one -/// or two values (per usual, if the second value is 0px, the default, it must -/// be omitted when serializing; however if 0% is the second value, it is included). -/// -/// If a 3d translation is specified and the value can be expressed as 2d, we treat as 2d and -/// serialize accoringly. Otherwise, we serialize all three values. -/// https://github.com/w3c/csswg-drafts/issues/3305 -/// -/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum GenericTranslate<LengthPercentage, Length> -where - LengthPercentage: Zero + ZeroNoPercent, - Length: Zero, -{ - /// 'none' - None, - /// <length-percentage> [ <length-percentage> <length>? ]? - Translate( - LengthPercentage, - #[css(contextual_skip_if = "y_axis_and_z_axis_are_zero")] LengthPercentage, - #[css(skip_if = "Zero::is_zero")] Length, - ), -} - -pub use self::GenericTranslate as Translate; - -#[allow(missing_docs)] -#[derive( - Clone, - Copy, - Debug, - MallocSizeOf, - Parse, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[repr(u8)] -pub enum TransformStyle { - Flat, - #[css(keyword = "preserve-3d")] - Preserve3d, -} |