1use std::mem::MaybeUninit;
2
3use paste::paste;
4use thiserror::Error;
5
6use crate::{ffi, FVector, Fixed, Vector};
7
8macro_rules! impl_transform {
9 ($(#[$attr:meta])* $name:ident, ffi => $ffi:path, impl => $impl:ident, vector_t => $vector_t:path$(,)?) => {
10 $(#[$attr])*
11 pub struct $name($ffi);
12
13 impl $name {
14 pub fn transform_bounds(&self, mut b: $crate::Box16) -> Option<$crate::Box16> {
16 let res = unsafe { paste!($crate::ffi::[<$impl _bounds>](self.as_ptr(), &mut b)) };
17 if res == 1 {
18 Some(b)
19 } else {
20 None
21 }
22 }
23
24 #[inline]
26 pub fn identity() -> Self {
27 let mut transform = MaybeUninit::uninit();
28 unsafe {
29 paste!($crate::ffi::[<$impl _init_identity>](transform.as_mut_ptr()));
30 }
31 Self(unsafe { transform.assume_init() })
32 }
33
34 pub fn invert(&self) -> Option<Self> {
36 let mut transform = MaybeUninit::uninit();
37 let res = unsafe { paste!($crate::ffi::[<$impl _invert>](transform.as_mut_ptr(), self.as_ptr())) };
38
39 if res == 1 {
40 Some(Self(unsafe { transform.assume_init() }))
41 } else {
42 None
43 }
44 }
45
46 pub fn multiply(&self, other: &$name) -> Self {
48 let mut transform = MaybeUninit::uninit();
49 unsafe {
50 paste!($crate::ffi::[<$impl _multiply>](transform.as_mut_ptr(), self.as_ptr(), other.as_ptr()));
51 };
52 Self(unsafe { transform.assume_init() })
53 }
54
55 pub fn transform_point(&self, mut vector: $vector_t) -> Option<$vector_t> {
57 let res = unsafe { paste!($crate::ffi::[<$impl _point>](self.as_ptr(), vector.as_mut_ptr())) };
58 if res == 1 {
59 Some(vector)
60 } else {
61 None
62 }
63 }
64
65 pub fn transform_point_3d(&self, mut vector: $vector_t) -> $vector_t {
67 unsafe { paste!($crate::ffi::[<$impl _point_3d>](self.as_ptr(), vector.as_mut_ptr())) };
68 vector
69 }
70
71 #[inline]
72 pub(crate) fn as_ptr(&self) -> *const $ffi {
73 &self.0 as *const $ffi
74 }
75
76 #[inline]
77 pub(crate) fn as_mut_ptr(&mut self) -> *mut $ffi {
78 &mut self.0 as *mut $ffi
79 }
80 }
81
82 impl From<$ffi> for $name {
83 #[inline]
84 fn from(value: $ffi) -> Self {
85 Self(value)
86 }
87 }
88
89 impl From<$name> for $ffi {
90 #[inline]
91 fn from(value: $name) -> Self {
92 value.0
93 }
94 }
95 };
96}
97
98impl_transform! {
99 #[derive(Debug, Clone, Copy)]
101 #[repr(transparent)]
102 Transform,
103 ffi => crate::ffi::pixman_transform_t,
104 impl => pixman_transform,
105 vector_t => Vector,
106}
107
108impl_transform! {
109 #[derive(Debug, Clone, Copy)]
111 #[repr(transparent)]
112 FTransform,
113 ffi => crate::ffi::pixman_f_transform_t,
114 impl => pixman_f_transform,
115 vector_t => FVector,
116}
117
118impl Transform {
119 #[inline]
121 pub fn new<T: Into<Fixed> + Copy>(matrix: [[T; 3]; 3]) -> Self {
122 let matrix = [
123 [
124 matrix[0][0].into().into_raw(),
125 matrix[0][1].into().into_raw(),
126 matrix[0][2].into().into_raw(),
127 ],
128 [
129 matrix[1][0].into().into_raw(),
130 matrix[1][1].into().into_raw(),
131 matrix[1][2].into().into_raw(),
132 ],
133 [
134 matrix[2][0].into().into_raw(),
135 matrix[2][1].into().into_raw(),
136 matrix[2][2].into().into_raw(),
137 ],
138 ];
139 Self(ffi::pixman_transform { matrix })
140 }
141
142 #[inline]
144 pub fn from_rotation(cos: impl Into<Fixed>, sin: impl Into<Fixed>) -> Self {
145 let mut transform = MaybeUninit::uninit();
146 unsafe {
147 ffi::pixman_transform_init_rotate(
148 transform.as_mut_ptr(),
149 cos.into().into_raw(),
150 sin.into().into_raw(),
151 );
152 }
153 Self(unsafe { transform.assume_init() })
154 }
155
156 #[inline]
158 pub fn from_scale(sx: impl Into<Fixed>, sy: impl Into<Fixed>) -> Self {
159 let mut transform = MaybeUninit::uninit();
160 unsafe {
161 ffi::pixman_transform_init_scale(
162 transform.as_mut_ptr(),
163 sx.into().into_raw(),
164 sy.into().into_raw(),
165 );
166 }
167 Self(unsafe { transform.assume_init() })
168 }
169
170 #[inline]
172 pub fn from_translation(tx: impl Into<Fixed>, ty: impl Into<Fixed>) -> Self {
173 let mut transform = MaybeUninit::uninit();
174 unsafe {
175 ffi::pixman_transform_init_translate(
176 transform.as_mut_ptr(),
177 tx.into().into_raw(),
178 ty.into().into_raw(),
179 );
180 }
181 Self(unsafe { transform.assume_init() })
182 }
183
184 pub fn is_identity(&self) -> bool {
186 unsafe { ffi::pixman_transform_is_identity(self.as_ptr()) == 1 }
187 }
188
189 pub fn is_int_translate(&self) -> bool {
191 unsafe { ffi::pixman_transform_is_int_translate(self.as_ptr()) == 1 }
192 }
193
194 pub fn is_inverse(&self, other: &Transform) -> bool {
196 unsafe { ffi::pixman_transform_is_inverse(self.as_ptr(), other.as_ptr()) == 1 }
197 }
198
199 pub fn is_scale(&self) -> bool {
201 unsafe { ffi::pixman_transform_is_scale(self.as_ptr()) == 1 }
202 }
203
204 pub fn rotate(
206 mut self,
207 c: impl Into<Fixed>,
208 s: impl Into<Fixed>,
209 reverse: bool,
210 ) -> Option<Self> {
211 let c = c.into().into_raw();
212 let s = s.into().into_raw();
213 let res = if reverse {
214 unsafe { ffi::pixman_transform_rotate(std::ptr::null_mut(), self.as_mut_ptr(), c, s) }
215 } else {
216 unsafe { ffi::pixman_transform_rotate(self.as_mut_ptr(), std::ptr::null_mut(), c, s) }
217 };
218
219 if res == 1 {
220 Some(self)
221 } else {
222 None
223 }
224 }
225
226 pub fn scale(
228 mut self,
229 sx: impl Into<Fixed>,
230 sy: impl Into<Fixed>,
231 reverse: bool,
232 ) -> Option<Self> {
233 let sx = sx.into().into_raw();
234 let sy = sy.into().into_raw();
235 let res = if reverse {
236 unsafe { ffi::pixman_transform_scale(std::ptr::null_mut(), self.as_mut_ptr(), sx, sy) }
237 } else {
238 unsafe { ffi::pixman_transform_scale(self.as_mut_ptr(), std::ptr::null_mut(), sx, sy) }
239 };
240
241 if res == 1 {
242 Some(self)
243 } else {
244 None
245 }
246 }
247
248 pub fn translate(
250 mut self,
251 tx: impl Into<Fixed>,
252 ty: impl Into<Fixed>,
253 reverse: bool,
254 ) -> Option<Self> {
255 let tx = tx.into().into_raw();
256 let ty = ty.into().into_raw();
257 let res = if reverse {
258 unsafe {
259 ffi::pixman_transform_translate(std::ptr::null_mut(), self.as_mut_ptr(), tx, ty)
260 }
261 } else {
262 unsafe {
263 ffi::pixman_transform_translate(self.as_mut_ptr(), std::ptr::null_mut(), tx, ty)
264 }
265 };
266
267 if res == 1 {
268 Some(self)
269 } else {
270 None
271 }
272 }
273
274 #[inline]
276 pub fn matrix(&self) -> [[Fixed; 3]; 3] {
277 [
278 [
279 Fixed::from_raw(self.0.matrix[0][0]),
280 Fixed::from_raw(self.0.matrix[0][1]),
281 Fixed::from_raw(self.0.matrix[0][2]),
282 ],
283 [
284 Fixed::from_raw(self.0.matrix[1][0]),
285 Fixed::from_raw(self.0.matrix[1][1]),
286 Fixed::from_raw(self.0.matrix[1][2]),
287 ],
288 [
289 Fixed::from_raw(self.0.matrix[2][0]),
290 Fixed::from_raw(self.0.matrix[2][1]),
291 Fixed::from_raw(self.0.matrix[2][2]),
292 ],
293 ]
294 }
295}
296
297impl<T: Into<Fixed> + Copy> From<[[T; 3]; 3]> for Transform {
298 #[inline]
299 fn from(value: [[T; 3]; 3]) -> Self {
300 Transform::new(value)
301 }
302}
303
304#[derive(Debug, Error)]
306#[error("Failed to init Transform from FTransform")]
307pub struct TransformConvertError;
308
309impl TryFrom<FTransform> for Transform {
310 type Error = TransformConvertError;
311
312 fn try_from(value: FTransform) -> Result<Self, Self::Error> {
313 let mut transform = MaybeUninit::uninit();
314 let res = unsafe {
315 ffi::pixman_transform_from_pixman_f_transform(transform.as_mut_ptr(), value.as_ptr())
316 };
317 if res != 1 {
318 Err(TransformConvertError)
319 } else {
320 Ok(Self(unsafe { transform.assume_init() }))
321 }
322 }
323}
324
325impl FTransform {
326 #[inline]
328 pub fn new(m: [[f64; 3]; 3]) -> Self {
329 let m = [
330 [m[0][0], m[0][1], m[0][2]],
331 [m[1][0], m[1][1], m[1][2]],
332 [m[2][0], m[2][1], m[2][2]],
333 ];
334 Self(ffi::pixman_f_transform_t { m })
335 }
336
337 #[inline]
339 pub fn from_rotation(cos: f64, sin: f64) -> Self {
340 let mut transform = MaybeUninit::uninit();
341 unsafe {
342 ffi::pixman_f_transform_init_rotate(transform.as_mut_ptr(), cos, sin);
343 }
344 Self(unsafe { transform.assume_init() })
345 }
346
347 #[inline]
349 pub fn from_scale(sx: f64, sy: f64) -> Self {
350 let mut transform = MaybeUninit::uninit();
351 unsafe {
352 ffi::pixman_f_transform_init_scale(transform.as_mut_ptr(), sx, sy);
353 }
354 Self(unsafe { transform.assume_init() })
355 }
356
357 #[inline]
359 pub fn from_translation(tx: f64, ty: f64) -> Self {
360 let mut transform = MaybeUninit::uninit();
361 unsafe {
362 ffi::pixman_f_transform_init_translate(transform.as_mut_ptr(), tx, ty);
363 }
364 Self(unsafe { transform.assume_init() })
365 }
366
367 pub fn rotate(mut self, c: f64, s: f64, reverse: bool) -> Option<Self> {
369 let res = if reverse {
370 unsafe { ffi::pixman_f_transform_rotate(std::ptr::null_mut(), self.as_mut_ptr(), c, s) }
371 } else {
372 unsafe { ffi::pixman_f_transform_rotate(self.as_mut_ptr(), std::ptr::null_mut(), c, s) }
373 };
374
375 if res == 1 {
376 Some(self)
377 } else {
378 None
379 }
380 }
381
382 pub fn scale(mut self, sx: f64, sy: f64, reverse: bool) -> Option<Self> {
384 let res = if reverse {
385 unsafe {
386 ffi::pixman_f_transform_scale(std::ptr::null_mut(), self.as_mut_ptr(), sx, sy)
387 }
388 } else {
389 unsafe {
390 ffi::pixman_f_transform_scale(self.as_mut_ptr(), std::ptr::null_mut(), sx, sy)
391 }
392 };
393
394 if res == 1 {
395 Some(self)
396 } else {
397 None
398 }
399 }
400
401 pub fn translate(mut self, tx: f64, ty: f64, reverse: bool) -> Option<Self> {
403 let res = if reverse {
404 unsafe {
405 ffi::pixman_f_transform_translate(std::ptr::null_mut(), self.as_mut_ptr(), tx, ty)
406 }
407 } else {
408 unsafe {
409 ffi::pixman_f_transform_translate(self.as_mut_ptr(), std::ptr::null_mut(), tx, ty)
410 }
411 };
412
413 if res == 1 {
414 Some(self)
415 } else {
416 None
417 }
418 }
419
420 #[inline]
422 pub fn matrix(&self) -> [[f64; 3]; 3] {
423 self.0.m
424 }
425}
426
427impl From<[[f64; 3]; 3]> for FTransform {
428 #[inline]
429 fn from(value: [[f64; 3]; 3]) -> Self {
430 FTransform::new(value)
431 }
432}
433
434impl From<Transform> for FTransform {
435 fn from(value: Transform) -> Self {
436 let mut transform = MaybeUninit::uninit();
437 unsafe {
438 ffi::pixman_f_transform_from_pixman_transform(transform.as_mut_ptr(), value.as_ptr());
439 }
440 Self(unsafe { transform.assume_init() })
441 }
442}