skia_safe/core/
matrix.rs

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