aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/values/generics/transform.rs
diff options
context:
space:
mode:
authorDelan Azabani <dazabani@igalia.com>2024-02-27 23:39:06 +0800
committerGitHub <noreply@github.com>2024-02-27 15:39:06 +0000
commitfaf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch)
tree4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/values/generics/transform.rs
parentb07505417e629bbb081be9683630f2d7a5f50544 (diff)
downloadservo-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.rs886
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,
-}