From 7f74def4b5ebcd84d129abaef54a46dd85a9604a Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 11 Jun 2026 12:50:36 -0400 Subject: [PATCH] gpui_macos: Initialize fallback fonts with primary font weight and style (#56771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes an issue where font properties like bolds and italics would be lost when falling back to a fallback font. The problem we identified was that when loading the fallback fonts, we were just loading them by name. This meant that when the original font had a different font weight (e.g., bold) or style applied to it this would not cascade to the fallback font. To reproduce the problem, we used the following text in a Markdown file: ```md **한글 bold** ``` With the following font configuration in Zed: ```json "buffer_font_family": "Victor Mono", "buffer_font_fallbacks": [ "D2Coding" ] ``` The fonts can be obtained from their respective locations: - [Victor Mono](https://rubjo.github.io/victor-mono/) - [D2Coding](https://github.com/naver/d2codingfont) #### Before Screenshot 2026-05-14 at 1 15 15 PM #### After Screenshot 2026-05-14 at 1 16 04 PM Closes #51460. Release Notes: - macOS: Fixed fallback fonts missing weight/style. --------- Co-authored-by: Mikayla Maki --- crates/gpui_macos/src/open_type.rs | 53 ++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/crates/gpui_macos/src/open_type.rs b/crates/gpui_macos/src/open_type.rs index 8a30508de2..4489191038 100644 --- a/crates/gpui_macos/src/open_type.rs +++ b/crates/gpui_macos/src/open_type.rs @@ -15,6 +15,10 @@ use core_foundation::{ }; use core_foundation_sys::locale::CFLocaleCopyPreferredLanguages; use core_graphics::{display::CFDictionary, geometry::CGAffineTransform}; +use core_text::font_descriptor::{ + TraitAccessors, kCTFontFamilyNameAttribute, kCTFontItalicTrait, kCTFontSlantTrait, + kCTFontTraitsAttribute, kCTFontWeightTrait, kCTFontWidthTrait, +}; use core_text::{ font::{CTFont, CTFontRef, cascade_list_for_languages}, font_descriptor::{ @@ -39,10 +43,7 @@ pub fn apply_features_and_fallbacks( && !fallbacks.fallback_list().is_empty() { keys.push(kCTFontCascadeListAttribute); - values.push(generate_fallback_array( - fallbacks, - font.native_font().as_concrete_TypeRef(), - )); + values.push(generate_fallback_array(fallbacks, font)); } let attrs = CFDictionaryCreate( kCFAllocatorDefault, @@ -98,16 +99,54 @@ fn generate_feature_array(features: &FontFeatures) -> CFMutableArrayRef { } } -fn generate_fallback_array(fallbacks: &FontFallbacks, font_ref: CTFontRef) -> CFMutableArrayRef { +fn generate_fallback_array(fallbacks: &FontFallbacks, font: &mut FontKitFont) -> CFMutableArrayRef { unsafe { + let symbolic_traits = font.native_font().symbolic_traits(); + let all_traits = font.native_font().all_traits(); + let fallback_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); for user_fallback in fallbacks.fallback_list() { let name = CFString::from(user_fallback.as_str()); - let fallback_desc = - CTFontDescriptorCreateWithNameAndSize(name.as_concrete_TypeRef(), 0.0); + + let traits_keys = [kCTFontWeightTrait, kCTFontSlantTrait]; + let weight_value = CFNumber::from(all_traits.normalized_weight()); + let slant_value = CFNumber::from(if (symbolic_traits & kCTFontItalicTrait) != 0 { + 1.0 + } else { + 0.0 + }); + let traits_values = [weight_value.as_CFTypeRef(), slant_value.as_CFTypeRef()]; + let traits = CFDictionaryCreate( + kCFAllocatorDefault, + &traits_keys as *const _ as _, + &traits_values as *const _ as _, + traits_keys.len() as isize, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks, + ); + drop(weight_value); + drop(slant_value); + + let attr_keys = [kCTFontFamilyNameAttribute, kCTFontTraitsAttribute]; + let attr_values = [name.as_CFTypeRef(), traits as _]; + let attrs = CFDictionaryCreate( + kCFAllocatorDefault, + &attr_keys as *const _ as _, + &attr_values as *const _ as _, + attr_keys.len() as isize, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks, + ); + CFRelease(traits as _); + + let fallback_desc = CTFontDescriptorCreateWithAttributes(attrs); + CFRelease(attrs as _); + CFArrayAppendValue(fallback_array, fallback_desc as _); CFRelease(fallback_desc as _); } + + let font_ref = font.native_font().as_concrete_TypeRef(); append_system_fallbacks(fallback_array, font_ref); fallback_array }