1use crate::bridge::ffi;
29use crate::point::Point;
30use crate::rect::Rect;
31use std::ops::{Index, IndexMut, Mul};
32
33#[repr(i32)]
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39pub enum ScaleToFit {
40 Fill = 0,
43 Start = 1,
46 Center = 2,
49 End = 3,
52}
53
54pub mod matrix_type {
57 #![allow(dead_code)]
58 pub const IDENTITY: u32 = 0;
60 pub const TRANSLATE: u32 = 0x01;
62 pub const SCALE: u32 = 0x02;
64 pub const AFFINE: u32 = 0x04;
66 pub const PERSPECTIVE: u32 = 0x08;
68}
69
70pub mod coeff {
73 pub const M_SCALE_X: usize = 0;
75 pub const M_SKEW_X: usize = 1;
77 pub const M_TRANS_X: usize = 2;
79 pub const M_SKEW_Y: usize = 3;
81 pub const M_SCALE_Y: usize = 4;
83 pub const M_TRANS_Y: usize = 5;
85 pub const M_PERSP_0: usize = 6;
87 pub const M_PERSP_1: usize = 7;
89 pub const M_PERSP_2: usize = 8;
91}
92
93#[derive(Debug, Clone, Copy)]
96pub struct Matrix {
97 pub mat: [f32; 9],
100}
101
102impl Matrix {
103 pub const IDENTITY: Self = Self {
105 mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
106 };
107
108 #[inline]
110 pub const fn identity() -> Self {
111 Self::IDENTITY
112 }
113
114 pub fn invalid() -> Self {
117 let x = f32::MAX;
118 Self { mat: [x; 9] }
119 }
120
121 #[inline]
125 pub fn scale(sx: f32, sy: f32) -> Self {
126 let mut m = Self::IDENTITY;
127 m.set_scale(sx, sy);
128 m
129 }
130
131 #[inline]
133 pub fn translate(dx: f32, dy: f32) -> Self {
134 let mut m = Self::IDENTITY;
135 m.set_translate(dx, dy);
136 m
137 }
138
139 pub fn rotate_deg(degrees: f32) -> Self {
141 let mut m = Self::IDENTITY;
142 m.set_rotate(degrees);
143 m
144 }
145
146 #[inline]
148 pub fn make_all(
149 scale_x: f32,
150 skew_x: f32,
151 trans_x: f32,
152 skew_y: f32,
153 scale_y: f32,
154 trans_y: f32,
155 pers0: f32,
156 pers1: f32,
157 pers2: f32,
158 ) -> Self {
159 let mut m = Self::IDENTITY;
160 m.set_all(
161 scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
162 );
163 m
164 }
165
166 #[inline]
168 pub const fn from_row_major_9(mat: [f32; 9]) -> Self {
169 Self { mat }
170 }
171
172 #[inline]
174 pub fn concat(a: &Matrix, b: &Matrix) -> Matrix {
175 let mut out = Self::IDENTITY;
176 ffi::matrix_set_concat(out.mat.as_mut_slice(), a.mat.as_slice(), b.mat.as_slice());
177 out
178 }
179
180 #[inline]
184 pub fn reset(&mut self) -> &mut Self {
185 ffi::matrix_reset(self.mat.as_mut_slice());
186 self
187 }
188
189 #[inline]
191 pub fn set_identity(&mut self) -> &mut Self {
192 self.reset()
193 }
194
195 pub fn set_all(
197 &mut self,
198 scale_x: f32,
199 skew_x: f32,
200 trans_x: f32,
201 skew_y: f32,
202 scale_y: f32,
203 trans_y: f32,
204 pers0: f32,
205 pers1: f32,
206 pers2: f32,
207 ) -> &mut Self {
208 ffi::matrix_set_all(
209 self.mat.as_mut_slice(),
210 scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
211 );
212 self
213 }
214
215 #[inline]
217 pub fn set_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
218 ffi::matrix_set_translate(self.mat.as_mut_slice(), dx, dy);
219 self
220 }
221
222 #[inline]
224 pub fn set_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
225 ffi::matrix_set_scale(self.mat.as_mut_slice(), sx, sy);
226 self
227 }
228
229 #[inline]
231 pub fn set_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
232 ffi::matrix_set_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
233 self
234 }
235
236 #[inline]
238 pub fn set_rotate(&mut self, degrees: f32) -> &mut Self {
239 ffi::matrix_set_rotate(self.mat.as_mut_slice(), degrees);
240 self
241 }
242
243 #[inline]
245 pub fn set_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
246 ffi::matrix_set_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
247 self
248 }
249
250 #[inline]
252 pub fn set_sin_cos(&mut self, sin_v: f32, cos_v: f32) -> &mut Self {
253 ffi::matrix_set_sin_cos(self.mat.as_mut_slice(), sin_v, cos_v);
254 self
255 }
256
257 #[inline]
259 pub fn set_sin_cos_pivot(&mut self, sin_v: f32, cos_v: f32, px: f32, py: f32) -> &mut Self {
260 ffi::matrix_set_sin_cos_pivot(self.mat.as_mut_slice(), sin_v, cos_v, px, py);
261 self
262 }
263
264 #[inline]
266 pub fn set_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
267 ffi::matrix_set_skew(self.mat.as_mut_slice(), kx, ky);
268 self
269 }
270
271 #[inline]
273 pub fn set_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
274 ffi::matrix_set_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
275 self
276 }
277
278 #[inline]
280 pub fn set_scale_translate(&mut self, sx: f32, sy: f32, tx: f32, ty: f32) -> &mut Self {
281 ffi::matrix_set_scale_translate(self.mat.as_mut_slice(), sx, sy, tx, ty);
282 self
283 }
284
285 #[inline]
287 pub fn set_concat(&mut self, a: &Matrix, b: &Matrix) -> &mut Self {
288 ffi::matrix_set_concat(
289 self.mat.as_mut_slice(),
290 a.mat.as_slice(),
291 b.mat.as_slice(),
292 );
293 self
294 }
295
296 pub fn set_rect_to_rect(&mut self, src: &Rect, dst: &Rect, stf: ScaleToFit) -> bool {
299 let sr: ffi::Rect = (*src).into();
300 let dr: ffi::Rect = (*dst).into();
301 ffi::matrix_set_rect_to_rect(self.mat.as_mut_slice(), &sr, &dr, stf as i32)
302 }
303
304 #[inline]
308 pub fn pre_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
309 ffi::matrix_pre_translate(self.mat.as_mut_slice(), dx, dy);
310 self
311 }
312 #[inline]
314 pub fn pre_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
315 ffi::matrix_pre_scale(self.mat.as_mut_slice(), sx, sy);
316 self
317 }
318 #[inline]
320 pub fn pre_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
321 ffi::matrix_pre_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
322 self
323 }
324 #[inline]
326 pub fn pre_rotate(&mut self, degrees: f32) -> &mut Self {
327 ffi::matrix_pre_rotate(self.mat.as_mut_slice(), degrees);
328 self
329 }
330 #[inline]
332 pub fn pre_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
333 ffi::matrix_pre_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
334 self
335 }
336 #[inline]
338 pub fn pre_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
339 ffi::matrix_pre_skew(self.mat.as_mut_slice(), kx, ky);
340 self
341 }
342 #[inline]
344 pub fn pre_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
345 ffi::matrix_pre_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
346 self
347 }
348 #[inline]
350 pub fn pre_concat(&mut self, other: &Matrix) -> &mut Self {
351 ffi::matrix_pre_concat(self.mat.as_mut_slice(), other.mat.as_slice());
352 self
353 }
354
355 #[inline]
357 pub fn post_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
358 ffi::matrix_post_translate(self.mat.as_mut_slice(), dx, dy);
359 self
360 }
361 #[inline]
363 pub fn post_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
364 ffi::matrix_post_scale(self.mat.as_mut_slice(), sx, sy);
365 self
366 }
367 #[inline]
369 pub fn post_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
370 ffi::matrix_post_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
371 self
372 }
373 #[inline]
375 pub fn post_rotate(&mut self, degrees: f32) -> &mut Self {
376 ffi::matrix_post_rotate(self.mat.as_mut_slice(), degrees);
377 self
378 }
379 #[inline]
381 pub fn post_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
382 ffi::matrix_post_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
383 self
384 }
385 #[inline]
387 pub fn post_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
388 ffi::matrix_post_skew(self.mat.as_mut_slice(), kx, ky);
389 self
390 }
391 #[inline]
393 pub fn post_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
394 ffi::matrix_post_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
395 self
396 }
397 #[inline]
399 pub fn post_concat(&mut self, other: &Matrix) -> &mut Self {
400 ffi::matrix_post_concat(self.mat.as_mut_slice(), other.mat.as_slice());
401 self
402 }
403
404 #[inline]
408 pub fn get_type(&self) -> u32 {
409 ffi::matrix_get_type(self.mat.as_slice())
410 }
411
412 #[inline]
414 pub fn is_identity(&self) -> bool {
415 ffi::matrix_is_identity(self.mat.as_slice())
416 }
417
418 #[inline]
420 pub fn is_scale_translate(&self) -> bool {
421 ffi::matrix_is_scale_translate_matrix(self.mat.as_slice())
422 }
423
424 #[inline]
426 pub fn rect_stays_rect(&self) -> bool {
427 ffi::matrix_rect_stays_rect(self.mat.as_slice())
428 }
429
430 #[inline]
433 pub fn preserves_axis_alignment(&self) -> bool {
434 self.rect_stays_rect()
435 }
436
437 #[inline]
439 pub fn has_perspective(&self) -> bool {
440 ffi::matrix_has_perspective(self.mat.as_slice())
441 }
442
443 #[inline]
445 pub fn is_finite(&self) -> bool {
446 ffi::matrix_is_finite_matrix(self.mat.as_slice())
447 }
448
449 #[inline]
451 pub fn get_scale_x(&self) -> f32 {
452 self.mat[coeff::M_SCALE_X]
453 }
454 #[inline]
456 pub fn get_skew_x(&self) -> f32 {
457 self.mat[coeff::M_SKEW_X]
458 }
459 #[inline]
461 pub fn get_translate_x(&self) -> f32 {
462 self.mat[coeff::M_TRANS_X]
463 }
464 #[inline]
466 pub fn get_skew_y(&self) -> f32 {
467 self.mat[coeff::M_SKEW_Y]
468 }
469 #[inline]
471 pub fn get_scale_y(&self) -> f32 {
472 self.mat[coeff::M_SCALE_Y]
473 }
474 #[inline]
476 pub fn get_translate_y(&self) -> f32 {
477 self.mat[coeff::M_TRANS_Y]
478 }
479 #[inline]
481 pub fn get_persp_x(&self) -> f32 {
482 self.mat[coeff::M_PERSP_0]
483 }
484 #[inline]
486 pub fn get_persp_y(&self) -> f32 {
487 self.mat[coeff::M_PERSP_1]
488 }
489 #[inline]
491 pub fn get_persp_z(&self) -> f32 {
492 self.mat[coeff::M_PERSP_2]
493 }
494
495 #[inline]
497 pub fn get(&self, index: usize) -> f32 {
498 self.mat[index]
499 }
500
501 #[inline]
503 pub fn set_coeff(&mut self, index: usize, value: f32) -> &mut Self {
504 self.mat[index] = value;
505 self
506 }
507
508 pub fn invert_to(&self, out_or_inverse: &mut Matrix) -> bool {
510 ffi::matrix_invert(
511 self.mat.as_slice(),
512 out_or_inverse.mat.as_mut_slice(),
513 )
514 }
515
516 pub fn try_inverse(&self) -> Option<Matrix> {
518 let mut out = Self::IDENTITY;
519 if self.invert_to(&mut out) {
520 Some(out)
521 } else {
522 None
523 }
524 }
525
526 #[inline]
528 pub fn map_xy(&self, x: f32, y: f32) -> Point {
529 let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
530 ffi::matrix_map_xy(self.mat.as_slice(), x, y, &mut p);
531 p.into()
532 }
533
534 #[inline]
536 pub fn map_point(&self, p: Point) -> Point {
537 self.map_xy(p.x, p.y)
538 }
539
540 pub fn map_homogeneous(&self, x: f32, y: f32, z: f32) -> [f32; 3] {
543 let m = &self.mat;
544 [
545 m[0] * x + m[1] * y + m[2] * z,
546 m[3] * x + m[4] * y + m[5] * z,
547 m[6] * x + m[7] * y + m[8] * z,
548 ]
549 }
550
551 pub fn map_points(&self, dst: &mut [Point], src: &[Point]) {
553 let n = src.len().min(dst.len());
554 for i in 0..n {
555 dst[i] = self.map_point(src[i]);
556 }
557 }
558
559 pub fn map_points_inplace(&self, pts: &mut [Point]) {
561 for p in pts.iter_mut() {
562 *p = self.map_point(*p);
563 }
564 }
565
566 #[inline]
568 pub fn map_origin(&self) -> Point {
569 let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
570 ffi::matrix_map_origin(self.mat.as_slice(), &mut p);
571 p.into()
572 }
573
574 pub fn map_rect(&self, src: &Rect) -> (Rect, bool) {
576 let mut d = ffi::Rect {
577 fLeft: 0.0,
578 fTop: 0.0,
579 fRight: 0.0,
580 fBottom: 0.0,
581 };
582 let s: ffi::Rect = (*src).into();
583 let axis = ffi::matrix_map_rect(self.mat.as_slice(), &s, &mut d);
584 (d.into(), axis)
585 }
586
587 pub fn map_rect_scale_translate(&self, src: &Rect) -> Rect {
589 let mut d = ffi::Rect {
590 fLeft: 0.0,
591 fTop: 0.0,
592 fRight: 0.0,
593 fBottom: 0.0,
594 };
595 let s: ffi::Rect = (*src).into();
596 ffi::matrix_map_rect_scale_translate(self.mat.as_slice(), &s, &mut d);
597 d.into()
598 }
599
600 #[inline]
602 pub fn get_min_scale(&self) -> f32 {
603 ffi::matrix_get_min_scale(self.mat.as_slice())
604 }
605
606 #[inline]
608 pub fn get_max_scale(&self) -> f32 {
609 ffi::matrix_get_max_scale(self.mat.as_slice())
610 }
611
612 pub fn get_min_max_scales(&self) -> Option<(f32, f32)> {
614 let mut a = 0.0f32;
615 let mut b = 0.0f32;
616 if ffi::matrix_get_min_max_scales(self.mat.as_slice(), &mut a, &mut b) {
617 Some((a, b))
618 } else {
619 None
620 }
621 }
622
623 pub fn write_to_memory(&self, buf: &mut [u8]) -> usize {
625 ffi::matrix_write_to_memory(self.mat.as_slice(), buf)
626 }
627
628 pub fn read_from_memory(&mut self, buf: &[u8]) -> usize {
630 ffi::matrix_read_from_memory(self.mat.as_mut_slice(), buf)
631 }
632}
633
634impl Default for Matrix {
635 fn default() -> Self {
637 Self::IDENTITY
638 }
639}
640
641impl PartialEq for Matrix {
642 fn eq(&self, other: &Self) -> bool {
644 ffi::matrix_equals(self.mat.as_slice(), other.mat.as_slice())
645 }
646}
647
648impl Eq for Matrix {}
649
650impl Index<usize> for Matrix {
651 type Output = f32;
652 fn index(&self, index: usize) -> &f32 {
653 &self.mat[index]
654 }
655}
656
657impl IndexMut<usize> for Matrix {
658 fn index_mut(&mut self, index: usize) -> &mut f32 {
659 &mut self.mat[index]
660 }
661}
662
663impl Mul for Matrix {
665 type Output = Matrix;
666 fn mul(self, rhs: Matrix) -> Matrix {
667 Matrix::concat(&self, &rhs)
668 }
669}
670
671impl Mul<&Matrix> for Matrix {
673 type Output = Matrix;
674 fn mul(self, rhs: &Matrix) -> Matrix {
675 Matrix::concat(&self, rhs)
676 }
677}
678
679impl Mul<Matrix> for &Matrix {
681 type Output = Matrix;
682 fn mul(self, rhs: Matrix) -> Matrix {
683 Matrix::concat(self, &rhs)
684 }
685}
686
687impl Mul for &Matrix {
689 type Output = Matrix;
690 fn mul(self, rhs: &Matrix) -> Matrix {
691 Matrix::concat(self, rhs)
692 }
693}