aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2023-05-22 15:05:17 +0200
committerOriol Brufau <obrufau@igalia.com>2023-05-24 18:32:43 +0200
commitfa840e166636d1f4529ac8dbaef6fa326d07289b (patch)
tree59d1216482f67be25ea61a071eed9f98d7d65d52
parentce45f68d9c07b34cb017ec0fe89de542f0771744 (diff)
downloadservo-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.rs30
-rw-r--r--components/style/values/computed/transform.rs5
-rw-r--r--components/style/values/generics/transform.rs46
-rw-r--r--components/style/values/specified/transform.rs10
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(()),
};