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 #[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}