/* StarForth — Steady-State Virtual Machine Runtime Copyright (c) 2023–2025 Robert A. James All rights reserved. Licensed under the StarForth License, Version 1.0. */ /** * ttftest.c — Host-side unit test for src/starkernel/hal/ttf.c (FABRIC.md * item 4.3.7). No QEMU needed, same pattern as tools/README.md's fbtest.c * entry (that file is itself missing from tools/ — stale doc, reported * separately, not fixed here). * * Expected values below were independently computed by a from-scratch * Python/struct reference reader (not this codebase's parser), against * JetBrainsMono-Regular.ttf. * * Usage: ./ttftest */ #include #include #include #include "../include/starkernel/ttf.h" typedef struct { uint32_t codepoint; uint32_t expect_glyph; int16_t expect_contours; int16_t expect_xmin, expect_ymin, expect_xmax, expect_ymax; uint32_t expect_glyf_offset; uint32_t expect_glyf_length; } expect_t; static const expect_t EXPECTED[] = { /* cp glyph nc xmin ymin xmax ymax off len */ {0x0041, 1, 2, 50, 0, 550, 730, 35536, 112}, /* 'A' */ {0x0061, 198, 2, 67, -10, 508, 560, 46968, 244}, /* 'a' */ {0x0030, 737, 3, 80, -10, 520, 740, 92152, 184}, /* '0' */ {0x002E, 908, 1, 218, -10, 382, 152, 110044, 72}, /* '.' */ {0x0021, 913, 2, 225, -5, 375, 730, 110632, 108}, /* '!' */ {0x0040, 1151, 2, 45, -180, 560, 740, 144400, 224}, /* '@' */ {0x0020, 821, 0, 0, 0, 0, 0, 99448, 0}, /* space, empty glyph */ }; static int failures = 0; static void check_eq_i(const char *what, uint32_t cp, long got, long want) { if (got != want) { printf(" FAIL U+%04X %s: got %ld want %ld\n", cp, what, got, want); failures++; } } int main(int argc, char **argv) { FILE *fp; long size; uint8_t *buf; ttf_font_t font; int rc; size_t i; if (argc < 2) { fprintf(stderr, "usage: %s \n", argv[0]); return 2; } fp = fopen(argv[1], "rb"); if (!fp) { perror("fopen"); return 2; } fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); buf = malloc((size_t) size); if (!buf || fread(buf, 1, (size_t) size, fp) != (size_t) size) { fprintf(stderr, "read failed\n"); return 2; } fclose(fp); rc = ttf_parse(buf, (uint32_t) size, &font); if (rc != TTF_OK) { printf("ttf_parse failed: rc=%d\n", rc); return 1; } printf("parsed: unitsPerEm=%u numGlyphs=%u indexToLocFormat=%d has_cmap=%d\n", font.units_per_em, font.num_glyphs, font.index_to_loc_format, font.has_cmap); for (i = 0; i < sizeof(EXPECTED) / sizeof(EXPECTED[0]); i++) { const expect_t *e = &EXPECTED[i]; uint32_t gid = ttf_codepoint_to_glyph(&font, e->codepoint); ttf_glyph_header_t hdr; int hrc; printf("U+%04X -> glyph %u (want %u)\n", e->codepoint, gid, e->expect_glyph); check_eq_i("glyph", e->codepoint, gid, e->expect_glyph); hrc = ttf_glyph_header(&font, gid, &hdr); if (hrc != TTF_OK) { printf(" FAIL U+%04X ttf_glyph_header rc=%d\n", e->codepoint, hrc); failures++; continue; } check_eq_i("num_contours", e->codepoint, hdr.num_contours, e->expect_contours); check_eq_i("x_min", e->codepoint, hdr.x_min, e->expect_xmin); check_eq_i("y_min", e->codepoint, hdr.y_min, e->expect_ymin); check_eq_i("x_max", e->codepoint, hdr.x_max, e->expect_xmax); check_eq_i("y_max", e->codepoint, hdr.y_max, e->expect_ymax); check_eq_i("glyf_offset", e->codepoint, hdr.glyf_offset, e->expect_glyf_offset); check_eq_i("glyf_length", e->codepoint, hdr.glyf_length, e->expect_glyf_length); } free(buf); if (failures) { printf("%d check(s) FAILED\n", failures); return 1; } printf("all checks passed\n"); return 0; }