diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2023-05-22 15:05:17 +0200 |
---|---|---|
committer | Oriol Brufau <obrufau@igalia.com> | 2023-05-24 18:32:43 +0200 |
commit | fa840e166636d1f4529ac8dbaef6fa326d07289b (patch) | |
tree | 59d1216482f67be25ea61a071eed9f98d7d65d52 | |
parent | ce45f68d9c07b34cb017ec0fe89de542f0771744 (diff) | |
download | servo-fa840e166636d1f4529ac8dbaef6fa326d07289b.tar.gz servo-fa840e166636d1f4529ac8dbaef6fa326d07289b.zip |
style: Implement transform: perspective(none)
Differential Revision: https://phabricator.services.mozilla.com/D123350
-rw-r--r-- | components/style/values/animated/transform.rs | 30 | ||||
-rw-r--r-- | components/style/values/computed/transform.rs | 5 | ||||
-rw-r--r-- | components/style/values/generics/transform.rs | 46 | ||||
-rw-r--r-- | components/style/values/specified/transform.rs | 10 |
4 files changed, 72 insertions, 19 deletions
diff --git a/components/style/values/animated/transform.rs b/components/style/values/animated/transform.rs index 57d1900a0f9..598bf9b59a7 100644 --- a/components/style/values/animated/transform.rs +++ b/components/style/values/animated/transform.rs @@ -1105,8 +1105,8 @@ impl Animate for ComputedTransformOperation { // interpolated as defined in section Interpolation of // Matrices afterwards. // - let from = create_perspective_matrix(fd.px()); - let to = create_perspective_matrix(td.px()); + let from = create_perspective_matrix(fd.infinity_or(|l| l.px())); + let to = create_perspective_matrix(td.infinity_or(|l| l.px())); let interpolated = Matrix3D::from(from).animate(&Matrix3D::from(to), procedure)?; @@ -1115,15 +1115,17 @@ impl Animate for ComputedTransformOperation { // Clamp results outside of the -1 to 0 range so that we get perspective // function values between 1 and infinity. let used_value = if perspective_z >= 0. { - std::f32::INFINITY - } else if perspective_z <= -1. { - 1. + transform::PerspectiveFunction::None } else { - -1. / perspective_z + transform::PerspectiveFunction::Length(CSSPixelLength::new( + if perspective_z <= -1. { + 1. + } else { + -1. / perspective_z + } + )) }; - Ok(TransformOperation::Perspective(CSSPixelLength::new( - used_value, - ))) + Ok(TransformOperation::Perspective(used_value)) }, _ if self.is_translate() && other.is_translate() => self .to_translate_3d() @@ -1202,14 +1204,18 @@ impl ComputeSquaredDistance for ComputedTransformOperation { ( &TransformOperation::Perspective(ref fd), &TransformOperation::Perspective(ref td), - ) => fd.compute_squared_distance(td), + ) => { + fd.infinity_or(|l| l.px()) + .compute_squared_distance(&td.infinity_or(|l| l.px())) + }, (&TransformOperation::Perspective(ref p), &TransformOperation::Matrix3D(ref m)) | (&TransformOperation::Matrix3D(ref m), &TransformOperation::Perspective(ref p)) => { // FIXME(emilio): Is this right? Why interpolating this with // Perspective but not with anything else? let mut p_matrix = Matrix3D::identity(); - if p.px() >= 0. { - p_matrix.m34 = -1. / p.px().max(1.); + let p = p.infinity_or(|p| p.px()); + if p >= 0. { + p_matrix.m34 = -1. / p.max(1.); } p_matrix.compute_squared_distance(&m) }, diff --git a/components/style/values/computed/transform.rs b/components/style/values/computed/transform.rs index 431893973f5..5eafa0cd627 100644 --- a/components/style/values/computed/transform.rs +++ b/components/style/values/computed/transform.rs @@ -24,6 +24,9 @@ pub type Transform = generic::GenericTransform<TransformOperation>; pub type TransformOrigin = generic::GenericTransformOrigin<LengthPercentage, LengthPercentage, Length>; +/// The computed value of the `perspective()` transform function. +pub type PerspectiveFunction = generic::PerspectiveFunction<Length>; + /// A vector to represent the direction vector (rotate axis) for Rotate3D. pub type DirectionVector = Vector3D<CSSFloat>; @@ -517,7 +520,7 @@ impl ToAnimatedZero for TransformOperation { Ok(generic::TransformOperation::Rotate(Angle::zero())) }, generic::TransformOperation::Perspective(_) => Ok( - generic::TransformOperation::Perspective(Length::new(std::f32::INFINITY)) + generic::TransformOperation::Perspective(generic::PerspectiveFunction::None) ), generic::TransformOperation::AccumulateMatrix { .. } | generic::TransformOperation::InterpolateMatrix { .. } => { diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 95f5e999b77..92987f89fe4 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -141,6 +141,41 @@ 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 => std::f32::INFINITY, + Self::Length(ref l) => f(l), + } + } +} + +pub use self::GenericPerspectiveFunction as PerspectiveFunction; + #[derive( Clone, Debug, @@ -240,7 +275,7 @@ where /// /// The value must be greater than or equal to zero. #[css(function)] - Perspective(Length), + Perspective(GenericPerspectiveFunction<Length>), /// A intermediate type for interpolation of mismatched transform lists. #[allow(missing_docs)] #[css(comma, function = "interpolatematrix")] @@ -469,9 +504,12 @@ where let theta = euclid::Angle::radians(theta.radians64()); Transform3D::rotation(0., 0., 1., theta) }, - Perspective(ref d) => { - let m = create_perspective_matrix(d.to_pixel_length(None)?); - m.cast() + Perspective(ref p) => { + let px = match p { + PerspectiveFunction::None => std::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.), diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index ba2be4ee8d3..c10b79a089b 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -238,8 +238,14 @@ impl Transform { Ok(generic::TransformOperation::SkewY(theta)) }, "perspective" => { - let d = specified::Length::parse_non_negative(context, input)?; - Ok(generic::TransformOperation::Perspective(d)) + let p = match input.try_parse(|input| specified::Length::parse_non_negative(context, input)) { + Ok(p) => generic::PerspectiveFunction::Length(p), + Err(..) => { + input.expect_ident_matching("none")?; + generic::PerspectiveFunction::None + } + }; + Ok(generic::TransformOperation::Perspective(p)) }, _ => Err(()), }; |