pixman/
transform.rs

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            /// Transform the provided bounds
15            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            /// Initialize an identity transform
25            #[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            /// Invert this transform
35            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            /// Multiply this transform with the provided transform
47            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            /// Transform the given point
56            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            /// Transform the given point
66            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    /// Fixed-point transform
100    #[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    /// Floating-point transform
110    #[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    /// Initialize a transform from the provided matrix
120    #[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    /// Initialize a transform from a rotation
143    #[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    /// Initialize a transform from a scale
157    #[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    /// Initialize a transform from a translation
171    #[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    /// Whether this transform represents an identity transform
185    pub fn is_identity(&self) -> bool {
186        unsafe { ffi::pixman_transform_is_identity(self.as_ptr()) == 1 }
187    }
188
189    /// TODO: Docs
190    pub fn is_int_translate(&self) -> bool {
191        unsafe { ffi::pixman_transform_is_int_translate(self.as_ptr()) == 1 }
192    }
193
194    /// Whether this transform represents an inverse transform
195    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    /// Whether this transform contains a scale transform
200    pub fn is_scale(&self) -> bool {
201        unsafe { ffi::pixman_transform_is_scale(self.as_ptr()) == 1 }
202    }
203
204    /// Add a rotation to this transform
205    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    /// Add a scale to this transform
227    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    /// Add a translation to this transform
249    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    /// Access the current transform matrix
275    #[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/// Failed to init Transform from FTransform
305#[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    /// Initialize a transform from the provided matrix
327    #[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    /// Initialize a transform from a rotation
338    #[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    /// Initialize a transform from a scale
348    #[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    /// Initialize a transform from a translation
358    #[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    /// Add a rotation to this transform
368    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    /// Add a scale to this transform
383    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    /// Add a translation to this transform
402    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    /// Access the current transform matrix
421    #[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}