1use crate::derives::*;
8use crate::values::computed::length::Length as ComputedLength;
9use crate::values::computed::length::LengthPercentage as ComputedLengthPercentage;
10use crate::values::specified::angle::Angle as SpecifiedAngle;
11use crate::values::specified::length::Length as SpecifiedLength;
12use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage;
13use crate::values::{computed, CSSFloat};
14use crate::{Zero, ZeroNoPercent};
15use euclid::default::{Rect, Transform3D};
16use std::fmt::{self, Write};
17use std::ops::Neg;
18use style_traits::{CssWriter, ToCss};
19
20#[allow(missing_docs)]
22#[derive(
23 Clone,
24 Copy,
25 Debug,
26 Deserialize,
27 MallocSizeOf,
28 PartialEq,
29 Serialize,
30 SpecifiedValueInfo,
31 ToAnimatedValue,
32 ToComputedValue,
33 ToCss,
34 ToResolvedValue,
35 ToShmem,
36)]
37#[css(comma, function = "matrix")]
38#[repr(C)]
39pub struct GenericMatrix<T> {
40 pub a: T,
41 pub b: T,
42 pub c: T,
43 pub d: T,
44 pub e: T,
45 pub f: T,
46}
47
48pub use self::GenericMatrix as Matrix;
49
50#[allow(missing_docs)]
51#[cfg_attr(rustfmt, rustfmt_skip)]
52#[derive(
53 Clone,
54 Copy,
55 Debug,
56 Deserialize,
57 MallocSizeOf,
58 PartialEq,
59 Serialize,
60 SpecifiedValueInfo,
61 ToAnimatedValue,
62 ToComputedValue,
63 ToCss,
64 ToResolvedValue,
65 ToShmem,
66)]
67#[css(comma, function = "matrix3d")]
68#[repr(C)]
69pub struct GenericMatrix3D<T> {
70 pub m11: T, pub m12: T, pub m13: T, pub m14: T,
71 pub m21: T, pub m22: T, pub m23: T, pub m24: T,
72 pub m31: T, pub m32: T, pub m33: T, pub m34: T,
73 pub m41: T, pub m42: T, pub m43: T, pub m44: T,
74}
75
76pub use self::GenericMatrix3D as Matrix3D;
77
78#[cfg_attr(rustfmt, rustfmt_skip)]
79impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
80 #[inline]
81 fn from(m: Matrix<T>) -> Self {
82 Transform3D::new(
83 m.a.into(), m.b.into(), 0.0, 0.0,
84 m.c.into(), m.d.into(), 0.0, 0.0,
85 0.0, 0.0, 1.0, 0.0,
86 m.e.into(), m.f.into(), 0.0, 1.0,
87 )
88 }
89}
90
91#[cfg_attr(rustfmt, rustfmt_skip)]
92impl<T: Into<f64>> From<Matrix3D<T>> for Transform3D<f64> {
93 #[inline]
94 fn from(m: Matrix3D<T>) -> Self {
95 Transform3D::new(
96 m.m11.into(), m.m12.into(), m.m13.into(), m.m14.into(),
97 m.m21.into(), m.m22.into(), m.m23.into(), m.m24.into(),
98 m.m31.into(), m.m32.into(), m.m33.into(), m.m34.into(),
99 m.m41.into(), m.m42.into(), m.m43.into(), m.m44.into(),
100 )
101 }
102}
103
104#[derive(
106 Animate,
107 Clone,
108 ComputeSquaredDistance,
109 Copy,
110 Debug,
111 MallocSizeOf,
112 PartialEq,
113 SpecifiedValueInfo,
114 ToAnimatedValue,
115 ToAnimatedZero,
116 ToComputedValue,
117 ToCss,
118 ToResolvedValue,
119 ToShmem,
120 ToTyped,
121)]
122#[repr(C)]
123#[typed(todo_derive_fields)]
124pub struct GenericTransformOrigin<H, V, Depth> {
125 pub horizontal: H,
127 pub vertical: V,
129 pub depth: Depth,
131}
132
133pub use self::GenericTransformOrigin as TransformOrigin;
134
135impl<H, V, D> TransformOrigin<H, V, D> {
136 pub fn new(horizontal: H, vertical: V, depth: D) -> Self {
138 Self {
139 horizontal,
140 vertical,
141 depth,
142 }
143 }
144}
145
146fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
147 x == y
148}
149
150#[derive(
153 Clone,
154 Debug,
155 Deserialize,
156 MallocSizeOf,
157 PartialEq,
158 Serialize,
159 SpecifiedValueInfo,
160 ToAnimatedValue,
161 ToComputedValue,
162 ToCss,
163 ToResolvedValue,
164 ToShmem,
165)]
166#[repr(C, u8)]
167pub enum GenericPerspectiveFunction<L> {
168 None,
170 Length(L),
172}
173
174impl<L> GenericPerspectiveFunction<L> {
175 pub fn infinity_or(&self, f: impl FnOnce(&L) -> f32) -> f32 {
177 match *self {
178 Self::None => f32::INFINITY,
179 Self::Length(ref l) => f(l),
180 }
181 }
182}
183
184pub use self::GenericPerspectiveFunction as PerspectiveFunction;
185
186#[derive(
187 Clone,
188 Debug,
189 Deserialize,
190 MallocSizeOf,
191 PartialEq,
192 Serialize,
193 SpecifiedValueInfo,
194 ToAnimatedValue,
195 ToComputedValue,
196 ToCss,
197 ToResolvedValue,
198 ToShmem,
199)]
200#[repr(C, u8)]
201pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>
203where
204 Angle: Zero,
205 LengthPercentage: Zero + ZeroNoPercent,
206 Number: PartialEq,
207{
208 Matrix(GenericMatrix<Number>),
210 Matrix3D(GenericMatrix3D<Number>),
212 #[css(comma, function)]
218 Skew(Angle, #[css(skip_if = "Zero::is_zero")] Angle),
219 #[css(function = "skewX")]
221 SkewX(Angle),
222 #[css(function = "skewY")]
224 SkewY(Angle),
225 #[css(comma, function)]
227 Translate(
228 LengthPercentage,
229 #[css(skip_if = "ZeroNoPercent::is_zero_no_percent")] LengthPercentage,
230 ),
231 #[css(function = "translateX")]
233 TranslateX(LengthPercentage),
234 #[css(function = "translateY")]
236 TranslateY(LengthPercentage),
237 #[css(function = "translateZ")]
239 TranslateZ(Length),
240 #[css(comma, function = "translate3d")]
242 Translate3D(LengthPercentage, LengthPercentage, Length),
243 #[css(comma, function)]
247 Scale(Number, #[css(contextual_skip_if = "is_same")] Number),
248 #[css(function = "scaleX")]
250 ScaleX(Number),
251 #[css(function = "scaleY")]
253 ScaleY(Number),
254 #[css(function = "scaleZ")]
256 ScaleZ(Number),
257 #[css(comma, function = "scale3d")]
259 Scale3D(Number, Number, Number),
260 #[css(function)]
264 Rotate(Angle),
265 #[css(function = "rotateX")]
267 RotateX(Angle),
268 #[css(function = "rotateY")]
270 RotateY(Angle),
271 #[css(function = "rotateZ")]
273 RotateZ(Angle),
274 #[css(comma, function = "rotate3d")]
278 Rotate3D(Number, Number, Number, Angle),
279 #[css(function)]
286 Perspective(GenericPerspectiveFunction<Length>),
287 #[allow(missing_docs)]
289 #[css(comma, function = "interpolatematrix")]
290 InterpolateMatrix {
291 from_list: GenericTransform<
292 GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
293 >,
294 to_list: GenericTransform<
295 GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
296 >,
297 progress: computed::Percentage,
298 },
299 #[allow(missing_docs)]
301 #[css(comma, function = "accumulatematrix")]
302 AccumulateMatrix {
303 from_list: GenericTransform<
304 GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
305 >,
306 to_list: GenericTransform<
307 GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
308 >,
309 count: Integer,
310 },
311}
312
313pub use self::GenericTransformOperation as TransformOperation;
314
315#[derive(
316 Clone,
317 Debug,
318 Deserialize,
319 MallocSizeOf,
320 PartialEq,
321 Serialize,
322 SpecifiedValueInfo,
323 ToAnimatedValue,
324 ToComputedValue,
325 ToCss,
326 ToResolvedValue,
327 ToShmem,
328 ToTyped,
329)]
330#[repr(C)]
331#[typed(todo_derive_fields)]
332pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>);
334
335pub use self::GenericTransform as Transform;
336
337impl<Angle, Number, Length, Integer, LengthPercentage>
338 TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
339where
340 Angle: Zero,
341 LengthPercentage: Zero + ZeroNoPercent,
342 Number: PartialEq,
343{
344 pub fn is_rotate(&self) -> bool {
346 use self::TransformOperation::*;
347 matches!(
348 *self,
349 Rotate(..) | Rotate3D(..) | RotateX(..) | RotateY(..) | RotateZ(..)
350 )
351 }
352
353 pub fn is_translate(&self) -> bool {
355 use self::TransformOperation::*;
356 match *self {
357 Translate(..) | Translate3D(..) | TranslateX(..) | TranslateY(..) | TranslateZ(..) => {
358 true
359 },
360 _ => false,
361 }
362 }
363
364 pub fn is_scale(&self) -> bool {
366 use self::TransformOperation::*;
367 match *self {
368 Scale(..) | Scale3D(..) | ScaleX(..) | ScaleY(..) | ScaleZ(..) => true,
369 _ => false,
370 }
371 }
372}
373
374pub trait ToAbsoluteLength {
376 fn to_pixel_length(&self, containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()>;
378}
379
380impl ToAbsoluteLength for SpecifiedLength {
381 #[inline]
385 fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> {
386 match *self {
387 SpecifiedLength::NoCalc(len) => len.to_computed_pixel_length_without_context(),
388 SpecifiedLength::Calc(ref calc) => calc.to_computed_pixel_length_without_context(),
389 }
390 }
391}
392
393impl ToAbsoluteLength for SpecifiedLengthPercentage {
394 #[inline]
398 fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> {
399 use self::SpecifiedLengthPercentage::*;
400 match *self {
401 Length(len) => len.to_computed_pixel_length_without_context(),
402 Calc(ref calc) => calc.to_computed_pixel_length_without_context(),
403 Percentage(..) => Err(()),
404 }
405 }
406}
407
408impl ToAbsoluteLength for ComputedLength {
409 #[inline]
410 fn to_pixel_length(&self, _containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> {
411 Ok(self.px())
412 }
413}
414
415impl ToAbsoluteLength for ComputedLengthPercentage {
416 #[inline]
417 fn to_pixel_length(&self, containing_len: Option<ComputedLength>) -> Result<CSSFloat, ()> {
418 Ok(self
419 .maybe_percentage_relative_to(containing_len)
420 .ok_or(())?
421 .px())
422 }
423}
424
425pub trait ToMatrix {
427 fn is_3d(&self) -> bool;
429
430 fn to_3d_matrix(
432 &self,
433 reference_box: Option<&Rect<ComputedLength>>,
434 ) -> Result<Transform3D<f64>, ()>;
435}
436
437pub trait ToRadians {
439 fn radians64(&self) -> f64;
441}
442
443impl ToRadians for computed::angle::Angle {
444 #[inline]
445 fn radians64(&self) -> f64 {
446 computed::angle::Angle::radians64(self)
447 }
448}
449
450impl ToRadians for SpecifiedAngle {
451 #[inline]
452 fn radians64(&self) -> f64 {
453 computed::angle::Angle::from_degrees(self.degrees()).radians64()
454 }
455}
456
457impl<Angle, Number, Length, Integer, LoP> ToMatrix
458 for TransformOperation<Angle, Number, Length, Integer, LoP>
459where
460 Angle: Zero + ToRadians + Copy,
461 Number: PartialEq + Copy + Into<f32> + Into<f64>,
462 Length: ToAbsoluteLength,
463 LoP: Zero + ToAbsoluteLength + ZeroNoPercent,
464{
465 #[inline]
466 fn is_3d(&self) -> bool {
467 use self::TransformOperation::*;
468 match *self {
469 Translate3D(..) | TranslateZ(..) | Rotate3D(..) | RotateX(..) | RotateY(..)
470 | RotateZ(..) | Scale3D(..) | ScaleZ(..) | Perspective(..) | Matrix3D(..) => true,
471 _ => false,
472 }
473 }
474
475 #[inline]
480 fn to_3d_matrix(
481 &self,
482 reference_box: Option<&Rect<ComputedLength>>,
483 ) -> Result<Transform3D<f64>, ()> {
484 use self::TransformOperation::*;
485
486 let reference_width = reference_box.map(|v| v.size.width);
487 let reference_height = reference_box.map(|v| v.size.height);
488 let matrix = match *self {
489 Rotate3D(ax, ay, az, theta) => {
490 let theta = theta.radians64();
491 let (ax, ay, az, theta) =
492 get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta);
493 Transform3D::rotation(
494 ax as f64,
495 ay as f64,
496 az as f64,
497 euclid::Angle::radians(theta),
498 )
499 },
500 RotateX(theta) => {
501 let theta = euclid::Angle::radians(theta.radians64());
502 Transform3D::rotation(1., 0., 0., theta)
503 },
504 RotateY(theta) => {
505 let theta = euclid::Angle::radians(theta.radians64());
506 Transform3D::rotation(0., 1., 0., theta)
507 },
508 RotateZ(theta) | Rotate(theta) => {
509 let theta = euclid::Angle::radians(theta.radians64());
510 Transform3D::rotation(0., 0., 1., theta)
511 },
512 Perspective(ref p) => {
513 let px = match p {
514 PerspectiveFunction::None => f32::INFINITY,
515 PerspectiveFunction::Length(ref p) => p.to_pixel_length(None)?,
516 };
517 create_perspective_matrix(px).cast()
518 },
519 Scale3D(sx, sy, sz) => Transform3D::scale(sx.into(), sy.into(), sz.into()),
520 Scale(sx, sy) => Transform3D::scale(sx.into(), sy.into(), 1.),
521 ScaleX(s) => Transform3D::scale(s.into(), 1., 1.),
522 ScaleY(s) => Transform3D::scale(1., s.into(), 1.),
523 ScaleZ(s) => Transform3D::scale(1., 1., s.into()),
524 Translate3D(ref tx, ref ty, ref tz) => {
525 let tx = tx.to_pixel_length(reference_width)? as f64;
526 let ty = ty.to_pixel_length(reference_height)? as f64;
527 Transform3D::translation(tx, ty, tz.to_pixel_length(None)? as f64)
528 },
529 Translate(ref tx, ref ty) => {
530 let tx = tx.to_pixel_length(reference_width)? as f64;
531 let ty = ty.to_pixel_length(reference_height)? as f64;
532 Transform3D::translation(tx, ty, 0.)
533 },
534 TranslateX(ref t) => {
535 let t = t.to_pixel_length(reference_width)? as f64;
536 Transform3D::translation(t, 0., 0.)
537 },
538 TranslateY(ref t) => {
539 let t = t.to_pixel_length(reference_height)? as f64;
540 Transform3D::translation(0., t, 0.)
541 },
542 TranslateZ(ref z) => Transform3D::translation(0., 0., z.to_pixel_length(None)? as f64),
543 Skew(theta_x, theta_y) => Transform3D::skew(
544 euclid::Angle::radians(theta_x.radians64()),
545 euclid::Angle::radians(theta_y.radians64()),
546 ),
547 SkewX(theta) => Transform3D::skew(
548 euclid::Angle::radians(theta.radians64()),
549 euclid::Angle::radians(0.),
550 ),
551 SkewY(theta) => Transform3D::skew(
552 euclid::Angle::radians(0.),
553 euclid::Angle::radians(theta.radians64()),
554 ),
555 Matrix3D(m) => m.into(),
556 Matrix(m) => m.into(),
557 InterpolateMatrix { .. } | AccumulateMatrix { .. } => {
558 Transform3D::identity()
565 },
566 };
567 Ok(matrix)
568 }
569}
570
571impl<T> Transform<T> {
572 pub fn none() -> Self {
574 Transform(Default::default())
575 }
576}
577
578impl<T: ToMatrix> Transform<T> {
579 #[cfg_attr(rustfmt, rustfmt_skip)]
584 pub fn to_transform_3d_matrix(
585 &self,
586 reference_box: Option<&Rect<ComputedLength>>
587 ) -> Result<(Transform3D<CSSFloat>, bool), ()> {
588 Self::components_to_transform_3d_matrix(&self.0, reference_box)
589 }
590
591 #[cfg_attr(rustfmt, rustfmt_skip)]
593 pub fn components_to_transform_3d_matrix(
594 ops: &[T],
595 reference_box: Option<&Rect<ComputedLength>>,
596 ) -> Result<(Transform3D<CSSFloat>, bool), ()> {
597 let cast_3d_transform = |m: Transform3D<f64>| -> Transform3D<CSSFloat> {
598 use std::{f32, f64};
599 let cast = |v: f64| v.min(f32::MAX as f64).max(f32::MIN as f64) as f32;
600 Transform3D::new(
601 cast(m.m11), cast(m.m12), cast(m.m13), cast(m.m14),
602 cast(m.m21), cast(m.m22), cast(m.m23), cast(m.m24),
603 cast(m.m31), cast(m.m32), cast(m.m33), cast(m.m34),
604 cast(m.m41), cast(m.m42), cast(m.m43), cast(m.m44),
605 )
606 };
607
608 let (m, is_3d) = Self::components_to_transform_3d_matrix_f64(ops, reference_box)?;
609 Ok((cast_3d_transform(m), is_3d))
610 }
611
612 pub fn to_transform_3d_matrix_f64(
614 &self,
615 reference_box: Option<&Rect<ComputedLength>>,
616 ) -> Result<(Transform3D<f64>, bool), ()> {
617 Self::components_to_transform_3d_matrix_f64(&self.0, reference_box)
618 }
619
620 fn components_to_transform_3d_matrix_f64(
622 ops: &[T],
623 reference_box: Option<&Rect<ComputedLength>>,
624 ) -> Result<(Transform3D<f64>, bool), ()> {
625 let mut transform = Transform3D::<f64>::identity();
632 let mut contain_3d = false;
633
634 for operation in ops {
635 let matrix = operation.to_3d_matrix(reference_box)?;
636 contain_3d = contain_3d || operation.is_3d();
637 transform = matrix.then(&transform);
638 }
639
640 Ok((transform, contain_3d))
641 }
642}
643
644#[inline]
646pub fn create_perspective_matrix(d: CSSFloat) -> Transform3D<CSSFloat> {
647 if d.is_finite() {
648 Transform3D::perspective(d.max(1.))
649 } else {
650 Transform3D::identity()
651 }
652}
653
654pub fn get_normalized_vector_and_angle<T: Zero>(
656 x: CSSFloat,
657 y: CSSFloat,
658 z: CSSFloat,
659 angle: T,
660) -> (CSSFloat, CSSFloat, CSSFloat, T) {
661 use crate::values::computed::transform::DirectionVector;
662 use euclid::approxeq::ApproxEq;
663 let vector = DirectionVector::new(x, y, z);
664 if vector.square_length().approx_eq(&f32::zero()) {
665 (0., 0., 1., T::zero())
669 } else {
670 let vector = vector.robust_normalize();
671 (vector.x, vector.y, vector.z, angle)
672 }
673}
674
675#[derive(
676 Clone,
677 Copy,
678 Debug,
679 Deserialize,
680 MallocSizeOf,
681 PartialEq,
682 Serialize,
683 SpecifiedValueInfo,
684 ToAnimatedValue,
685 ToAnimatedZero,
686 ToComputedValue,
687 ToResolvedValue,
688 ToShmem,
689 ToTyped,
690)]
691#[repr(C, u8)]
692#[typed(todo_derive_fields)]
693pub enum GenericRotate<Number, Angle> {
697 None,
699 Rotate(Angle),
701 Rotate3D(Number, Number, Number, Angle),
703}
704
705pub use self::GenericRotate as Rotate;
706
707pub trait IsParallelTo {
710 fn is_parallel_to(&self, vector: &computed::transform::DirectionVector) -> bool;
712}
713
714impl<Number, Angle> ToCss for Rotate<Number, Angle>
715where
716 Number: Copy + PartialOrd + ToCss + Zero,
717 Angle: Copy + Neg<Output = Angle> + ToCss + Zero,
718 (Number, Number, Number): IsParallelTo,
719{
720 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
721 where
722 W: fmt::Write,
723 {
724 use crate::values::computed::transform::DirectionVector;
725 match *self {
726 Rotate::None => dest.write_str("none"),
727 Rotate::Rotate(ref angle) => angle.to_css(dest),
728 Rotate::Rotate3D(x, y, z, angle) => {
729 let v = (x, y, z);
738 let (axis, angle) = if x.is_zero() && y.is_zero() && z.is_zero() {
739 (None, angle)
746 } else if v.is_parallel_to(&DirectionVector::new(1., 0., 0.)) {
747 (
748 Some("x "),
749 if v.0 < Number::zero() { -angle } else { angle },
750 )
751 } else if v.is_parallel_to(&DirectionVector::new(0., 1., 0.)) {
752 (
753 Some("y "),
754 if v.1 < Number::zero() { -angle } else { angle },
755 )
756 } else if v.is_parallel_to(&DirectionVector::new(0., 0., 1.)) {
757 let angle = if v.2 < Number::zero() { -angle } else { angle };
759 return angle.to_css(dest);
760 } else {
761 (None, angle)
762 };
763 match axis {
764 Some(a) => dest.write_str(a)?,
765 None => {
766 x.to_css(dest)?;
767 dest.write_char(' ')?;
768 y.to_css(dest)?;
769 dest.write_char(' ')?;
770 z.to_css(dest)?;
771 dest.write_char(' ')?;
772 },
773 }
774 angle.to_css(dest)
775 },
776 }
777 }
778}
779
780#[derive(
781 Clone,
782 Copy,
783 Debug,
784 Deserialize,
785 MallocSizeOf,
786 PartialEq,
787 Serialize,
788 SpecifiedValueInfo,
789 ToAnimatedValue,
790 ToAnimatedZero,
791 ToComputedValue,
792 ToResolvedValue,
793 ToShmem,
794 ToTyped,
795)]
796#[repr(C, u8)]
797pub enum GenericScale<Number> {
801 None,
803 Scale(Number, Number, Number),
805}
806
807pub use self::GenericScale as Scale;
808
809impl<Number> ToCss for Scale<Number>
810where
811 Number: ToCss + PartialEq + Copy,
812 f32: From<Number>,
813{
814 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
815 where
816 W: fmt::Write,
817 f32: From<Number>,
818 {
819 match *self {
820 Scale::None => dest.write_str("none"),
821 Scale::Scale(ref x, ref y, ref z) => {
822 x.to_css(dest)?;
823
824 let is_3d = f32::from(*z) != 1.0;
825 if is_3d || x != y {
826 dest.write_char(' ')?;
827 y.to_css(dest)?;
828 }
829
830 if is_3d {
831 dest.write_char(' ')?;
832 z.to_css(dest)?;
833 }
834 Ok(())
835 },
836 }
837 }
838}
839
840#[inline]
841fn y_axis_and_z_axis_are_zero<LengthPercentage: Zero + ZeroNoPercent, Length: Zero>(
842 _: &LengthPercentage,
843 y: &LengthPercentage,
844 z: &Length,
845) -> bool {
846 y.is_zero_no_percent() && z.is_zero()
847}
848
849#[derive(
850 Clone,
851 Debug,
852 Deserialize,
853 MallocSizeOf,
854 PartialEq,
855 Serialize,
856 SpecifiedValueInfo,
857 ToAnimatedValue,
858 ToAnimatedZero,
859 ToComputedValue,
860 ToCss,
861 ToResolvedValue,
862 ToShmem,
863 ToTyped,
864)]
865#[repr(C, u8)]
866pub enum GenericTranslate<LengthPercentage, Length>
880where
881 LengthPercentage: Zero + ZeroNoPercent,
882 Length: Zero,
883{
884 None,
886 Translate(
888 LengthPercentage,
889 #[css(contextual_skip_if = "y_axis_and_z_axis_are_zero")] LengthPercentage,
890 #[css(skip_if = "Zero::is_zero")] Length,
891 ),
892}
893
894pub use self::GenericTranslate as Translate;
895
896#[allow(missing_docs)]
897#[derive(
898 Clone,
899 Copy,
900 Debug,
901 MallocSizeOf,
902 Parse,
903 PartialEq,
904 SpecifiedValueInfo,
905 ToComputedValue,
906 ToCss,
907 ToResolvedValue,
908 ToShmem,
909 ToTyped,
910)]
911#[repr(u8)]
912pub enum TransformStyle {
913 Flat,
914 #[css(keyword = "preserve-3d")]
915 Preserve3d,
916}