Vinculum 1.4.2
Correctness release: Linux font metrics, two parser data-loss bugs, and FreeType memory/thread safety. No API changes — a pure bug-fix patch.
If you render on Linux with anything but Latin Modern, your output changes (and is now correct).
Fixed
-
Linux: every font now uses its own MATH constants. (#1)
MathTableParserparses a MATH table, but the Linux renderer handed it the whole.otf— whose first bytes are the sfnt tag ('OTTO'), failing the version guard.constantsreturnednil, and the?? .latinModernfallback silently gave Termes, Pagella, STIX Two and Fira Math Latin Modern's metrics — so font choice had no effect on Linux layout, and nothing went red. The table is now extracted with FreeType, mirroring the Apple path'sCGFont.table(for:).
Measured: Fira Math's axis height is 0.28 and STIX Two's 0.258 — both had been rendering as 0.25. Axis height places every fraction bar and minus sign. Latin Modern is unchanged. -
Parser: a stateful switch no longer swallows
\end. (#2)
\bf/\color{…}/\displaystyleas the last token of an environment cell scanned straight through the environment's own\end, absorbing the terminator, the env name, and any trailing content — silently lost. -
Parser: double sub/superscript degrades visibly instead of dropping content. (#9)
a_b_c/x^2^3(TeX's "Double subscript" error) silently discarded the earlier atom and rendereda_c. It now degrades to a visible, source-locatable fallback. Behavior note: that input previously rendereda_c; it now shows a fallback card. That's the fix — it was deleting your content. -
Linux:
FreeTypeFontowns its font bytes. (#4)
FT_New_Memory_Facedoesn't copy — it reads through the pointer for the face's whole lifetime — but the pointer came fromData.withUnsafeBytes, which only guarantees validity inside the closure. Correctness rested onData's undocumented representation. -
Linux:
FreeTypeFont's sharedFT_Faceis locked. (#3)
Its@unchecked Sendablewas a false promise: every accessor callsFT_Load_Glyph, which mutates the face's shared glyph slot. Sharing one font across threads didn't merely race — it crashed (SIGBUS). Now serialized behind anNSLock, mirroringMathFont.ctFontLockon the Apple side.
Under the hood
- Reproducible Linux CI (#32) — the only job that builds the Silica/Cairo/FreeType backend was resolving
branch:masteragainst upstream HEAD every run. It now restores a pinned, CI-scoped lockfile. Default consumers stay Silica-free. - A Linux render-regression net (#11) — the backend's only assertion was "is it a valid PNG?", so a blank or garbled render passed silently. Renders are now diffed against committed ink signatures.
- Doc-drift guard (#31, #47) — CI now fails if
CONTRIBUTING.md's statedswift-tools-versiondiverges fromPackage.swift; the ARCHITECTURE checklist now lists all seven exhaustiveMathNodeswitches (it claimed four).
Performance claims were re-verified in release after the parser changes rather than assumed — the published numbers hold (parse 22.7µs, warm hit 0.50µs, headless layout 7.9µs, ~76% of a cold render is CoreText). See docs/PERFORMANCE.md.
Install
.package(url: "https://github.com/2389-research/Vinculum.git", from: "1.4.2")Full detail: CHANGELOG.md · Docs & gallery