Add font import for Now, Gotham and Open Sauce One overrides; package fonts for Void

Font import:
- Migration M6 adds user_fonts; files are stored content-addressed under
  the local data dir. New Rust commands inspect, import, list, read and
  remove fonts, refusing WOFF2, collections, variable fonts and
  restricted fsType, and unpacking WOFF1 to plain sfnt.
- Imported fonts register in the render worker as user:<Face> families
  with an italic alias, and are pinned in the frozen render prefs so
  issued invoices can still re-render. Fonts referenced by issued
  invoices are hidden, never deleted.
- Size and tracking compensations tuned for the substitutes apply only
  while the face is not overridden; default output and fingerprint
  goldens are unchanged.
- Settings gets a Fonts section with a licence acknowledgement.

Void packaging:
- Install fonts to /usr/share/fonts/voiced with per-family OFL licences,
  set font_dirs, and add INSTALL/REMOVE scripts that run fc-cache.
  xbps-create carries both scripts (verified in a void-glibc container).
- Fix xbps-create dependency specs in build-xbps.sh.
This commit is contained in:
2026-10-04 13:58:06 +05:30
parent 4d18a50753
commit afbc0aa56f
37 changed files with 2436 additions and 72 deletions
+12 -1
View File
@@ -1,11 +1,22 @@
import { createAutoClient, type RenderClient } from "../pdf/render/client";
import type { UserFace } from "../pdf/fonts/userFontStore";
import { api } from "./api";
let client: RenderClient | null = null;
let lastId = 0;
/** The one render client (and so one worker) shared by the preview and export. */
export function getRenderClient(): RenderClient {
client ??= createAutoClient();
client ??= createAutoClient({
// Font metadata comes from the database row, the bytes over the binary IPC; both by the file's sha256.
loadUserFont: async (sha256) => {
const rows = await api.listUserFonts(true);
const row = rows.find((r) => r.sha256 === sha256);
if (!row) throw new Error("An imported font used by this invoice is no longer in the font library");
const bytes = await api.getUserFontBytes(sha256);
return { face: row.face as UserFace, weight: row.weight, italic: row.style === "italic", sha256, bytes };
},
});
return client;
}