1use std::ops::{Mul, MulAssign};
3
4use read_fonts::ReadError;
5
6use super::instance::ResolvedPaint;
7
8#[cfg(feature = "libm")]
9#[allow(unused_imports)]
10use core_maths::*;
11
12#[cfg(test)]
13use serde::{Deserialize, Serialize};
14
15#[derive(Clone, Debug, PartialEq)]
16#[cfg_attr(test, derive(Serialize, Deserialize))]
17#[derive(Copy)]
26pub struct Transform {
27 pub xx: f32,
28 pub yx: f32,
29 pub xy: f32,
30 pub yy: f32,
31 pub dx: f32,
32 pub dy: f32,
33}
34
35impl MulAssign for Transform {
36 fn mul_assign(&mut self, rhs: Self) {
37 *self = *self * rhs;
38 }
39}
40
41impl Mul for Transform {
42 type Output = Self;
43
44 fn mul(self, rhs: Self) -> Self::Output {
45 fn muladdmul(a: f32, b: f32, c: f32, d: f32) -> f32 {
46 a * b + c * d
47 }
48 Self {
49 xx: muladdmul(self.xx, rhs.xx, self.xy, rhs.yx),
50 xy: muladdmul(self.xx, rhs.xy, self.xy, rhs.yy),
51 dx: muladdmul(self.xx, rhs.dx, self.xy, rhs.dy) + self.dx,
52 yx: muladdmul(self.yx, rhs.xx, self.yy, rhs.yx),
53 yy: muladdmul(self.yx, rhs.xy, self.yy, rhs.yy),
54 dy: muladdmul(self.yx, rhs.dx, self.yy, rhs.dy) + self.dy,
55 }
56 }
57}
58
59impl Default for Transform {
60 fn default() -> Self {
61 Transform {
62 xx: 1.0,
63 yx: 0.0,
64 xy: 0.0,
65 yy: 1.0,
66 dx: 0.0,
67 dy: 0.0,
68 }
69 }
70}
71
72impl TryFrom<&ResolvedPaint<'_>> for Transform {
73 type Error = ReadError;
74
75 fn try_from(paint: &ResolvedPaint<'_>) -> Result<Self, Self::Error> {
76 match paint {
77 ResolvedPaint::Rotate {
78 angle,
79 around_center,
80 ..
81 } => {
82 let sin_v = (angle * 180.0).to_radians().sin();
83 let cos_v = (angle * 180.0).to_radians().cos();
84 let mut out_transform = Transform {
85 xx: cos_v,
86 xy: -sin_v,
87 yx: sin_v,
88 yy: cos_v,
89 ..Default::default()
90 };
91
92 fn scalar_dot_product(a: f32, b: f32, c: f32, d: f32) -> f32 {
93 a * b + c * d
94 }
95
96 if let Some(center) = around_center {
97 out_transform.dx = scalar_dot_product(sin_v, center.y, 1.0 - cos_v, center.x);
98 out_transform.dy = scalar_dot_product(-sin_v, center.x, 1.0 - cos_v, center.y);
99 }
100 Ok(out_transform)
101 }
102 ResolvedPaint::Scale {
103 scale_x,
104 scale_y,
105 around_center,
106 paint: _,
107 } => {
108 let mut out_transform = Transform {
109 xx: *scale_x,
110 yy: *scale_y,
111 ..Transform::default()
112 };
113
114 if let Some(center) = around_center {
115 out_transform.dx = center.x - scale_x * center.x;
116 out_transform.dy = center.y - scale_y * center.y;
117 }
118 Ok(out_transform)
119 }
120 ResolvedPaint::Skew {
121 x_skew_angle,
122 y_skew_angle,
123 around_center,
124 paint: _,
125 } => {
126 let tan_x = (x_skew_angle * 180.0).to_radians().tan();
127 let tan_y = (y_skew_angle * 180.0).to_radians().tan();
128 let mut out_transform = Transform {
129 xy: -tan_x,
130 yx: tan_y,
131 ..Transform::default()
132 };
133
134 if let Some(center) = around_center {
135 out_transform.dx = tan_x * center.y;
136 out_transform.dy = -tan_y * center.x;
137 }
138 Ok(out_transform)
139 }
140 ResolvedPaint::Transform {
141 xx,
142 yx,
143 xy,
144 yy,
145 dx,
146 dy,
147 paint: _,
148 } => Ok(Transform {
149 xx: *xx,
150 yx: *yx,
151 xy: *xy,
152 yy: *yy,
153 dx: *dx,
154 dy: *dy,
155 }),
156 ResolvedPaint::Translate { dx, dy, .. } => Ok(Transform {
157 dx: *dx,
158 dy: *dy,
159 ..Default::default()
160 }),
161 _ => Err(ReadError::MalformedData(
162 "ResolvedPaint cannot be converted into a transform.",
163 )),
164 }
165 }
166}