From 2acf27f665f8a926d244efa58f6ef2c92d65e8c4 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Sun, 27 Sep 2026 08:56:47 +0100 Subject: Store symbol outlines as point chains, and keep glyph advances whole Format 2 (VEGASYM2) writes each contour as a chain of 4-byte points, on or off the curve as in TrueType: endpoints are shared, lines have no control point, and two off points imply the on point between them. A curve is still had from one point and its two neighbours, so a GPU can point at curves by point index and upload the table as it is. Cubics (CFF, SVG curves and arcs) become quadratic splines the cu2qu way, joins left implied, within a unit. Files are about half of format 1: 1.3-1.4x a TrueType font's glyf (the whole subset font's size), 2.0-2.9x CFF, 2.6x smaller than the SVG icons. Opening checks each symbol's first and last point instead of every curve: 0.34 ms rather than 19 ms for 11,172 Hangul syllables. Points decode without branching on their flags (9.7 ns a point), still 1.2-10x cheaper than FreeType's outline. Glyph advances were half their width since outlines are doubled for FreeType's implied points; they now match hmtx, and the check says so. --- src/symbols.h | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'src/symbols.h') diff --git a/src/symbols.h b/src/symbols.h index da33e34..998ff3f 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -4,12 +4,19 @@ #include #include -/* Symbols: glyphs and icons as quadratic curves in one file, verified once - * and then read where it lies (docs/design/002-symbol-format.md). */ -enum { VEGA_SYMBOLS_HEADER = 28, VEGA_SYMBOL_BYTES = 24, VEGA_CURVE_BYTES = 12 }; -typedef struct { int16_t x0, y0, x1, y1, x2, y2; } VegaCurve; +/* Symbols: glyphs and icons as outlines of quadratic curves in one file, + * verified once and then read where it lies (docs/design/002-symbol-format.md). + * An outline is a chain of points, on or off the curve, as in TrueType: two + * off points in a row imply the on point halfway between them. */ +enum { VEGA_SYMBOLS_HEADER = 28, VEGA_SYMBOL_BYTES = 24, VEGA_POINT_BYTES = 4 }; typedef struct { - uint32_t code, first, count; /* its curves: [first, first + count) */ + int16_t x, y; + bool off; /* a control point */ + bool move; /* starts a contour */ +} VegaPoint; +typedef struct { float x0, y0, x1, y1, x2, y2; } VegaCurve; /* a line has its middle as control */ +typedef struct { + uint32_t code, first, count; /* its points: [first, first + count) */ int16_t left, bottom, right, top; /* bounds, in units, y up */ int16_t advance; } VegaSymbol; @@ -17,20 +24,29 @@ typedef struct { const unsigned char *bytes; size_t size; uint16_t units; /* per em */ - uint32_t symbols, curves; + uint32_t symbols, points; } VegaSymbols; /* Verify bytes as a symbol file (kept, not copied); false with why. What - * reading needs is checked, per symbol: after this no read leaves the file. - * The curves themselves are not: one outside its symbol's bounds draws wrong. */ + * reading needs is checked, per symbol: after this no read leaves the file + * or its symbol. The points themselves are not: one outside its symbol's + * bounds draws wrong. */ bool vega_symbols_open(VegaSymbols *, const unsigned char *bytes, size_t size, char *error, size_t error_size); /* The symbol of code (a binary search), or false. */ bool vega_symbol(const VegaSymbols *, uint32_t code, VegaSymbol *out); VegaSymbol vega_symbol_at(const VegaSymbols *, uint32_t index); -VegaCurve vega_curve(const VegaSymbols *, uint32_t index); +VegaPoint vega_point(const VegaSymbols *, uint32_t index); +/* The curve that point index of symbol begins, if any: an off point is the + * control of one, and an on point followed by another on point in the same + * contour starts a line. Every curve of a symbol is had once this way, from + * the point and its two neighbours alone (as a GPU would fetch it). */ +bool vega_symbol_curve(const VegaSymbols *, const VegaSymbol *, uint32_t index, VegaCurve *out); +/* All of a symbol's curves, in one pass over its points; out has room for + * symbol->count (a symbol has no more curves than points). */ +uint32_t vega_symbol_curves(const VegaSymbols *, const VegaSymbol *, VegaCurve *out); /* The coverage (0 to 1) of the pixel whose center is (x, y) in units, at - * scale pixels per unit: as a GPU would compute it per pixel. */ -double vega_symbol_coverage(const VegaSymbols *, const VegaSymbol *, double scale, double x, double y); + * scale pixels per unit: the exact area the curves' outline covers. */ +double vega_coverage(const VegaCurve *, uint32_t count, double scale, double x, double y); /* width x height 8-bit coverage, rows top first; pixel (i, j) has its center * at (left + (i + 0.5) / scale, top - (j + 0.5) / scale) in units. */ void vega_symbol_raster(const VegaSymbols *, const VegaSymbol *, double scale, double left, double top, int width, -- cgit v1.2.3