v1.2.0

Outlines in C

daegun does not rasterize. It hands your rasterizer each glyph's outline through adaegun_pen: five callbacks and a pointer of your own, which daegun passes back untouched.

static void on_move(void *user, float x, float y) { /* start a contour */ }
static void on_line(void *user, float x, float y) { /* a straight edge */ }
static void on_quad(void *user, float cx, float cy, float x, float y) { /* TrueType curves */ }
static void on_cubic(void *user, float c1x, float c1y, float c2x, float c2y, float x, float y) { /* CFF curves */ }
static void on_close(void *user) { /* end the contour */ }

Any callback may be NULL, and that event is then skipped. Your callbacks must not unwind: a C++ exception or a longjmp through daegun is undefined behavior. They may call back into daegun, on the same font too.

Prepared outlines

daegun_outline_options opts;
daegun_outline_options_default(&opts);
opts.hinting = DAEGUN_HINT_AUTO;
opts.has_embolden = 1;
opts.embolden = 40.0f;   /* font units; widens the advances too */

daegun_pen pen = { on_move, on_line, on_quad, on_cubic, on_close, &my_rasterizer };
daegun_prepared_glyph glyph;
if (daegun_font_prepared_outline(font, gid, 16.0f, NULL, 0, &opts, &pen, &glyph) == DAEGUN_OK) {
    /* points arrived in pixels, y up from the glyph's origin; glyph.hinted says a hinter ran */
}

The transform's offsets are in font units, and it applies after hinting; the oblique applies before it. A stroke or embolden overlaps itself, which a non-zero fill hides and a rasterizer that sums coverage does not: resolve the overlaps for that one. The call draws nothing and returnsDAEGUN_RANGE for a size that is not finite and above zero, an option that is not finite, anything that overflows once scaled, or a stroke or embolden pastDAEGUN_MAX_FLATTEN_POINTS points. DAEGUN_ABSENT means no such glyph.

Quadratic curves and polygons

daegun_quads *quads = NULL;
if (daegun_font_glyph_quads(font, gid, NULL, 0, &quads) == DAEGUN_OK) {
    size_t curves = 0;
    const float *q = daegun_quads_data(quads, &curves);   /* x0 y0 cx cy x1 y1 per curve, em units */
    daegun_quads_free(quads);
}

Curves come in em units, y up and wound clockwise, each standing alone, the shape a curve-evaluating shader takes. An empty outline, such as a space, is DAEGUN_ABSENT.daegun_path_quads does the same for any path you built.

For a rasterizer that walks straight edges, capture the outline into a path throughdaegun_path_as_pen, with daegun_font_outline_glyph for font units, then flatten it with daegun_path_flatten. daegun_flatten_max_area_for gives the tolerance 1.1.7's rasterizer flattened with. A rasterizer that sums coverage then wantsdaegun_contours_resolve_overlaps, which matches points to 1e-4 and so expects font units, not ems.

Color scenes

daegun_font_colr_scene gives a COLR v0 or v1 glyph as fill, clip and layer ops to paint in order, back to front, with paths in font units, y up. daegun_font_colr_clip_box sizes a surface without walking the scene. daegun_color_scene_ramp makes a scene's gradient ready to sample with daegun_ramp_sample, which answers straight alpha, anddaegun_composite lays one pixel over another in any of COLR's 28 modes, answering premultiplied, so a rasterizer drawing a scene needs no blend math of its own. Thereference walks a scene end to end.

Subpixel filters

A subpixel layout describes a display's stripes for a rasterizer that filters subpixels itself.daegun_subpixel_layout_new takes a named DAEGUN_LAYOUT_*, anddaegun_subpixel_layout_from_weights a filter of your own. Coverage is sampled_oversample times a pixel, and each channel is its _weights over a_taps window that starts _origin samples from the pixel's first._pad is how far a glyph's box must grow a side, _channels is 1 or 3, and_cache_key is an identity to key a cache of filtered glyphs by.

Type to search.