ttf.c/ttf.h/ttftest.c: TrueType parser core -- sfnt/head/maxp/loca/glyf/cmap (item 4.3.7)

Freestanding C module resolving a Unicode codepoint (cmap format 4) to a
glyph index and its outline header (contour count, bounding box), verified
against an independent from-scratch Python reference reader via
tools/ttftest.c. Not yet wired into the boot path or capsule system.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-10 21:41:42 -04:00
co-authored by Claude Sonnet 5
parent b9b7cb2c6a
commit 5f6cc054d4
4 changed files with 552 additions and 1 deletions
+132
View File
@@ -0,0 +1,132 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* ttf.h - TrueType font parser core (Freestanding)
*
* FABRIC.md item 4.3.7. Reads a TTF's sfnt directory plus head/maxp/loca/
* glyf/cmap tables, resolving a Unicode codepoint to a glyph index and its
* outline header (contour count, bounding box). Does NOT extract outline
* points or rasterize — that is 4.3.7a/4.3.7c. No floating point; all
* fields read here are raw integers straight from the font's own
* big-endian on-disk format (see FABRIC.md §27.7 decision #2 for why the
* Q48.16-vs-float call was made, and why it doesn't bind this file, which
* never scales anything).
*
* cmap: only format 4 (Windows/Unicode BMP) subtables are resolved. This
* covers ASCII and all of the BMP, which is what the v1 glyph repertoire
* (§27.6.4) needs. Format 12 (supplementary planes) is deferred — no
* v1 glyph requires it.
*/
#ifndef STARKERNEL_TTF_H
#define STARKERNEL_TTF_H
#include <stdint.h>
#include <stddef.h>
#include "q48_16.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TTF_OK 0
#define TTF_ERR_BAD_SFNT -1
#define TTF_ERR_TABLE_MISSING -2
#define TTF_ERR_BAD_TABLE -3
#define TTF_ERR_BAD_GLYPH_INDEX -4
#define TTF_ERR_OUT_OF_BOUNDS -5
/** Glyph index returned for "no mapping" by ttf_codepoint_to_glyph(). */
#define TTF_GLYPH_MISSING 0
/**
* Parsed font handle. Borrows the caller's buffer (does not copy or own
* it) — the buffer must outlive the ttf_font_t.
*/
typedef struct {
const uint8_t *data;
uint32_t size;
uint32_t head_off;
uint32_t maxp_off;
uint32_t loca_off;
uint32_t loca_len;
uint32_t glyf_off;
uint32_t glyf_len;
uint16_t units_per_em;
int16_t index_to_loc_format; /* 0 = Offset16 (x2), 1 = Offset32 */
uint16_t num_glyphs;
/* Selected cmap subtable (format 4 only, see file header comment). */
uint32_t cmap_subtable_off;
int has_cmap;
} ttf_font_t;
/** Raw glyf record header, per §27.6/4.3.7's "done when" clause. */
typedef struct {
int16_t num_contours; /* >= 0 simple glyph, < 0 composite glyph */
int16_t x_min;
int16_t y_min;
int16_t x_max;
int16_t y_max;
uint32_t glyf_offset; /* absolute file offset of this glyph's record */
uint32_t glyf_length; /* bytes; 0 for an empty glyph (e.g. space) */
} ttf_glyph_header_t;
/**
* ttf_parse - Locate and validate the sfnt directory and the head/maxp/
* loca/glyf tables (cmap is optional; ttf_codepoint_to_glyph() fails
* cleanly if absent). Does not copy `data` — `out` borrows it.
*
* @param data Whole .ttf file contents
* @param size Length of data in bytes
* @param out Parsed handle to populate
* @return TTF_OK, or a TTF_ERR_* code
*/
int ttf_parse(const uint8_t *data, uint32_t size, ttf_font_t *out);
/**
* ttf_codepoint_to_glyph - Resolve a Unicode codepoint via the font's
* format-4 cmap subtable.
*
* @return glyph index, or TTF_GLYPH_MISSING if unmapped or no cmap
*/
uint32_t ttf_codepoint_to_glyph(const ttf_font_t *font, uint32_t codepoint);
/**
* ttf_glyph_header - Read a glyph's outline header (contour count,
* bounding box) via loca + glyf. Does not extract contour points.
*
* @param glyph_index As returned by ttf_codepoint_to_glyph()
* @param out Header to populate
* @return TTF_OK, or a TTF_ERR_* code
*/
int ttf_glyph_header(const ttf_font_t *font, uint32_t glyph_index,
ttf_glyph_header_t *out);
#ifdef __cplusplus
}
#endif
#endif /* STARKERNEL_TTF_H */