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