Skip to content

fix: lift TrueType quadratics to cubics on binary import#120

Merged
kostyafarber merged 1 commit into
mainfrom
fix/ttf-quad-import
Jul 2, 2026
Merged

fix: lift TrueType quadratics to cubics on binary import#120
kostyafarber merged 1 commit into
mainfrom
fix/ttf-quad-import

Conversation

@kostyafarber

Copy link
Copy Markdown
Collaborator

Closes the TTF-import geometry-corruption path from the 2026-07 review: the binary reader emitted quadratic segments as generic off/on-curve runs, which the UFO writer then classified as spec-invalid one-control-point cubics.

  • quad_to now lifts each quadratic to its exact cubic equivalent (c1 = q0 + ⅔(q1−q0), c2 = q2 + ⅔(q1−q2)) — mathematically lossless. Policy documented at the site: binary imports produce cubic-only IR (wire/renderer layers don't support quadratics).
  • Bonus bug found in the pen audit: skrifa's finish() emits an explicit on-curve at the start coordinates before close() when a contour's last segment ends at its start point — the old pen kept it, so closed contours imported with a duplicated first/last point (confirmed on MutatorSans's O). Now deduped.
  • Verified against skrifa 0.32's pen contract in source: implied on-curve midpoints are resolved before the pen is called.

Tests: structural validator over every contour of MutatorSans .ttf and .otf (every on-curve preceded by exactly 0 or 2 off-curves, no duplicated closing points); geometric fidelity sampled at 1e-9 against skrifa's own quad elements; end-to-end TTF → UFO → norad reload asserting every curve is spec-valid. Regression-verified: tests fail against the old reader with the fix stashed.

cargo test --workspace: 306 passed, 0 failed. clippy zero warnings.

🤖 Generated with Claude Code

The binary reader's pen emitted each quadratic as a single off-curve
plus an on-curve, which the UFO writer then classified as a cubic
curve segment with one control point — corrupting TTF imports on
save. Each quad is now lifted to its exact cubic equivalent, keeping
the IR cubic-only (the wire and renderer layers have no quadratic
support).

Also drop the duplicate start point skrifa emits when a contour's
closing segment is a curve; closed contours already imply a return to
the first point.
@kostyafarber kostyafarber merged commit 878ea20 into main Jul 2, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant