text, font, fill

tape
@profile(t1);
import fs from "fs";
import gfx from "gfx";
import font from "font";
import fill from "fill";
import text from "text";
import io from "io";

/* What text works in: the caller's memory, no allocation inside */
struct TextMemory {
    glyphs: [256]text.Glyph;
    atlas: [65536]u8;
    edges: [2048]fill.Edge;
    order: [2048]i32;
    active: [2048]i32;
    cov: [512]u32;
    outline: font.Outline;
    filler: fill.Filler;
}

var mem: TextMemory;

fn main() -> i32 {
    let bytes: string = fs.read_file("C:/Windows/Fonts/arial.ttf") or { return 1; };
    let face: font.Face = font.open(bytes) or { io.println("not a font: {err}"); return 2; };
    fill.init(&mem.filler, mem.edges[0..2048], mem.order[0..2048], mem.active[0..2048], mem.cov[0..512]);
    var c: text.Context;
    text.init(&c, &face, 24, mem.glyphs[0..256], mem.atlas[0..65536], &mem.outline, &mem.filler);

    var s: gfx.Surface = gfx.new_surface(320, 64, gfx.Format.Rgbx) or { return 3; };
    s.clear(#FFFFFF);
    let t: text.Target = text.target(s.pixels() as *u32, s.width, s.height, s.stride, true);
    let end_x: i64 = text.draw(&c, &t, 10, 40, 0x202020, 255, "Hyvää päivää, tape!");
    io.println("drawn {end_x - 10} px wide; measure says {text.measure(&c, "Hyvää päivää, tape!")}");
    s.free();
    return 0;
}

Three modules draw TrueType text: font reads the font file, fill turns outlines into anti-aliased coverage, and text caches glyphs and draws lines of UTF-8. They allocate nothing: you give them their memory, so the same code runs in a program, in a kernel and on Uusi. gfx’s own draw_text is a small bitmap font; use these for real fonts at any size.

font

FunctionDoes
open(bytes) -> Face or FontErrorRead a TrueType file (.ttf); the Face borrows bytes, so keep them
glyph_index(&face, code_point) -> i64The glyph for a code point (0: the font has none)
advance(&face, glyph), left_bearing(&face, glyph)Metrics in font units
kerning(&face, left, right)The kerning between two glyphs, font units
scale(units, px, face.units_per_em)Font units to pixels at px pixels per em
outline(&face, glyph, &o)The glyph’s contours into an Outline

face.ascender, descender (negative) and line_gap are in font units. OpenType fonts with CFF outlines (.otf that start OTTO) are refused with NotTrueType; a damaged font gives an error, never a crash.

text

FunctionDoes
init(&c, &face, px, glyphs, atlas, &outline, &filler)A context for face at px pixels per em, caching in glyphs and atlas
target(pixels, width, height, stride, bgr) -> TargetPixels to draw on
draw(&c, &target, x, baseline_y, rgb, alpha, s) -> i64Draw one line of UTF-8; the x after it
measure(&c, s) -> i64Its width in pixels
draw_tracked, measure_trackedThe same with extra spacing after each glyph (26.6 pixels)
draw_fx, measure_fxPositions and widths in 26.6 fixed point, for a layout that adds them up

c.ascent, c.descent and c.line_height are in pixels: the next line’s baseline is c.line_height below. rgb is 0xRRGGBB and alpha 0 to 255. A target clips to its clip_x, clip_y, clip_w, clip_h rectangle (the whole surface from target). bgr: true means the pixels are 0xRRGGBB words, as a gfx.Surface and Windows bitmaps are.

Glyphs are drawn at quarter-pixel positions and kerned, so text keeps the font’s spacing. When the cache’s memory is full it starts over: give it room for the sizes you use (64 bytes a glyph record, 256 KiB of atlas for a few sizes of interface text).

One code point is one glyph: no ligatures, right-to-left text or combining marks.

fill

fill is the rasterizer under text, for any outline: lines, quadratic and cubic curves in 26.6 fixed-point pixels (fill.ONE is one pixel, y down), filled into an 8-bit coverage Mask with the nonzero or even-odd rule.

FunctionDoes
init(&f, edges, order, active, cov)A filler working in your arrays (a few hundred edges for a glyph)
begin(&f, width, height)Start a shape the size of the mask
line, quad, cubicAdd its segments
fill(&f, &mask, rule)Write the coverage (0 to 255 a pixel)

More edges than the arrays hold set f.overflow instead of writing past them.

Last modified: