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: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}
867