# Peta::FFI::Cairo::Font
📦 std
`Cairo::Font` family plug-in: FontFace, ToyFontFace, ScaledFont,
FontOptions, and the (deferred) FtFontFace.
This module owns the font cairo symbols (`cairo_font_face_*`,
`cairo_toy_font_face_*`, `cairo_scaled_font_*`, `cairo_font_options_*`),
resolving them itself via `super::cairo_dlsym` over the shared handle so
the foundation’s symbol table never carries font entries. It mirrors
CairoFont.xs (census sections 2.7 / 2.8).
## Cross-package refcount / ABI contract (Context depends on this)
The Context and Surface packages already bless cairo objects into OUR
packages and rely on OUR `DESTROY` to balance the reference they took.
Getting these three destructors wrong leaks or double-frees:
- Context/Surface `get_font_options` allocate via
`cairo_font_options_create()` (+1 owned) and bless into
`Cairo::FontOptions`. So `Cairo::FontOptions::DESTROY` MUST call
`cairo_font_options_destroy`.
- Context `get_scaled_font` blesses a `Cairo::ScaledFont` AFTER taking a
reference (`cairo_scaled_font_reference`). So
`Cairo::ScaledFont::DESTROY` MUST call `cairo_scaled_font_destroy`.
- Context `get_font_face` blesses a type-dispatched FontFace subclass
after `cairo_font_face_reference`. So `Cairo::FontFace::DESTROY` MUST
call `cairo_font_face_destroy` (inherited by ToyFontFace/FtFontFace via
@ISA, so registering it once on the base is sufficient).
## Refcount contract (census section 4)
FontFace/ScaledFont/FontOptions are cairo-refcounted. Our constructors
(`ToyFontFace::create`, `ScaledFont::create`, `FontOptions::create`)
return +1 and bless the pointer directly. Borrowed getters
(`ScaledFont::get_font_face`) `cairo_*_reference` before blessing. Every
`DESTROY` drops exactly one reference. FontFace blessing is
TYPE-DISPATCHED via `cairo_font_face_get_type` (0->ToyFontFace,
1->FtFontFace, else FontFace).
## Matrix / FontOptions cross-package allocation (see Context ABI note)
`ScaledFont::get_font_matrix`/`get_ctm`/`get_scale_matrix` return a
`Cairo::Matrix`, which upstream is a `libc::malloc`ed `cairo_matrix_t`
(6 f64 = 48 bytes) freed by `Cairo::Matrix::DESTROY`’s `libc::free`; we
mirror that exactly. `get_font_options` allocates via
`cairo_font_options_create()` and blesses into `Cairo::FontOptions`.
## Functions
### Other Functions
#### `face_status`
`$face->status` -> status nickname (enum-string return).
#### `face_get_type`
`$face->get_type` -> font-type nickname (>=1.2).
#### `face_destroy`
`$face->DESTROY` -> cairo_font_face_destroy, dropping the wrapper’s one reference. Inherited by ToyFontFace/FtFontFace via @ISA. Balances the reference Context’s get_font_face took (see module ABI contract).
#### `toy_create`
`Cairo::ToyFontFace->create($family, $slant, $weight)` -> blessed Cairo::ToyFontFace. cairo_toy_font_face_create returns +1; bless directly. ST(0) is the class (dropped). Mirrors the XS C_ARGS (family, slant, weight).
#### `toy_get_family`
`$face->get_family` -> the font family (UTF-8 string).
#### `toy_get_slant`
`$face->get_slant` -> slant nickname.
#### `toy_get_weight`
`$face->get_weight` -> weight nickname.
#### `sf_create`
`Cairo::ScaledFont->create($face, $font_matrix, $ctm, $options)` -> blessed Cairo::ScaledFont. cairo_scaled_font_create returns +1; bless directly. ST(0) is the class. Mirrors the XS C_ARGS (font_face, font_matrix, ctm, options).
#### `sf_status`
`$sf->status` -> status nickname.
#### `sf_get_type`
`$sf->get_type` -> font-type nickname (>=1.2).
#### `sf_extents`
`$sf->extents` -> font_extents hashref {ascent,descent,height,max_x_advance,max_y_advance}.
#### `sf_text_extents`
`$sf->text_extents($utf8)` -> text_extents hashref {x_bearing,y_bearing,width,height,x_advance,y_advance} (>=1.2).
#### `sf_get_font_face`
`$sf->get_font_face` -> Cairo::FontFace subclass (>=1.2, borrowed: reference + type-dispatched bless).
#### `sf_get_font_matrix`
`$sf->get_font_matrix` -> Cairo::Matrix (>=1.2, out-param copy).
#### `sf_get_ctm`
`$sf->get_ctm` -> Cairo::Matrix (>=1.2, out-param copy).
#### `sf_get_scale_matrix`
`$sf->get_scale_matrix` -> Cairo::Matrix (>=1.8, out-param copy).
#### `sf_get_font_options`
`$sf->get_font_options` -> Cairo::FontOptions (>=1.2). Allocs a fresh options object (cairo_font_options_create, +1 owned), fills it, blesses into Cairo::FontOptions (whose DESTROY calls cairo_font_options_destroy).
#### `sf_destroy`
`$sf->DESTROY` -> cairo_scaled_font_destroy, dropping the wrapper’s one reference. Balances the reference Context’s get_scaled_font took (see ABI note).
#### `sf_glyph_extents`
`$sf->glyph_extents(@glyphs)` (CairoFont.xs) -> text_extents hashref {x_bearing,y_bearing,width,height,x_advance,y_advance}. Variadic glyph LIST, same prologue as the Context variant.
#### `sf_text_to_glyphs`
`$sf->text_to_glyphs($x, $y, $utf8)` (CairoFont.xs, >=1.8). Returns a LIST: `(status_nickname, glyphs_ref, clusters_ref, cluster_flags_ref)`. The status SV is ALWAYS pushed; the three data refs are pushed only when status is SUCCESS (the PPCODE mirrors this exactly). cairo ALLOCATES the glyph and cluster arrays; we build the Perl hashref arrays from them, then free the C arrays with cairo_glyph_free / cairo_text_cluster_free.
#### `opts_create`
`Cairo::FontOptions->create` -> blessed Cairo::FontOptions. cairo_font_options_create takes void (C_ARGS void) and returns +1.
#### `opts_status`
`$opts->status` -> status nickname.
#### `opts_merge`
`$opts->merge($other)`.
#### `opts_equal`
`$opts->equal($other)` -> bool.
#### `opts_hash`
`$opts->hash` -> UV (cairo_font_options_hash returns unsigned long).
#### `opts_destroy`
`$opts->DESTROY` -> cairo_font_options_destroy, dropping the wrapper’s one reference. Balances the +1 from Context/Surface get_font_options and our own create (see module ABI contract).
#### `opts_set_color_mode`
`$opts->set_color_mode($mode)` (>=1.18). Enum: default/no-color/color.
#### `opts_get_color_mode`
`$opts->get_color_mode` (>=1.18) -> mode nickname.
#### `opts_set_color_palette`
`$opts->set_color_palette($index)` (>=1.18). UV index (CPAL palette).
#### `opts_get_color_palette`
`$opts->get_color_palette` (>=1.18) -> UV palette index.
#### `opts_set_custom_palette_color`
`$opts->set_custom_palette_color($index, $r, $g, $b, $a)` (>=1.18).
#### `opts_get_custom_palette_color`
`$opts->get_custom_palette_color($index)` (>=1.18) -> list (status, r, g, b, a). The C signature returns a status and writes r/g/b/a out; we surface the status nickname first (a missing entry yields e.g. »invalid-index«), then the four color components.
#### `ft_create`
Deferred by DEPENDENCY, not by effort. Per CairoFt.xs, this method takes a blessed `Font::FreeType::Face` object and extracts a raw `FT_Face` from its IV (`SvIV(SvRV(face))`), then calls `cairo_ft_font_face_create_for_ft_face`. That `FT_Face` can only exist if `Font::FreeType` produced it - and `Font::FreeType` is itself an XS-over-libfreetype module that pperl does not yet provide (absent from perl5-modules/ and the system perl). There is no faithful way to accept a `Font::FreeType::Face` when nothing can create one. Unblocking this requires porting `Font::FreeType` as its own native module (a libfreetype binding); until then the phenotype has no valid input. The FtFontFace->FontFace @ISA is still installed so `isa`/`can` are correct.