gpui_macos: Fix glyph rendering when fonts share a PostScript name (#57250)

On macOS, `load_family` was inserting every font into
`font_ids_by_postscript_name` without checking for duplicates. When two
installed font files claim the same PostScript name — typically an older
Geist Mono left behind alongside the current brew cask — the second
insert overwrote the first. After shaping, `id_for_native_font` looked
up that PostScript name and got back the *other* font's `FontId`, so the
rasterizer drew glyphs from the wrong table
See #55472 for the screenshot

This adds a local `HashSet` to dedup within a single `load_family` call.
Scoping it to one call (rather than the global map) matters: the same
family gets reloaded under different `FontKey`s when `FontFeatures` or
`FontFallbacks` change, and a global check would skip every font on the
reload and break weight selection.

Cross-family PostScript name collisions and CoreText fallback
substitutions that re-introduce a conflict are out of scope here

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed glyph rendering when fonts share a PostScript name on macOS

---------

Co-authored-by: Lukas Wirth <lukas@zed.dev>
This commit is contained in:
Ankan Misra 2026-07-07 14:29:55 +05:30 committed by GitHub
parent e7803a88f5
commit 20a93f6195
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,6 @@
use anyhow::anyhow;
use cocoa::appkit::CGFloat;
use collections::HashMap;
use collections::{HashMap, HashSet};
use core_foundation::{
array::{CFArray, CFArrayRef},
attributed_string::CFMutableAttributedString,
@ -282,6 +282,7 @@ impl MacTextSystemState {
let name = gpui::font_name_with_fallbacks(name, ".AppleSystemUIFont");
let mut font_ids = SmallVec::new();
let mut postscript_names_seen = HashSet::default();
let family = self
.memory_source
.select_family_by_name(name)
@ -340,15 +341,38 @@ impl MacTextSystemState {
.is_some())
} {
log::error!(
"Failed to read traits for font {:?}",
font.postscript_name().unwrap()
"Failed to read traits for font {:?} (PostScript name {:?})",
font.full_name(),
font.postscript_name(),
);
continue;
}
let Some(postscript_name) = font.postscript_name() else {
log::warn!(
"font {:?} in family {:?} has no PostScript name; skipping",
font.full_name(),
name,
);
continue;
};
// Dedup is scoped to this single `load_family` call (issue #55472).
// The same family can be reloaded later under a different `FontKey`
// (different features/fallbacks); a global check against
// `font_ids_by_postscript_name` would skip every already-registered
// font and leave the second call's `font_ids` empty.
if !postscript_names_seen.insert(postscript_name.clone()) {
log::warn!(
"skipping duplicate font {:?} with PostScript name {:?} \
in family {:?}",
font.full_name(),
postscript_name,
name,
);
continue;
}
let font_id = FontId(self.fonts.len());
font_ids.push(font_id);
let postscript_name = font.postscript_name().unwrap();
self.font_ids_by_postscript_name
.insert(postscript_name.clone(), font_id);
self.postscript_names_by_font_id