# Peta::FFI::Cairo::Context
📦 std
`Cairo::Context` package plug-in. The drawing context (`cairo_t`). This module owns the context cairo symbols, resolving them itself via `super::cairo_dlsym` over the shared handle so the foundation’s symbol table never carries context entries. Refcount contract (census section 4): `create` returns a +1 context blessed directly; `DESTROY` drops exactly one reference via `cairo_destroy`. Borrowed getters (`get_source`, `get_target`, `get_group_target`, `get_font_face`) return objects the caller does not own, so we `cairo_*_reference` them before blessing; `pop_group` already returns +1 (matching `newSVCairoPattern_noinc`) so it is blessed directly. ## Cross-package ABI assumptions (FLAGGED for review) Two getters here manufacture objects that live in SIBLING packages, so this file makes allocator/refcount assumptions about how those packages” `DESTROY` will free them. Both are documented at their call sites: - `get_matrix` / `get_font_matrix` return a `Cairo::Matrix`. Upstream `cairo_perl_copy_matrix` does `New(0, m, 1, cairo_matrix_t); *m = src` and `Cairo::Matrix::DESTROY` does `Safefree(m)`. We mirror that with a raw `libc::malloc` of `size_of::()` (6 f64 = 48 bytes), write the matrix into it via `cairo_get_matrix`, and bless the pointer into `Cairo::Matrix`. The Matrix package’s `DESTROY` MUST free it with the matching `libc::free`. If Matrix uses a different allocator, this is a mismatch - hence the shared-repr definition below. - `get_font_options` returns a `Cairo::FontOptions` allocated with `cairo_font_options_create()` (a +1 cairo object). The Font package’s `Cairo::FontOptions::DESTROY` MUST call `cairo_font_options_destroy`. ## Functions ### Other Functions #### `context_create` `Cairo::Context->create($surface)` -> blessed Cairo::Context. Mirrors cairo_create with the `_noinc` contract; ST(0) is the class (dropped). #### `context_destroy` `$cr->DESTROY` -> cairo_destroy, dropping the wrapper’s one reference. #### `context_status` `$cr->status` -> status nickname (enum-string return). #### `pop_group` `$cr->pop_group` -> the group as a pattern. cairo_pop_group already returns +1 (newSVCairoPattern_noinc), so we bless directly, type-dispatched. #### `get_source` `$cr->get_source` -> the current source pattern (borrowed; reference + type-dispatched bless). #### `set_dash` `$cr->set_dash($offset, @dashes)`. Variadic: mirrors the XS which mallocs `items - 2` doubles from ST(2..) and passes (dashes, ndash, offset). #### `get_dash` `$cr->get_dash` -> list ($offset, @dashes). Mirrors the PPCODE XS: cairo_get_dash_count then cairo_get_dash into a buffer, push offset first. #### `has_current_point` `$cr->has_current_point` -> bool (>=1.6). dlsym-gated: absent -> croak. #### `get_current_point` `$cr->get_current_point` -> ($x, $y) OUTLIST. #### `in_clip` `$cr->in_clip(x, y)` -> bool (>=1.10). dlsym-gated via context_hit. #### `select_font_face` `$cr->select_font_face($family, $slant, $weight)`. utf8 family + 2 enums. #### `get_font_options` `$cr->get_font_options` -> Cairo::FontOptions. Allocs a fresh options object (cairo_font_options_create, +1 owned), fills it, blesses into the Font package’s FontOptions (whose DESTROY calls cairo_font_options_destroy). See module ABI note. #### `get_scaled_font` `$cr->get_scaled_font` -> Cairo::ScaledFont (>=1.4). This is a borrowed getter in the XS (ref-INC via newSVCairoScaledFont); we take a reference through cairo_scaled_font_reference if present, then bless into the nominal Cairo::ScaledFont (no subclass dispatch for scaled fonts). #### `show_text` `$cr->show_text($utf8)`. #### `text_path` `$cr->text_path($utf8)`. #### `get_font_face` `$cr->get_font_face` -> Cairo::FontFace subclass (borrowed; ref + dispatch). #### `font_extents` `$cr->font_extents` -> hashref {ascent,descent,height,max_x_advance, max_y_advance}. Keys fixed by newSVCairoFontExtents. #### `text_extents` `$cr->text_extents($utf8)` -> hashref {x_bearing,y_bearing,width,height, x_advance,y_advance}. Keys fixed by newSVCairoTextExtents. #### `get_target` `$cr->get_target` -> the target surface (borrowed; ref + type-dispatch). #### `get_group_target` `$cr->get_group_target` -> the current group’s target surface (>=1.2). #### `tag_begin` `$cr->tag_begin($tag_name, $attributes)` (>=1.16). dlsym-gated. #### `tag_end` `$cr->tag_end($tag_name)` (>=1.16). dlsym-gated. #### `show_glyphs` `$cr->show_glyphs(@glyphs)` (Cairo.xs). Variadic LIST of glyph hashrefs; marshal each with SvCairoGlyph, then `cairo_show_glyphs`. Void return. #### `glyph_path` `$cr->glyph_path(@glyphs)` (Cairo.xs). Variadic LIST; `cairo_glyph_path`. Void return. #### `glyph_extents` `$cr->glyph_extents(@glyphs)` (Cairo.xs) -> text_extents hashref {x_bearing,y_bearing,width,height,x_advance,y_advance}. Variadic LIST. #### `show_text_glyphs` `$cr->show_text_glyphs($utf8, \@glyphs, \@clusters, $cluster_flags)` (Cairo.xs, >=1.8). utf8 string + glyph arrayref + cluster arrayref + text-cluster-flags. The XS allocates the glyph/cluster arrays with cairo’s own `cairo_glyph_allocate` / `cairo_text_cluster_allocate` and frees them with the matching `_free` after the call, so we do the same. Void return. #### `copy_path` `Cairo::Context::copy_path` (Cairo.xs:893) -> cairo_copy_path -> a tied `Cairo::Path` live view. cairo returns a +1 path; the tie’s DESTROY frees it via cairo_path_destroy, so we wrap it directly (newSVCairoPath). #### `copy_path_flat` `Cairo::Context::copy_path_flat` (Cairo.xs:895): same wrapping, flattened path (curves approximated by line segments). #### `append_path` `Cairo::Context::append_path` (Cairo.xs:897): take a `Cairo::Path` (or a plain arrayref-of-hashes) and cairo_append_path it. `SvCairoPath` recovers the C pointer from tie magic, or marshals an arrayref via path_from_array; the latter is a temp we must free once cairo has copied it (cairo acts on the path immediately, per CairoPath.xs:129-132). #### `copy_clip_rectangle_list` `Cairo::Context::copy_clip_rectangle_list` (Cairo.xs:641-651): return the current clip as a list of `{x,y,width,height}` (nv) hashrefs. Mirrors the XS PPCODE: check list->status (croak on error), push each rectangle, then cairo_rectangle_list_destroy. Not a tie - a plain list return (census 2.2). Requires libcairo >= 1.4 (dlsym-gated).