Skip to main content

skrifa/color/
transform.rs

1//! Contains a [`Transform`] object holding values of an affine transformation matrix.
2
3use super::instance::ResolvedPaint;
4#[cfg(feature = "libm")]
5#[allow(unused_imports)]
6use core_maths::*;
7use read_fonts::{types::Matrix, ReadError};
8
9/// A transformation matrix.
10pub type Transform = Matrix<f32>;
11
12impl TryFrom<&ResolvedPaint<'_>> for Transform {
13    type Error = ReadError;
14
15    fn try_from(paint: &ResolvedPaint<'_>) -> Result<Self, Self::Error> {
16        match paint {
17            ResolvedPaint::Rotate {
18                angle,
19                around_center,
20                ..
21            } => {
22                let sin_v = (angle * 180.0).to_radians().sin();
23                let cos_v = (angle * 180.0).to_radians().cos();
24                let mut out_transform = Transform {
25                    xx: cos_v,
26                    xy: -sin_v,
27                    yx: sin_v,
28                    yy: cos_v,
29                    ..Default::default()
30                };
31
32                fn scalar_dot_product(a: f32, b: f32, c: f32, d: f32) -> f32 {
33                    a * b + c * d
34                }
35
36                if let Some(center) = around_center {
37                    out_transform.dx = scalar_dot_product(sin_v, center.y, 1.0 - cos_v, center.x);
38                    out_transform.dy = scalar_dot_product(-sin_v, center.x, 1.0 - cos_v, center.y);
39                }
40                Ok(out_transform)
41            }
42            ResolvedPaint::Scale {
43                scale_x,
44                scale_y,
45                around_center,
46                paint: _,
47            } => {
48                let mut out_transform = Transform {
49                    xx: *scale_x,
50                    yy: *scale_y,
51                    ..Transform::default()
52                };
53
54                if let Some(center) = around_center {
55                    out_transform.dx = center.x - scale_x * center.x;
56                    out_transform.dy = center.y - scale_y * center.y;
57                }
58                Ok(out_transform)
59            }
60            ResolvedPaint::Skew {
61                x_skew_angle,
62                y_skew_angle,
63                around_center,
64                paint: _,
65            } => {
66                let tan_x = (x_skew_angle * 180.0).to_radians().tan();
67                let tan_y = (y_skew_angle * 180.0).to_radians().tan();
68                let mut out_transform = Transform {
69                    xy: -tan_x,
70                    yx: tan_y,
71                    ..Transform::default()
72                };
73
74                if let Some(center) = around_center {
75                    out_transform.dx = tan_x * center.y;
76                    out_transform.dy = -tan_y * center.x;
77                }
78                Ok(out_transform)
79            }
80            ResolvedPaint::Transform {
81                xx,
82                yx,
83                xy,
84                yy,
85                dx,
86                dy,
87                paint: _,
88            } => Ok(Transform {
89                xx: *xx,
90                yx: *yx,
91                xy: *xy,
92                yy: *yy,
93                dx: *dx,
94                dy: *dy,
95            }),
96            ResolvedPaint::Translate { dx, dy, .. } => Ok(Transform {
97                dx: *dx,
98                dy: *dy,
99                ..Default::default()
100            }),
101            _ => Err(ReadError::MalformedData(
102                "ResolvedPaint cannot be converted into a transform.",
103            )),
104        }
105    }
106}