Files
ghostty-rs/docs/rewrite/notes/macos-M1-font.md
T
ddidderr 452b782149 feat(macos): port Ghostty's macOS code paths (Metal, CoreText, Darwin)
Ports the macOS-specific Zig code behind cfg(target_os = "macos"):
- renderer: a GraphicsApi trait with generic::Renderer<G>; Metal backend
  (all renderer/metal/* files, shaders.metal verbatim, runtime library
  compile, IOSurface layer, CVDisplayLink), shadertoy -> MSL via naga;
  OpenGL remains the backend elsewhere.
- font: CoreText face, shaper and discovery with build.rs backend
  selection (coretext default; coretext-freetype / coretext-harfbuzz /
  coretext-noshape features), no fontconfig/freetype/harfbuzz on Apple.
- input: KeymapDarwin via UCKeyTranslate, option-as-alt, mac keycodes.
- os: macos, mach, cf_release_thread, NSProcessInfo args and macOS
  branches; config: macOS defaults, keybinds, Application Support paths.
- termio/core: login(1) wrapping, openpty/execvpe, Darwin child exit
  handling, os_log logging.

Compile-checked for aarch64/x86_64-apple-darwin (clippy -D warnings
clean) using the cross setup in docs/rewrite/notes/macos-M1.md; cannot
run here. The embedded runtime/C API (embedded.zig) is the next step.

Also includes the cross-platform integration edits shared by the crash,
verification, Windows and macOS work (Cargo target-gating, thread
crash-context hooks, apprt-gtk surface/IME refactor, termio/os cfg
gates), a cfg fix so ghostty-config builds on wasm32, and an allow for
the intentional recursion in the crash overflow test.

Test Plan:
- cargo test --workspace (3224 passed)
- cargo clippy --workspace --all-targets -- -D warnings
- cargo check --target aarch64-apple-darwin -p ghostty-renderer (with
  the documented cross env)
2026-10-12 06:02:39 +02:00

57 lines
4.4 KiB
Markdown

# macOS CoreText font backend (M1 / font)
Crate: `ghostty-font`. Compile-checked with
`cargo check|clippy --target aarch64-apple-darwin|x86_64-apple-darwin -p ghostty-font --all-targets`
(clean, `-D warnings`); never run on real macOS. Linux behaviour unchanged
(`cargo test -p ghostty-font`: 203 pass / 3 ignored, clippy `-D warnings`, nightly fmt).
## Backend selection (`font/backend.zig`)
`build.rs` emits cfgs from target + cargo features: `font_freetype`, `font_fontconfig`,
`font_harfbuzz`, `font_coretext` (Apple), `font_coretext_face`, `font_coretext_shaper`, `font_noshape`.
* Linux/other: fontconfig + FreeType + HarfBuzz (unchanged). wasm32: web_canvas (unchanged).
* Apple targets, default `Backend::Coretext`: CoreText discovery/face/shaper; freetype-sys,
harfbuzz-sys, fontconfig are NOT linked (freetype/harfbuzz are optional deps, `bundled`, apple only).
* Cargo features (apple only): `coretext-freetype` (CT discovery, FreeType face, HarfBuzz shaper),
`coretext-harfbuzz` (CT face + HarfBuzz via `hb_coretext_font_create`), `coretext-noshape`
(no-op shaper). `backend::OPTIONS` follows the features. `face::DEFAULT_DPI` is 72 on macOS.
## Module map (Zig -> Rust, `crates/ghostty-font/src/`)
| Zig | Rust |
|---|---|
| face/coretext.zig | `face/coretext.rs` (CTFont face, CoreGraphics bitmap rasterization, `ColorState`) + `face/coretext_math.rs` (pure math, tested on Linux) |
| shaper/coretext.zig | `shaper/coretext.rs` (CTTypesetter/CTLine/CTRun, feature dicts, per-font attr-dict cache) + `shaper/coretext_cells.rs` (pure cluster/ligature logic, tested) + `shaper/cf_release.rs` |
| discovery.zig CoreText + `toCoreTextDescriptor` | `discovery_coretext.rs` (`CoreText`, `Score`-based sorting, CJK / `CTFontCreateForString` fallbacks) |
| DeferredFace.zig CoreText | `deferred_face_coretext.rs` (+ `coretext_freetype` file-path load) |
| library.zig (noop for CT) | `library.rs` (empty library when no FreeType) |
| SharedGridSet.zig Apple Emoji branch | `shared_grid_set.rs` (Apple Color Emoji via discovery on CT; embedded Noto emoji otherwise) |
| (CF helpers of the `macos` package) | `coretext_util.rs` (`CfBox` Send+Sync wrapper, tables, glyph lookup, variation axes) |
API unification (so collection/grid/resolver stop naming `face::freetype::*`): `face::{Face, FaceError,
RenderError, HbFont}`, `shape::{Shaper, ShapeError, ShapeRunError}`, `discovery::{Discover, NextError}`.
`discover_fallback` now takes `&mut Collection` (CT needs `get_face`); no-op shaper gained `shape_run`,
`ShapeError` and `new -> Result`.
## Tests
Ported & platform-independent (run on Linux): metrics table priority (OS/2 typo vs hhea vs win),
underline/strikethrough fallbacks, synthetic-bold width, glyph bearing/canvas layout (incl. sbix, thicken,
bold), UTF-16/surrogate table, CoreText cell building incl. ligature/out-of-order-cluster/non-LTR heuristics,
discovery `Score` ordering, style fuzzy/exact scoring, variation-axis bold/italic thresholds, backend
capability predicates. macOS-only tests written but not runnable here (`#[cfg(font_coretext...)]`):
face (Monaco ASCII, name, emoji, in-memory, variable, set variation, SVG table, glyphIndex colored vs text),
discovery (coretext, codepoint, sorting), deferred face. The Zig CoreText shaper tests (23, need
Terminal/RenderState + system fonts) are NOT ported; resolver/collection tests adjusted for CT
(`Coretext doesn't support Noto's format`, text-emoji index 1).
## Caveats / TODO(integration)
* Never executed on macOS: rasterization (CGBitmapContext flags, colour spaces), shaping and discovery are
faithful ports but unverified at runtime.
* `coretext-freetype` / `coretext-harfbuzz` cannot be cross-checked here: bundled harfbuzz with CoreText
needs the macOS SDK headers (`ApplicationServices`). `coretext-noshape` and the default are checked.
* `face_metrics` returns `Some(..)` for cap/ex/ascii height always (Zig returns plain values for CT).
* CF release thread is local to the font crate (`shaper/cf_release.rs`, std thread + channel);
switch to `ghostty_os::cf_release_thread` once that exists.
* `Face::init` copies in-memory font data into a CFData (Zig used no-copy).
* Renderer crate must use `ghostty_font::shape::{ShapeError, ShapeRunError}` instead of
`shaper::harfbuzz::{ShapeError, ShapeRunError}` (generic.rs lines ~144-146) to build on macOS.
* Cross-check env: `CC_<target>`/`AR_<target>` zig-cc wrappers (onig_sys C build); `GETTEXT_DIR` dummy.