# 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.