transform.rs (23514B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Computed types for CSS values that are related to transformations. 6 7 use super::CSSFloat; 8 use crate::values::animated::transform::{Perspective, Scale3D, Translate3D}; 9 use crate::values::animated::ToAnimatedZero; 10 use crate::values::computed::{Angle, Integer, Length, LengthPercentage, Number, Percentage}; 11 use crate::values::generics::transform as generic; 12 use crate::Zero; 13 use euclid::default::{Transform3D, Vector3D}; 14 15 pub use crate::values::generics::transform::TransformStyle; 16 pub use crate::values::specified::transform::TransformBox; 17 18 /// A single operation in a computed CSS `transform` 19 pub type TransformOperation = 20 generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>; 21 /// A computed CSS `transform` 22 pub type Transform = generic::GenericTransform<TransformOperation>; 23 24 /// The computed value of a CSS `<transform-origin>` 25 pub type TransformOrigin = 26 generic::GenericTransformOrigin<LengthPercentage, LengthPercentage, Length>; 27 28 /// The computed value of the `perspective()` transform function. 29 pub type PerspectiveFunction = generic::PerspectiveFunction<Length>; 30 31 /// A vector to represent the direction vector (rotate axis) for Rotate3D. 32 pub type DirectionVector = Vector3D<CSSFloat>; 33 34 impl TransformOrigin { 35 /// Returns the initial computed value for `transform-origin`. 36 #[inline] 37 pub fn initial_value() -> Self { 38 Self::new( 39 LengthPercentage::new_percent(Percentage(0.5)), 40 LengthPercentage::new_percent(Percentage(0.5)), 41 Length::new(0.), 42 ) 43 } 44 } 45 46 /// computed value of matrix3d() 47 pub type Matrix3D = generic::Matrix3D<Number>; 48 49 /// computed value of matrix() 50 pub type Matrix = generic::Matrix<Number>; 51 52 // we rustfmt_skip here because we want the matrices to look like 53 // matrices instead of being split across lines 54 #[cfg_attr(rustfmt, rustfmt_skip)] 55 impl Matrix3D { 56 /// Get an identity matrix 57 #[inline] 58 pub fn identity() -> Self { 59 Self { 60 m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, 61 m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0, 62 m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, 63 m41: 0., m42: 0., m43: 0., m44: 1.0 64 } 65 } 66 67 /// Convert to a 2D Matrix 68 #[inline] 69 pub fn into_2d(self) -> Result<Matrix, ()> { 70 if self.m13 == 0. && self.m23 == 0. && 71 self.m31 == 0. && self.m32 == 0. && 72 self.m33 == 1. && self.m34 == 0. && 73 self.m14 == 0. && self.m24 == 0. && 74 self.m43 == 0. && self.m44 == 1. { 75 Ok(Matrix { 76 a: self.m11, c: self.m21, e: self.m41, 77 b: self.m12, d: self.m22, f: self.m42, 78 }) 79 } else { 80 Err(()) 81 } 82 } 83 84 /// Return true if this has 3D components. 85 #[inline] 86 pub fn is_3d(&self) -> bool { 87 self.m13 != 0.0 || self.m14 != 0.0 || 88 self.m23 != 0.0 || self.m24 != 0.0 || 89 self.m31 != 0.0 || self.m32 != 0.0 || 90 self.m33 != 1.0 || self.m34 != 0.0 || 91 self.m43 != 0.0 || self.m44 != 1.0 92 } 93 94 /// Return determinant value. 95 #[inline] 96 pub fn determinant(&self) -> CSSFloat { 97 self.m14 * self.m23 * self.m32 * self.m41 - 98 self.m13 * self.m24 * self.m32 * self.m41 - 99 self.m14 * self.m22 * self.m33 * self.m41 + 100 self.m12 * self.m24 * self.m33 * self.m41 + 101 self.m13 * self.m22 * self.m34 * self.m41 - 102 self.m12 * self.m23 * self.m34 * self.m41 - 103 self.m14 * self.m23 * self.m31 * self.m42 + 104 self.m13 * self.m24 * self.m31 * self.m42 + 105 self.m14 * self.m21 * self.m33 * self.m42 - 106 self.m11 * self.m24 * self.m33 * self.m42 - 107 self.m13 * self.m21 * self.m34 * self.m42 + 108 self.m11 * self.m23 * self.m34 * self.m42 + 109 self.m14 * self.m22 * self.m31 * self.m43 - 110 self.m12 * self.m24 * self.m31 * self.m43 - 111 self.m14 * self.m21 * self.m32 * self.m43 + 112 self.m11 * self.m24 * self.m32 * self.m43 + 113 self.m12 * self.m21 * self.m34 * self.m43 - 114 self.m11 * self.m22 * self.m34 * self.m43 - 115 self.m13 * self.m22 * self.m31 * self.m44 + 116 self.m12 * self.m23 * self.m31 * self.m44 + 117 self.m13 * self.m21 * self.m32 * self.m44 - 118 self.m11 * self.m23 * self.m32 * self.m44 - 119 self.m12 * self.m21 * self.m33 * self.m44 + 120 self.m11 * self.m22 * self.m33 * self.m44 121 } 122 123 /// Transpose a matrix. 124 #[inline] 125 pub fn transpose(&self) -> Self { 126 Self { 127 m11: self.m11, m12: self.m21, m13: self.m31, m14: self.m41, 128 m21: self.m12, m22: self.m22, m23: self.m32, m24: self.m42, 129 m31: self.m13, m32: self.m23, m33: self.m33, m34: self.m43, 130 m41: self.m14, m42: self.m24, m43: self.m34, m44: self.m44, 131 } 132 } 133 134 /// Return inverse matrix. 135 pub fn inverse(&self) -> Result<Matrix3D, ()> { 136 let mut det = self.determinant(); 137 138 if det == 0.0 { 139 return Err(()); 140 } 141 142 det = 1.0 / det; 143 let x = Matrix3D { 144 m11: det * 145 (self.m23 * self.m34 * self.m42 - self.m24 * self.m33 * self.m42 + 146 self.m24 * self.m32 * self.m43 - self.m22 * self.m34 * self.m43 - 147 self.m23 * self.m32 * self.m44 + self.m22 * self.m33 * self.m44), 148 m12: det * 149 (self.m14 * self.m33 * self.m42 - self.m13 * self.m34 * self.m42 - 150 self.m14 * self.m32 * self.m43 + self.m12 * self.m34 * self.m43 + 151 self.m13 * self.m32 * self.m44 - self.m12 * self.m33 * self.m44), 152 m13: det * 153 (self.m13 * self.m24 * self.m42 - self.m14 * self.m23 * self.m42 + 154 self.m14 * self.m22 * self.m43 - self.m12 * self.m24 * self.m43 - 155 self.m13 * self.m22 * self.m44 + self.m12 * self.m23 * self.m44), 156 m14: det * 157 (self.m14 * self.m23 * self.m32 - self.m13 * self.m24 * self.m32 - 158 self.m14 * self.m22 * self.m33 + self.m12 * self.m24 * self.m33 + 159 self.m13 * self.m22 * self.m34 - self.m12 * self.m23 * self.m34), 160 m21: det * 161 (self.m24 * self.m33 * self.m41 - self.m23 * self.m34 * self.m41 - 162 self.m24 * self.m31 * self.m43 + self.m21 * self.m34 * self.m43 + 163 self.m23 * self.m31 * self.m44 - self.m21 * self.m33 * self.m44), 164 m22: det * 165 (self.m13 * self.m34 * self.m41 - self.m14 * self.m33 * self.m41 + 166 self.m14 * self.m31 * self.m43 - self.m11 * self.m34 * self.m43 - 167 self.m13 * self.m31 * self.m44 + self.m11 * self.m33 * self.m44), 168 m23: det * 169 (self.m14 * self.m23 * self.m41 - self.m13 * self.m24 * self.m41 - 170 self.m14 * self.m21 * self.m43 + self.m11 * self.m24 * self.m43 + 171 self.m13 * self.m21 * self.m44 - self.m11 * self.m23 * self.m44), 172 m24: det * 173 (self.m13 * self.m24 * self.m31 - self.m14 * self.m23 * self.m31 + 174 self.m14 * self.m21 * self.m33 - self.m11 * self.m24 * self.m33 - 175 self.m13 * self.m21 * self.m34 + self.m11 * self.m23 * self.m34), 176 m31: det * 177 (self.m22 * self.m34 * self.m41 - self.m24 * self.m32 * self.m41 + 178 self.m24 * self.m31 * self.m42 - self.m21 * self.m34 * self.m42 - 179 self.m22 * self.m31 * self.m44 + self.m21 * self.m32 * self.m44), 180 m32: det * 181 (self.m14 * self.m32 * self.m41 - self.m12 * self.m34 * self.m41 - 182 self.m14 * self.m31 * self.m42 + self.m11 * self.m34 * self.m42 + 183 self.m12 * self.m31 * self.m44 - self.m11 * self.m32 * self.m44), 184 m33: det * 185 (self.m12 * self.m24 * self.m41 - self.m14 * self.m22 * self.m41 + 186 self.m14 * self.m21 * self.m42 - self.m11 * self.m24 * self.m42 - 187 self.m12 * self.m21 * self.m44 + self.m11 * self.m22 * self.m44), 188 m34: det * 189 (self.m14 * self.m22 * self.m31 - self.m12 * self.m24 * self.m31 - 190 self.m14 * self.m21 * self.m32 + self.m11 * self.m24 * self.m32 + 191 self.m12 * self.m21 * self.m34 - self.m11 * self.m22 * self.m34), 192 m41: det * 193 (self.m23 * self.m32 * self.m41 - self.m22 * self.m33 * self.m41 - 194 self.m23 * self.m31 * self.m42 + self.m21 * self.m33 * self.m42 + 195 self.m22 * self.m31 * self.m43 - self.m21 * self.m32 * self.m43), 196 m42: det * 197 (self.m12 * self.m33 * self.m41 - self.m13 * self.m32 * self.m41 + 198 self.m13 * self.m31 * self.m42 - self.m11 * self.m33 * self.m42 - 199 self.m12 * self.m31 * self.m43 + self.m11 * self.m32 * self.m43), 200 m43: det * 201 (self.m13 * self.m22 * self.m41 - self.m12 * self.m23 * self.m41 - 202 self.m13 * self.m21 * self.m42 + self.m11 * self.m23 * self.m42 + 203 self.m12 * self.m21 * self.m43 - self.m11 * self.m22 * self.m43), 204 m44: det * 205 (self.m12 * self.m23 * self.m31 - self.m13 * self.m22 * self.m31 + 206 self.m13 * self.m21 * self.m32 - self.m11 * self.m23 * self.m32 - 207 self.m12 * self.m21 * self.m33 + self.m11 * self.m22 * self.m33), 208 }; 209 210 Ok(x) 211 } 212 213 /// Multiply `pin * self`. 214 #[inline] 215 pub fn pre_mul_point4(&self, pin: &[f32; 4]) -> [f32; 4] { 216 [ 217 pin[0] * self.m11 + pin[1] * self.m21 + pin[2] * self.m31 + pin[3] * self.m41, 218 pin[0] * self.m12 + pin[1] * self.m22 + pin[2] * self.m32 + pin[3] * self.m42, 219 pin[0] * self.m13 + pin[1] * self.m23 + pin[2] * self.m33 + pin[3] * self.m43, 220 pin[0] * self.m14 + pin[1] * self.m24 + pin[2] * self.m34 + pin[3] * self.m44, 221 ] 222 } 223 224 /// Return the multiplication of two 4x4 matrices. 225 #[inline] 226 pub fn multiply(&self, other: &Self) -> Self { 227 Matrix3D { 228 m11: self.m11 * other.m11 + self.m12 * other.m21 + 229 self.m13 * other.m31 + self.m14 * other.m41, 230 m12: self.m11 * other.m12 + self.m12 * other.m22 + 231 self.m13 * other.m32 + self.m14 * other.m42, 232 m13: self.m11 * other.m13 + self.m12 * other.m23 + 233 self.m13 * other.m33 + self.m14 * other.m43, 234 m14: self.m11 * other.m14 + self.m12 * other.m24 + 235 self.m13 * other.m34 + self.m14 * other.m44, 236 m21: self.m21 * other.m11 + self.m22 * other.m21 + 237 self.m23 * other.m31 + self.m24 * other.m41, 238 m22: self.m21 * other.m12 + self.m22 * other.m22 + 239 self.m23 * other.m32 + self.m24 * other.m42, 240 m23: self.m21 * other.m13 + self.m22 * other.m23 + 241 self.m23 * other.m33 + self.m24 * other.m43, 242 m24: self.m21 * other.m14 + self.m22 * other.m24 + 243 self.m23 * other.m34 + self.m24 * other.m44, 244 m31: self.m31 * other.m11 + self.m32 * other.m21 + 245 self.m33 * other.m31 + self.m34 * other.m41, 246 m32: self.m31 * other.m12 + self.m32 * other.m22 + 247 self.m33 * other.m32 + self.m34 * other.m42, 248 m33: self.m31 * other.m13 + self.m32 * other.m23 + 249 self.m33 * other.m33 + self.m34 * other.m43, 250 m34: self.m31 * other.m14 + self.m32 * other.m24 + 251 self.m33 * other.m34 + self.m34 * other.m44, 252 m41: self.m41 * other.m11 + self.m42 * other.m21 + 253 self.m43 * other.m31 + self.m44 * other.m41, 254 m42: self.m41 * other.m12 + self.m42 * other.m22 + 255 self.m43 * other.m32 + self.m44 * other.m42, 256 m43: self.m41 * other.m13 + self.m42 * other.m23 + 257 self.m43 * other.m33 + self.m44 * other.m43, 258 m44: self.m41 * other.m14 + self.m42 * other.m24 + 259 self.m43 * other.m34 + self.m44 * other.m44, 260 } 261 } 262 263 /// Scale the matrix by a factor. 264 #[inline] 265 pub fn scale_by_factor(&mut self, scaling_factor: CSSFloat) { 266 self.m11 *= scaling_factor; 267 self.m12 *= scaling_factor; 268 self.m13 *= scaling_factor; 269 self.m14 *= scaling_factor; 270 self.m21 *= scaling_factor; 271 self.m22 *= scaling_factor; 272 self.m23 *= scaling_factor; 273 self.m24 *= scaling_factor; 274 self.m31 *= scaling_factor; 275 self.m32 *= scaling_factor; 276 self.m33 *= scaling_factor; 277 self.m34 *= scaling_factor; 278 self.m41 *= scaling_factor; 279 self.m42 *= scaling_factor; 280 self.m43 *= scaling_factor; 281 self.m44 *= scaling_factor; 282 } 283 284 /// Return the matrix 3x3 part (top-left corner). 285 /// This is used by retrieving the scale and shear factors 286 /// during decomposing a 3d matrix. 287 #[inline] 288 pub fn get_matrix_3x3_part(&self) -> [[f32; 3]; 3] { 289 [ 290 [ self.m11, self.m12, self.m13 ], 291 [ self.m21, self.m22, self.m23 ], 292 [ self.m31, self.m32, self.m33 ], 293 ] 294 } 295 296 /// Set perspective on the matrix. 297 #[inline] 298 pub fn set_perspective(&mut self, perspective: &Perspective) { 299 self.m14 = perspective.0; 300 self.m24 = perspective.1; 301 self.m34 = perspective.2; 302 self.m44 = perspective.3; 303 } 304 305 /// Apply translate on the matrix. 306 #[inline] 307 pub fn apply_translate(&mut self, translate: &Translate3D) { 308 self.m41 += translate.0 * self.m11 + translate.1 * self.m21 + translate.2 * self.m31; 309 self.m42 += translate.0 * self.m12 + translate.1 * self.m22 + translate.2 * self.m32; 310 self.m43 += translate.0 * self.m13 + translate.1 * self.m23 + translate.2 * self.m33; 311 self.m44 += translate.0 * self.m14 + translate.1 * self.m24 + translate.2 * self.m34; 312 } 313 314 /// Apply scale on the matrix. 315 #[inline] 316 pub fn apply_scale(&mut self, scale: &Scale3D) { 317 self.m11 *= scale.0; 318 self.m12 *= scale.0; 319 self.m13 *= scale.0; 320 self.m14 *= scale.0; 321 self.m21 *= scale.1; 322 self.m22 *= scale.1; 323 self.m23 *= scale.1; 324 self.m24 *= scale.1; 325 self.m31 *= scale.2; 326 self.m32 *= scale.2; 327 self.m33 *= scale.2; 328 self.m34 *= scale.2; 329 } 330 } 331 332 #[cfg_attr(rustfmt, rustfmt_skip)] 333 impl Matrix { 334 #[inline] 335 /// Get an identity matrix 336 pub fn identity() -> Self { 337 Self { 338 a: 1., c: 0., /* 0 0*/ 339 b: 0., d: 1., /* 0 0*/ 340 /* 0 0 1 0 */ 341 e: 0., f: 0., /* 0 1 */ 342 } 343 } 344 } 345 346 #[cfg_attr(rustfmt, rustfmt_skip)] 347 impl From<Matrix> for Matrix3D { 348 fn from(m: Matrix) -> Self { 349 Self { 350 m11: m.a, m12: m.b, m13: 0.0, m14: 0.0, 351 m21: m.c, m22: m.d, m23: 0.0, m24: 0.0, 352 m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, 353 m41: m.e, m42: m.f, m43: 0.0, m44: 1.0 354 } 355 } 356 } 357 358 #[cfg_attr(rustfmt, rustfmt_skip)] 359 impl From<Transform3D<CSSFloat>> for Matrix3D { 360 #[inline] 361 fn from(m: Transform3D<CSSFloat>) -> Self { 362 Matrix3D { 363 m11: m.m11, m12: m.m12, m13: m.m13, m14: m.m14, 364 m21: m.m21, m22: m.m22, m23: m.m23, m24: m.m24, 365 m31: m.m31, m32: m.m32, m33: m.m33, m34: m.m34, 366 m41: m.m41, m42: m.m42, m43: m.m43, m44: m.m44 367 } 368 } 369 } 370 371 impl TransformOperation { 372 /// Convert to a Translate3D. 373 /// 374 /// Must be called on a Translate function 375 pub fn to_translate_3d(&self) -> Self { 376 match *self { 377 generic::TransformOperation::Translate3D(..) => self.clone(), 378 generic::TransformOperation::TranslateX(ref x) => { 379 generic::TransformOperation::Translate3D( 380 x.clone(), 381 LengthPercentage::zero(), 382 Length::zero(), 383 ) 384 }, 385 generic::TransformOperation::Translate(ref x, ref y) => { 386 generic::TransformOperation::Translate3D(x.clone(), y.clone(), Length::zero()) 387 }, 388 generic::TransformOperation::TranslateY(ref y) => { 389 generic::TransformOperation::Translate3D( 390 LengthPercentage::zero(), 391 y.clone(), 392 Length::zero(), 393 ) 394 }, 395 generic::TransformOperation::TranslateZ(ref z) => { 396 generic::TransformOperation::Translate3D( 397 LengthPercentage::zero(), 398 LengthPercentage::zero(), 399 z.clone(), 400 ) 401 }, 402 _ => unreachable!(), 403 } 404 } 405 406 /// Convert to a Rotate3D. 407 /// 408 /// Must be called on a Rotate function. 409 pub fn to_rotate_3d(&self) -> Self { 410 match *self { 411 generic::TransformOperation::Rotate3D(..) => self.clone(), 412 generic::TransformOperation::RotateZ(ref angle) 413 | generic::TransformOperation::Rotate(ref angle) => { 414 generic::TransformOperation::Rotate3D(0., 0., 1., angle.clone()) 415 }, 416 generic::TransformOperation::RotateX(ref angle) => { 417 generic::TransformOperation::Rotate3D(1., 0., 0., angle.clone()) 418 }, 419 generic::TransformOperation::RotateY(ref angle) => { 420 generic::TransformOperation::Rotate3D(0., 1., 0., angle.clone()) 421 }, 422 _ => unreachable!(), 423 } 424 } 425 426 /// Convert to a Scale3D. 427 /// 428 /// Must be called on a Scale function 429 pub fn to_scale_3d(&self) -> Self { 430 match *self { 431 generic::TransformOperation::Scale3D(..) => self.clone(), 432 generic::TransformOperation::Scale(x, y) => { 433 generic::TransformOperation::Scale3D(x, y, 1.) 434 }, 435 generic::TransformOperation::ScaleX(x) => { 436 generic::TransformOperation::Scale3D(x, 1., 1.) 437 }, 438 generic::TransformOperation::ScaleY(y) => { 439 generic::TransformOperation::Scale3D(1., y, 1.) 440 }, 441 generic::TransformOperation::ScaleZ(z) => { 442 generic::TransformOperation::Scale3D(1., 1., z) 443 }, 444 _ => unreachable!(), 445 } 446 } 447 } 448 449 /// Build an equivalent 'identity transform function list' based 450 /// on an existing transform list. 451 /// http://dev.w3.org/csswg/css-transforms/#none-transform-animation 452 impl ToAnimatedZero for TransformOperation { 453 fn to_animated_zero(&self) -> Result<Self, ()> { 454 match *self { 455 generic::TransformOperation::Matrix3D(..) => { 456 Ok(generic::TransformOperation::Matrix3D(Matrix3D::identity())) 457 }, 458 generic::TransformOperation::Matrix(..) => { 459 Ok(generic::TransformOperation::Matrix(Matrix::identity())) 460 }, 461 generic::TransformOperation::Skew(sx, sy) => Ok(generic::TransformOperation::Skew( 462 sx.to_animated_zero()?, 463 sy.to_animated_zero()?, 464 )), 465 generic::TransformOperation::SkewX(s) => { 466 Ok(generic::TransformOperation::SkewX(s.to_animated_zero()?)) 467 }, 468 generic::TransformOperation::SkewY(s) => { 469 Ok(generic::TransformOperation::SkewY(s.to_animated_zero()?)) 470 }, 471 generic::TransformOperation::Translate3D(ref tx, ref ty, ref tz) => { 472 Ok(generic::TransformOperation::Translate3D( 473 tx.to_animated_zero()?, 474 ty.to_animated_zero()?, 475 tz.to_animated_zero()?, 476 )) 477 }, 478 generic::TransformOperation::Translate(ref tx, ref ty) => { 479 Ok(generic::TransformOperation::Translate( 480 tx.to_animated_zero()?, 481 ty.to_animated_zero()?, 482 )) 483 }, 484 generic::TransformOperation::TranslateX(ref t) => Ok( 485 generic::TransformOperation::TranslateX(t.to_animated_zero()?), 486 ), 487 generic::TransformOperation::TranslateY(ref t) => Ok( 488 generic::TransformOperation::TranslateY(t.to_animated_zero()?), 489 ), 490 generic::TransformOperation::TranslateZ(ref t) => Ok( 491 generic::TransformOperation::TranslateZ(t.to_animated_zero()?), 492 ), 493 generic::TransformOperation::Scale3D(..) => { 494 Ok(generic::TransformOperation::Scale3D(1.0, 1.0, 1.0)) 495 }, 496 generic::TransformOperation::Scale(_, _) => { 497 Ok(generic::TransformOperation::Scale(1.0, 1.0)) 498 }, 499 generic::TransformOperation::ScaleX(..) => Ok(generic::TransformOperation::ScaleX(1.0)), 500 generic::TransformOperation::ScaleY(..) => Ok(generic::TransformOperation::ScaleY(1.0)), 501 generic::TransformOperation::ScaleZ(..) => Ok(generic::TransformOperation::ScaleZ(1.0)), 502 generic::TransformOperation::Rotate3D(x, y, z, a) => { 503 let (x, y, z, _) = generic::get_normalized_vector_and_angle(x, y, z, a); 504 Ok(generic::TransformOperation::Rotate3D( 505 x, 506 y, 507 z, 508 Angle::zero(), 509 )) 510 }, 511 generic::TransformOperation::RotateX(_) => { 512 Ok(generic::TransformOperation::RotateX(Angle::zero())) 513 }, 514 generic::TransformOperation::RotateY(_) => { 515 Ok(generic::TransformOperation::RotateY(Angle::zero())) 516 }, 517 generic::TransformOperation::RotateZ(_) => { 518 Ok(generic::TransformOperation::RotateZ(Angle::zero())) 519 }, 520 generic::TransformOperation::Rotate(_) => { 521 Ok(generic::TransformOperation::Rotate(Angle::zero())) 522 }, 523 generic::TransformOperation::Perspective(_) => Ok( 524 generic::TransformOperation::Perspective(generic::PerspectiveFunction::None), 525 ), 526 generic::TransformOperation::AccumulateMatrix { .. } 527 | generic::TransformOperation::InterpolateMatrix { .. } => { 528 // AccumulateMatrix/InterpolateMatrix: We do interpolation on 529 // AccumulateMatrix/InterpolateMatrix by reading it as a ComputedMatrix 530 // (with layout information), and then do matrix interpolation. 531 // 532 // Therefore, we use an identity matrix to represent the identity transform list. 533 // http://dev.w3.org/csswg/css-transforms/#identity-transform-function 534 Ok(generic::TransformOperation::Matrix3D(Matrix3D::identity())) 535 }, 536 } 537 } 538 } 539 540 impl ToAnimatedZero for Transform { 541 #[inline] 542 fn to_animated_zero(&self) -> Result<Self, ()> { 543 Ok(generic::Transform( 544 self.0 545 .iter() 546 .map(|op| op.to_animated_zero()) 547 .collect::<Result<crate::OwnedSlice<_>, _>>()?, 548 )) 549 } 550 } 551 552 /// A computed CSS `rotate` 553 pub type Rotate = generic::GenericRotate<Number, Angle>; 554 555 /// A computed CSS `translate` 556 pub type Translate = generic::GenericTranslate<LengthPercentage, Length>; 557 558 /// A computed CSS `scale` 559 pub type Scale = generic::GenericScale<Number>;