Skip to content

Fix #206 — system font lookup on Linux through fontconfig - #207

Merged
sbeitzel merged 1 commit into
feature/fix_191from
feature/fix_206
Oct 3, 2026
Merged

sbeitzel merged 1 commit into
feature/fix_191from
feature/fix_206

Conversation

@sbeitzel

@sbeitzel sbeitzel commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Fix #206

Stacked on #205 (#191, which this builds on: SystemFonts.listing, availableFaces). Base is feature/fix_191; retarget to develop once #205 merges.

Lookup

  • New Fontconfig (Linux only): dlopen("libfontconfig.so.1") at first use, resolving FcInitLoadConfigAndFonts, FcPattern*, FcObjectSet*, FcFontList and FcFontSetDestroy. There is no build-time dependency. Where the library is missing, lookup finds nothing, as before.
  • FcFontList only, never FcFontMatch: a family that isn't installed must find nothing, not fontconfig's nearest guess.
  • SystemFonts.faces(family:), faces(postScriptName:) and listing use it on Linux. Faces in formats OpenTypeFont can't read (Type 1, PCF, …) are skipped by FC_FONTFORMAT before any file is read.
  • OpenTypeFont.summary(_:faceIndex:) reads names, weight, slant, format and fsType without parsing outlines, so the Linux listing costs one read per file. It shares readStyle with parse, so the listing and the provider can't disagree.
  • Docs: SVGRenderConfig.systemFonts and CONFORMANCE.md now describe Linux.

Tests and CI

  • The CI Linux job installs fontconfig fonts-liberation fonts-ebgaramond fonts-urw-base35 fonts-wqy-microhei and copies CeolKitTest.ttc into /usr/local/share/fonts, then runs the tests with CEOLKIT_FONT_FIXTURES=1.
  • FontconfigTests (compiled only without CoreText):
    • Ungated: an absent family or PostScript name finds nothing.
    • Gated:
      • PostScript-name lookups across CFF .otf, TrueType, .otf installed beside Type 1, and .ttc face 0;
      • Times-Bold → LiberationSerif-Bold, reported as a note;
      • family lookup in the requested weight and style;
      • .ttc face 1 (CeolKitTest-Restricted): drawn as <text>, refused as outlines with fontNotEmbeddable;
      • the listing includes these faces with the right format, weight, style and embeddability, and lists each Nimbus .otf face once.
  • Verified in Docker (swift:6.3):
    • without fonts, the gated tests skip (17 run in the two suites);
    • with fonts and the flag, the full suite passes (1457 tests);
    • sabotage checks: ignoring the query pattern fails the absent-family test, and a missing library fails the fixture tests (30 issues).
  • macOS: swift test passes; the CoreText path is unchanged.

🤖 Generated with Claude Code

- Fontconfig: libfontconfig.so.1 loaded with dlopen at first use (no build-time
  dependency; absent library = no system fonts, as before). FcFontList only, never
  FcFontMatch, so an uninstalled family finds nothing.
- SystemFonts: family and PostScript-name lookups and the listing go through it on
  Linux; faces in formats OpenTypeFont cannot read (Type 1, bitmap) are passed over.
- OpenTypeFont.summary: names, weight, slant, format and fsType without parsing
  outlines, sharing readStyle with parse.
- CI Linux job installs fontconfig, Liberation, EB Garamond, URW base 35, WenQuanYi
  and the CeolKitTest.ttc fixture, and sets CEOLKIT_FONT_FIXTURES=1 for the gated
  FontconfigTests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sbeitzel
sbeitzel merged commit ed94c44 into feature/fix_191 Oct 3, 2026
@sbeitzel
sbeitzel deleted the feature/fix_206 branch October 4, 2026 04:01
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