Fix #189 — OpenTypeFont reads TrueType outlines and font collections - #200
Merged
Merged
Conversation
OpenTypeFont could only outline CFF-flavoured faces and rejected
collections outright, which ruled out most installed fonts (Times.ttc,
Courier New.ttf, DejaVu, Liberation).
- TrueTypeGlyphs reads glyf via loca, both short and long formats.
- Simple glyphs: run-length flags, short and long deltas, implied
on-curve midpoints, contours that start off-curve or have no on-curve
point. Contours start where fontTools and FreeType start them.
- Composite glyphs: byte and word offsets, the three transform forms,
and SCALED_COMPONENT_OFFSET. Nesting is limited to 8 levels, so a
cycle throws compositeTooDeep instead of recursing forever.
Point-matched components are skipped.
- Hinting instructions are ignored.
- GlyphPath gains .quadCurve, emitted as SVG Q, plus an affine transform
for composite components.
- Collections: parse(_:faceIndex:), parse(_:postScriptName:), and
postScriptNames(in:) from name ID 6. Table offsets are file-relative in
both single fonts and collections.
- OS/2.fsType is exposed as EmbeddingPermissions. allowsOutlineEmbedding
refuses restricted, bitmap-only and no-subsetting faces, ready for #190.
The bundled CFF faces take the same path as before.
Fixtures are CeolKit's own fonts, generated by a committed fontTools
script, with fontTools' reading of the same bytes as the reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #189
What changed
TrueTypeGlyphs(new): readsglyfthroughloca, in both the short and long formats.Zalone.ARG_1_AND_2_ARE_WORDSand byte offsets;WE_HAVE_A_SCALE,X_AND_Y_SCALEandTWO_BY_TWO;SCALED_COMPONENT_OFFSET(unlessUNSCALED_COMPONENT_OFFSETis also set);compositeTooDeepis thrown, so a self-including composite fails instead of recursing forever.ARGS_ARE_XY_VALUESclear) are skipped. The issue allows this for now; there is no diagnostic channel this deep in font parsing.GlyphPath:.quadCurve(control:to:), written as SVGQ. Quadratics are kept as they are rather than converted to cubics, which keeps the path data smaller.transformed(…)for placing composite components.OpenTypeFont.parse(_:faceIndex:),parse(_:postScriptName:)andpostScriptNames(in:), the last readingnameID 6.postScriptName.faceNotFound.OpenTypeFont.embedding: EmbeddingPermissions, read fromOS/2.fsType.allowsOutlineEmbeddingrefuses Restricted License, bitmap-only and no-subsetting faces; an outline document embeds only the glyphs it draws, which is a subset. Font provider: use host-registered and system fonts instead of bundling more faces #190 will use this to fall back to a bundled face.Fixtures
Tests/CeolKitSVGRendererTests/Resources/truetype-fixtures.pygenerates three fonts with CeolKit's own outlines, so there is no third-party licence.truetype-fixtures-PROVENANCE.txtdescribes them.CeolKitTest-Short.ttfandCeolKitTest-Long.ttf: the same glyphs with eachlocaformat. The long format is forced by giving one glyph an odd-length hinting program.CeolKitTest.ttc: two faces with different PostScript names andfsTypevalues (0 and Restricted).The fixtures cover on-curve-only contours, implied midpoints, an off-curve start, an all-off-curve contour, composites with byte and word offsets, all three transforms, a nested composite and a point-matched component. The oracle is fontTools' own reading of the same bytes, recorded in
truetype-reference.json.Tests (
TrueTypeOutlineTests, 10)locaformats, along with its advance width.Qpath data for an all-off-curve contour.compositeTooDeep.fsTypedecoding./System/Library/Fonts/Supplementalare compared with CoreText for glyph IDs and control-point bounding boxes acrossAgQé&ß. This test is skipped where the files are missing. It catches misplaced or missing contours and composite parts, but not errors in implied midpoints; the reference tests cover those.With the midpoint arithmetic deliberately broken, the reference tests fail (17 issues).
swift test: all tests pass.Out of scope (per the issue)
GPOS/GSUB.glyfcubic-flag extension.🤖 Generated with Claude Code