Fix #190 — font lookup: registered, system and bundled faces - #201
Merged
Merged
Conversation
The renderer could draw text only in the faces it bundles, and OutlineFontSet.resolve answered nil for any other name. - FontRequest (public): family, weight and style, or parsed from a PostScript name (Times-BoldItalic, Helvetica-Oblique). The base 14 and the generic families (serif, sans-serif, monospace) list stand-ins: Times/Times New Roman/Liberation Serif/Nimbus/DejaVu and so on. - FontLibrary (public, immutable, Sendable): faces the host supplies as font Data, CFF or TrueType, single faces or collections, parsed once. Set on SVGRenderConfig.fontLibrary. Per-config rather than process-wide, so a config always gives the same output. - SVGRenderConfig.systemFonts (default false): installed fonts on Apple platforms. CoreText only locates the file and face, which our own parser (#189) then reads, so every face is outlined and fsType-checked by the same code. With a mandatory attribute set, CoreText's everything-is-Helvetica fallback cannot answer a missing family. - FontProvider resolves a request through registered, then system, then bundled faces. For each family (asked-for first, then stand-ins), an exact face from any source beats a near one. Faces whose fsType forbids embedding are skipped when outlining. Results are cached per provider. The emitter's own Bravura and Libertinus Serif requests go straight to the bundle, so existing output is unchanged. - FontResolution (public) records the face used, its origin and any refusals. diagnostics(at:) produces .fontSubstituted (info for a stand-in, warning otherwise) and .fontNotEmbeddable, for #186 to report against the directive that named the font. - FaceKey becomes an open-ended key. Bundled faces keep their ids; other faces get "f-<PostScript name>". - TextOutliner.outline(_:font:fontSize:fill:library:systemFonts:) draws a named face, and OutlinedText.resolution says which face was used. - OpenTypeFont reads family (name 16/1), usWeightClass and italic, with head.macStyle as the fallback for faces without OS/2 (macOS Courier.ttc). 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 #190
What changed
FontRequest(public): a family, weight (regular/bold) and style (upright/italic, with oblique counted as italic).init(postScriptName:)parsesTimes-Roman,Times-BoldItalic,Helvetica-Oblique,Courier-Boldand similar names, and keeps the original name for an exact match.serif/sans-serif/monospacecome with stand-in lists, following abcm2ps (serif = Times, sans-serif = Helvetica): the macOS/Windows equivalents, then Liberation, Nimbus (URW) and DejaVu.FontLibrary(public, immutable,Sendable): fonts the host supplies asData, CFF or TrueType, single fonts or collections (OpenTypeFont: read TrueType (glyf) outlines and font collections (.ttc) #189), parsed once.SVGRenderConfig.fontLibrary.SVGRenderConfig.systemFonts, defaultfalse, uses installed fonts on Apple platforms. On Linux there is no system lookup; a host supplies fonts throughFontLibraryinstead.FontProviderresolves a request:fsTypeforbids embedding is skipped when outlining.BravuraandLibertinus Serifrequests go straight to the bundled fonts, so existing output is unchanged. The snapshot tests pass.FontResolution(public) records the face used, its origin and any faces refused.diagnostics(at:)produces two new codes:.fontSubstituted: an info note when a stand-in answered, otherwise a warning;.fontNotEmbeddable: a warning.Support the §11.4.2 font directives (%%titlefont, %%vocalfont, %%wordsfont, …) #186 will report these against the directive that named the font.
FaceKeyis now an open-ended key. The bundled fonts keep their<defs>ids, and other fonts getf-<PostScript name>.TextOutliner.outline(_:font:fontSize:fill:library:systemFonts:)draws text in a named font.OutlinedText.resolutionreports which face was used.OpenTypeFontnow also reads the family name (nameID 16, else 1),usWeightClassand the italic flag. Where a font has noOS/2table (macOS's ownCourier.ttc), weight and italic come fromhead.macStyle.A deliberate departure from the issue
The issue suggested converting CoreText glyph paths (
CTFontCreatePathForGlyph→CGPath→GlyphPath). Instead, CoreText is used only to find the font file and face name, and the file is read by our own parser from #189. As a result, every face, wherever it came from, goes through the same measuring, outlining andfsTypechecks, and a system font draws exactly as the same file supplied by a host would. A system font in a format we can't read is skipped.Lookups pass the family or PostScript name as a mandatory attribute. Otherwise CoreText answers any query, including one for a family that isn't installed, with some fallback face (usually Helvetica).
Tests (
FontProviderTests, 14)fsType 0x0002) face is refused, producingfontNotEmbeddableandfontSubstituted.SVGBuilderwritesf-CeolKitTest-Regular-g…glyph definitions for a host-supplied font.Courier-Boldresolves through CoreText to the system'sCourier-Boldand is outlined (0.6 em monospaced advances);serifitalic →Times-Italic, reported as an info note;swift test: all tests pass on macOS. Linux: built and tested in theswift:6.3container as CI does, and all 1,420 tests pass (the CoreText tests compile out).Not yet wired
Nothing in a document names a font yet. #186 will map the font directives onto
FontRequest, reportFontResolutiondiagnostics at the directive's source, and route layout measurements through the provider. #191 builds onFontResolutionandFontLibrary.🤖 Generated with Claude Code