skia_safe/core/
matrix.rs

1use super::scalar_;
2use crate::{prelude::*, scalar, Point, Point3, RSXform, Rect, Scalar, Size, Vector};
3use skia_bindings::{self as sb, SkMatrix};
4use std::{
5    ops::{Index, IndexMut, Mul},
6    slice,
7};
8
9pub use skia_bindings::SkApplyPerspectiveClip as ApplyPerspectiveClip;
10variant_name!(ApplyPerspectiveClip::Yes);
11
12bitflags! {
13    // m85: On Windows the SkMatrix_TypeMask is defined as i32,
14    // but we stick to u32 (macOS / Linux), because there is no need to leak
15    // the platform difference to the Rust side.
16    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17    pub struct TypeMask: u32 {
18        const IDENTITY = sb::SkMatrix_TypeMask_kIdentity_Mask as _;
19        const TRANSLATE = sb::SkMatrix_TypeMask_kTranslate_Mask as _;
20        const SCALE = sb::SkMatrix_TypeMask_kScale_Mask as _;
21        const AFFINE = sb::SkMatrix_TypeMask_kAffine_Mask as _;
22        const PERSPECTIVE = sb::SkMatrix_TypeMask_kPerspective_Mask as _;
23    }
24}
25
26impl TypeMask {
27    const UNKNOWN: u32 = sb::SkMatrix_kUnknown_Mask as _;
28}
29
30pub use skia_bindings::SkMatrix_ScaleToFit as ScaleToFit;
31variant_name!(ScaleToFit::Fill);
32
33#[repr(C)]
34#[derive(Copy, Clone, Debug)]
35pub struct Matrix {
36    mat: [scalar; 9usize],
37    type_mask: u32,
38}
39
40native_transmutable!(SkMatrix, Matrix, matrix_layout);
41
42impl PartialEq for Matrix {
43    fn eq(&self, rhs: &Self) -> bool {
44        unsafe { sb::C_SkMatrix_Equals(self.native(), rhs.native()) }
45    }
46}
47
48impl Mul for Matrix {
49    type Output = Self;
50    fn mul(self, rhs: Matrix) -> Self::Output {
51        Matrix::concat(&self, &rhs)
52    }
53}
54
55#[derive(Copy, Clone, PartialEq, Eq, Debug)]
56pub enum Member {
57    ScaleX = 0,
58    SkewX = 1,
59    TransX = 2,
60    SkewY = 3,
61    ScaleY = 4,
62    TransY = 5,
63    Persp0 = 6,
64    Persp1 = 7,
65    Persp2 = 8,
66}
67
68#[derive(Copy, Clone, PartialEq, Eq, Debug)]
69pub enum AffineMember {
70    ScaleX = 0,
71    SkewY = 1,
72    SkewX = 2,
73    ScaleY = 3,
74    TransX = 4,
75    TransY = 5,
76}
77
78impl Index<Member> for Matrix {
79    type Output = scalar;
80
81    fn index(&self, index: Member) -> &Self::Output {
82        &self[index as usize]
83    }
84}
85
86impl Index<AffineMember> for Matrix {
87    type Output = scalar;
88
89    fn index(&self, index: AffineMember) -> &Self::Output {
90        &self[index as usize]
91    }
92}
93
94impl Index<usize> for Matrix {
95    type Output = scalar;
96
97    fn index(&self, index: usize) -> &Self::Output {
98        &self.native().fMat[index]
99    }
100}
101
102impl IndexMut<Member> for Matrix {
103    fn index_mut(&mut self, index: Member) -> &mut Self::Output {
104        self.index_mut(index as usize)
105    }
106}
107
108impl IndexMut<AffineMember> for Matrix {
109    fn index_mut(&mut self, index: AffineMember) -> &mut Self::Output {
110        self.index_mut(index as usize)
111    }
112}
113
114impl IndexMut<usize> for Matrix {
115    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
116        unsafe { &mut *sb::C_SkMatrix_SubscriptMut(self.native_mut(), index) }
117    }
118}
119
120impl Default for Matrix {
121    fn default() -> Self {
122        Matrix::new()
123    }
124}
125
126impl Matrix {
127    const fn new() -> Self {
128        Self {
129            mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
130            type_mask: TypeMask::IDENTITY.bits() | 0x10,
131        }
132    }
133
134    #[deprecated(since = "0.33.0", note = "use Matrix::scale()")]
135    pub fn new_scale(scale: (scalar, scalar)) -> Self {
136        Self::scale(scale)
137    }
138
139    #[must_use]
140    pub fn scale((sx, sy): (scalar, scalar)) -> Self {
141        let mut m = Self::new();
142        m.set_scale((sx, sy), None);
143        m
144    }
145
146    #[deprecated(since = "0.33.0", note = "use Matrix::translate()")]
147    pub fn new_trans(d: impl Into<Vector>) -> Self {
148        Self::translate(d)
149    }
150
151    #[must_use]
152    pub fn translate(d: impl Into<Vector>) -> Self {
153        let mut m = Self::new();
154        m.set_translate(d);
155        m
156    }
157
158    #[must_use]
159    pub fn rotate_deg(deg: scalar) -> Self {
160        let mut m = Self::new();
161        m.set_rotate(deg, None);
162        m
163    }
164
165    #[must_use]
166    pub fn rotate_deg_pivot(deg: scalar, pivot: impl Into<Point>) -> Self {
167        let mut m = Self::new();
168        m.set_rotate(deg, pivot.into());
169        m
170    }
171
172    #[must_use]
173    pub fn rotate_rad(rad: scalar) -> Self {
174        Self::rotate_deg(scalar_::radians_to_degrees(rad))
175    }
176
177    #[must_use]
178    pub fn skew((kx, ky): (scalar, scalar)) -> Self {
179        let mut m = Self::new();
180        m.set_skew((kx, ky), None);
181        m
182    }
183
184    #[must_use]
185    pub fn rect_to_rect(
186        src: impl AsRef<Rect>,
187        dst: impl AsRef<Rect>,
188        scale_to_fit: impl Into<Option<ScaleToFit>>,
189    ) -> Option<Self> {
190        Self::from_rect_to_rect(src, dst, scale_to_fit.into().unwrap_or(ScaleToFit::Fill))
191    }
192
193    #[must_use]
194    #[allow(clippy::too_many_arguments)]
195    pub fn new_all(
196        scale_x: scalar,
197        skew_x: scalar,
198        trans_x: scalar,
199        skew_y: scalar,
200        scale_y: scalar,
201        trans_y: scalar,
202        pers_0: scalar,
203        pers_1: scalar,
204        pers_2: scalar,
205    ) -> Self {
206        let mut m = Self::new();
207        m.set_all(
208            scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers_0, pers_1, pers_2,
209        );
210        m
211    }
212
213    pub fn get_type(&self) -> TypeMask {
214        TypeMask::from_bits_truncate(unsafe { sb::C_SkMatrix_getType(self.native()) } as _)
215    }
216
217    pub fn is_identity(&self) -> bool {
218        self.get_type() == TypeMask::IDENTITY
219    }
220
221    pub fn is_scale_translate(&self) -> bool {
222        (self.get_type() & !(TypeMask::SCALE | TypeMask::TRANSLATE)).is_empty()
223    }
224
225    pub fn is_translate(&self) -> bool {
226        (self.get_type() & !TypeMask::TRANSLATE).is_empty()
227    }
228
229    pub fn rect_stays_rect(&self) -> bool {
230        unsafe { sb::C_SkMatrix_rectStaysRect(self.native()) }
231    }
232
233    pub fn preserves_axis_alignment(&self) -> bool {
234        self.rect_stays_rect()
235    }
236
237    pub fn has_perspective(&self) -> bool {
238        unsafe { sb::C_SkMatrix_hasPerspective(self.native()) }
239    }
240
241    pub fn is_similarity(&self) -> bool {
242        unsafe { self.native().isSimilarity(scalar::NEARLY_ZERO) }
243    }
244
245    pub fn preserves_right_angles(&self) -> bool {
246        unsafe { self.native().preservesRightAngles(scalar::NEARLY_ZERO) }
247    }
248
249    pub fn rc(&self, r: usize, c: usize) -> scalar {
250        assert!(r <= 2);
251        assert!(c <= 2);
252        self[r * 3 + c]
253    }
254
255    pub fn scale_x(&self) -> scalar {
256        self[Member::ScaleX]
257    }
258
259    pub fn scale_y(&self) -> scalar {
260        self[Member::ScaleY]
261    }
262
263    pub fn skew_y(&self) -> scalar {
264        self[Member::SkewY]
265    }
266
267    pub fn skew_x(&self) -> scalar {
268        self[Member::SkewX]
269    }
270
271    pub fn translate_x(&self) -> scalar {
272        self[Member::TransX]
273    }
274
275    pub fn translate_y(&self) -> scalar {
276        self[Member::TransY]
277    }
278
279    pub fn persp_x(&self) -> scalar {
280        self[Member::Persp0]
281    }
282
283    pub fn persp_y(&self) -> scalar {
284        self[Member::Persp1]
285    }
286
287    pub fn set_scale_x(&mut self, v: scalar) -> &mut Self {
288        self.set(Member::ScaleX, v)
289    }
290
291    pub fn set_scale_y(&mut self, v: scalar) -> &mut Self {
292        self.set(Member::ScaleY, v)
293    }
294
295    pub fn set_skew_y(&mut self, v: scalar) -> &mut Self {
296        self.set(Member::SkewY, v)
297    }
298
299    pub fn set_skew_x(&mut self, v: scalar) -> &mut Self {
300        self.set(Member::SkewX, v)
301    }
302
303    pub fn set_translate_x(&mut self, v: scalar) -> &mut Self {
304        self.set(Member::TransX, v)
305    }
306
307    pub fn set_translate_y(&mut self, v: scalar) -> &mut Self {
308        self.set(Member::TransY, v)
309    }
310
311    pub fn set_persp_x(&mut self, v: scalar) -> &mut Self {
312        self.set(Member::Persp0, v)
313    }
314
315    pub fn set_persp_y(&mut self, v: scalar) -> &mut Self {
316        self.set(Member::Persp1, v)
317    }
318
319    #[allow(clippy::too_many_arguments)]
320    pub fn set_all(
321        &mut self,
322        scale_x: scalar,
323        skew_x: scalar,
324        trans_x: scalar,
325        skew_y: scalar,
326        scale_y: scalar,
327        trans_y: scalar,
328        persp_0: scalar,
329        persp_1: scalar,
330        persp_2: scalar,
331    ) -> &mut Self {
332        self[Member::ScaleX] = scale_x;
333        self[Member::SkewX] = skew_x;
334        self[Member::TransX] = trans_x;
335        self[Member::SkewY] = skew_y;
336        self[Member::ScaleY] = scale_y;
337        self[Member::TransY] = trans_y;
338        self[Member::Persp0] = persp_0;
339        self[Member::Persp1] = persp_1;
340        self[Member::Persp2] = persp_2;
341        self.type_mask = TypeMask::UNKNOWN;
342        self
343    }
344
345    pub fn get_9(&self, buffer: &mut [scalar; 9]) {
346        buffer.copy_from_slice(&self.mat)
347    }
348
349    pub fn set_9(&mut self, buffer: &[scalar; 9]) -> &mut Self {
350        unsafe {
351            self.native_mut().set9(buffer.as_ptr());
352        }
353        self
354    }
355
356    pub fn reset(&mut self) -> &mut Self {
357        unsafe {
358            self.native_mut().reset();
359        }
360        self
361    }
362
363    pub fn set_identity(&mut self) -> &mut Self {
364        self.reset();
365        self
366    }
367
368    pub fn set_translate(&mut self, v: impl Into<Vector>) -> &mut Self {
369        let v = v.into();
370        unsafe {
371            self.native_mut().setTranslate(v.x, v.y);
372        }
373        self
374    }
375
376    pub fn set_scale(
377        &mut self,
378        (sx, sy): (scalar, scalar),
379        pivot: impl Into<Option<Point>>,
380    ) -> &mut Self {
381        let pivot = pivot.into().unwrap_or_default();
382        unsafe {
383            self.native_mut().setScale(sx, sy, pivot.x, pivot.y);
384        }
385        self
386    }
387
388    pub fn set_rotate(&mut self, degrees: scalar, pivot: impl Into<Option<Point>>) -> &mut Self {
389        let pivot = pivot.into().unwrap_or_default();
390        unsafe {
391            self.native_mut().setRotate(degrees, pivot.x, pivot.y);
392        }
393        self
394    }
395
396    pub fn set_sin_cos(
397        &mut self,
398        (sin_value, cos_value): (scalar, scalar),
399        pivot: impl Into<Option<Point>>,
400    ) -> &mut Self {
401        let pivot = pivot.into().unwrap_or_default();
402        unsafe {
403            self.native_mut()
404                .setSinCos(sin_value, cos_value, pivot.x, pivot.y);
405        }
406        self
407    }
408
409    pub fn set_rsxform(&mut self, rsxform: &RSXform) -> &mut Self {
410        unsafe {
411            self.native_mut().setRSXform(rsxform.native());
412        }
413        self
414    }
415
416    pub fn set_skew(
417        &mut self,
418        (kx, ky): (scalar, scalar),
419        pivot: impl Into<Option<Point>>,
420    ) -> &mut Self {
421        let pivot = pivot.into().unwrap_or_default();
422        unsafe {
423            self.native_mut().setSkew(kx, ky, pivot.x, pivot.y);
424        }
425        self
426    }
427
428    pub fn set_concat(&mut self, a: &Self, b: &Self) -> &mut Self {
429        unsafe {
430            self.native_mut().setConcat(a.native(), b.native());
431        }
432        self
433    }
434
435    pub fn pre_translate(&mut self, delta: impl Into<Vector>) -> &mut Self {
436        let delta = delta.into();
437        unsafe {
438            self.native_mut().preTranslate(delta.x, delta.y);
439        }
440        self
441    }
442
443    pub fn pre_scale(
444        &mut self,
445        (sx, sy): (scalar, scalar),
446        pivot: impl Into<Option<Point>>,
447    ) -> &mut Self {
448        let pivot = pivot.into().unwrap_or_default();
449        unsafe {
450            self.native_mut().preScale(sx, sy, pivot.x, pivot.y);
451        }
452        self
453    }
454
455    pub fn pre_rotate(&mut self, degrees: scalar, pivot: impl Into<Option<Point>>) -> &mut Self {
456        let pivot = pivot.into().unwrap_or_default();
457        unsafe {
458            self.native_mut().preRotate(degrees, pivot.x, pivot.y);
459        }
460        self
461    }
462
463    pub fn pre_skew(
464        &mut self,
465        (kx, ky): (scalar, scalar),
466        pivot: impl Into<Option<Point>>,
467    ) -> &mut Self {
468        let pivot = pivot.into().unwrap_or_default();
469        unsafe {
470            self.native_mut().preSkew(kx, ky, pivot.x, pivot.y);
471        }
472        self
473    }
474
475    pub fn pre_concat(&mut self, other: &Self) -> &mut Self {
476        unsafe {
477            self.native_mut().preConcat(other.native());
478        }
479        self
480    }
481
482    pub fn post_translate(&mut self, delta: impl Into<Vector>) -> &mut Self {
483        let delta = delta.into();
484        unsafe {
485            self.native_mut().postTranslate(delta.x, delta.y);
486        }
487        self
488    }
489
490    pub fn post_scale(
491        &mut self,
492        (sx, sy): (scalar, scalar),
493        pivot: impl Into<Option<Point>>,
494    ) -> &mut Self {
495        let pivot = pivot.into().unwrap_or_default();
496        unsafe {
497            self.native_mut().postScale(sx, sy, pivot.x, pivot.y);
498        }
499        self
500    }
501
502    #[deprecated(
503        since = "0.27.0",
504        note = "use post_scale((1.0 / x as scalar, 1.0 / y as scalar), None)"
505    )]
506    pub fn post_idiv(&mut self, (div_x, div_y): (i32, i32)) -> bool {
507        if div_x == 0 || div_y == 0 {
508            return false;
509        }
510        self.post_scale((1.0 / div_x as scalar, 1.0 / div_y as scalar), None);
511        true
512    }
513
514    pub fn post_rotate(&mut self, degrees: scalar, pivot: impl Into<Option<Point>>) -> &mut Self {
515        let pivot = pivot.into().unwrap_or_default();
516        unsafe {
517            self.native_mut().postRotate(degrees, pivot.x, pivot.y);
518        }
519        self
520    }
521
522    pub fn post_skew(
523        &mut self,
524        (kx, ky): (scalar, scalar),
525        pivot: impl Into<Option<Point>>,
526    ) -> &mut Self {
527        let pivot = pivot.into().unwrap_or_default();
528        unsafe {
529            self.native_mut().postSkew(kx, ky, pivot.x, pivot.y);
530        }
531        self
532    }
533
534    pub fn post_concat(&mut self, other: &Matrix) -> &mut Self {
535        unsafe {
536            self.native_mut().postConcat(other.native());
537        }
538        self
539    }
540
541    pub fn set_rect_to_rect(
542        &mut self,
543        src: impl AsRef<Rect>,
544        dst: impl AsRef<Rect>,
545        stf: ScaleToFit,
546    ) -> bool {
547        unsafe {
548            self.native_mut()
549                .setRectToRect(src.as_ref().native(), dst.as_ref().native(), stf)
550        }
551    }
552
553    pub fn from_rect_to_rect(
554        src: impl AsRef<Rect>,
555        dst: impl AsRef<Rect>,
556        stf: ScaleToFit,
557    ) -> Option<Self> {
558        let mut m = Self::new_identity();
559        m.set_rect_to_rect(src, dst, stf).if_true_some(m)
560    }
561
562    pub fn set_poly_to_poly(&mut self, src: &[Point], dst: &[Point]) -> bool {
563        if src.len() != dst.len() {
564            return false;
565        }
566        unsafe {
567            self.native_mut().setPolyToPoly(
568                src.native().as_ptr(),
569                dst.native().as_ptr(),
570                src.len().try_into().unwrap(),
571            )
572        }
573    }
574
575    pub fn from_poly_to_poly(src: &[Point], dst: &[Point]) -> Option<Matrix> {
576        let mut m = Matrix::new_identity();
577        m.set_poly_to_poly(src, dst).if_true_some(m)
578    }
579
580    #[must_use]
581    pub fn invert(&self) -> Option<Matrix> {
582        let mut m = Matrix::new_identity();
583        unsafe { sb::C_SkMatrix_invert(self.native(), m.native_mut()) }.if_true_some(m)
584    }
585
586    pub fn set_affine_identity(affine: &mut [scalar; 6]) {
587        unsafe { SkMatrix::SetAffineIdentity(affine.as_mut_ptr()) }
588    }
589
590    #[must_use]
591    pub fn to_affine(self) -> Option<[scalar; 6]> {
592        let mut affine = [scalar::default(); 6];
593        unsafe { self.native().asAffine(affine.as_mut_ptr()) }.if_true_some(affine)
594    }
595
596    pub fn set_affine(&mut self, affine: &[scalar; 6]) -> &mut Self {
597        unsafe { self.native_mut().setAffine(affine.as_ptr()) };
598        self
599    }
600
601    pub fn from_affine(affine: &[scalar; 6]) -> Matrix {
602        let mut m = Matrix::new_identity();
603        unsafe {
604            m.native_mut().setAffine(affine.as_ptr());
605        }
606        m
607    }
608
609    pub fn normalize_perspective(&mut self) {
610        unsafe { sb::C_SkMatrix_normalizePerspective(self.native_mut()) }
611    }
612
613    pub fn map_points(&self, dst: &mut [Point], src: &[Point]) {
614        assert!(dst.len() >= src.len());
615
616        unsafe {
617            self.native().mapPoints(
618                dst.native_mut().as_mut_ptr(),
619                src.native().as_ptr(),
620                src.len().try_into().unwrap(),
621            )
622        };
623    }
624
625    pub fn map_points_inplace(&self, pts: &mut [Point]) {
626        let ptr = pts.native_mut().as_mut_ptr();
627        unsafe {
628            self.native()
629                .mapPoints(ptr, ptr, pts.len().try_into().unwrap())
630        };
631    }
632
633    pub fn map_homogeneous_points(&self, dst: &mut [Point3], src: &[Point3]) {
634        assert!(dst.len() >= src.len());
635
636        unsafe {
637            self.native().mapHomogeneousPoints(
638                dst.native_mut().as_mut_ptr(),
639                src.native().as_ptr(),
640                src.len().try_into().unwrap(),
641            )
642        };
643    }
644
645    pub fn map_homogeneous_points_2d(&self, dst: &mut [Point3], src: &[Point]) {
646        assert!(dst.len() >= src.len());
647
648        unsafe {
649            self.native().mapHomogeneousPoints1(
650                dst.native_mut().as_mut_ptr(),
651                src.native().as_ptr(),
652                src.len().try_into().unwrap(),
653            )
654        };
655    }
656
657    pub fn map_point(&self, point: impl Into<Point>) -> Point {
658        let point = point.into();
659        let mut p = Point::default();
660        unsafe { self.native().mapXY(point.x, point.y, p.native_mut()) };
661        p
662    }
663
664    pub fn map_xy(&self, x: scalar, y: scalar) -> Point {
665        self.map_point((x, y))
666    }
667
668    pub fn map_origin(&self) -> Point {
669        let mut x = self.translate_x();
670        let mut y = self.translate_y();
671        if self.has_perspective() {
672            let mut w = self[Member::Persp2];
673            if w != 0.0 {
674                w = 1.0 / w;
675            }
676            x *= w;
677            y *= w;
678        }
679        Point::new(x, y)
680    }
681
682    pub fn map_vectors(&self, dst: &mut [Vector], src: &[Vector]) {
683        assert!(dst.len() >= src.len());
684        unsafe {
685            self.native().mapVectors(
686                dst.native_mut().as_mut_ptr(),
687                src.native().as_ptr(),
688                src.len().try_into().unwrap(),
689            )
690        }
691    }
692
693    pub fn map_vectors_inplace(&self, vecs: &mut [Vector]) {
694        let ptr = vecs.native_mut().as_mut_ptr();
695        unsafe {
696            self.native()
697                .mapVectors(ptr, ptr, vecs.len().try_into().unwrap())
698        }
699    }
700
701    pub fn map_vector(&self, vec: impl Into<Vector>) -> Vector {
702        let mut vec = vec.into();
703        self.map_vectors_inplace(slice::from_mut(&mut vec));
704        vec
705    }
706
707    pub fn map_rect(&self, rect: impl AsRef<Rect>) -> (Rect, bool) {
708        self.map_rect_with_perspective_clip(rect, ApplyPerspectiveClip::Yes)
709    }
710
711    pub fn map_rect_with_perspective_clip(
712        &self,
713        rect: impl AsRef<Rect>,
714        perspective_clip: ApplyPerspectiveClip,
715    ) -> (Rect, bool) {
716        let mut rect = *rect.as_ref();
717        let ptr = rect.native_mut();
718        let rect_stays_rect = unsafe { self.native().mapRect(ptr, ptr, perspective_clip) };
719        (rect, rect_stays_rect)
720    }
721
722    pub fn map_rect_to_quad(&self, rect: impl AsRef<Rect>) -> [Point; 4] {
723        let mut quad = rect.as_ref().to_quad();
724        self.map_points_inplace(quad.as_mut());
725        quad
726    }
727
728    pub fn map_rect_scale_translate(&self, src: impl AsRef<Rect>) -> Option<Rect> {
729        if self.is_scale_translate() {
730            let mut rect = Rect::default();
731            unsafe {
732                self.native()
733                    .mapRectScaleTranslate(rect.native_mut(), src.as_ref().native())
734            };
735            Some(rect)
736        } else {
737            None
738        }
739    }
740
741    pub fn map_radius(&self, radius: scalar) -> Option<scalar> {
742        if !self.has_perspective() {
743            Some(unsafe { self.native().mapRadius(radius) })
744        } else {
745            None
746        }
747    }
748
749    #[deprecated(since = "0.27.0", note = "removed without replacement")]
750    pub fn is_fixed_step_in_x(&self) -> ! {
751        unimplemented!("removed without replacement")
752    }
753
754    #[deprecated(since = "0.27.0", note = "removed without replacement")]
755    pub fn fixed_step_in_x(&self, _y: scalar) -> ! {
756        unimplemented!("removed without replacement")
757    }
758
759    #[deprecated(since = "0.27.0", note = "removed without replacement")]
760    pub fn cheap_equal_to(&self, _other: &Matrix) -> ! {
761        unimplemented!("removed without replacement")
762    }
763
764    pub fn dump(&self) {
765        unsafe { self.native().dump() }
766    }
767
768    pub fn min_scale(&self) -> scalar {
769        unsafe { self.native().getMinScale() }
770    }
771
772    pub fn max_scale(&self) -> scalar {
773        unsafe { self.native().getMaxScale() }
774    }
775
776    #[must_use]
777    pub fn min_max_scales(&self) -> (scalar, scalar) {
778        let mut r: [scalar; 2] = Default::default();
779        unsafe { self.native().getMinMaxScales(r.as_mut_ptr()) };
780        #[allow(clippy::tuple_array_conversions)]
781        (r[0], r[1])
782    }
783
784    pub fn decompose_scale(&self, mut remaining: Option<&mut Matrix>) -> Option<Size> {
785        let mut size = Size::default();
786        unsafe {
787            self.native()
788                .decomposeScale(size.native_mut(), remaining.native_ptr_or_null_mut())
789        }
790        .if_true_some(size)
791    }
792
793    pub fn i() -> &'static Matrix {
794        &IDENTITY
795    }
796
797    pub fn invalid_matrix() -> &'static Matrix {
798        Self::from_native_ref(unsafe { &*sb::C_SkMatrix_InvalidMatrix() })
799    }
800
801    pub fn concat(a: &Matrix, b: &Matrix) -> Matrix {
802        let mut m = Matrix::new_identity();
803        unsafe { m.native_mut().setConcat(a.native(), b.native()) };
804        m
805    }
806
807    pub fn dirty_matrix_type_cache(&mut self) {
808        self.native_mut().fTypeMask = 0x80;
809    }
810
811    pub fn set_scale_translate(
812        &mut self,
813        (sx, sy): (scalar, scalar),
814        t: impl Into<Vector>,
815    ) -> &mut Self {
816        let t = t.into();
817        unsafe { sb::C_SkMatrix_setScaleTranslate(self.native_mut(), sx, sy, t.x, t.y) }
818        self
819    }
820
821    pub fn is_finite(&self) -> bool {
822        unsafe { sb::C_SkMatrix_isFinite(self.native()) }
823    }
824
825    pub const fn new_identity() -> Self {
826        Self::new()
827    }
828}
829
830impl IndexGet for Matrix {}
831impl IndexSet for Matrix {}
832
833pub const IDENTITY: Matrix = Matrix::new_identity();
834
835#[cfg(test)]
836mod tests {
837    use super::{AffineMember, Matrix, TypeMask};
838    use crate::prelude::*;
839
840    #[test]
841    fn test_get_set_trait_compilation() {
842        let mut m = Matrix::new_identity();
843        let _x = m.get(AffineMember::ScaleX);
844        m.set(AffineMember::ScaleX, 1.0);
845    }
846
847    #[test]
848    #[allow(clippy::float_cmp)]
849    fn test_tuple_to_vector() {
850        let mut m = Matrix::new_identity();
851        m.set_translate((10.0, 11.0));
852        assert_eq!(10.0, m.translate_x());
853        assert_eq!(11.0, m.translate_y());
854    }
855
856    #[test]
857    fn setting_a_matrix_component_recomputes_typemask() {
858        let mut m = Matrix::default();
859        assert_eq!(TypeMask::IDENTITY, m.get_type());
860        m.set_persp_x(0.1);
861        assert_eq!(
862            TypeMask::TRANSLATE | TypeMask::SCALE | TypeMask::AFFINE | TypeMask::PERSPECTIVE,
863            m.get_type()
864        );
865    }
866}