# Peta::FFI::Cairo::Matrix
📦 std
`Cairo::Matrix` package plug-in.
The affine transform value type (`cairo_matrix_t`). Unlike every other
cairo object, a matrix is NOT cairo-refcounted: upstream CairoMatrix.xs
models it as a blessed pointer to a HEAP `cairo_matrix_t` allocated with
Perl’s `New` (== `malloc`) and released with `Safefree` (== `free`) in
DESTROY. `cairo_perl_copy_matrix` does `New(0, dst, 1, cairo_matrix_t)`
then field-copies. All matrix-producing methods return a fresh copy.
## CROSS-PACKAGE ABI CONTRACT (review-critical)
`Cairo::Context`’s `get_matrix` / `get_font_matrix` allocate a matrix
with `libc::malloc(size_of::())` (6 f64 = 48 bytes),
let cairo fill it, and bless the raw pointer into `Cairo::Matrix` -
handing it to THIS package to eventually free. Therefore:
- our constructors MUST allocate the referent with `libc::malloc(48)`
(NOT Box, NOT Vec) so every `Cairo::Matrix` pointer is uniformly
`libc::free`-compatible regardless of who created it;
- our `DESTROY` MUST `libc::free` the pointer.
A `size_of::() == 48` assertion in the unit tests guards the
shared layout against drift. Any mismatch here double-frees or leaks the
matrices Context manufactures.
This module owns the `cairo_matrix_*` symbols, resolving them itself via
`super::cairo_dlsym` over the shared handle. The matrix API is stable
since cairo 1.0, so there is no version gating.
## Functions
### Other Functions
#### `init`
`Cairo::Matrix->init($xx, $yx, $xy, $yy, $x0, $y0)` -> blessed matrix. Mirrors the XS: cairo_matrix_init into a fresh malloc’d struct, bless.
#### `init_identity`
`Cairo::Matrix->init_identity` -> blessed identity matrix.
#### `init_translate`
`Cairo::Matrix->init_translate($tx, $ty)` -> blessed translation matrix.
#### `init_scale`
`Cairo::Matrix->init_scale($sx, $sy)` -> blessed scale matrix.
#### `init_rotate`
`Cairo::Matrix->init_rotate($radians)` -> blessed rotation matrix.
#### `translate`
`$matrix->translate($tx, $ty)` -> void; cairo_matrix_translate in place.
#### `scale`
`$matrix->scale($sx, $sy)` -> void; cairo_matrix_scale in place.
#### `rotate`
`$matrix->rotate($radians)` -> void; cairo_matrix_rotate in place.
#### `invert`
`$matrix->invert` -> status nickname. cairo_matrix_invert mutates the matrix in place and returns a cairo_status_t; we surface the nickname (mirrors the XS `cairo_status_t` return type -> `cairo_status_to_sv`).
#### `multiply`
`$a->multiply($b)` -> a NEW blessed Cairo::Matrix = a x b.
#### `transform_distance`
`$matrix->transform_distance($dx, $dy)` -> ($dx”, $dy”). IN_OUTLIST: the matrix’s linear part (no translation) transforms the distance vector.
#### `transform_point`
`$matrix->transform_point($x, $y)` -> ($x”, $y”). IN_OUTLIST: the full affine transform (including translation) applied to the point.
#### `destroy`
`$matrix->DESTROY` -> libc::free the referent. Mirrors the XS `Safefree(matrix)`; there is NO cairo call (a matrix is not refcounted). The pointer was allocated with libc::malloc either here (init/multiply) or by Context::get_matrix - both use the same 48-byte allocator, so this free is always valid. See the module ABI contract.