cairo/
matrices.rs
1use std::fmt;
4#[cfg(feature = "use_glib")]
5use std::marker::PhantomData;
6
7use crate::{ffi, utils::status_to_result, Error};
8
9#[repr(transparent)]
10#[derive(Clone, Copy, PartialEq)]
11#[doc(alias = "cairo_matrix_t")]
12pub struct Matrix(ffi::cairo_matrix_t);
13
14impl Default for Matrix {
15 fn default() -> Self {
16 Self::identity()
17 }
18}
19
20impl Matrix {
21 #[inline]
22 pub(crate) fn ptr(&self) -> *const ffi::cairo_matrix_t {
23 self as *const Matrix as _
24 }
25
26 #[inline]
27 pub(crate) fn mut_ptr(&mut self) -> *mut ffi::cairo_matrix_t {
28 self as *mut Matrix as _
29 }
30
31 #[inline]
32 pub(crate) fn null() -> Self {
33 Self(ffi::cairo_matrix_t {
34 xx: 0.0,
35 yx: 0.0,
36 xy: 0.0,
37 yy: 0.0,
38 x0: 0.0,
39 y0: 0.0,
40 })
41 }
42
43 #[inline]
44 pub fn identity() -> Self {
45 Self(ffi::cairo_matrix_t {
46 xx: 1.0,
47 yx: 0.0,
48 xy: 0.0,
49 yy: 1.0,
50 x0: 0.0,
51 y0: 0.0,
52 })
53 }
54
55 #[inline]
56 pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Self {
57 Self(ffi::cairo_matrix_t {
58 xx,
59 yx,
60 xy,
61 yy,
62 x0,
63 y0,
64 })
65 }
66
67 #[inline]
68 pub fn xx(&self) -> f64 {
69 self.0.xx
70 }
71 #[inline]
72 pub fn set_xx(&mut self, xx: f64) {
73 self.0.xx = xx;
74 }
75 #[inline]
76 pub fn yx(&self) -> f64 {
77 self.0.yx
78 }
79 #[inline]
80 pub fn set_yx(&mut self, yx: f64) {
81 self.0.yx = yx;
82 }
83 #[inline]
84 pub fn xy(&self) -> f64 {
85 self.0.xy
86 }
87 #[inline]
88 pub fn set_xy(&mut self, xy: f64) {
89 self.0.xy = xy;
90 }
91 #[inline]
92 pub fn yy(&self) -> f64 {
93 self.0.yy
94 }
95 #[inline]
96 pub fn set_yy(&mut self, yy: f64) {
97 self.0.yy = yy;
98 }
99 #[inline]
100 pub fn x0(&self) -> f64 {
101 self.0.x0
102 }
103 #[inline]
104 pub fn set_x0(&mut self, x0: f64) {
105 self.0.x0 = x0;
106 }
107 #[inline]
108 pub fn y0(&self) -> f64 {
109 self.0.y0
110 }
111 #[inline]
112 pub fn set_y0(&mut self, y0: f64) {
113 self.0.y0 = y0;
114 }
115
116 #[doc(alias = "cairo_matrix_multiply")]
117 #[inline]
118 pub fn multiply(left: &Matrix, right: &Matrix) -> Matrix {
119 let mut matrix = Self::null();
120 unsafe {
121 ffi::cairo_matrix_multiply(matrix.mut_ptr(), left.ptr(), right.ptr());
122 }
123 matrix
124 }
125
126 #[doc(alias = "cairo_matrix_translate")]
127 #[inline]
128 pub fn translate(&mut self, tx: f64, ty: f64) {
129 unsafe { ffi::cairo_matrix_translate(self.mut_ptr(), tx, ty) }
130 }
131
132 #[doc(alias = "cairo_matrix_scale")]
133 #[inline]
134 pub fn scale(&mut self, sx: f64, sy: f64) {
135 unsafe { ffi::cairo_matrix_scale(self.mut_ptr(), sx, sy) }
136 }
137
138 #[doc(alias = "cairo_matrix_rotate")]
139 #[inline]
140 pub fn rotate(&mut self, angle: f64) {
141 unsafe { ffi::cairo_matrix_rotate(self.mut_ptr(), angle) }
142 }
143
144 #[doc(alias = "cairo_matrix_invert")]
145 #[inline]
146 pub fn invert(&mut self) {
147 let status = unsafe { ffi::cairo_matrix_invert(self.mut_ptr()) };
148 status_to_result(status).expect("Failed to invert the matrix")
149 }
150
151 #[doc(alias = "cairo_matrix_invert")]
152 pub fn try_invert(&self) -> Result<Matrix, Error> {
153 let mut matrix = *self;
154
155 let status = unsafe { ffi::cairo_matrix_invert(matrix.mut_ptr()) };
156 status_to_result(status)?;
157 Ok(matrix)
158 }
159
160 #[doc(alias = "cairo_matrix_transform_distance")]
161 #[inline]
162 pub fn transform_distance(&self, _dx: f64, _dy: f64) -> (f64, f64) {
163 let mut dx = _dx;
164 let mut dy = _dy;
165
166 unsafe {
167 ffi::cairo_matrix_transform_distance(self.ptr(), &mut dx, &mut dy);
168 }
169 (dx, dy)
170 }
171
172 #[doc(alias = "cairo_matrix_transform_point")]
173 #[inline]
174 pub fn transform_point(&self, _x: f64, _y: f64) -> (f64, f64) {
175 let mut x = _x;
176 let mut y = _y;
177
178 unsafe {
179 ffi::cairo_matrix_transform_point(self.ptr(), &mut x, &mut y);
180 }
181 (x, y)
182 }
183}
184
185impl fmt::Debug for Matrix {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("Matrix")
188 .field("xx", &self.xx())
189 .field("yx", &self.yx())
190 .field("xy", &self.xy())
191 .field("yy", &self.yy())
192 .field("x0", &self.x0())
193 .field("y0", &self.y0())
194 .finish()
195 }
196}
197
198#[cfg(feature = "use_glib")]
199#[doc(hidden)]
200impl Uninitialized for Matrix {
201 #[inline]
202 unsafe fn uninitialized() -> Self {
203 std::mem::zeroed()
204 }
205}
206
207#[cfg(feature = "use_glib")]
208#[doc(hidden)]
209impl<'a> ToGlibPtr<'a, *const ffi::cairo_matrix_t> for Matrix {
210 type Storage = PhantomData<&'a Self>;
211
212 #[inline]
213 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::cairo_matrix_t, Self> {
214 Stash(
215 self as *const Matrix as *const ffi::cairo_matrix_t,
216 PhantomData,
217 )
218 }
219}
220
221#[cfg(feature = "use_glib")]
222#[doc(hidden)]
223impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_matrix_t> for Matrix {
224 type Storage = PhantomData<&'a mut Self>;
225
226 #[inline]
227 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_matrix_t, Self> {
228 StashMut(self as *mut Matrix as *mut ffi::cairo_matrix_t, PhantomData)
229 }
230}
231
232#[cfg(feature = "use_glib")]
233#[doc(hidden)]
234impl FromGlibPtrNone<*const ffi::cairo_matrix_t> for Matrix {
235 #[inline]
236 unsafe fn from_glib_none(ptr: *const ffi::cairo_matrix_t) -> Self {
237 *(ptr as *const Matrix)
238 }
239}
240
241#[cfg(feature = "use_glib")]
242#[doc(hidden)]
243impl FromGlibPtrBorrow<*mut ffi::cairo_matrix_t> for Matrix {
244 #[inline]
245 unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_matrix_t) -> crate::Borrowed<Self> {
246 crate::Borrowed::new(*(ptr as *mut Matrix))
247 }
248}
249
250#[cfg(feature = "use_glib")]
251#[doc(hidden)]
252impl FromGlibPtrNone<*mut ffi::cairo_matrix_t> for Matrix {
253 #[inline]
254 unsafe fn from_glib_none(ptr: *mut ffi::cairo_matrix_t) -> Self {
255 *(ptr as *mut Matrix)
256 }
257}
258
259#[cfg(feature = "use_glib")]
260gvalue_impl_inline!(
261 Matrix,
262 ffi::cairo_matrix_t,
263 ffi::gobject::cairo_gobject_matrix_get_type
264);
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn invalid_matrix_does_not_invert() {
272 let matrix = Matrix::null();
273 assert!(matrix.try_invert().is_err());
274 }
275
276 #[test]
277 #[should_panic]
278 fn inverting_invalid_matrix_panics() {
279 let mut matrix = Matrix::null();
280 matrix.invert();
281 }
282
283 #[test]
284 fn valid_matrix_try_invert() {
285 let matrix = Matrix::identity();
286 assert_eq!(matrix.try_invert().unwrap(), Matrix::identity());
287 }
288
289 #[test]
290 fn valid_matrix_invert() {
291 let mut matrix = Matrix::identity();
292 matrix.invert();
293 assert_eq!(matrix, Matrix::identity());
294 }
295}