#pragma once // Text rendering. // // The console draws text by indexing `font_data[256][16]` and stepping the // cursor eight pixels. That is a *character cell grid*, and it is the thing in // the way -- not the font. A grid cannot do variable-width glyphs, cannot // position text anywhere except on a multiple of eight, cannot anti-alias, and // cannot represent a codepoint above 255. Swapping the bitmap for a nicer // bitmap changes none of that. // // So this is a layer, not a font. Three things it fixes: // // *Glyphs have metrics.* A glyph knows its own size, its bearing and how far // to advance afterwards. That is what variable-width text is; everything else // follows from it. // // *It draws into a surface, not into the screen.* A compositor draws into an // off-screen buffer and presents it. Rendering that writes straight to the // VGA aperture is unusable to it, which is why this takes a target. // // *The font is behind an interface.* The bitmap font is one implementation. // A TrueType rasteriser is another, and arrives without any caller changing: // glyphs carry 8-bit coverage, so an anti-aliased outline renderer already // has somewhere to put its output. struct font; // Somewhere to draw. Deliberately not a `struct device` or a framebuffer: the // same code has to work on the virtio-gpu back buffer, on a window's own // buffer, and on the VGA aperture, and none of those know about each other. struct surface { void *pixels; // 32-bit 0x00RRGGBB, the format everything here uses uint32 stride; // bytes per row, not pixels -- they differ on real hardware int width, height; }; // One rendered glyph. `cov` is 8-bit coverage, not a bitmap: 0 is background, // 255 is solid, and everything between is an anti-aliased edge. A bitmap font // fills it with 0 and 255 only, and costs nothing for the generality. struct glyph { const unsigned char *cov; // w*h bytes, row-major int w, h; // size of the coverage bitmap int bearing_x, bearing_y; // offset from the pen to the top-left of `cov` int advance; // how far the pen moves afterwards }; struct font_ops { // Fill `out` for `cp`. Returns 0, or -1 if the font has no such glyph -- // callers substitute rather than failing, because a missing glyph must not // stop a line of text. int (*glyph)(struct font *, uint32 cp, struct glyph *out); int (*height)(struct font *); // line height int (*baseline)(struct font *); // pen offset from the top of the line }; struct font { const struct font_ops *ops; void *priv; }; // The built-in bitmap font, as a font provider. Always available, needs no // allocation, and is what the console falls back to before any filesystem // exists to load a real typeface from. struct font *font_builtin(void); // Draw one UTF-8 string. Returns the x advance. // // `x, y` is the pen position on the *baseline*, which is how every text API // that is not a terminal works -- glyphs of different heights then sit on a // common line instead of being top-aligned. int text_draw(struct surface *, struct font *, int x, int y, const char *utf8, uint32 color); // Width the same string would occupy, without drawing it. Needed before you // draw, for centring and for laying out anything at all. int text_measure(struct font *, const char *utf8); // One glyph, for callers doing their own layout. int text_draw_glyph(struct surface *, struct font *, int x, int y, uint32 cp, uint32 color); // Decode one UTF-8 sequence. Returns the codepoint and advances *p. // Malformed input yields U+FFFD and consumes one byte, so a decoder loop // always terminates. uint32 utf8_next(const char **p);