import { Font } from "@react-pdf/renderer"; import { FONT_MANIFEST } from "./manifest"; import { familySources } from "./stack"; export { FONT_STACK, familySources, stack, type FamilySource } from "./stack"; let registered = false; /** * Registers every bundled family from the manifest. Idempotent; never call Font.reset(), the fonts * would not load again. * * `base` is a URL prefix in the app ("/fonts") and a directory under Node (tests). Only static TTF is * used: WOFF2 embeds glyphs without outlines (invisible text) and variable fonts embed only their * default instance. */ export function registerBundledFonts(base: string): void { if (registered) return; registered = true; for (const fam of FONT_MANIFEST.families) { const sources = familySources(fam).map((s) => ({ src: `${base}/${fam.folder}/${s.file}`, fontWeight: s.fontWeight, fontStyle: s.fontStyle, })); Font.register({ family: fam.family, fonts: sources }); } // The default hyphenation inserts "-" into e-mail addresses, URLs and identifiers. Font.registerHyphenationCallback((word) => [word]); } const MIN_FONT_BYTES = 10 * 1024; function hasTrueTypeMagic(b: Uint8Array): boolean { if (b.length < 4) return false; if (b[0] === 0 && b[1] === 1 && b[2] === 0 && b[3] === 0) return true; return String.fromCharCode(b[0], b[1], b[2], b[3]) === "true"; } /** * Fetches every bundled font and returns a list of problems (empty when all are fine). Tauri answers * an unknown path with index.html and HTTP 200, so the response bytes must be checked, not the status. */ export async function preflightFonts( fetchBytes: (url: string) => Promise, base: string, ): Promise { const problems: string[] = []; for (const fam of FONT_MANIFEST.families) { for (const font of fam.fonts) { const url = `${base}/${fam.folder}/${font.file}`; try { const bytes = await fetchBytes(url); if (!hasTrueTypeMagic(bytes)) problems.push(`${url}: not a TrueType font`); else if (bytes.length <= MIN_FONT_BYTES) problems.push(`${url}: only ${bytes.length} bytes`); } catch (err) { problems.push(`${url}: ${err instanceof Error ? err.message : String(err)}`); } } } return problems; }