Skip to main content

path_kit/
matrix.rs

1//! 3×3 仿射/透视变换矩阵,与 pathkit 中 `pk::SkMatrix` 的**公开** API 语义一致。
2//! 3×3 affine/perspective transform matrix; behavior matches public `pk::SkMatrix` in pathkit.
3//!
4//! ## 存储 / Storage
5//!
6//! 九个系数按 `SkMatrix::get9` / `set9` 顺序存放在 [`Matrix::mat`],下标见 [`coeff`];行优先、与 Skia 文档一致:
7//! `[scaleX, skewX, transX, skewY, scaleY, transY, persp0, persp1, persp2]`。
8//! Nine coeffs in `get9`/`set9` order in [`Matrix::mat`]; indices in [`coeff`]. Row-major layout matches Skia.
9//!
10//! ## 前乘与后乘 / Pre vs post
11//!
12//! 与 `SkMatrix` 文档一致:`pre*` 为 **`self = self * T`**(新变换在乘积**右侧**;点空间上可理解为「先 `T` 再原矩阵」),
13//! `post*` 为 **`self = T * self`**(新变换在**左侧**;「先原矩阵再 `T`」)。
14//! Same as Skia docs: `pre*` is `self = self * T` (new transform on the **right**), `post*` is `self = T * self` (on the **left**).
15//!
16//! - [`Matrix::concat`] / [`Mul`]:与 `SkMatrix::setConcat` / `Concat(a, b)` 相同,结果为 **`a * b`**(对列向量 `p' = a * b * p`)。
17//!
18//! ## 未覆盖项 / Not wired to C++
19//!
20//! - `postIDiv` 等在 Skia 中非 public,当前无 FFI。
21//! - [`Matrix::map_homogeneous`] 仅在 Rust 侧做线性组合;完整 `mapHomogeneousPoints` / `SkPoint3` 批处理未暴露。
22//! - [`Matrix::invalid`] 为占位实现(全 `f32::MAX`),未调用 `SkMatrix::InvalidMatrix()` 单例。
23//!
24//! ## 序列化 / Serialization
25//!
26//! [`Matrix::write_to_memory`] / [`Matrix::read_from_memory`] 为固定 **36 字节**(9×`f32`),与当前 `SkMatrix::writeToMemory` / `readFromMemory` 布局一致。
27
28use crate::bridge::ffi;
29use crate::point::Point;
30use crate::rect::Rect;
31use std::ops::{Index, IndexMut, Mul};
32
33/// 源矩形映射到目标矩形时的缩放/对齐策略,对应 `SkMatrix::ScaleToFit`。
34/// Scale/align policy when mapping a source rect to a destination rect (`SkMatrix::ScaleToFit`).
35///
36/// 用于 [`Matrix::set_rect_to_rect`]。
37#[repr(i32)]
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39pub enum ScaleToFit {
40    /// 独立缩放 sx/sy 以完全填满 `dst`(可能非等比)。
41    /// Scale X and Y independently to fill `dst` (aspect ratio may change).
42    Fill = 0,
43    /// 等比缩放并靠 `dst` 的「起始」边对齐(与 Skia `Start` 一致)。
44    /// Uniform scale; aligned to the start edge of `dst` per Skia.
45    Start = 1,
46    /// 等比缩放并在 `dst` 内居中。
47    /// Uniform scale; centered within `dst`.
48    Center = 2,
49    /// 等比缩放并靠「结束」边对齐。
50    /// Uniform scale; aligned to the end edge of `dst`.
51    End = 3,
52}
53
54/// `SkMatrix::TypeMask` 中与类别相关的公开位,可与 `|` 组合;[`Matrix::get_type`] 的返回值可与此做位运算。
55/// Public `SkMatrix::TypeMask` bits; combine with `|`; use with [`Matrix::get_type`].
56pub mod matrix_type {
57    #![allow(dead_code)]
58    /// 单位矩阵(无数值分类)。Identity (no transform classification).
59    pub const IDENTITY: u32 = 0;
60    /// 位:含平移分量。Bit: translation present.
61    pub const TRANSLATE: u32 = 0x01;
62    /// 位:含缩放。Bit: scale present.
63    pub const SCALE: u32 = 0x02;
64    /// 位:含一般仿射(错切、旋转等)。Bit: general affine.
65    pub const AFFINE: u32 = 0x04;
66    /// 位:含透视(`persp0`/`persp1` 非零等)。Bit: perspective.
67    pub const PERSPECTIVE: u32 = 0x08;
68}
69
70/// `SkMatrix` 九个系数在 [`Matrix::mat`] 中的下标(`kMScaleX` … `kMPersp2`)。
71/// Indices of the nine coeffs in [`Matrix::mat`] (`kMScaleX` …).
72pub mod coeff {
73    /// `scaleX`(x 方向缩放)。`scaleX`.
74    pub const M_SCALE_X: usize = 0;
75    /// `skewX`(x 受 y 影响的错切)。`skewX`.
76    pub const M_SKEW_X: usize = 1;
77    /// `transX`(x 平移)。`transX`.
78    pub const M_TRANS_X: usize = 2;
79    /// `skewY`(y 受 x 影响的错切)。`skewY`.
80    pub const M_SKEW_Y: usize = 3;
81    /// `scaleY`(y 方向缩放)。`scaleY`.
82    pub const M_SCALE_Y: usize = 4;
83    /// `transY`(y 平移)。`transY`.
84    pub const M_TRANS_Y: usize = 5;
85    /// 透视行第一列系数。Perspective row, first coeff.
86    pub const M_PERSP_0: usize = 6;
87    /// 透视行第二列系数。Perspective row, second coeff.
88    pub const M_PERSP_1: usize = 7;
89    /// 透视行第三列系数(通常为 1)。Perspective row, third coeff (often 1).
90    pub const M_PERSP_2: usize = 8;
91}
92
93/// 3×3 变换矩阵(列向量形式 `p' = M * p`),系数布局见模块说明。
94/// 3×3 transform (column vectors `p' = M * p`); layout described at module level.
95#[derive(Debug, Clone, Copy)]
96pub struct Matrix {
97    /// 与 `SkMatrix::fMat` / `get9` / `set9` 顺序一致。
98    /// Same order as `SkMatrix::fMat` / `get9` / `set9`.
99    pub mat: [f32; 9],
100}
101
102impl Matrix {
103    /// 单位矩阵常量。Identity matrix constant.
104    pub const IDENTITY: Self = Self {
105        mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
106    };
107
108    /// 返回单位矩阵。Returns the identity matrix.
109    #[inline]
110    pub const fn identity() -> Self {
111        Self::IDENTITY
112    }
113
114    /// 非法/哨兵矩阵占位,**非** Skia 单例;系数全为 `f32::MAX`,勿用于几何变换。
115    /// Sentinel / invalid placeholder (not the Skia singleton); all coeffs `f32::MAX`; do not use for mapping.
116    pub fn invalid() -> Self {
117        let x = f32::MAX;
118        Self { mat: [x; 9] }
119    }
120
121    // —— 静态工厂(与 SkMatrix 同名语义)——
122
123    /// 缩放矩阵:内部 `setScale(sx, sy)`。Scale matrix via `setScale(sx, sy)`.
124    #[inline]
125    pub fn scale(sx: f32, sy: f32) -> Self {
126        let mut m = Self::IDENTITY;
127        m.set_scale(sx, sy);
128        m
129    }
130
131    /// 平移矩阵:`setTranslate`。Translation matrix via `setTranslate`.
132    #[inline]
133    pub fn translate(dx: f32, dy: f32) -> Self {
134        let mut m = Self::IDENTITY;
135        m.set_translate(dx, dy);
136        m
137    }
138
139    /// 绕原点旋转;**正角度顺时针**(Skia 约定)。Rotate about origin; **positive degrees = clockwise** (Skia).
140    pub fn rotate_deg(degrees: f32) -> Self {
141        let mut m = Self::IDENTITY;
142        m.set_rotate(degrees);
143        m
144    }
145
146    /// 由九个系数构造,等价 `SkMatrix::MakeAll` / `setAll`。Build from nine coeffs (`MakeAll` / `setAll`).
147    #[inline]
148    pub fn make_all(
149        scale_x: f32,
150        skew_x: f32,
151        trans_x: f32,
152        skew_y: f32,
153        scale_y: f32,
154        trans_y: f32,
155        pers0: f32,
156        pers1: f32,
157        pers2: f32,
158    ) -> Self {
159        let mut m = Self::IDENTITY;
160        m.set_all(
161            scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
162        );
163        m
164    }
165
166    /// 从已有 `get9` 顺序数组封装,**不**校验数值。Wrap raw `get9` array; **no** validation.
167    #[inline]
168    pub const fn from_row_major_9(mat: [f32; 9]) -> Self {
169        Self { mat }
170    }
171
172    /// 矩阵乘积 `a * b`,对齐 `SkMatrix::Concat(a, b)`。Matrix product `a * b` (`SkMatrix::Concat`).
173    #[inline]
174    pub fn concat(a: &Matrix, b: &Matrix) -> Matrix {
175        let mut out = Self::IDENTITY;
176        ffi::matrix_set_concat(out.mat.as_mut_slice(), a.mat.as_slice(), b.mat.as_slice());
177        out
178    }
179
180    // —— 替换型 set —— //
181
182    /// 置为单位矩阵。Reset to identity (`SkMatrix::reset`).
183    #[inline]
184    pub fn reset(&mut self) -> &mut Self {
185        ffi::matrix_reset(self.mat.as_mut_slice());
186        self
187    }
188
189    /// 同 [`Self::reset`]。Alias for [`Self::reset`].
190    #[inline]
191    pub fn set_identity(&mut self) -> &mut Self {
192        self.reset()
193    }
194
195    /// 一次性写入九个系数,见模块「存储」说明。Set all nine coeffs (`setAll`).
196    pub fn set_all(
197        &mut self,
198        scale_x: f32,
199        skew_x: f32,
200        trans_x: f32,
201        skew_y: f32,
202        scale_y: f32,
203        trans_y: f32,
204        pers0: f32,
205        pers1: f32,
206        pers2: f32,
207    ) -> &mut Self {
208        ffi::matrix_set_all(
209            self.mat.as_mut_slice(),
210            scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
211        );
212        self
213    }
214
215    /// 替换为纯平移。Replace with translation (`setTranslate`).
216    #[inline]
217    pub fn set_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
218        ffi::matrix_set_translate(self.mat.as_mut_slice(), dx, dy);
219        self
220    }
221
222    /// 替换为以原点为基准的缩放。Replace with scale about origin.
223    #[inline]
224    pub fn set_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
225        ffi::matrix_set_scale(self.mat.as_mut_slice(), sx, sy);
226        self
227    }
228
229    /// 替换为绕 `(px, py)` 的缩放。Replace with scale about pivot `(px, py)`.
230    #[inline]
231    pub fn set_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
232        ffi::matrix_set_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
233        self
234    }
235
236    /// 替换为绕原点旋转(正角度顺时针)。Replace with rotation about origin (CW positive).
237    #[inline]
238    pub fn set_rotate(&mut self, degrees: f32) -> &mut Self {
239        ffi::matrix_set_rotate(self.mat.as_mut_slice(), degrees);
240        self
241    }
242
243    /// 替换为绕 `(px, py)` 旋转。Replace with rotation about `(px, py)`.
244    #[inline]
245    pub fn set_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
246        ffi::matrix_set_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
247        self
248    }
249
250    /// 替换为由 `sin`/`cos` 给出的旋转(绕原点)。Rotation from `sin`/`cos` about origin.
251    #[inline]
252    pub fn set_sin_cos(&mut self, sin_v: f32, cos_v: f32) -> &mut Self {
253        ffi::matrix_set_sin_cos(self.mat.as_mut_slice(), sin_v, cos_v);
254        self
255    }
256
257    /// 同上,支点为 `(px, py)`。Same with pivot `(px, py)`.
258    #[inline]
259    pub fn set_sin_cos_pivot(&mut self, sin_v: f32, cos_v: f32, px: f32, py: f32) -> &mut Self {
260        ffi::matrix_set_sin_cos_pivot(self.mat.as_mut_slice(), sin_v, cos_v, px, py);
261        self
262    }
263
264    /// 替换为错切(原点)。Replace with skew about origin.
265    #[inline]
266    pub fn set_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
267        ffi::matrix_set_skew(self.mat.as_mut_slice(), kx, ky);
268        self
269    }
270
271    /// 替换为绕 `(px, py)` 的错切。Replace with skew about `(px, py)`.
272    #[inline]
273    pub fn set_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
274        ffi::matrix_set_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
275        self
276    }
277
278    /// 替换为无错切、无透视的缩放+平移(常用优化形式)。Replace with scale+translate only.
279    #[inline]
280    pub fn set_scale_translate(&mut self, sx: f32, sy: f32, tx: f32, ty: f32) -> &mut Self {
281        ffi::matrix_set_scale_translate(self.mat.as_mut_slice(), sx, sy, tx, ty);
282        self
283    }
284
285    /// `self = a * b`([`Self::concat`])。`self = a * b` (`setConcat`).
286    #[inline]
287    pub fn set_concat(&mut self, a: &Matrix, b: &Matrix) -> &mut Self {
288        ffi::matrix_set_concat(
289            self.mat.as_mut_slice(),
290            a.mat.as_slice(),
291            b.mat.as_slice(),
292        );
293        self
294    }
295
296    /// 构造将 `src` 映射到 `dst` 的变换(按 [`ScaleToFit`]);成功时覆盖 `self`,失败时行为与 Skia 一致。
297    /// Map `src` onto `dst` per [`ScaleToFit`]; on failure matches Skia `setRectToRect`.
298    pub fn set_rect_to_rect(&mut self, src: &Rect, dst: &Rect, stf: ScaleToFit) -> bool {
299        let sr: ffi::Rect = (*src).into();
300        let dr: ffi::Rect = (*dst).into();
301        ffi::matrix_set_rect_to_rect(self.mat.as_mut_slice(), &sr, &dr, stf as i32)
302    }
303
304    // —— pre / post —— //
305
306    /// `self = self * T(dx, dy)`。`preTranslate`.
307    #[inline]
308    pub fn pre_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
309        ffi::matrix_pre_translate(self.mat.as_mut_slice(), dx, dy);
310        self
311    }
312    /// `self = self * S(sx, sy)`。`preScale`.
313    #[inline]
314    pub fn pre_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
315        ffi::matrix_pre_scale(self.mat.as_mut_slice(), sx, sy);
316        self
317    }
318    /// 带支点的 `preScale`。`preScale` with pivot.
319    #[inline]
320    pub fn pre_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
321        ffi::matrix_pre_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
322        self
323    }
324    /// `preRotate`(正角度顺时针)。`preRotate` (CW positive).
325    #[inline]
326    pub fn pre_rotate(&mut self, degrees: f32) -> &mut Self {
327        ffi::matrix_pre_rotate(self.mat.as_mut_slice(), degrees);
328        self
329    }
330    /// 带支点的 `preRotate`。`preRotate` with pivot.
331    #[inline]
332    pub fn pre_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
333        ffi::matrix_pre_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
334        self
335    }
336    /// `preSkew`。`preSkew`.
337    #[inline]
338    pub fn pre_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
339        ffi::matrix_pre_skew(self.mat.as_mut_slice(), kx, ky);
340        self
341    }
342    /// 带支点的 `preSkew`。`preSkew` with pivot.
343    #[inline]
344    pub fn pre_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
345        ffi::matrix_pre_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
346        self
347    }
348    /// `self = self * other`。`preConcat`.
349    #[inline]
350    pub fn pre_concat(&mut self, other: &Matrix) -> &mut Self {
351        ffi::matrix_pre_concat(self.mat.as_mut_slice(), other.mat.as_slice());
352        self
353    }
354
355    /// `self = T(dx, dy) * self`。`postTranslate`.
356    #[inline]
357    pub fn post_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
358        ffi::matrix_post_translate(self.mat.as_mut_slice(), dx, dy);
359        self
360    }
361    /// `postScale`。`postScale`.
362    #[inline]
363    pub fn post_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
364        ffi::matrix_post_scale(self.mat.as_mut_slice(), sx, sy);
365        self
366    }
367    /// 带支点的 `postScale`。`postScale` with pivot.
368    #[inline]
369    pub fn post_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
370        ffi::matrix_post_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
371        self
372    }
373    /// `postRotate`(正角度顺时针)。`postRotate` (CW positive).
374    #[inline]
375    pub fn post_rotate(&mut self, degrees: f32) -> &mut Self {
376        ffi::matrix_post_rotate(self.mat.as_mut_slice(), degrees);
377        self
378    }
379    /// 带支点的 `postRotate`。`postRotate` with pivot.
380    #[inline]
381    pub fn post_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
382        ffi::matrix_post_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
383        self
384    }
385    /// `postSkew`。`postSkew`.
386    #[inline]
387    pub fn post_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
388        ffi::matrix_post_skew(self.mat.as_mut_slice(), kx, ky);
389        self
390    }
391    /// 带支点的 `postSkew`。`postSkew` with pivot.
392    #[inline]
393    pub fn post_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
394        ffi::matrix_post_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
395        self
396    }
397    /// `self = other * self`。`postConcat`.
398    #[inline]
399    pub fn post_concat(&mut self, other: &Matrix) -> &mut Self {
400        ffi::matrix_post_concat(self.mat.as_mut_slice(), other.mat.as_slice());
401        self
402    }
403
404    // —— 查询 —— //
405
406    /// 类型掩码([`matrix_type`] 中的位)。Type mask (`getType`).
407    #[inline]
408    pub fn get_type(&self) -> u32 {
409        ffi::matrix_get_type(self.mat.as_slice())
410    }
411
412    /// 是否单位矩阵(容差内)。`isIdentity`.
413    #[inline]
414    pub fn is_identity(&self) -> bool {
415        ffi::matrix_is_identity(self.mat.as_slice())
416    }
417
418    /// 是否可表示为仅有缩放与平移(无错切/旋转/透视)。`isScaleTranslate`.
419    #[inline]
420    pub fn is_scale_translate(&self) -> bool {
421        ffi::matrix_is_scale_translate_matrix(self.mat.as_slice())
422    }
423
424    /// 是否将任意轴对齐矩形仍映射为轴对齐矩形。`rectStaysRect`.
425    #[inline]
426    pub fn rect_stays_rect(&self) -> bool {
427        ffi::matrix_rect_stays_rect(self.mat.as_slice())
428    }
429
430    /// 同 `SkMatrix::preservesAxisAlignment`(等同于 [`Self::rect_stays_rect`]。)。
431    /// Same as `preservesAxisAlignment` (alias of [`Self::rect_stays_rect`]).
432    #[inline]
433    pub fn preserves_axis_alignment(&self) -> bool {
434        self.rect_stays_rect()
435    }
436
437    /// 是否含透视分量。`hasPerspective`.
438    #[inline]
439    pub fn has_perspective(&self) -> bool {
440        ffi::matrix_has_perspective(self.mat.as_slice())
441    }
442
443    /// 所有系数是否均为有限浮点。`SkMatrix` finite check (`isFinite`-class API).
444    #[inline]
445    pub fn is_finite(&self) -> bool {
446        ffi::matrix_is_finite_matrix(self.mat.as_slice())
447    }
448
449    /// `mat[coeff::M_SCALE_X]`。`getScaleX`.
450    #[inline]
451    pub fn get_scale_x(&self) -> f32 {
452        self.mat[coeff::M_SCALE_X]
453    }
454    /// `getSkewX`.
455    #[inline]
456    pub fn get_skew_x(&self) -> f32 {
457        self.mat[coeff::M_SKEW_X]
458    }
459    /// `getTranslateX`.
460    #[inline]
461    pub fn get_translate_x(&self) -> f32 {
462        self.mat[coeff::M_TRANS_X]
463    }
464    /// `getSkewY`.
465    #[inline]
466    pub fn get_skew_y(&self) -> f32 {
467        self.mat[coeff::M_SKEW_Y]
468    }
469    /// `getScaleY`.
470    #[inline]
471    pub fn get_scale_y(&self) -> f32 {
472        self.mat[coeff::M_SCALE_Y]
473    }
474    /// `getTranslateY`.
475    #[inline]
476    pub fn get_translate_y(&self) -> f32 {
477        self.mat[coeff::M_TRANS_Y]
478    }
479    /// 透视行:`getPerspX` / `fMat[kMPersp0]`.
480    #[inline]
481    pub fn get_persp_x(&self) -> f32 {
482        self.mat[coeff::M_PERSP_0]
483    }
484    /// `getPerspY`.
485    #[inline]
486    pub fn get_persp_y(&self) -> f32 {
487        self.mat[coeff::M_PERSP_1]
488    }
489    /// `getPerspZ`(末元通常 1)。`getPerspZ` (often 1).
490    #[inline]
491    pub fn get_persp_z(&self) -> f32 {
492        self.mat[coeff::M_PERSP_2]
493    }
494
495    /// 按线性下标 `0..9` 读系数。Raw index `0..9` into [`Self::mat`].
496    #[inline]
497    pub fn get(&self, index: usize) -> f32 {
498        self.mat[index]
499    }
500
501    /// 按线性下标写系数(**不**更新 Skia 内部缓存分类;仅改数组)。Set coeff by index (raw write; no Skia type cache update).
502    #[inline]
503    pub fn set_coeff(&mut self, index: usize, value: f32) -> &mut Self {
504        self.mat[index] = value;
505        self
506    }
507
508    /// 求逆写入 `out_or_inverse`;不可逆返回 `false`。`SkMatrix::invert`.
509    pub fn invert_to(&self, out_or_inverse: &mut Matrix) -> bool {
510        ffi::matrix_invert(
511            self.mat.as_slice(),
512            out_or_inverse.mat.as_mut_slice(),
513        )
514    }
515
516    /// 可逆时 `Some(逆矩阵)`,否则 `None`。`invert` wrapped in `Option`.
517    pub fn try_inverse(&self) -> Option<Matrix> {
518        let mut out = Self::IDENTITY;
519        if self.invert_to(&mut out) {
520            Some(out)
521        } else {
522            None
523        }
524    }
525
526    /// 映射 `(x, y)`(透视下含 projective divide),与 `SkMatrix::mapXY` 一致。Map point (`mapXY`).
527    #[inline]
528    pub fn map_xy(&self, x: f32, y: f32) -> Point {
529        let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
530        ffi::matrix_map_xy(self.mat.as_slice(), x, y, &mut p);
531        p.into()
532    }
533
534    /// [`Self::map_xy`] 的便捷封装。Convenience over [`Self::map_xy`].
535    #[inline]
536    pub fn map_point(&self, p: Point) -> Point {
537        self.map_xy(p.x, p.y)
538    }
539
540    /// 线性部分左乘齐次向量 `[x,y,z]^T`,**不**做透视除法;与 `SkMatrix::mapHomogeneousPoints` 的线性步骤一致。
541    /// Homogeneous multiply **without** divide-by-w; matches linear step of `mapHomogeneousPoints`.
542    pub fn map_homogeneous(&self, x: f32, y: f32, z: f32) -> [f32; 3] {
543        let m = &self.mat;
544        [
545            m[0] * x + m[1] * y + m[2] * z,
546            m[3] * x + m[4] * y + m[5] * z,
547            m[6] * x + m[7] * y + m[8] * z,
548        ]
549    }
550
551    /// 将 `src` 前 `min(len)` 项映射写入 `dst`(与 `mapPoints(dst, src)` 批量语义一致)。Batch map like `mapPoints`.
552    pub fn map_points(&self, dst: &mut [Point], src: &[Point]) {
553        let n = src.len().min(dst.len());
554        for i in 0..n {
555            dst[i] = self.map_point(src[i]);
556        }
557    }
558
559    /// 原地映射点集。In-place `mapPoints`.
560    pub fn map_points_inplace(&self, pts: &mut [Point]) {
561        for p in pts.iter_mut() {
562            *p = self.map_point(*p);
563        }
564    }
565
566    /// `mapXY(0, 0)`,即原点经本矩阵映射后的位置。`SkMatrix::mapOrigin`.
567    #[inline]
568    pub fn map_origin(&self) -> Point {
569        let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
570        ffi::matrix_map_origin(self.mat.as_slice(), &mut p);
571        p.into()
572    }
573
574    /// 将矩形 `src` 经本矩阵映射;返回 `(包围盒, 是否仍为轴对齐矩形)`。`SkMatrix::mapRect`.
575    pub fn map_rect(&self, src: &Rect) -> (Rect, bool) {
576        let mut d = ffi::Rect {
577            fLeft: 0.0,
578            fTop: 0.0,
579            fRight: 0.0,
580            fBottom: 0.0,
581        };
582        let s: ffi::Rect = (*src).into();
583        let axis = ffi::matrix_map_rect(self.mat.as_slice(), &s, &mut d);
584        (d.into(), axis)
585    }
586
587    /// 当 [`Self::is_scale_translate`] 为真时的快速矩形映射(行为 undefined 若矩阵不满足前提——与 Skia 一致)。Fast path `mapRectScaleTranslate`.
588    pub fn map_rect_scale_translate(&self, src: &Rect) -> Rect {
589        let mut d = ffi::Rect {
590            fLeft: 0.0,
591            fTop: 0.0,
592            fRight: 0.0,
593            fBottom: 0.0,
594        };
595        let s: ffi::Rect = (*src).into();
596        ffi::matrix_map_rect_scale_translate(self.mat.as_slice(), &s, &mut d);
597        d.into()
598    }
599
600    /// 局部最小缩放因子(Skia 定义)。`getMinScale`.
601    #[inline]
602    pub fn get_min_scale(&self) -> f32 {
603        ffi::matrix_get_min_scale(self.mat.as_slice())
604    }
605
606    /// 局部最大缩放因子。`getMaxScale`.
607    #[inline]
608    pub fn get_max_scale(&self) -> f32 {
609        ffi::matrix_get_max_scale(self.mat.as_slice())
610    }
611
612    /// 同时取得最小/最大缩放;若矩阵退化或无法计算则 `None`。`getMinMaxScales`.
613    pub fn get_min_max_scales(&self) -> Option<(f32, f32)> {
614        let mut a = 0.0f32;
615        let mut b = 0.0f32;
616        if ffi::matrix_get_min_max_scales(self.mat.as_slice(), &mut a, &mut b) {
617            Some((a, b))
618        } else {
619            None
620        }
621    }
622
623    /// 序列化 **9×`f32`** 到 `buf`;返回实际写入字节数,不足时写入 0。`writeToMemory`.
624    pub fn write_to_memory(&self, buf: &mut [u8]) -> usize {
625        ffi::matrix_write_to_memory(self.mat.as_slice(), buf)
626    }
627
628    /// 从 `buf` 反序列化;成功返回读取字节数。`readFromMemory`.
629    pub fn read_from_memory(&mut self, buf: &[u8]) -> usize {
630        ffi::matrix_read_from_memory(self.mat.as_mut_slice(), buf)
631    }
632}
633
634impl Default for Matrix {
635    /// 单位矩阵。Identity.
636    fn default() -> Self {
637        Self::IDENTITY
638    }
639}
640
641impl PartialEq for Matrix {
642    /// Skia `SkMatrix` 相等语义(非简单逐位 `==`)。Skia matrix equality (not naive bit-compare).
643    fn eq(&self, other: &Self) -> bool {
644        ffi::matrix_equals(self.mat.as_slice(), other.mat.as_slice())
645    }
646}
647
648impl Eq for Matrix {}
649
650impl Index<usize> for Matrix {
651    type Output = f32;
652    fn index(&self, index: usize) -> &f32 {
653        &self.mat[index]
654    }
655}
656
657impl IndexMut<usize> for Matrix {
658    fn index_mut(&mut self, index: usize) -> &mut f32 {
659        &mut self.mat[index]
660    }
661}
662
663/// 矩阵乘法:`lhs * rhs` 与 [`Matrix::concat`] 语义相同。`Mul`: same as [`Matrix::concat`].
664impl Mul for Matrix {
665    type Output = Matrix;
666    fn mul(self, rhs: Matrix) -> Matrix {
667        Matrix::concat(&self, &rhs)
668    }
669}
670
671/// 同上。Same as [`Matrix::concat`].
672impl Mul<&Matrix> for Matrix {
673    type Output = Matrix;
674    fn mul(self, rhs: &Matrix) -> Matrix {
675        Matrix::concat(&self, rhs)
676    }
677}
678
679/// 同上。Same as [`Matrix::concat`].
680impl Mul<Matrix> for &Matrix {
681    type Output = Matrix;
682    fn mul(self, rhs: Matrix) -> Matrix {
683        Matrix::concat(self, &rhs)
684    }
685}
686
687/// 同上。Same as [`Matrix::concat`].
688impl Mul for &Matrix {
689    type Output = Matrix;
690    fn mul(self, rhs: &Matrix) -> Matrix {
691        Matrix::concat(self, rhs)
692    }
693}